Modalities of Using the ADC Module of PIC16F877A

30
Syed Tahmid Mahbub MODALITIES OF USING THE ADC MODULE OF PIC 16F877A

description

I have tried to explain the ADC module of the PIC 16F877A thoroughly so that any one can use it after going through this extensive tutorial.

Transcript of Modalities of Using the ADC Module of PIC16F877A

Page 1: Modalities of Using the ADC Module of PIC16F877A

Syed Tahmid Mahbub

MODALITIES OF USING THE ADC

MODULE OF PIC 16F877A

Page 2: Modalities of Using the ADC Module of PIC16F877A

2

2 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).

Page 3: Modalities of Using the ADC Module of PIC16F877A

3

3 MODALITIES OF USING THE ADC MODULE OF PIC 16F877A – Syed Tahmid Mahbub Introduction

The ADC is used to convert an analogue input signal (an analogue voltage within a specific range)

to a corresponding digital data that can be processed and used by the PIC. The PIC, without the

conversion to digital, can do almost nothing with an analogue input (unless you use the analogue

comparator). But you probably already know this much.

I have seen that many people, especially newbies, are not clear regarding the modalities of using

the ADC module of PIC microcontroller. Many even assume it to be a daunting task after looking at

all the possible settings and configurations. Hence, here I have made an effort to explain

everything I could about the ADC module of the PIC microcontroller, by using the popular PIC

16F877A as reference.

The PIC 16F877A has a 10-bit ADC. That means that the ADC result can have 210

values. That's 1024

values. So, the ADC reading can vary from 0 to 1023.

Page 4: Modalities of Using the ADC Module of PIC16F877A

4

4 MODALITIES OF USING THE ADC MODULE OF PIC 16F877A – Syed Tahmid Mahbub Voltage Reference and ADC result

The ADC has a reference voltage. For now, let's say that the reference voltage is 5V.

So, your input voltage has to range from 0V to 5V. You can't input anything higher than 5V since

that's your positive reference voltage. You can't input anything lower than 0V since that's your

negative reference voltage. Anything in between is read and converted by the PIC ADC.

So, what is the conversion value/result you obtain?

If the ADC input is 5V, the output is maximum as the input is at its maximum level. So, ADC

conversion result is 1023. If ADC input is 0V, the output is minimum as the input is at its minimum

level. So, ADC conversion result is 0. If ADC input is 2.5V, you might have figured out that the ADC

conversion result would be 511. Since the input is midway between its maximum and minimum

possible values, so is the output. So the input and output have a pretty simple linear relationship.

One thing to note here is that the ADC conversion result is 511, not 512, not 511.5. Even though

1023/2 = 511.5, the ADC cannot give results in decimal points and it will only output an integer.

Thus 511 is obtained. Take note that the output is NOT rounded off. That's why it's not 512. So, if

you had gotten an expected ADC conversion result of say 511.8, the real result would be 511.

There is no rounding off, so you get 511.

The simple linear relationship between ADC input and output is given by:

ADC result = (Vin * 1023) / Vref

= (Vin / Vref) * 1023

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

Page 5: Modalities of Using the ADC Module of PIC16F877A

5

5 MODALITIES OF USING THE ADC MODULE OF PIC 16F877A – Syed Tahmid Mahbub for using an internal reference. So, if you want 5V reference, a specific configuration of the ADC

registers will allow you to select the PIC VDD to be used as VR)EF+ and PIC VSS to be used as VREF-.

(We will look at the register configurations later in the tutorial).

The advantage here is that you do not need to connect +5V and 0V externally. This means that you

can save 2 I/O pins. What you have to understand here is that the internal reference is equal to

VDD, not 5V. So, if VDD = 5V, VREF+ = 5V. But if VDD = 3.3V, VREF+ = 3.3V. In both cases, VSS is 0V,

so VREF- is 0V.

Now, let's say we want to measure an input that we know will always be less than 2V. So, we know

that the maximum ADC reading in such a situation will be that for the maximum voltage of 2V in

this case. That would produce a corresponding ADC conversion result of: (2/5)*1023 = 409. So, we

know that we'll never have a result greater than 409. So, the result is in 409 steps and effectively

the resolution is (log 409 / log 2) = 8.7. So, in this case, we're not utilizing the entire 10-bit range of

the ADC. So, now, to improve accuracy, we can use an external reference voltage of 2.5V. So,

maximum ADC result now is: (2/2.5)*1023 = 818. The resolution now is (log 818 / log 2) = 9.7. In

this case, we've made much better use of the ADC. In terms of accuracy, since we have a higher

