In this chapter, we’ll focus on Learning ADC of PIC microcontrollers. ADC or Analog to Digital Converter is one of the most fundamental features of a microcontroller. And whenever we work with microcontrollers, we need this feature almost all the time. So we have to learn it which is a must. Let’s start.
Disclaimer:
Handling electricity carries inherent risks. It’s essential to have the appropriate skills to manage it safely. Proceed at your own risk, as the author disclaims responsibility for any misuse, harm, or errors. All content on this website is unique and copyrighted; please avoid unauthorized copying. While most articles are open-source for your benefit, feel free to use the knowledge provided. If you find our resources helpful, consider purchasing available materials to support our work.
For assistance or guidance, leave a comment below; the author is committed to helping. Some articles may contain affiliate links that support the author with a commission at no additional cost to you. Thank you for your understanding and support.
Table of Contents
About the previous chapter:
If you miss the previous chapter, you can read it here.
What is ADC:
In electronics, an analog-to-digital converter (ADC, A/D, or A-to-D) is a system that converts an analog signal, such as a sound picked up by a microphone or light entering a digital camera, into a digital signal. An ADC may also provide an isolated measurement such as an electronic device that converts an analog input voltage or current to a digital number representing the magnitude of the voltage or current. Typically the digital output is a two’s complement binary number that is proportional to the input, but there are other possibilities.
to read more on ADC you can check wiki link here.
But if you tell me to explain ADC in short, then I’ll say it converts analog voltage to a digital number with respect to MCU’s ADC resolution.
Say, you have a voltage of 2.5V, and the digital value for this voltage of a 5V reference, 8-bit MCU will be 127. Let’s explain how.
If your microcontroller’s ADC is 8bit, so you have a maximum number of ADC is 28 = 256. Now, if you set the reference voltage to the VDD of 5V, then the ADC will divide that 5V in a 5/256 scale. So for each value of ADC, the analog voltage difference will be 5/256 = 0.0196V or 19.6mV.
That means if you at any moment, your ADC’s result is 200, in this setting the actual sensing voltage is 200×19.6mV or 3.92V.
Now if you set the reference to 2.5V then the ADC will divide that reference voltage into 2.5/256 scale. That means in this case per ADC count the analog voltage difference is 2.5/256 = 9.8mV. Now if you find the ADC reading is 100(say) at any moment that means the actual analog voltage sensed by the ADC is: 100*9.8mV or 0.98V.
I think it is much clear to you.
Calculative parameters to keep as a note:
To make it easy, you can keep the following notes.
- First, find the ADC resolution whether it is 8bit or 10 bit or 12bit or 24bit or 32 or 64 or even more.
- Then calculate the maximum range of ADC result from this calculation: 2x | Where x is the bit. [Example: 8bit >> 28 = 256, 10bit >> 210 = 1024].
- Find the reference voltage of the ADC. In most cases it is ≦ VDD.
- For per count Analog voltage value, V/cnt = Ref. / Resolution max value. [Example: 5V/1024].
- Now to find out the exact voltage sensed by the ADC, sensed voltage = ADC reading x V/cnt.
Now let’s be practical.
If you open the datasheet of any PIC microcontroller you can find details about the ADC. For example:
As you can see, the ADC has three registers to control all the settings of the ADC. Which channel will be used, what is the reference voltage, speed of the ADC, and so on. So these are the registers you need to configure to work the ADC properly.
***Note: Some microcontrollers have ANSEL/ANSELH to set more parameters. So do now worry just read the datasheet first.
Now, let’s create a project in mikroC so that you can understand more.
Coding:
To use the ADC library in mikroC do not forget to activate the library from the library section. Otherwise, it will not work.
/* Project name: Test Project for learning PIC MCU Programmer: Mithun K. Das Email: mithun060@gmail.com Date:21-05-2023 */ void main() { TRISB = 0x00;//set all output TRISA = 0xFF;//set all input TRISC = 0x00;//set all output ADCON1 = 0x00;//Ref VDD, all channel analog ADCON0 = 0x01;//activate ADC channel 0 PORTB = 0x00;//clear port B PORTC = 0x00;//clear port C while(1) { PORTB = ADC_Read(0); Delay_ms(10);//not must, but should delay a bit to make it smooth }//end of while(1) }//end of void main()
This is a very basic code of ADC. Here I’m using channel 0 and kept the reference voltage to VDD which is 5V in this case. Now, the output will be found directly on PORTB.
You may know the binary counting system. If yes, you’ll understand it. If not, let me give you something.
In decimal, or the number we usually use is 1,2,3,4… etc right? Now these numbers are presented in binary like this:
Decimal | Binary[8bit] |
0 | 0000 0000 |
1 | 0000 0001 |
2 | 0000 0010 |
3 | 0000 0011 |
255 | 1111 1111 |
The PORTB output is in binary and you can now find the decimal value of that. But if you want to use the ADC result without those, you can do it too.
Example:
while(1) { if(ADC_Read(0) >127) { PORTB = 0xF0; } else { PORTB = 0x0F; } }//end of while(1)
&&
So it is working, right? Yes, you can use the value directly like decimal. Now, if you used any kind of digital display such as LCD or Seven Segment, you could print the ADC value directly on that. But as you are not using anything else except LEDs here so you can see the LED outputs only here. But this is not meaning that the ADC is not working on the right scale. It is working fine.
Well, this is the end of this article for now. later on when it’s time we will interface LCD or any other display to show results on that display. Till then keep practicing and learning it. See you soon.
Read more on:
- Learning PIC Microcontrollers Programming in C: Chapter 4
- Improve your code learning PIC MCU in C: Chapter 5
- Learning PIC MCU Chapter 6: Interfacing passive components with Microcontrollers
- Learning PIC MCU Chapter 7: How to interface buttons with microcontrollers
For Professional Designs or Help:
20 Comments
iffi · 12/06/2023 at 12:25 am
Sir, Thanks for the Tutorial. Your way of teaching is very simple and easy. i like it very much.
MKDas · 14/06/2023 at 11:59 am
Thank you
iffi · 12/06/2023 at 12:28 am
Sir is there any mistake i have write ?? . increasing and decreasing the Led with push buttons. Pic16f877A. Please Tell me please. thanx
int button1;
int button2;
unsigned int dim_led = 0;
void main() {
TRISB = 0xFF;
TRISC = 0x00;
while (1){
button1 = RB0_bit;
button2 = RB1_bit;
if (button1 == 1 && dim_led = 255)
{
dim_led = dim_led-1;
}
Delay_ms(20);
RC2_bit = dim_led;
} }
MKDas · 14/06/2023 at 12:01 pm
Wrong
iffi · 24/06/2023 at 1:56 am
Hi, Sir my code is running nicely But RC5_bit is not working right time. what is the problem you think.
Please see and reply , thanx
int adc_value;
void main() {
ANSEL = 0b00000001;
TRISA = 0b00000001;;
TRISC = 0b00000000;
PORTC = 0b00000000;
ADC_Init();
while (1){
adc_value = ADC_Read(0);
if (adc_value > 825)
{
PORTC = 0b00000001;
}
else
{
Delay_ms(200);
PORTC = 0b00000000;
}
if (adc_value > 855)
{
PORTC = 0b00000011;
}
else
{
Delay_ms(200);
PORTC = 0b00000001;
}
if (adc_value > 890)
{
PORTC = 0b00000111;
}
else
{
Delay_ms(200);
PORTC = 0b00000011;
}
if (adc_value > 925)
{
PORTC = 0b00001111;
}
else
{
Delay_ms(200);
PORTC = 0b00000111;
}
if (adc_value > 975)
{
PORTC = 0b00011111;
}
else
{
Delay_ms(200);
PORTC = 0b00001111;
}
if (adc_value > 960)
{
RA5_bit = 0;
}
else if (adc_value < 930)
{ RA5_bit = 1;
Delay_ms(250);
}
if (adc_value < 950)
{
RC5_bit = 0;
}
else if (adc_value < 810)
{
RC5_bit = 1;
}
Delay_ms(200);
} }
MKDas · 02/07/2023 at 7:30 pm
disable other features of RC5 PIN.
iffi · 14/07/2023 at 6:16 am
Sir my PWM is not stoping at 255, HOW CAN i stop it at maximum 255. Please make change to code. please please reply thanks.
int count = 0;
void main () {
TRISD.F2 =1;
PORTD.F2 =1;
Delay_ms(100);
TRISD.F3 =1;
PORTD.F3 =1;
Delay_ms(100);
PWM1_Init (5000);
Delay_ms(100);
count = 0;
while (1){
PWM1_Start();
Delay_ms(20);
if (PORTD.F3 == 0)
{
PWM1_Set_Duty(count); // 0 to 255
count = count + 10;
Delay_ms(30);
}
else if (PORTD.F2 == 0)
{
PWM1_Set_Duty(count); // 0 to 255
count = count – 10;
Delay_ms(30);
}
}}
MKDas · 15/07/2023 at 8:09 pm
your count is exceeding 255. and when it cross 255, it substracts 255 from it. so PWM will never stop.
iffi · 17/07/2023 at 3:58 am
Dear Sir, i notice ” my count is exceeding” i ask how can i stop this . Please write 2 lines Just, Please thanks.
MKDas · 22/07/2023 at 9:31 pm
example: if(myCount<250)myCount+=5; //so it never cross 255.
iffi · 23/07/2023 at 6:12 am
Sir Thanks for the reply from your precious time. I change the Code and its working.
if (PORTD.F3 == 0)
{
PWM1_Set_Duty(count); // 0 to 255
count = count ++;
if(count>255)
{
count = 255;
}}
MKDas · 23/07/2023 at 2:24 pm
welcome
iffi · 23/07/2023 at 6:17 am
Dear Sir , How can i Read Multiple ADC from single (MCU). I write a code but its not working. Please Guide little.
int read1;
int read2;
int read3;
void main() {
ADCON0 = 0x41;
ADCON1 = 0x89;
TRISA = 0b00000111;
PORTA = 0b00000000;
TRISB = 0b00000000;
TRISB = 0b00000000;
ADC_Init();
Delay_ms(20);
while (1){
read1 = ADC_Read (0);
read2 = ADC_Read (1);
read3 = ADC_Read (3);
if(((read1 == 250) && (read2 == 250) && (read3 == 250)))
{
PORTB = 0b00000001;
}
else {
PORTB = 0b00000000;
}
Delay_ms(5000);
if(((read1 <= 200) && (read2 == 250) && (read3 == 250)))
{
PORTB = 0b00000010;
}
else {
PORTB = 0b00000000;
}
MKDas · 23/07/2023 at 2:24 pm
every time you read a ADC channel, you need to select that channel using ADCON0 register.
iffi · 10/08/2023 at 1:51 am
Every time i need to reset the value of ADCON0 ???
In void main or while loop ???
Like this ?? ADCON0 = 0x41;
ADCON0 = 0x01;
???
MKDas · 12/08/2023 at 6:14 pm
yes, just before you read from a channel and if you are reading from multiple channel then you need to activate that channel with proper settings. That is why, you need to call ADCON0 every time. But if you read only one channel then you can call it once outside while loop.
iffi · 20/08/2023 at 1:42 am
Sir, How can i contact you with email that you reply me fast, Please i really really want to learn PIC programming.
MKDas · 21/08/2023 at 10:54 am
WhatsApp
iffi · 02/09/2023 at 7:43 am
Hi, Sir In this code i want to delay before Turning high , But its not working. It delay as well as in LOW time too. How can i make delay Only in Turning On. ( No delay for turning ON).
void main() {
TRISB = 0b00000111;
PORTB = 0b00000000;
TRISC = 0b00000000;
PORTC = 0b00000000;
while(1){
if (PORTB == 0b00000111)
{
Delay_ms(8000);
PORTC = 0b00000001;
}
else {
PORTC = 0b00000000;
}
}
}
MKDas · 04/09/2023 at 8:30 pm
check conditions, simulate it.