Take the Rough with the Smooth Part 4 (PIC Microcontroller)

At the same time as the comparison is resolved, delta will be updated to reflect the outcome (i.e. +1 if analog < (PORT_B + delta), -1 if analog > (PORT_B + delta)). The value delta is returned by the function to allow the caller function to update its variable hysteresis. Thus to activate the comparator outputs and also update hysteresis at the same time the caller might have a statement such as hysteresis = compare(hysteresis);. An alternative would be to define the variable hysteresis before the main function main() making it global; that is known to all functions. In this situation its value need not be passed by the caller back and forth to any appropriate function.

The declarations #use fast_io(n);have not been used here as the input(pin) and output_bit(pin,value) internal functions have not been used and the ports have been treated as simple memory bytes.

Conversion from a digital quantity to an analog equivalent is somewhat simpler than the converse and not so commonly required. Perhaps for these reasons digital to analog converters (DACs) are not often found as an integral function in most MCU families.

We have already seen that a rather crude way of providing this mapping is to vary the mark:space ratio of a pulse train of constant repetitive duration, as shown in Fig. 13.9. Here a small digital number gives a skinny pulse, which when smoothed out by a low-pass filter (which gives the average or d.c. value) translates to a low voltage. Conversely, a large digital number leads to a correspondingly large mark:space ratio, which in turn after smoothing yields a higher voltage.


PWM conversion can be very accurate and is simple to implement. However, extensive filtering is required to remove harmonics of the pulse rate and this makes the conversion slow to respond to changes in the digital input. Normally PWM is used to control heavy loads, such as motors or heaters, where the inertia of these devices inherently provides the smoothing action. Furthermore, the pulsed nature of the signal is ideally suited to power control, activating thyristor firing circuits.

Many commercial DAC devices are available which can be controlled via standard digital I/O ports. Two examples were given in Figs. 12.4 and 12.6 where the MCU transferred digital data in series. Here we will look at an example where parallel data transfer is used.

The majority of proprietary devices are based on an R-2R ladder network, such as that shown in Fig. 14.12(a). Voltage appearing at any bit switch node emerges at the output node in an attenuated form. As our analysis will show, each move to the left attenuates this voltage bn by 50%, which is the binary weighting relationship:

tmpA72_thumb[2][2][2]

for an N-bit word.