resolution for a reference voltage of 2.5V, this will give more accurate readings. Let's consider the

situation with 5V reference voltage: For 2V, the ADC conversion result is 409. So, that's 409 steps

for 2V. Each step corresponds to (2/409) = 0.0049V. For the second situation, we have 818 steps.

Each step corresponds to (2/818) = 0.0024V. So, we have twice as much accuracy with a 2.5V

reference than for a 5V reference.

Let's consider another situation. Let's say we have an input that will vary between 2.5V and 3.3V,

never less than 2.5V, never greater than 3.3V. As you may have already guessed, instead of using a

5V reference, to improve resolution and accuracy, we can use a 3.5V reference. So, maximum

reading will be (3.3/3.5)*1023 = 964. In this case, we should also consider minimum reading:

(2.5/3.5)*1023 = 730. So, the reading varies between 730 and 964. One thing to note here is,

although we've used a 3.5V reference, the range is still very small as we have (964-730+1) = 235

steps. We could improve this situation. But how, you may ask.

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 VREF-

of 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.

Page 6: Modalities of Using the ADC Module of PIC16F877A

6

6 MODALITIES OF USING THE ADC MODULE OF PIC 16F877A – Syed Tahmid Mahbub 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

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

Page 7: Modalities of Using the ADC Module of PIC16F877A

7

7 MODALITIES OF USING THE ADC MODULE OF PIC 16F877A – Syed Tahmid Mahbub Acquisition Time

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.72μs. 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.72μs 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 50μs. 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.

Page 8: Modalities of Using the ADC Module of PIC16F877A

8

8 MODALITIES OF USING THE ADC MODULE OF PIC 16F877A – Syed Tahmid Mahbub Example:

For correct analogue to digital conversion, what are the possible TAD options, when a 20MHz

crystal oscillator is used?

Solution:

FOSC = 20MHz

TOSC = (1/20MHz) = 0.05μs

For 1.6μs, TAD = (1.6μs/0.05μs) TOSC = 32 TOSC

So, when TAD = 32 TOSC, 1 TAD = 1.6μs (minimum required time).

Since 1.6μs is the minimum value, let's give it a little more time. As 32 TOSC, 64 TOSC and the

internal ADC module RC oscillator can all be used and 32 TOSC meets only the minimum required

time, we can use the other settings. When 1 TAD = 64 TOSC, 1 TAD = 64(0.05μs) = 3.2μs

The internal ADC module RC oscillator has a typical TAD time of 4μs, that is, 1 TAD = 4μs. But the

actual value may vary from 2μs to 6μs – the entire range meets the required minimum time of 1

TAD = 1.6μs.

The analogue to digital conversion takes 12 TAD. So, in the above example, if we used 64 TOSC, 1

TAD = 64(0.05μs) = 3.2μs. The conversion will take 12TAD = 12*3.2μs = 38.4μs. 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 40μs for the

acquisition delay, the minimum total analogue to digital conversion time would be (40+38.4)μs =

78.4μs. When TAD is to be selected, it is better to select a choice that is significantly larger than the

minimum specified value of 1.6μs.

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.

Page 9: Modalities of Using the ADC Module of PIC16F877A

9

9 MODALITIES OF USING THE ADC MODULE OF PIC 16F877A – Syed Tahmid Mahbub Right / Left Justification

The ADC conversion gives a 10-bit result. We know that the PIC is an 8-bit microcontroller and the

registers are all 8-bit. For anything greater, multiple registers must be used. Thus, for storing a 10-

bit result, two registers are used: ADRESH and ADRESL. Now, if a 10-bit value is stored in 2 bytes,

there is more than one way the value may be stored. In the PIC, the result may be stored in one of

two ways as set in software. The result may be left-justified or right-justified.

Now, what is justification, you may ask. It's actually pretty simple.

Let's start with the more commonly used setting: right-justification. We all know of right-

justification in word-processors. It's when you start typing from the absolute right of the page /

typing area and whatever you type is shifted to the left to accommodate. The right-justification of

the ADC result storage is similar to this. The LSB (least significant bit) is stored in the right most bit

of the ADRESL register – bit 0. Each of the other bits holds the other bits of the result. So, in

ADRESL, bit 0 stores bit 0 of the ADC conversion result, bit 1 stores bit 1, bit 2 stores bit 2, and so

on. So, bit 7 of ADRESL stores bit 7 of the ADC conversion result. That leaves us with 2 more bits –

bits 8 and 9. These are stored in ADRESH. Bit 8 of the ADC conversion result is stored in bit 0 of

ADRESH and bit 9 of the ADC conversion result is stored in bit 1 of ADRESH. So, the MSB (most

significant bit) is stored in the left most bit of ADRESH – bit 1. Bits 2 and onwards till bit 7 store 0.

This is pretty much all there is to right-justification. Simple, isn't it?

If you're still not clear, this example may help clear any doubts.

Example:

A circuit for analogue to digital conversion is set up, to utilize the internal ADC of the PIC16F877A.

VREF+ = 5.0V, VREF- = 0V. The value of TAD is selected such that TAD > 1.6μs. An input voltage of

2.0V is “measured” by the ADC and the corresponding value is stored in the registers ADRESH and

ADRESL. What are the values of ADRESH and ADRESL, if the result is right-justified ?

Solution:

ADC conversion result = (2.0 / 5.0) * 1023 = 409

ADRESL stores the lower 8 bits. 409 in binary is 01 1001 1001. The lower 8 bits are stored in

ADRESL and the upper 2 bits are stored in ADRESH. So, ADRESL stores 1001 1001. ADRESH stores

0000 0001.

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

Page 10: Modalities of Using the ADC Module of PIC16F877A

10

10 MODALITIES OF USING THE ADC MODULE OF PIC 16F877A – Syed Tahmid Mahbub 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.

Example:

A circuit for analogue to digital conversion is set up, to utilize the internal ADC of the PIC16F877A.

VREF+ = 5.0V, VREF- = 0V. The value of TAD is selected such that TAD > 1.6μs. An input voltage of

2.0V is “measured” by the ADC and the corresponding value is stored in the registers ADRESH and

ADRESL. What are the values of ADRESH and ADRESL, if the result is left-justified ?

Solution:

ADC conversion result = (2.0/5.0)*1023 = 409

ADRESH stores the upper 8 bits. 409 in binary is 01 1001 1001. The lower 2 bits are stored in

ADRESL So, ADRESL stores 0100 0000. ADRESH stores 0110 0110.

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,

Page 11: Modalities of Using the ADC Module of PIC16F877A

11

11 MODALITIES OF USING THE ADC MODULE OF PIC 16F877A – Syed Tahmid Mahbub we have 10 0000, which is the same as 0010 0000. 0010 0000 is equivalent to 32 in decimal.

128/32 = 4. So, by bit-shifting 128 to the right twice, we divided it by 4.

Let's take a more “complicated” number: 255. In binary it is represented as 1111 1111. If we shift it

to the right twice, we have 0011 1111. This is equivalent to 63. We now know that bit-shifting to

the right twice means dividing by 4. 255/4 = 63.75. For the PIC, with simple integer math, this is

stored as 63. See, we get the same value when dividing by 4 or bit-shifting to the right twice.

So, if we have a 10-bit number and shift it to the right twice, we get an 8-bit number. We divided

the number by four and got rid of the lowest two bits as these get “lost” as they are “shifted out”.

What we have left is the 8-bit number which is just the highest 8 bits of the 10 bits with the lowest

two bits discarded.

Now think about ADRESH and ADRESL when the ADC conversion result is stored left-justified. So,

ADRESH stores the higher 8 bits and ADRESL stores the lower 2 bits along with 6 zeroes. If we do

not consider ADRESL and think of only ADRESH, it contains the higher 8 bits of the 10 bit ADC

conversion result. So, if that 10 bit result is divided by 4 or bit-shifted twice to the right to an 8-bit

number, the result is the upper 8 bits, which is what is stored in ADRESH. So, if we do not consider

ADRESL and consider only ADRESH, ADRESH stores the 8-bit equivalent value of the 10-bit ADC

result. An example should clear this.

Example:

A circuit for analogue to digital conversion is set up, to utilize the internal ADC of the PIC16F877A.

VREF+ = 5.0V, VREF- = 0V. The value of TAD is selected such that TAD > 1.6μs. An input voltage of

2.0V is “measured” by the ADC and the corresponding value is stored in the registers ADRESH and

ADRESL. What are the values of ADRESH and ADRESL, if the result is left-justified ?

Solution:

ADC conversion result = (2.0/5.0)*1023 = 409

ADRESH stores the upper 8 bits. 409 in binary is 01 1001 1001. The lower 2 bits are stored in

ADRESL So, ADRESL stores 0100 0000. ADRESH stores 0110 0110.

ADRESH stores 0110 0110, which is equivalent to the decimal number 102. The 10-bit result was

409. 409/4 = 102 for the PIC. This is what ADRESH stores. If we reassess the situation, assuming,

