First and foremost, we must have a clear picture on what the built-in ADC is doing. Think of it like there’s a little guy living inside the chip that’s doing all the conversion process. By default it is off, and the user need to ask it to ‘wake up’ to execute the conversion. Here’s a flow diagram to better illustrate the ADC process.
The flow diagram above does not include the configuration but I’ll cover it as I go. Having a rough picture of the ADC process is essential for understanding the ADC on the PIC16F877A.
Now, onto the configuration of the ADC. There are only FOUR registers that you need to understand to configure the ADC. They are ADCON0, ADCON1, ADRESH and ADRESL. The two most important ones are ADCON0 and ADCON1. ADRESH and ADRESL are just the registers where the ADC stores the result of the conversion.
The user has to select the correct clock conversion. The period must be at least more than 1.6us to obtain an accurate conversion. For example, I’m using a 4MHz crystal oscillator on my PIC16F877A. So if I select Fosc/2, thats 2MHz and the period is just 500ns and it’s far less than the 1.6us required.
What if I select Fosc/8? That will give me 0.5MHz and the period is 2us. That is more than 1.6us so it can be selected. So, my ADCON0 is now 01xx xxxx.
Now onto selecting the Analog Channel. The ADC can only have one input at a time so the user must select which pin he/she wants to use.
Referring to the PIC16F877A pinout diagram,
These are the Analog Channels available. Let’s say in my circuit I have an input into Analog Channel 3 (which is also PORTA bit 3), so I have to set ADCON0 to 0101 1xxx.
Lastly, we will set all these bits to 0 because this is just the initialization, the actual program has yet to start (Later in the code I will individually set these bits to enable ADC). So that makes ADCON0 to be 0101 1000.
The ADFM bit determines how the result of the ADC is justified. The ADC on the PIC16F877A has 10-bits of resolution, so of course a single register (that has 8 bits) is not enough to contain the 10-bits result. Therefore, two registers are required to store the results. ADRESH and ADRESL (H is the high byte while L is the low byte).
Two registers will allow us to store up to 16 bits, but since there are only 10 bits, we have the flexibility to align it right justified or left justified. Hopefully you will get the picture from the diagram below.
Storing the result in left justified mode is weird and unusual but it gives the user flexibility. Let’s say my application does not need the 10-bit accuracy, 8 bits is more than enough. So I can just take the result in ADRESH and ignore the remaining two least significant bits in ADRESL (you cannot ignore the two highest significant bit because that will cause the result to be inaccurate). That makes it easier to move values to other registers. Yes, the accuracy of the result will be slightly affected but it is not so critical in applications where you don’t need accuracy, like my ADC Demo shown here. So, now the value of ADCON1 is 0xxx xxxx.
Next is the ADCS2 bit. Earlier, I calculated that Fosc/8 is adequate, so I selected it in ADCON0. But for Fosc/8, we need to set the ADCS2 bit in ADCON1 also. So, the value of ADCON1 will be 00xx xxxx.
Lastly, the most important part of the ADC configuration is to select the mode for each Analog channel. As shown before, we have Analog Channel 0 to 7. All these inputs can either be set to analog or digital. Referring to the table above, if we don’t need any analog inputs and require more digital pins (let’s say for a few LCDs), we can set the PCFG3:0 bits to be 011x. But in this case we do need the Analog inputs, so for simplicity we will set all of them to be in analog mode. Therefore, our final value for ADCON1 is 0000 0000.
One important thing to note is that I’ve selected Vdd as the Vref+ and Vss as the Vref-, that means that my conversion range is from 0V to 5V. If you need it to be other than that, you can set a custom Vref value by choosing other configurations of PCFG3:0.
That should be it for the configuration of the ADC on the PIC16F877A. I hope this will help you to get started. Thanks for reading 🙂