Файл: Interfacing with C plus plus-programing communication with microcontrolers (K. Bentley, 2006).pdf

ВУЗ: Не указан

Категория: Не указан

Дисциплина: Не указана

Добавлен: 14.06.2025

Просмотров: 3561

Скачиваний: 1

ВНИМАНИЕ! Если данный файл нарушает Ваши авторские права, то обязательно сообщите нам.

11 ANALOG-TO-DIGITAL CONVERSION 351

Digital Inputs to the ADC: To drive the ADC input pin /START C., we can use data bit D0 of the port at address BASE+2. The ADC data bus is configured to an active state by connecting /CS and /READ directly to GND using interconnecting leads. We can do this because our ADC’s output data is not connected to a shared data bus.

Digital Outputs from the ADC: The software must read eight digital output signals from the ADC being sent through the parallel port (/DATA VALID not used). The parallel port has five input signals (D3 to D7) available from the port at address BASE+1. Note that we have not used port address BASE+2 in input mode as it can be unreliable at higher data transfer rates.

The interface board has been fitted with a four-channel 2-to-1 multiplexer (as shown in Figure 11-19) to provide extra capability for transfer of data to the port. If we make use of this device, we can transfer eight data bits to the port using only four signals. We do this by separating the eight data bits from the ADC into two groups of four bits. The first group is selected by the multiplexer and the port then reads these four data bits. This is followed by selection of the second group of four bits that are then read by the port. Note that we need one output data bit from the port to control the multiplexer’s selection operation. Since the eight bits from the ADC represent one byte of data, driving the multiplexer’s Select input low will select the low nibble (D0 to D3). Conversely, driving the Select input high will select the high nibble (D4 to D7).

/DATA VALID

D0

D0

D1

D1

VIN

D2

D2

ADC

D3

D3

/READ

D4

D4

Interconnect

Leads

/CS

D5

D5

D6

D6

D0

START C.

D7

D7

BASE+2

Address

D1

Select

MULTIPLEXER

(SW position)

(MUX)

D3 (not used)

D4

D5 BASE+1 Address

D6

D7

Figure 11-19 Complete ADC system using the Multiplexer.

Now that we know how to read the eight bits of data from the ADC using only four transmission signals, we can establish the configuration for the remainder of the


352 11 ANALOG-TO-DIGITAL CONVERSION

parallel port data bits. We can use four input data bits (D4 to D7) of the port at address BASE+1 to read the four output signals from the multiplexer that transmits the ADC output byte as two nibbles.

If you should decide to modify the program to detect the narrow output pulse /DATA VALID from the ADC, then connect a lead from this pin to data bit D3 of the port at BASE+1 and write extra program statements to read its status.

Digital Input to the Multiplexer: We can drive the Select input of the multiplexer to control which nibble at its input pins is switched to its output by using an output data bit (D1) of the port at address BASE+2.

A summary of all connections for interfacing the parallel port to the ADC, to the DAC, and to the Multiplexer is given in Table 11-4. This table does not provide the internal connections needed on the interface board between the ADC and the Multiplexer - they are shown in Figure 11-19.

Table 11-4 Parallel Port interface connections for the DAC, ADC, and MUX.

BASE Address

BASE+1 Address

BASE+2 Address

D0

DAC, D0

D3

(ADC, /DATA VALID)

D0

ADC, /START C.

D1

DAC, D1

D4

MUX, D4

D1

MUX, Select

D2

DAC, D2

D5

MUX, D5

D3

DAC, D3

D6

MUX, D6

D4

DAC, D4

D7

MUX, D7

D5

DAC, D5

D6

DAC, D6

D7

DAC, D7

Note: 1. ADC inputs /CS and /READ must be connected to GND using interconnect leads.

2.ADC output /DATA VALID is not used for our program.

3.Set DAC to Unipolar mode by fitting the jumper across header position marked LINK1.

We are now in a position to define the member function ADConvert(). Listing 11-2 shows one possible definition of the function.

Listing 11-2 Member function ADConvert().

unsigned char ADC::ADConvert()

{

//Declare variables to store nibbles. unsigned char LowNibble, HighNibble;

//Start conversion pulse.

WritePort2(0x01); // set /START C to high

WritePort2(0x00); // pull /START C to low


11 ANALOG-TO-DIGITAL CONVERSION 353

WritePort2(0x01); // set /START C back to high

//Set Select signal of multiplexer (D1) to logic-high and

//maintain /START C high. This operation takes more time

//than the conversion of the ADC, so we do not need to

//check for signal /DATA VALID. */

WritePort2(0x03); // 0000 0011

//Conversion finished by this time.

//Read high nibble and nullify low nibble.

HighNibble = ReadPort1() & 0xF0;

//Set Select signal of multiplexer (D1) to logic-low. WritePort2(0x01); // 0000 0001

//Read low nibble, move data bits across into position

//and nullify high nibble.

LowNibble = (ReadPort1() >> 4) & 0x0F;

// Form complete byte.

ADCValue = HighNibble + LowNibble;

return ADCValue;

}