for the time being, that the PIC ADC has a resolution of 8-bits and not 10-bits. So, the conversion

result is in the range 0 to 255, 255 being the maximum possible value.

So, ADC conversion result for the above problem = (2.0/5.0)*255 = 102

This is what ADRESH stores. So, ADRESH stores the 8-bit equivalent of the 10-bit ADC conversion

result.

Page 12: Modalities of Using the ADC Module of PIC16F877A

12 MODALITIES OF USING THE ADC MODULE OF PIC 16F877A

ADC pinout of PIC 16F877A

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 o

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, PORT

analogue channel 4, PORTE0 is is analogue channel 5, PORTE1 is analogue channel 6, PORTE2 is

analogue channel 7. Each of these channels

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

AN is used to denote analogue channel. AN0 means analogue channel 0. AN5 means analogue

channel 5. And so on. 12

MODALITIES OF USING THE ADC MODULE OF PIC 16F877A – Syed Tahmid Mahbub

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.

do the conversions simultaneously, so it must be done one by one. This will be

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

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

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

check the logic state of the pin – if it is 0 or 1.

used to denote analogue channel. AN0 means analogue channel 0. AN5 means analogue

Tahmid Mahbub

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.

ne by one. This will be

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

A3 is analogue channel 3, PORTA5 is

analogue channel 4, PORTE0 is is analogue channel 5, PORTE1 is analogue channel 6, PORTE2 is

read one by one as required (set in code). By default

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

used to denote analogue channel. AN0 means analogue channel 0. AN5 means analogue

Page 13: Modalities of Using the ADC Module of PIC16F877A

13 MODALITIES OF USING THE ADC MODULE OF PIC 16F877A

Register Description: ADCON0 and ADCON1

There may be situations when we need only one or two channels to be used

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

digital and which pins will be used as VREF+ and VREF

But before discussing the ADCON1 register, let's discuss the ADCON0 register.

Bits 7 and 6 of the ADCON0 register, along with bit

conversion clock, used to define TAD. I'll discuss that a little later.

Bits 5, 4 and 3 are used to select which channel is to be “measured” and the corresponding

analogue voltage converted. The value of these 3 bit

defines which channel is to be measured and converted. If bit 5 = 1, bit 4 = 1, bit 3 = 0, the

corresponding binary value of these 3 pins is, 110, which in decimal is equal to 6. So, channel 6 will

be measured and the analogue voltage at channel 6 will be converted. The default value of these 3

bits at chip reset (start-up) is 0, so the default channel to be measured (unless you change the

value of bits 5, 4 and/or 3) is channel 0 (PORTA0). If you are curious, the

name of bit 4 is CHS1 and the name of bit 3 is CHS0. So, in conclusion, it is the value of CHS[2:0]

that determines which channel will be measured.

Bit 2 of the ADCON0 register is GO/DONE. To start an analogue to digital conver

be set. After that, you must monitor the value of this bit. When the analogue to digital conversion

is complete, GO/DONE is cleared by hardware automatically, ie, GO/DONE equals to 0. At any time,

the value of GO/DONE can be monitored t

conversion has ended. If the conversion is going on, bit 2

conversion is going on, or if the conversion is complete, bit 2

conversion, by setting GO/DONE to one, the ADC must first be turned on by setting bit 0

discussed in the paragraph below.

Bit 0 of the ADCON0 register is ADON. If this bit is set (ADON = 1), the PIC ADC is turned on and can

be used for conversions. If this bit is

used for conversions. (in this situation, the PIC ADC will consume no operating current) ADON may

be set to 1 at the beginning of the code and it is not necessary to turn off the ADC, unless pow

to be saved.

13

MODALITIES OF USING THE ADC MODULE OF PIC 16F877A – Syed Tahmid Mahbub

: ADCON0 and ADCON1

There may be situations when we need only one or two channels to be used – only that one or two

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.

But before discussing the ADCON1 register, let's discuss the ADCON0 register.

Bits 7 and 6 of the ADCON0 register, along with bit 6 of the ADCON1 register select the ADC

conversion clock, used to define TAD. I'll discuss that a little later.

Bits 5, 4 and 3 are used to select which channel is to be “measured” and the corresponding

analogue voltage converted. The value of these 3 bits – bit 5 being the MSB and bit 3 the LSB

defines which channel is to be measured and converted. If bit 5 = 1, bit 4 = 1, bit 3 = 0, the

corresponding binary value of these 3 pins is, 110, which in decimal is equal to 6. So, channel 6 will