In Fig. 14.6(b) at mode A looking to the left we see a resistance of R (2R// 2R) and the voltage is attenuated by two. As we move to the right the process is repeated with each voltage divided by two. Thus, at node B the voltage b0/2 is further divided by two and the next digital node voltage is divided by two giving VB= b0/4 + b1/2. As the network is symmetrical the resistance looking right at any mode is also 2R. This means that as seen from any digital switch, the total resistance is 2R + 2R//2R = 3R. This is important as the characteristics of a transistor switch, such as resistance, are dependent on current and keeping this the same reduces error.

For clarity our analysis has been for three bits. This can be extended by simply moving the leftmost terminating resistor over and inserting the requisite number of sections. This does not affect the resistance as seen left of the mode, and therefore does not change the conditions of the rightmost sections. An inspection of our analysis shows that nowhere does the absolute value of resistance appear. In fact the accuracy of the analysis depends only on the R:2R ratio. While it is relatively easy to fabricate accurate ratioed resistors on a silicon die, this is certainly not the case for absolute values. For this reason R:2R networks are the standard technique used for most integrated circuit DACs.

R-2R digital-to-analog conversion.

Fig. 14.11 R-2R digital-to-analog conversion.

The Maxim MAX506 is an example of a commercial D/A converter (DAC). This 20-pin footprint device contains four separate DACs sharing a common external Vref. Digital data is presented to the D7:0 pins and one of four latch registers selected with the A1:0 address inputs. Once this is done, the datum byte is loaded into the selected register n and appears at the corresponding output VOUTn.

This output analog voltage ranges from zero (Analog GrouND) for a digital input of 00h through to Vref for a digital input of FFh.

Where VSS is connected to ground then Vref can be anything between 0 V and VDD (+5 V). However, VSS can be as low as – 5 V and in this case Vref can be anywhere in the range ± 5 V. If Vref is negative for dual supplies then the output voltage will also be negative. In either case, effectively the output can be treated as the product D x Vref where D is the digital input byte scaled to the range 0-1 (00 – FFh).

The MAX505 24-pin variant allows for separate reference voltages to be used for each of the four DAC channels. In addition, the MAX505′s DAC latches are isolated from the converter ladder circuits by a further layer of latches all clocked at the same time with a LDAC (Load DAC) control signal. This double buffering permits the programmer to update all four DACs simultaneously after their individual latches have been set up.

As an example, consider that a MAX506 quad DAC has its Address selected via RA1:0 and RA2 drives the WR input to latch in the addressed data from Port B. A software routine to generate a continuous staircase sawtooth waveform from DACD would look something like:

tmpA-74_thumb[2][2][2]

where we are assuming that PortB and PortA[2:0] have been set up as outputs.

A typical DAC staircase output waveform is shown in the oscillogram in Fig. 14.13. Here a 12 MHz crystal clocked PIC is shown which, with a loop cycle count of 6 cycles, gives a sawtooth duration of (256 x 6)/3 -0.5 ms at 2 /is per step.

The Maxim MAX506 quad 8-bit D/A converter.

Fig. 14.12 The Maxim MAX506 quad 8-bit D/A converter.

Generating a continuous sawtooth using a MAX506 DAC.

Fig. 14.13 Generating a continuous sawtooth using a MAX506 DAC.

Examples

Example 14.1

Augment the interrupt-driven ISR of Program 14.2 to implement a 16-deep buffer array of data to allow a limited mismatch between acquisition and reading rates.

Solution

One approach is shown in Fig. 14.14. A block of file registers is set aside by the programmer together with any other variables used by the programmer with a cblock directive of the form:

tmpA-77_thumb[2][2][2]

and the File Select Register used as a buffer pointer to the next empty location in the array of samples.

In acquiring data the foreground ISR of Program 14.6 simply pushes the datum from the ADRES into the location pointed to by the FSR using the indirect address mode and then increments this pointer ready for the next event.

Buffered data acquisition.

Fig. 14.14 Buffered data acquisition.

The problem with this approach is that if the background program does not pull data out of the buffer quickly enough, decrementing the FSR, the buffer will overflow. As a consequence, if there are variables stored above ARRAY+15 then they will be overwritten. In order to avoid this problem, on overflow no more data should be saved and the state of the OVERFLOW file register set to non zero to show the background software that data has been lost.

Based on this ISR, a background routine to fetch data from the buffer would be something like this:

tmpA-79_thumb[2][2][2]

Program 14.6 Buffered interrupt-driven data acquisition.

Program 14.6 Buffered interrupt-driven data acquisition.

It is essential to avoid any alteration to the FSR during a background buffer fetch, so GIE is zeroed before and enabled after the process to disable interrupts. If the buffer pointer is at the bottom of the array then no update is carried out and the file register EMPTY is left at zero to show that the buffer was empty. Otherwise the datum pointed to is copied to the Working register; the buffer pointer is decremented and EMPTY is set to non zero.

Example 14.2

Using C coding show how a digitized reading from Channel 3 of a PIC16C74 can be acquired with the processor in its Sleep state.

Solution

The CCS compiler uses the s1eep() function to put the MCU to sleep – this simply translates to the sleep instruction. A Sleep conversion cannot be implemented using the read_adc() function of Program 14.5 as this continuously polls the GO/DONE flag until it drops low. Instead we need to set and clear individual interrupt related bits before going to sleep in the manner outlined in the assembly-level Program 14.4. On wakening the state of ADRES can then be read ‘manually’.

Program 14.7 Sleep conversion in C.

Program 14.7 Sleep conversion in C.

Coding for this specification is shown in Program 14.7. Here the GO/DONE, PEIE and ADIF bits are defined using the #bit directive. This time the script ADC_CLOCK_INTERNAL is used with the setup_adc() internal function to select the internal CR clock for the DAC module, as necessary for the Sleep conversion.

The internal function disab1e_interrupts(GLOBAL) clears both GIE and PEIE mask bits. The complementary enab1e_interrupts(GLOBAL) sets both bits but we need to enable the PEIE only and leave GIE cleared. This is implemented by the ‘bit-twiddling’ statement PEIE=1;. Similarly, clearing the ADIF flag is directly actioned by ADIF=0;. Before calling sleep() the statement GO=1; manually starts the conversion. After sleep() the ADRES register is read giving the required digitized equivalent.

Example 14.3

The analog input channel voltage range for the PIC16C7X/71X devices10 is limited to the positive range 0-Vref, where Vref can either be the internal VDD voltage or an external voltage at RA3 in the range 3-VDD. Many situations require a digitized mapping from bipolar analog signals. Design a simple resistive network to translate a bipolar voltage range of ± 10 V to a unipolar range of 0-5 V, assuming Vref is +5 V.

Solution

A level-shifting resistor network.

Fig. 14.15 A level-shifting resistor network.

One possibility is shown in Fig. 14.15. In calculating the value of the three resistors, the following transfer relationships must be adhered to: 1. The value of Vref must appear at the summing node attenuated by 2 when Vin is zero; that is half scale. Thus a zero voltage 0 V 10000000b. To do this R1 paralleled with R2 must have the same resistance as R3; i.e.:

tmpA83_thumb[2][2][2]

Of course we have three unknowns and only two equations so we have to start off by choosing a value for one of them below 10 kQ, which is the maximum recommended value for input resistance. Picking 5 kQ for R3 gives R2 as 2 x 5 = 10kQ and R2 as R1 /(G — 1) = 10kQ.

For the situationtmpA84_thumb[2][2][2]thentmpA85_thumb[2][2][2]and R2 = R3.

Next post:

Previous post: