Está en la página 1de 30

MODALITIES OF USING THE ADC MODULE OF PIC 16F877A

Syed Tahmid Mahbub

Note: Images of registers and PIC 16F877A layout have been taken from the PIC 16F877A datasheet (ww1.microchip.com/downloads/en/devicedoc/39582b.pdf).

Syed Tahmid Mahbub

MODALITIES OF USING THE ADC MODULE OF PIC 16F877A Voltage Reference and ADC result

Syed Tahmid Mahbub

This is because (ADC result / 1023) = (Vin / Vref) You probably figured this out. It's quite simple. The ratio of ADC conversion result to maximum possible reading is equal to the ratio of input voltage (Vin) to maximum possible input voltage (Vref). This is because the input voltage is a fraction of the maximum possible voltage and hence the ADC output result is the same fraction of the maximum possible value 1023 in our case.

Example: So, for a reference of 5.00V, what will be the ADC result when input voltage is 1.23V? Solution: Expected value = (1.23 / 5.00) * 1023 = 251.658 So, ADC conversion result = 251 as you can't have a fractional result.

Above, the situation considered was simple as reference voltage is 5V with respect to ground. Now the thing to understand is, for reference, the PIC has two pins: VREF+ and VREF-. So, for 5V reference, 5V is to applied at VREF+ and 0V (ground) is to be applied at VREF-. The PIC has facilities

Syed Tahmid Mahbub