d the analogue voltage at channel 6 will be converted. The default value of these 3

up) is 0, so the default channel to be measured (unless you change the

value of bits 5, 4 and/or 3) is channel 0 (PORTA0). If you are curious, the name of bit 5 is CHS2, the

name of bit 4 is CHS1 and the name of bit 3 is CHS0. So, in conclusion, it is the value of CHS[2:0]

that determines which channel will be measured.

Bit 2 of the ADCON0 register is GO/DONE. To start an analogue to digital conversion, this bit must

be set. After that, you must monitor the value of this bit. When the analogue to digital conversion

is complete, GO/DONE is cleared by hardware automatically, ie, GO/DONE equals to 0. At any time,

the value of GO/DONE can be monitored to check if any conversion is taking place or if a

conversion has ended. If the conversion is going on, bit 2 – GO/DONE – equals to 1. If no

conversion is going on, or if the conversion is complete, bit 2 – GO/DONE – equals 0. To start the

tting GO/DONE to one, the ADC must first be turned on by setting bit 0

Bit 0 of the ADCON0 register is ADON. If this bit is set (ADON = 1), the PIC ADC is turned on and can

be used for conversions. If this bit is cleared (ADON = 0), the PIC ADC is turned off and can not be

used for conversions. (in this situation, the PIC ADC will consume no operating current) ADON may

be set to 1 at the beginning of the code and it is not necessary to turn off the ADC, unless pow

Tahmid Mahbub only that one or two

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

pins will be configured as

if they are to be connected externally.

6 of the ADCON1 register select the ADC

Bits 5, 4 and 3 are used to select which channel is to be “measured” and the corresponding

bit 5 being the MSB and bit 3 the LSB –

defines which channel is to be measured and converted. If bit 5 = 1, bit 4 = 1, bit 3 = 0, the

corresponding binary value of these 3 pins is, 110, which in decimal is equal to 6. So, channel 6 will

d the analogue voltage at channel 6 will be converted. The default value of these 3

up) is 0, so the default channel to be measured (unless you change the

name of bit 5 is CHS2, the

name of bit 4 is CHS1 and the name of bit 3 is CHS0. So, in conclusion, it is the value of CHS[2:0]

sion, this bit must

be set. After that, you must monitor the value of this bit. When the analogue to digital conversion

is complete, GO/DONE is cleared by hardware automatically, ie, GO/DONE equals to 0. At any time,

o check if any conversion is taking place or if a

equals to 1. If no

equals 0. To start the

tting GO/DONE to one, the ADC must first be turned on by setting bit 0 – ADON –

Bit 0 of the ADCON0 register is ADON. If this bit is set (ADON = 1), the PIC ADC is turned on and can

cleared (ADON = 0), the PIC ADC is turned off and can not be

used for conversions. (in this situation, the PIC ADC will consume no operating current) ADON may

be set to 1 at the beginning of the code and it is not necessary to turn off the ADC, unless power is

Page 14: Modalities of Using the ADC Module of PIC16F877A

14 MODALITIES OF USING THE ADC MODULE OF PIC 16F877A

Now, let's discuss the ADCON1 register.

Bit 7 is ADFM, which defines the justification discussed above. Setting ADFM to 1 selects right

justification. Clearing ADFM to 0 selects left

Bit 6 is ADCS2, which along with ADCON0 bit 7 (ADCS1) and ADCON0 bit 6 (ADCS0), define TAD.

The possible values are:

ADCON1 bit 6

(ADCS2)

ADCON0 bit 7

(ADCS1)

0 0

0 0

0 1

0 1

1 0

1 0

1 1

1 1

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

14

MODALITIES OF USING THE ADC MODULE OF PIC 16F877A – Syed Tahmid Mahbub

Now, let's discuss the ADCON1 register.

Bit 7 is ADFM, which defines the justification discussed above. Setting ADFM to 1 selects right

justification. Clearing ADFM to 0 selects left-justification.

with ADCON0 bit 7 (ADCS1) and ADCON0 bit 6 (ADCS0), define TAD.

ADCON0 bit 7 ADCON0 bit 6

(ADCS0)

Conversion Time

(1 TAD)

0 2 TOSC

1 8 TOSC

0 32 TOSC

1 1/FRC

0 4 TOSC

1 16 TOSC

0 64 TOSC

1 1/FRC

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

VREF+ and VREF-.

Tahmid Mahbub

Bit 7 is ADFM, which defines the justification discussed above. Setting ADFM to 1 selects right-

with ADCON0 bit 7 (ADCS1) and ADCON0 bit 6 (ADCS0), define TAD.

Conversion Time

(1 TAD)

2 TOSC

8 TOSC

32 TOSC

1/FRC

4 TOSC

16 TOSC

64 TOSC

FRC

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

Page 15: Modalities of Using the ADC Module of PIC16F877A

15 MODALITIES OF USING THE ADC MODULE OF PIC 16F877A

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

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

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

VDD externally.

When any pin is used for analogue circuitry,

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 example

15

MODALITIES OF USING THE ADC MODULE OF PIC 16F877A – Syed Tahmid Mahbub

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

nels and 0 external reference pins. So, we'll go with 3 analogue

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

= 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

When any pin is used for analogue circuitry, the corresponding TRIS bit must be set to 1, as it

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.

Tahmid Mahbub

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

nels and 0 external reference pins. So, we'll go with 3 analogue

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 pins.

= VSS. Alternatively, we can use the setting 0101 and have channels 0 and

= VSS). So, we can just connect AN3, ie PORTA3 to

