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:

Advertisements

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 (ADCA/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:

Learning ADC of PIC microcontrollers
Learning ADC of PIC microcontrollers
Learning ADC of PIC microcontrollers

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.

ADC library of mikroC
/*
 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.

ADC of PIC microcontroller

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:

DecimalBinary[8bit]
00000 0000
10000 0001
20000 0010
30000 0011
2551111 1111
Decimal to Binary table

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)
Learning ADC of PIC microcontrollers

&&

Learning ADC of PIC microcontrollers

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:

For Professional Designs or Help:

Loading


MKDas

Mithun K. Das; B. Sc. in EEE from KUET; Head of R&D @ M's Lab Engineering Solution. "This is my personal blog. I post articles on different subjects related to electronics in the easiest way so that everything becomes easy for all, especially for beginners. If you have any questions, feel free to ask through the contact us page." Thanks.

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.

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

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

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.

Leave a Reply

Avatar placeholder

Your email address will not be published. Required fields are marked *