The three statements from Listing 11-2 shown in bold typeface need explanation. Note that when reading the port at address BASE+1, only the bits D4-D7 carry data coming from the ADC. The data from the 8-bit ADC is read into the PC using these four bits in two stages; first the high nibble (four bits) is read and stored, followed by reading and storing the low nibble. Then the high and low nibbles are added to obtain the complete 8-bit result (ADCValue).

Actual data

Garbage data

1 0 1 1 0 1 0 1

Byte read from port at BASE+1

1 1 1 1 0 0 0 0

0xF0 used in AND operation

1 0 1 1 0 0 0 0

HighNibble Result, garbage bits forced to 0

Garbage bits forced to be zero

Figure 11-20 Reading the high nibble and filtering out unwanted bits.


354 11 ANALOG-TO-DIGITAL CONVERSION

We use the inherited member function ReadPort1() to read the high nibble through the port at address BASE+1 and then clear all unused bits that contain unpredictable (garbage) data (lower four bits) by carrying out an AND operation with 0xF0. This operation is shown in Figure 11-20.

When reading the low nibble, we first read the port and then shift these data bits by 4 locations to the right to reside in the low nibble of the final data byte. After shifting we carry out an AND operation with 0x0F to clear all bits in the high nibble that can contain unpredictable data. This is shown in Figure 11-21.

Wanted data Garbage data bits will drop out during shift operation

1 1 0 1 0 1 0 1

Byte read from port at BASE+1

Possibility of new

Shift to right by 4 positions

garbage data

? ? ? ? 1 1 0 1

Result of shift operation

0 0 0 0 1 1 1 1

0x0F used in AND operation

0 0 0 0 1 1 0 1

LowNibble Result, garbage bits forced to 0

Garbage bits forced to be zero

New location of wanted data

Figure 11-21 Reading the low nibble and filtering out unwanted bits.

Now we have an 8-bit number (unsigned char) named LowNibble, which has some data in the lower four bits and definitely zeros in the upper four bits. We also have an 8-bit number named HighNibble, which has some data in the upper four bits and definitely zeros in the lower four bits. Then we add these two bytes together to form one complete byte named ADCValue which has all 8 bits carrying the data from the analog-to-digital converter. Figure 11-22 shows the formation of ADCValue.

0

0

0

0

1

1

0

1

LowNibble

1

0

1

1

0

0

0

0

HighNibble

1

0

1

1

1

1

0

1

ADCValue

Figure 11-22 Add low & high nibbles to form the ADC output.

The function given in Listing 11-2 can be re-written in a slightly more efficient form as given in Listing 11-3. The data member ADCValue has been used to combine an operation and eliminate the need for variables LowNibble and

HighNibble.


11 ANALOG-TO-DIGITAL CONVERSION 355

Listing 11-3 A more efficient version of ADConvert().

unsigned char ADC::ADConvert()

{

// Start conversion pulse.

WritePort2(0x01); // set /START C to high WritePort2(0x00); // pull /START C to low WritePort2(0x01); // set /START C back to high

//Set Select signal of multiplexer (D1) to logic-high and

//maintain /START C high. This operation takes more time

//than the conversion of the ADC, so we do not need to

//check for signal /DATA VALID. */

WritePort2(0x03); // 0000 0011

//Conversion finished by this time.

//Read high nibble and nullify low nibble.

ADCValue = ReadPort1() & 0xF0;

//Set Select signal of multiplexer (D1) to logic-low. WritePort2(0x01); // 0000 0001

//Read low nibble and assemble the final 8-bit number.

ADCValue += (ReadPort1() >> 4) & 0x0F;

return ADCValue;

}

The complete definition of the ADC class must include the definitions of its member functions as given in Listing 11-4. The member function GetADCValue() provides access to the final 8-bit number ADCValue for functions outside the ADC class.

Listing 11-4 Member function definitions of the ADC class – adc.cpp.

#include "adc.h"

ADC::ADC(int baseaddress) : ParallelPort(baseaddress)

{

ADCValue = 0;

}

unsigned char ADC::ADConvert()

{

356 11 ANALOG-TO-DIGITAL CONVERSION

WritePort2(0x01); // Start C. pulse

WritePort2(0x00);

WritePort2(0x01);

WritePort2(0x03); // Set Mux to read high nibble. ADCValue = ReadPort1() & 0xF0;

WritePort2(0x01); // Set Mux to read low nibble. ADCValue += (ReadPort1() >> 4) & 0x0F; // Read, combine.

return ADCValue;

}

unsigned char ADC::GetADCValue()

{

return ADCValue;

}

11.6 Measuring Voltage Using the ADC

Recall that in Chapter 10 we developed a program to measure an analog voltage using the VCO. The MeasurePeriod() function in the VCO program returned a number representing the pulse period (and hence input voltage) of the VCO. We should be able to use the same program with the VCO object replaced by the ADC object. The function ADConvert()can then generate a number proportional to the analog voltage. Note that we have used a DAC object in the VCO program to provide an analog voltage. We will keep the same DAC object operating exactly the same way to provide the analog input to the ADC (at VIN).

Listing 11-5 shows the main() function from Listing 10-6 reproduced with the modifications needed to use it with the ADC.

Listing 11-5 Measuring voltage using the ADC – voltage.cpp.

#include <conio.h> #include <bios.h>

#include "dac.h" #include "adc.h"

void main()

{

DAC Dac;