the corresponding TRIS bit must be set to 1, as it

That should clear you up on how to use the above table for PCFG setting for selecting which pins

Page 16: Modalities of Using the ADC Module of PIC16F877A

16

16 MODALITIES OF USING THE ADC MODULE OF PIC 16F877A – Syed Tahmid Mahbub Example:

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 we’re 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.

Page 17: Modalities of Using the ADC Module of PIC16F877A

17

17 MODALITIES OF USING THE ADC MODULE OF PIC 16F877A – Syed Tahmid Mahbub SEQUENTIAL STEPS IN ANALOGUE TO DIGITAL CONVERSION USING THE INTERNAL ADC

So, here are the steps to configure the ADC and carry out the conversion:

• Decide which pins need to be analogue, which pins need to be digital and which (if any)

need to be configured as reference pins.

• Select the appropriate settings for PCFG[3:0] in ADCON1.

• Select ADC module conversion clock by setting ADCS[2:0] in ADCON1 and ADCON0.

• Select justification method – left-justification or right-justification by setting/clearing ADFM

in ADCON1.

• Turn on ADC module by setting ADON to 1 in ADCON0.

• Select which channel is to be sampled/measured and converted by setting CHS[2:0] in

ADCON0.

• Wait the required acquisition time.

• Start conversion by setting GO/DONE to 1 in ADCON0.

• Check if conversion is over by checking if GO/DONE has been cleared to 0.

• If conversion is over, read the results from ADRESH:ADRESL.

A simple code example will help clear this.

Page 18: Modalities of Using the ADC Module of PIC16F877A

18

18 MODALITIES OF USING THE ADC MODULE OF PIC 16F877A – Syed Tahmid Mahbub CODE EXAMPLES

Example:

We will sample AN0 and AN1. We'll use VDD as VREF+ and VSS as VREF-. We'll use right-

justification and display the larger of the two results on PORTD. The PIC 16F877A is to be run off a

16MHz crystal.

Solution:

So, we'll need a setting that allows for AN0 and AN1 to be analogue. We do not need any external

reference as VDD and VSS will be used for VREF+ and VREF-. PCFG<3:0> setting of 0100 will give us

that (we'll have another analogue channel, but there's no setting for only 2 channels with no

reference).

Next, let's calculate the settings for TAD.

FOSC = 16MHz

TOSC = (1/16MHz) = 0.0625μs

1.6μs/0.0625μs = 25.6

So, we should choose 32 TOSC. Let's check. 32 TOSC = 32(0.0625μs) = 2μs. This is marginally larger

than the minimum 1.6μs. So, we can choose 64 TOSC which will give a little bit more time. That will

give us 64(0.0625μs) = 4μs. This is good and is also significantly larger than the minimum 1.6μs. So

this should be chosen unless ADC conversion needs to be very quick, in which case, we'll want to

use 32 TOSC, where TAD = 2μs. For 64 TOSC, ADCS2 = 1, ADCS1 = 1, ADCS0 = 0.

We've decided on using right-justification.

As mentioned before, we'll use the arbitrary 50μs acquisition delay, which is larger than the

minimum mentioned 19.72μs

Instead of individually selecting the PCFG, ADCS2 and ADFM bits, we can set it all together in one

step by writing to the ADCON1 register. Same with ADCON0. Instead of writing to the bits

individually, we can write to ADCON0 in one step.

So, for ADCON0, ADCS0 = 0, ADCS1 = 1. We'll first sample channel 0, then channel 1. So, initially,