Remember, I mentioned that the PIC had 2 pins for reference: VREF+ and VREF-. All this while, we've talked about VREF+. Now, we'll go on to VREF-. If VREF+ is at 5V and VREF- is at 0V (which is the situation we've considered thus far), the reference voltage is (5-0) = 5V. But let's say, VREF- is at 3V, and not 0V. What's the reference voltage now? Is it still 5V as VREF+ is at 5V? The answer is: NO. You must remember that all this while, the reference voltage was 5V as VREF+ was at a potential of 5V with reference to VREF-. So, if VREF+ is 5V and VREF- is 3V, while VREF+ is at a potential of 5V above ground, what really matters is its potential with reference to VREF-. With reference to VREF-, VREF+ is at a potential of 2V. So, the reference voltage is in fact 2V, with VREFof 3V and VREF+ of 5V. So, the acceptable input voltage range is 3V to 5V. So, for the said situation of input between 2.5V and 3.3V, we can improve accuracy and resolution by altering the reference voltage. We've already used 3.5V as VREF+. We know input will always be above 2.5V, so we can use 2.0V for VREF-. Thus, our reference voltage is (3.5-2.0) = 1.5V. So, when input voltage is 2.5V, what is the ADC result now? Let's revise our previous formula a bit now.

MODALITIES OF USING THE ADC MODULE OF PIC 16F877A Previously, I mentioned this: ADC Result = (Vin / Vref) * 1023 Vin is actually (Input Voltage) (Ref-) Vref is actually (Ref+) - (Ref-) So, ADC Result = [(Vin-VREF-) / (VREF+ - VREF-)] * 1023 For the above situation, VREF+ = 3.5V, VREF- = 2.0V, Vin = 2.5V So, ADC Result = [(2.5-2.0)/(3.5-2.0)]*1023 = 341

Syed Tahmid Mahbub

This is the minimum value. For 3.3V input, ADC Result = [(3.3-2.0)/(3.5-2.0)]*1023 = 886

So, our range of values now lies between 341 and 886. That's (886-341+1) = 546 steps. We've more than doubled the accuracy by altering the reference voltage. I hope you've understood how to use the VREF+ and VREF- pins. I'll move on to the coding later. There are a few more things to consider here that are covered in PRACTICAL CONSIDERATIONS and onwards towards the end of the tutorial.

Example: A circuit is set up for analogue to digital conversion using the PIC's internal ADC, with VREF+ = 4.0V and VREF- = 2.0V. A few input voltages are measured: 2.2V, 2.35V, 2.8V, 3.36V, 3.46V, 3.9V. What are the corresponding ADC conversion results? Solution: For 2.2V: ADC conversion result = [(2.2-2.0)/(4.0-2.0)]*1023 = 102 For 2.35V: ADC conversion result: [(2.35-2.0)/(4.0-2.0)]*1023 = 179 For 2.8: Result = 409 For 3.36V: Result = 695 For 3.46V: Result = 746 For 3.9V: Result = 971

Syed Tahmid Mahbub

Before an analogue to digital conversion is to be started, a small amount of time must be allowed for the holding capacitor of the PIC ADC module to fully charge to the input level. This is how the ADC works and unless this minimum time is allowed, the ADC will give an incorrect result. This time is known as the acquisition time. The datasheet provides the equation for calculating the minimum acquisition time. If you want, you may check it out, but the datasheet also provides the value of the minimum acquisition time, which is 19.72s. For now, this is all you need to know. You don't need to know how it comes, but if you want to, you may check it out in the datasheet. So, when the ADC is on, a minimum of 19.72s must be allowed before the conversion can be started. Since, this is the minimum value, you can use a larger value. I will use around 50s. There is no special reason to choose this and it is a rather arbitrary value just chosen as it is quite a bit larger than the minimum required time more than twice as much. For the analogue input, the maximum recommended (by Microchip) input impedance is 2.5k. While larger input impedances may be used, it is best to stick to Microchip's recommendation. If the input does have a larger input impedance, an analogue buffer (voltage follower) employing an operational amplifier may be used. There are a few more things to consider here that are covered in PRACTICAL CONSIDERATIONS and onwards towards the end of the tutorial. ADC Conversion Clock (TAD) The analogue to digital conversion time per bit is defined as TAD. The analogue to digital conversion requires a minimum 12 TAD per 10-bit conversion. The source of the analogue to digital conversion clock is software selected. The seven possible options for TAD are: 2 TOSC 4 TOSC 8 TOSC 16 TOSC 32 TOSC 64 TOSC Internal ADC module RC oscillator (2-6 s)

TOSC = 1/FOSC, where FOSC is the frequency of the oscillator, off which the PIC is running. For a PIC16F877A running off a 20MHz crystal, FOSC = 20MHz. For correct analogue to digital conversions, the analogue to digital conversion clock (TAD) must be selected to ensure a minimum TAD of 1.6 s.

Syed Tahmid Mahbub

The analogue to digital conversion takes 12 TAD. So, in the above example, if we used 64 TOSC, 1 TAD = 64(0.05s) = 3.2s. The conversion will take 12TAD = 12*3.2s = 38.4s. The entire conversion will comprise of the initial acquisition delay plus the conversion time plus any delay in the middle, such as time taken for setting/configuring registers, etc. So, if we had used 40s for the acquisition delay, the minimum total analogue to digital conversion time would be (40+38.4)s = 78.4s. When TAD is to be selected, it is better to select a choice that is significantly larger than the minimum specified value of 1.6s. Note: When a 20MHz crystal oscillator is used, the frequency is internally divided by 4 by the PIC to 5MHz. But FOSC = 20MHz, not 5MHz. 5MHz is FCY. Microchip does not recommend the use of the internal ADC module RC oscillator for device frequencies greater than 1MHz (unless in sleep mode but we're not concerned with that now). While this does not mean that it can not be used, it is better not to use it as it is not recommended and we can simply select a setting for TAD from one of the other settings.

MODALITIES OF USING THE ADC MODULE OF PIC 16F877A Right / Left Justification

Syed Tahmid Mahbub

Now, let's talk about left-justification. While this is less commonly used, it is quite useful as you will find out. You must know the left-justification in word-processors. You start typing from the left and everything you write is shifted to the right. Left-justification is also like this. The 10-bit result is again stored in ADRESH and ADRESL but in a different way. While the result is left-justified, the upper 8 bits are stored in ADRESH and the lower 2 bits are stored in ADRESL. So, bits 9, 8, 7, 6, 5, 4, 3, 2 of the ADC conversion result are stored in ADRESH bits 7, 6, 5, 4, 3, 2, 1, 0 in that order. So, bits

Syed Tahmid Mahbub

01

01

1 and 0 of the ADC conversion result are stored in ADRESL bits 7 and 6 in that order. Bits 5 onwards to bit 0 store 0. This example should clear any doubts.

When you have a 10-bit number (range is 0 to 1023), if you divide the number by 4, you effectively just converted the 10-bit number to an 8-bit number. The new range is 0 to 255. You should already know that bit-shifting a number to the right once is equivalent to dividing the number by 2 and bit-shifting the number to the right twice is equivalent to dividing the number by 4. If you don't know about this, this should help you understand. Let's take the number 128. In binary, it is represented as 1000 0000. If we shift it to the right twice,

11

11

Syed Tahmid Mahbub

21

21

PIC16F877A has 8 ADC input channels. That means that 8 pins are multiplexed (connected) to the PIC ADC module. So, you can use the ADC module to convert analogue input from 8 inputs. PIC16F877A cannot do the conversions simultaneously, so it must be done one by one. This will be one shown later on. The 8 ADC input pins are PORTA0, PORTA1, PORTA2, PORTA3, PORTA5, PORTE0, PORTE1, PORTE2. Each of these is an ADC channel. PORTA0 is analogue channel 0, PORTA1 is analogue channel 1, PORTA2 is analogue channel 2, PORTA3 is analogue channel 3, PORTA5 is PORTA3 analogue channel 4, PORTE0 is is analogue channel 5, PORTE1 is analogue channel 6, PORTE2 is analogue channel 7. Each of these channels is read one by one as required (set in code). By default all the ADC input pins are configured as analogue pins. When a pin is configured as an analogue pin, it can be used by the ADC for conversion or by the analogue comparator. But we can not use it as a digital pin: we cannot check the logic state of the pin if it is 0 or 1. AN is used to denote analogue channel. AN0 means analogue channel 0. AN5 means analogue channel 5. And so on.

Syed Tahmid Mahbub

31

31

There may be situations when we need only one or two channels to be used only that one or two pins to be configured as analogue pin(s). We may need the other pins as digital pins. We may have switches connected to them and need to read the digital state of those pins. The ADCON1 register allows us to configure which pins will be configured as analogue, which pins will be configured as digital and which pins will be used as VREF+ and VREF if they are to be connected externally. VREFBut before discussing the ADCON1 register, let's discuss the ADCON0 register.

41

41

Now, let's discuss the ADCON1 register.

Bits 3, 2, 1 and 0 named PCFG3, PCFG2, PCFG1 and PCFG0 are used to define which pins will be analogue pins to be used by the ADC, which pins will be digital and which pins (if any) will be used for external reference VREF+ and VREF-. VREF

Syed Tahmid Mahbub

51

51

So, let's discuss this a bit. PCFG<3:0> refers to the values of PCFG3, PCFG2, PCFG1 and PCFG0 in that order. Let's say we need 2 ADC channels and will use VDD and VSS for reference. There is no setting for 2 analogue channels and 0 external reference pins. So, we'll go with 3 analogue nels channels and 0 external reference pins by using 0100 for PCFG<3:0>. For this setting, channels 0, 1 and 3 are analogue. So, PORTA0, PORTA1 and PORTA3 are analogue pins. The rest are digital p pins. VREF+ = VDD and VREF- = VSS. Alternatively, we can use the setting 0101 and have channels 0 and 1 as analogue and AN3 as VREF+ (and VREF- = VSS). So, we can just connect AN3, ie PORTA3 to VREF VDD externally. When any pin is used for analogue circuitry, the corresponding TRIS bit must be set to 1, as it becomes an input pin. That should clear you up on how to use the above table for PCFG setting for selecting which pins will be analogue or digital. The following examples should clear any doubts. example

Syed Tahmid Mahbub

61

61

If we're going to need 4 analogue pins, and will use VREF+ = 3.3V and VREF- = 2.0V, what setting of PCFG will we need? Solution: We'll need 4 pins for ADC conversion and 2 for reference. PCFG setting of 1011 gives us exactly that. AN3 is VREF+ where we must provide +3.3V. AN2 is VREF- where we must provide 2.0V.

Example: If we're going to need 4 analogue pins, and will use VREF+ = 3.3V and VREF- = 0V, what setting of PCFG will we need? Solution: We'll need 4 pins for ADC conversion and 1 for reference for VREF+ as VREF- will be VSS. PCFG setting of 0011 gives us exactly that. Alternatively, we can use PCFG setting of 1011 like in the previous example and connect VREF- externally to ground.

Example: If were going to need 5 analogue pins, will use VREF+ = 5V and VREF- = 0V and the PIC is powered off 5V, what setting of PCFG will be needed? Solution: We can use 0010 as, VREF+ can be VDD and VREF- can be VSS.

When AN3 is selected as VREF+, we must connect the positive voltage reference to this pin PORTA3. When AN2 is selected as VREF-, we must connect the negative voltage reference to this pin PORTA5. So, if we have VREF+ = 4.0V, VREF- = 2.0V, 4.0V is connected to PORTA3 and 2.0V is connected to PORTA5.

Syed Tahmid Mahbub

71

71

MODALITIES OF USING THE ADC MODULE OF PIC 16F877A CODE EXAMPLES Example:

81

81

Syed Tahmid Mahbub

91

91

Before going into sampling multiple inputs, let's look at a simple code to read off AN0 (channel 0): I'm using mikroC PRO for PIC for this. While you can apply this same concept to any compiler, the exact syntax is probably not going to work on another compiler. void main(void){ unsigned char l_byte, h_byte; unsigned int ADR; CMCON = 7; //Disable comparator PORTD = 0; //Clear initial value of PORTD TRISD = 0; //PORTD to be output ADCON0 = 0x81; //Check in description above ADCON1 = 0xC4; //Check in description above while (1){ delay_us(50); //Acquisition Delay GO_DONE_bit = 1; //Set GO_DONE bit to start conversion while (GO_DONE_bit == 1); //Wait for bit to be cleared //If bit is cleared, this means conversion is over l_byte = ADRESL; h_byte = ADRESH; ADR = (h_byte<<8)|l_byte; } }

The result is stored in ADR. The logic in this program is pretty simple and should be easy to understand if you've read through thoroughly.

Syed Tahmid Mahbub

02

02

The value of bits 2, 3 and 4 CHS dictates which channel is to be read. Therefore, the value of the channel to be read is shifted to the left thrice, so that CHS = value of channel to be read. The line: ADR = (h_byte<<8)|l_byte; is used to combine the two 8-bit registers into one 16-bit register. By shifting the 8-bit register h_byte 8 places to the left, it has been made the upper (more significant) 8-bits of the 16-bit register. Thus the lower 8 bits all have a value of 0 and when OR-ed with l_byte, take the value of l_byte.

Now, your task is to find out the result of this line: ADCON0 = 0x81 | (channel << 3); //Change channel For values of channel from 0 to 7, find the corresponding values of ADCON0 and then you will become clear as to how the channel changing is so easily done with just one line.

MODALITIES OF USING THE ADC MODULE OF PIC 16F877A Now, let's read the two channels AN0 and AN1. unsigned int ADCRead(unsigned char channel){

Syed Tahmid Mahbub

12

12

} AN0 and AN1 are read and the 8-bit equivalent of the 10-bit ADC result of the greater of the two inputs is displayed on PORTD.

Syed Tahmid Mahbub

22

22

We have a temperature sensor LM35 connected to AN0. Were going to make a kind of temperature checker. We have a fan connected at PORTD0 and a heater connected at PORTD1. If temperature is less than 25C, well start the heat. If temperature is greater than 30C, well start the cooler. For anything in between, theyll both be off. Now, if you dont already know this, the LM35 is a temperature sensor that outputs an analogue voltage corresponding to the temperature. For each C, the output is 0.01V, ie 10mV. So, if the temperature is 25C, the output from the LM35 is 0.25V. For a temperature of 35C, the output from the LM35 is 0.35V. Thats simple enough. The LM35 is rated for a maximum temperature of 150C. At 150C, the LM35 will output 1.5V. But in our application, lets take maximum temperature of 50C. That corresponds to an output voltage of 0.5V. We can use the reference voltage as 5V for sake of simplicity or we can take an external reference for improved accuracy. Lets take it as 5V for simplicity as we wont have to connect an external reference. Well use a 16MHz oscillator and the settings are as before. With 5V reference, 0.25V (for 25C) gives an ADC conversion result of: (0.25 / 5) * 1023 = 51 0.35V (for 35C) gives an ADC conversion result of: (0.35 / 5) * 1023 = 71

MODALITIES OF USING THE ADC MODULE OF PIC 16F877A unsigned int ADCRead(unsigned char channel){ unsigned char l_byte, h_byte; unsigned int ADR; ADCON0 = 0x81 | (channel << 3); //Change channel delay_us(50); //Acquisition Delay

Syed Tahmid Mahbub

32

32

GO_DONE_bit = 1; //Set GO_DONE bit to start conversion while (GO_DONE_bit == 1); //Wait for bit to be cleared //If bit is cleared, this means conversion is over l_byte = ADRESL; h_byte = ADRESH; ADR = (h_byte<<8)|l_byte; } return ADR;

void main(void){ #define Temp35 71 #define Temp25 51 unsigned int Ch0; CMCON = 7; //Disable comparator PORTD = 0; TRISD = 0; ADCON0 = 0x81; ADCON1 = 0xC4; while (1){ Ch0 = ADCRead(0); //Gets reading from channel 0 if (Ch0 > Temp35){ RD0_bit = 1; //Turn on heater } else{ RD0_bit = 0; //Turn off heater } if(Ch0 < Temp25){ RD1_bit = 1; //Turn on cooler } else{ RD1_bit = 0; //Turn off cooler }

That should be quite simple to understand. Now, your task should be to write a code with reference voltage 2.5V. You should be able to do that now.

Syed Tahmid Mahbub

42

42

MODALITIES OF USING THE ADC MODULE OF PIC 16F877A TIPS AND TRICKS

Syed Tahmid Mahbub

52

52

While using the ADC, you may sometimes notice that the result fluctuates over a small range. Ive seen many people panicking over this and assuming its a problem in the code. Usually, the problem lies in the hardware. The first thing to do when designing a circuit utilizing the internal ADC module of the PIC16F877A, or for that matter, any PIC, is to ensure that the reference voltage is stable. Make sure that the PIC VDD and VSS lines are properly decoupled even if theyre not the reference. If youre using external reference via AN2 and AN3, make sure that these are properly decoupled. If youre using both for VREF+ and VREF-, make sure you place a 0.1F ceramic capacitor across AN2 and AN3. Also, use a 10F electrolytic capacitor (take care with the polarity!). Another thing that should be done when using the PIC ADC module is to use filters at the inputs. The filters may be simple RC filters. The values of R and C are not overly critical. For most cases, a 1k resistor and a 0.1F capacitor may be used. If youre sampling an input with a high frequency, you should use a smaller capacitor. Use of the filter should make the ADC results more stable and is likely to be beneficial in most cases. Another thing you should do in most cases is to protect the analogue input channel from overvoltage. The maximum voltage that may be applied to the pin without damaging the internal circuitry is about +5.5V. However, you can only read/convert/measure voltages as high as VREF+ using the ADC. In many cases, VDD will be used as VREF+ and VSS as VREF-. So, the maximum voltage that can be read is VDD. If VDD is 5.0V, the maximum voltage that can be read is 5.0V. So, you should make sure that the voltage at the analogue input pin is never higher than 5.0V. You can do this using a simple zener diode. Something like this can be used for filtering and protecting the PIC ADC input pin from overvoltage:

Sometimes you may need to read voltages higher than 5.0V, such as 10V or even 100V. In such situations, you cannot read the input directly as it will damage the internal circuitry. In such a case, you can make use of the simple voltage divider employing resistors. So, to summarize all the hardware-related concepts presented above, lets consider the following example.

Syed Tahmid Mahbub

62

62

Example: To sample a DC input voltage ranging from 0V to 25V, what is the hardware interface required for ut 25V, the ADC input? Solution: Firstly, well need a voltage divider. Then, to improve the impedance, well use a voltage follower (analogue buffer). Finally, well use a filter and overvoltage protection circuitry. ).

We can use this circuit. In the voltage divider, you must take into account tolerance of the resistors and the errors they can into cause in the measurement. Thus it may be better to use a variable resistor or potentiometer instead of R2 and adjust the resistance to obtain an accurate reading of the ADC. The rest is pretty simple: an analogue buffer (voltage follower) employing an LM358; a simple RC filter employing R3 mple: and C1; a 5V (5.1V to be precise) zener for overvoltage protection.

Syed Tahmid Mahbub

72

72

A load (motor) is to be run off a variable DC power supply. The microcontroller is to control the circuit in the following way. The DC voltage varies between 10V and 28V. The microcontroller is powered off a constant 5V. If the DC voltage is less than 15V or if the DC voltage is greater than 25V, the DC motor is to be turned off. If voltage is between 15V and 25V, the motor is to be run. The motor is connected via a transistor whose base is connected to PORTD0. Solution: Well use the circuit shown in page 24 for the ADC interfacing to input voltage. For 28V input, ADC input = (28/6)V = 4.67V For 15V input, ADC input = (15/6)V = 2.5V PCFG setting of 1110 is used. VDD is used as VREF+ and VSS is used as VREF- as high accuracy is not needed and circuit simplicity is the priority here. ADC result for 4.67V input = (4.67/5)*1023 = 955 ADC result for 2.5V input = (2.5/5)*1023 = 511 Code is in the next page.

MODALITIES OF USING THE ADC MODULE OF PIC 16F877A unsigned int ADCRead(unsigned char channel){ unsigned char l_byte, h_byte; unsigned int ADR; ADCON0 = 0x81 | (channel << 3); //Change channel delay_us(40); //Acquisition Delay GO_DONE_bit = 1; //Set GO_DONE bit to start conversion while (GO_DONE_bit == 1); //Wait for bit to be cleared //If bit is cleared, this means conversion is over l_byte = ADRESL; h_byte = ADRESH; ADR = (h_byte<<8)|l_byte; } return ADR;

Syed Tahmid Mahbub

82

82

void main(void){ #define V28 955 #define V15 511 unsigned int Ch0; CMCON = 7; //Disable comparator PORTD = 0; TRISD = 0; ADCON0 = 0x81; ADCON1 = 0xCE; while (1){ Ch0 = ADCRead(0); //Gets reading from channel 0 if ((Ch0 < V15)|(Ch0>V28)){ RD0_bit = 0; //Turn off motor } else{ RD0_bit = 1; //Turn on motor } delay_ms(100); //Wait for some time

MODALITIES OF USING THE ADC MODULE OF PIC 16F877A Basic Hardware Connection:

92

92

Syed Tahmid Mahbub

03

03

The ADC module of PIC microcontroller is a very useful feature. Its use is immense in practical applications and hence, one must know its proper application if he or she wants to use that microcontroller in useful circuits. Though it may look very daunting at first, using this module is actually not so difficult if one knows all the modalities of using it properly. Learning these is actually easy if one wants to learn by heart. Here I have tried to cover all the sequential steps and intermediate settings. I hope that the tutorial that I have prepared and presented here will be of some use for those who are interested in learning and applying this module in practical applications. Visit my blog at tahmidmc.blogspot.com

_____