CCS C Software and Maintenance Offers
FAQFAQ   FAQForum Help   FAQOfficial CCS Support   SearchSearch  RegisterRegister 

ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

CCS does not monitor this forum on a regular basis.

Please do not post bug reports on this forum. Send them to CCS Technical Support

PIC16F77A - ADC resolution

 
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion
View previous topic :: View next topic  
Author Message
Minh Lam



Joined: 06 May 2025
Posts: 1

View user's profile Send private message

PIC16F77A - ADC resolution
PostPosted: Tue May 06, 2025 9:57 pm     Reply with quote

I'm working on the ADC module of PIC16F877A. The schematic is very simple, including a voltage divider connected to RA0: https://uomustansiriyah.edu.iq/media/lectures/5/5_2020_06_14!01_18_34_AM.pdf

What I do not understand is the resolution of the module. The ADC module has 10-bit resolution as read in the datasheet. I was guided that I should put #device ADC = 10 in the code. The real value would be read_adc() * 5/1023 . Everything is fine. My code is as follows:

Code:

#include <16f877a.h>
#include <def_877a.h>
#DEVICE ADC=10 //return 10 bit
#fuses HS, NOWDT, NOPROTECT, NOLVP, NODEBUG, NOBROWNOUT, NOCPD, NOWRT
#use delay(clock=8MHz)

#define LCD_RS_PIN PIN_A2
#define LCD_RW_PIN PIN_A3
#define LCD_ENABLE_PIN PIN_A5
#define LCD_DATA4 PIN_D4
#define LCD_DATA5 PIN_D5
#define LCD_DATA6 PIN_D6
#define LCD_DATA7 PIN_D7
#define LCD_DATA0 PIN_D0
#define LCD_DATA1 PIN_D1
#define LCD_DATA2 PIN_D2
#define LCD_DATA3 PIN_D3

#include <lcd.c>

float voltage;

void main() {
    setup_adc_ports(AN0);
    setup_adc(ADC_CLOCK_DIV_2);
    lcd_init();

    while(true) {
        set_adc_channel(0);
        delay_us(10); 
        voltage = (read_adc()*5.0)/1023;

        lcd_gotoxy(1, 1);
        lcd_putc("DHCN");   
        lcd_gotoxy(1, 2);
        printf(lcd_putc, "%1.2fV", voltage);
    }
}

But when I do not put the directive #device ADC = 10, the voltage must be divided by 65535 to get the correct voltage. OR, I can use ADC = 16 instead (?).

I'd highly appreciate it if someone can explain this. Thank you very much.
temtronic



Joined: 01 Jul 2010
Posts: 9476
Location: Greensville,Ontario

View user's profile Send private message

PostPosted: Wed May 07, 2025 5:28 am     Reply with quote

pretty sure it's the printf format.

"%1.2fV"

to me 1.2 is bad, '1' is total number of digits, '2' is number of digits after decimal point

try '4.2' and see what happens.

The manual isn't very clear about this,2 or 3 more example would be nice.
EmilyHarris



Joined: 16 May 2025
Posts: 1

View user's profile Send private message

PostPosted: Fri May 16, 2025 1:00 am     Reply with quote

I am replying here so that I can keep track of this thread.
Ttelmah



Joined: 11 Mar 2010
Posts: 19836

View user's profile Send private message

PostPosted: Sat May 17, 2025 3:41 am     Reply with quote

Lets make some comments:

First/1023 is wrong. You need /1024. Yes, the ADC has a maximum
reading of 1023, but it reaches this a little before Vref. So the value for
5v, would really be 1024, but the ADC never gives this. There is a graph
given in some of the datasheets of the conversion function, and
Microchip do somewhere have an application note about this.
Then your ADC clock setting is wrong. Datasheet again. For an 8MHz master
clock, you need to use /16. /2 is suitable for a maximum CPU clock rate
of just 1.25MHz. Table 11-1.
Then you don't need to keep reselecting the ADC channel. Select it once
outside the loop.
Jay has already pointed out the problem with your printf format. In C
the number in front of the decimal in printf, is the total field width. The
total number of characters to output, so for x.xx, four characters are
needed. Then the number after the decimal, is obvious, Jay comments
about the poor CCS documentation in this regard, but really the key here
is that this is standard C and is covered in every C textbook.
You'd probably want to slow the loop a little more. Most LCD's can only
update perhaps 4* per second, so taking the delay out to perhaps 200mSec
will work better..

Now on your quateion about the factors and adc=, you can use adc=16,
what happens is as follows:

ADC=8
00000000 VVVVVVVV - top 8 bits of ADC value only
ADC=10
000000VV VVVVVVVV - 10 bit ADC result
ADC=16
VVVVVVVV VV000000 - 10 bit ADC result left justified

So, yes, you can use ADC=16, but it then requires division by 65536

Now on both cases, don't divide!... Multiply instead. In the PIC (and most
other chips without a maths coprocessor), division is a much slower
maths operation, than multiplication. Typically at least four time slower
and resulting in larger code as well.
So instead of using /1024, or /65536, multiply by 0.0009765625, or
0.0000152587. This will result in smaller and faster code.
This also applies to your whole sum. Pre-solve the factor. So 5.0/1024=
0.0048828125

voltage = read_adc()*0.0048828125;

Is more efficient.
However we can go even better, Work in integers instead of float.
In integer, division by binary values (2, 4, 8 etc) is very efficient.
So:
Code:


void main(void)
{
    unsigned int16 adc_val;
    delay_ms(250); //most LCD's require at least 90mSec before they
    //can be initialised
    setup_adc_ports(AN0);
    setup_adc(ADC_CLOCK_DIV_16);
    set_adc_channel(0);
    lcd_init();

    while(TRUE)
    { 
        delay_ms(200);
        adc_val=read_adc();
        adc_val=(adc_val*31)+(adc_val/4); //Gives *31.25 very efficiently

        lcd_gotoxy(1, 1);
        lcd_putc("DHCN");   
        lcd_gotoxy(1, 2);
        printf(lcd_putc, "%4.2lw", (adc_val/64));
    }
}


*31.25/64 = 0.48828125 this is 100* 5/1024, so gives an integer in
hundredths of a volt. %4.2lw displays an integer as x.xx
Display posts from previous:   
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion All times are GMT - 6 Hours
Page 1 of 1

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum


Powered by phpBB © 2001, 2005 phpBB Group