CHS2 = CHS1 = CHS0 = 0. We'll have to turn the ADC on, so ADON = 1. Therefore, bits 7 and 1 are to

be set to 1, the rest cleared to 0. This means, ADCON0 must be loaded with the binary value 1000

0001. Represented as hexadecimal, this is 0x81.

Let's move on to ADCON1. ADFM = 1 for right-justification. ADCS2 = 1. Required PCFG<3:0> setting

has been found to be 0100. So, bits 7, 6 and 2 are to be set to 1, the rest cleared to 0. This means,

ADCON1 must be loaded with the binary value 1100 0100. Represented as hexadecimal, this is

0xC4.

Page 19: Modalities of Using the ADC Module of PIC16F877A

19

19 MODALITIES OF USING THE ADC MODULE OF PIC 16F877A – Syed Tahmid Mahbub 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.

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.

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;

Page 20: Modalities of Using the ADC Module of PIC16F877A

20

20 MODALITIES OF USING THE ADC MODULE OF PIC 16F877A – Syed Tahmid Mahbub 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

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;

Now let's make a simple function for the ADC reading.

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:

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:

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.

ADR = (h_byte<<8)|l_byte;

ADCON0 = 0x81 | (channel << 3); //Change channel

Page 21: Modalities of Using the ADC Module of PIC16F877A

21

21 MODALITIES OF USING THE ADC MODULE OF PIC 16F877A – Syed Tahmid Mahbub Now, let's read the two channels AN0 and AN1.

As you can see from the code above, the multiple channels of the ADC are read by first reading one

channel, then changing the value of CHS[3:0] in ADCON0, then reading the next channel and so on.

The logic for all the above programs is pretty straight forward and should be quite easy to

understand.

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.

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 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) unsigned int Ch0, Ch1; CMCON = 7; //Disable ADC PORTD = 0; TRISD = 0; ADCON0 = 0x81; ADCON1 = 0xC4; while (1) Ch0 = ADCRead(0); //Gets reading from channel 0 Ch1 = ADCRead(1); //Gets reading from channel 1 if (Ch1 > Ch0) //If voltage at AN1 > voltage at AN0 PORTD = Ch1>>2; //Display 8-bit ADC result of AN1 on PORTD else PORTD = Ch0>>2; //Display 8-bit ADC result of AN0 on PORTD

Page 22: Modalities of Using the ADC Module of PIC16F877A

22

22 MODALITIES OF USING THE ADC MODULE OF PIC 16F877A – Syed Tahmid Mahbub Example:

We have a temperature sensor LM35 connected to AN0. We’re 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 25°C, we’ll start the heat. If temperature is greater than 30°C, we’ll start

the cooler. For anything in between, they’ll both be off.

Now, if you don’t 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 25°C, the output from the LM35 is 0.25V. For a temperature of 35°C, the output

from the LM35 is 0.35V. That’s simple enough.

The LM35 is rated for a maximum temperature of 150°C. At 150°C, the LM35 will output 1.5V. But

in our application, let’s take maximum temperature of 50°C. 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.

Let’s take it as 5V for simplicity as we won’t have to connect an external reference.

We’ll use a 16MHz oscillator and the settings are as before.

With 5V reference, 0.25V (for 25°C) gives an ADC conversion result of:

(0.25 / 5) * 1023 = 51

0.35V (for 35°C) gives an ADC conversion result of:

(0.35 / 5) * 1023 = 71

Page 23: Modalities of Using the ADC Module of PIC16F877A

23

23 MODALITIES OF USING THE ADC MODULE OF PIC 16F877A – Syed Tahmid Mahbub

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.

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 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

Page 24: Modalities of Using the ADC Module of PIC16F877A

24

24 MODALITIES OF USING THE ADC MODULE OF PIC 16F877A – Syed Tahmid Mahbub PRACTICAL CONSIDERATIONS

All this while, we’ve talked about the software side of things when dealing with the ADC. Now, it’s

time to talk about the hardware side of things.

We’ve considered many situations in the discussions above. But not all of them can be used in your

circuits.

One such situation was the use of VREF+ = 3.5V and VREF- = 2.0V. This cannot be used in your

circuits. Microchip specifies that the minimum reference voltage must be 2.0V. That means the

difference between VREF+ and VREF- has to be at least 2.0V. So, if VREF+ = 3.5V, VREF- must be

1.5V or lower. If VREF- = 2.0V, VREF+ must be 4.0V or higher.

VREF+ also has minimum and maximum voltage ratings. The minimum value for VREF+ is VDD-

2.5V. So, if your PIC is powered off VDD=5V, the minimum allowable value for VREF+ is 2.5V. You

can not use anything lower than 2.5V for VREF+. The maximum value for VREF+ is VDD+0.3V. So, if

your PIC is powered off VDD=5V, the maximum allowable value for VREF+ is 5.3V. So, for VDD=5V,

VREF+ must lie between 2.5V and 5.3V.

The minimum value for VREF- is VSS-0.3V. So, as VSS = 0V, minimum value for VREF is -0.3V. But it’s

better not to use a negative voltage and to just stick with 0V. The maximum voltage for VREF- is

VREF+ minus 2V. This is because, as I’ve mentioned above, VREF+ minus VREF- must be at least

2.0V.

The minimum required acquisition time of 19.72µs mentioned in this article is for an input

impedance of 2.5kΩ. For anything lower, minimum required acquisition time is less than 19.72µs.

But you can just take it as 19.72µs. For input impedance greater than 2.5kΩ, the acquisition time is

higher. Do you remember, I mentioned that Microchip recommends a maximum input impedance

of 2.5kΩ? That’s what Microchip recommends. Microchip also specifies that the maximum

allowable input impedance is 10kΩ, although it is not recommended. So, it’s better to stick to

Microchip’s recommendation and use a voltage follower (analogue buffer) with an operational

amplifier, if needed.

Page 25: Modalities of Using the ADC Module of PIC16F877A

25

25 MODALITIES OF USING THE ADC MODULE OF PIC 16F877A – Syed Tahmid Mahbub TIPS AND TRICKS

While using the ADC, you may sometimes notice that the result fluctuates over a small range. I’ve

seen many people panicking over this and assuming it’s 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 they’re not the

reference. If you’re using external reference via AN2 and AN3, make sure that these are properly

decoupled. If you’re using both for VREF+ and VREF-, make sure you place a 0.1µF ceramic

capacitor across AN2 and AN3. Also, use a 10µF 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.1µF capacitor

may be used. If you’re 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 over-

voltage. 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, let’s consider the following

example.

Page 26: Modalities of Using the ADC Module of PIC16F877A

26 MODALITIES OF USING THE ADC MODULE OF PIC 16F877A

Example:

To sample a DC input voltage ranging from 0V to 25

the ADC input?

Solution:

Firstly, we’ll need a voltage divider. Then, to improve the impedance, we’ll use a voltage follower

(analogue buffer). Finally, we’ll use a filter and overvoltage protection circuitry.

We can use this circuit.

In the voltage divider, you must take int

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.

simple: an analogue buffer (voltage follower)

and C1; a 5V (5.1V to be precise) zener for overvoltage protection.

26

MODALITIES OF USING THE ADC MODULE OF PIC 16F877A – Syed Tahmid Mahbub

ut voltage ranging from 0V to 25V, what is the hardware interface required for

Firstly, we’ll need a voltage divider. Then, to improve the impedance, we’ll use a voltage follower

). Finally, we’ll use a filter and overvoltage protection circuitry.

In the voltage divider, you must take into account tolerance of the resistors and the errors they can

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

mple: an analogue buffer (voltage follower) employing an LM358; a simple RC filter employing R3

zener for overvoltage protection.

Tahmid Mahbub V, what is the hardware interface required for

Firstly, we’ll need a voltage divider. Then, to improve the impedance, we’ll use a voltage follower

o account tolerance of the resistors and the errors they can

cause in the measurement. Thus it may be better to use a variable resistor or potentiometer

The rest is pretty

employing an LM358; a simple RC filter employing R3

Page 27: Modalities of Using the ADC Module of PIC16F877A

27

27 MODALITIES OF USING THE ADC MODULE OF PIC 16F877A – Syed Tahmid Mahbub FINAL EXAMPLE

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:

We’ll 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.

Page 28: Modalities of Using the ADC Module of PIC16F877A

28

28 MODALITIES OF USING THE ADC MODULE OF PIC 16F877A – Syed Tahmid Mahbub 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; 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

Page 29: Modalities of Using the ADC Module of PIC16F877A

29 MODALITIES OF USING THE ADC MODULE OF PIC 16F877A

Basic Hardware Connection:

29

MODALITIES OF USING THE ADC MODULE OF PIC 16F877A – Syed Tahmid Mahbub

Tahmid Mahbub

Page 30: Modalities of Using the ADC Module of PIC16F877A

30

30 MODALITIES OF USING THE ADC MODULE OF PIC 16F877A – Syed Tahmid Mahbub CONCLUSION

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

_____

Syed Tahmid Mahbub