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 support@ccsinfo.com

Problem with ADC
Goto page 1, 2  Next
 
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion
View previous topic :: View next topic  
Author Message
haronraziq



Joined: 25 Aug 2011
Posts: 17

View user's profile Send private message

Problem with ADC
PostPosted: Sun Oct 16, 2011 9:35 pm     Reply with quote

I have been trying to get the ADC to work correctly based on a CCS C example, but for some reason the output of the ADC is incorrect. For example, an input of 5 volts displays only 3.76 volts.

Below is my code, any help is greatly appreciated.

Code:

void displayVoltage(int adc)
{
   char voltage[9];
   sprintf(voltage, "%f", (float)adc * .01960784); // Converts adc to text
   voltage[4] = '\0';                              // Limit shown digits to 3
   glcd_rect(45, 18, 69, 25, YES, OFF);            // Clear the old voltage
   glcd_text57(45, 18, voltage, 1, ON);            // Write the new voltage
}


void main()
{

   int8  adc = 0;

   setup_adc_ports(AN0_AN1_AN3);
   setup_adc(ADC_CLOCK_DIV_2);
   set_adc_channel(1);

   glcd_init(ON);

   adc = read_adc();                 // Read a value from the ADC
    displayVoltage(adc);              // Display the reading
haronraziq



Joined: 25 Aug 2011
Posts: 17

View user's profile Send private message

PostPosted: Sun Oct 16, 2011 9:40 pm     Reply with quote

I am using the PIC16f877 and a 20 MHz oscillator.
haronraziq



Joined: 25 Aug 2011
Posts: 17

View user's profile Send private message

PostPosted: Sun Oct 16, 2011 10:25 pm     Reply with quote

Also, for some reason it does not display any voltage greater than 5 volts or less than .1 volts. Please if anyone knows what the problem is, I would really appreciate the help.
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Sun Oct 16, 2011 10:44 pm     Reply with quote

Quote:
setup_adc(ADC_CLOCK_DIV_2);

I am using the PIC16f877 and a 20 MHz oscillator.

For example, an input of 5 volts displays only 3.76 volts.

Download the 16F877 data sheet:
http://ww1.microchip.com/downloads/en/DeviceDoc/30292c.pdf
Read this section. Look specifically at Table 11-1:
Quote:

11.2 Selecting the A/D Conversion Clock

TABLE 11-1: TAD vs. MAXIMUM DEVICE OPERATING FREQUENCIES (STANDARD DEVICES (C))

Note the clock divisor value that you should be using at 20 MHz.
Compare it to the one you're currently using.

Look in the 16F877.h file to see the list of clock divisor constants
that you are allowed to use. You will see the correct one in the list.
haronraziq



Joined: 25 Aug 2011
Posts: 17

View user's profile Send private message

PostPosted: Sun Oct 16, 2011 11:25 pm     Reply with quote

I tried changing it to the corrected value that but still no change. The output still will not show anything greater than 5 V or anything less than .1

Here is the new code.
Code:

void displayVoltage(int adc)
{
   char voltage[12];
   sprintf(voltage, "%f", adc * .01960784);         // Converts adc to text
   glcd_rect(45, 18, 69, 25, YES, OFF);            // Clear the old voltage
   glcd_text57(0, 24, voltage, 1, ON);            // Write the new voltage
}


void main()
{

   int16  adc = 0;

   setup_adc_ports(AN0_AN1_AN3);
   setup_adc(ADC_CLOCK_DIV_32);
   set_adc_channel(1);

   glcd_init(ON);

   adc = read_adc();                 // Read a value from the ADC
    displayVoltage(adc);              // Display the reading

}

and the defines/headers I have, which i did not mention before are:
Code:

#include <16f877.h>
#include <math.h>

#FUSES NOWDT                    //No Watch Dog Timer
#FUSES HS                       //Crystal osc <= 4mhz for PCM/PCH , 3mhz to 10 mhz for PCD
#FUSES NOBROWNOUT               //No brownout reset

#use delay(clock=20000000)

I also include some graphic lcd drivers but I am sure those are not causing the problem.
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Sun Oct 16, 2011 11:43 pm     Reply with quote

Quote:
The output still will not show anything greater than 5 V or anything less than .1

I'm not sure I understand this comment. Do you believe you can
directly read the A/D value of input voltages that are greater than +5.0v
and less than 0 volts (negative voltages) ?

You can't. To do it, you would need an external level-shifter circuit,
which is usually done with a resistor network (voltage divider) or an
Opamp circuit.

If you are trying to put voltages on the A/D pin that are outside of the
specified maximum and minimum range, you could damage the A/D pin
on the PIC. Look in the 16F877 data sheet, in the back, in the Electrical
Specifications section. It's all there.


Last edited by PCM programmer on Mon Oct 17, 2011 1:03 am; edited 2 times in total
haronraziq



Joined: 25 Aug 2011
Posts: 17

View user's profile Send private message

PostPosted: Sun Oct 16, 2011 11:57 pm     Reply with quote

Sorry for the confusion but I got mixed up. I understand the +5 volt limitation, I meant that it cannot read voltages greater than zero but less than .01. Is the resolution of the ADC too small for this?
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Mon Oct 17, 2011 1:00 am     Reply with quote

Quote:
void main()
{

int16 adc = 0;

setup_adc_ports(AN0_AN1_AN3);
setup_adc(ADC_CLOCK_DIV_32);
set_adc_channel(1);

glcd_init(ON);

adc = read_adc(); // Read a value from the ADC
displayVoltage(adc); // Display the reading

}


I notice that you don't have a delay after you set the ADC channel.
The spec for the acquisition time for the 16F877 is about 20 usec.
Look in this section. That's where I got the 20 usec value:
Quote:

11.1 A/D Acquisition Requirements


The link below has some tests that show what happens if you don't have
the correct acquisition time delay after you set the A/D channel:
http://www.ccsinfo.com/forum/viewtopic.php?t=44201&start=6
Note that the required delay is shorter for the 18F452. For your PIC,
it's 20 usec.

However, there is probably enough delay in the glcd_init() function
to do this. But just to be safe, put a delay_us(20); statement after
the set_adc_channel() line.

What is the output impedance of the device that supplies the voltage
to pin AN1 ? It must be 10K ohms or less (for the 16F877).
If the impedance is too high, you could easily get a reduced voltage
reading. What is the device that supplies the voltage to pin AN1 ?



One last thing. You really should add a while(1); statement at the the
end of main(). It prevents the program from running off the end of the
last brace, where it will execute a hidden SLEEP instruction and put the
pic in power-down mode.

Do it as shown in bold below:
Quote:
.
.
.
adc = read_adc(); // Read a value from the ADC
displayVoltage(adc); // Display the reading

while(1);
}
RF_Developer



Joined: 07 Feb 2011
Posts: 839

View user's profile Send private message

Magic numbers
PostPosted: Mon Oct 17, 2011 1:39 am     Reply with quote

How did you calculate the scaling value .01960784? This is what I call a magic number. It hides what you intended, and it hides whether you've made some error. Magic numbers are poor coding style. I always let the compiler derive these numbers from the relevant basic parameters as constants in#defines utilising constant collapsing. I won't show you how just yet as your number is not quite right and will give you inaccurate results even if everything else is working correctly. Not very wrong, but not precisely correct either. As with a school maths question I want to see the working out, not just the final result.

RF Developer
temtronic



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

View user's profile Send private message

PostPosted: Mon Oct 17, 2011 5:49 am     Reply with quote

ADC probably is in 8 bit mode...( 5V /255= .019......)

so 1 bit of ADC data is equal to = +-.019 volts.

Simply add code( as shown in header file) to get adc into 10 bit mode.
asmboy



Joined: 20 Nov 2007
Posts: 2128
Location: albany ny

View user's profile Send private message AIM Address

PostPosted: Mon Oct 17, 2011 10:08 am     Reply with quote

Do you have some reason that you are NOT using the improved 10 bit resolution of the '877 ?

Once you do sort out your clock and ADC setup issues -
4 times 8bit resolution is ready and waiting for you - ...;-))
haronraziq



Joined: 25 Aug 2011
Posts: 17

View user's profile Send private message

PostPosted: Mon Oct 17, 2011 10:50 am     Reply with quote

I am just testing by using a dc voltage source input.
haronraziq



Joined: 25 Aug 2011
Posts: 17

View user's profile Send private message

PostPosted: Mon Oct 17, 2011 3:03 pm     Reply with quote

I cannot find any code in the header file that corresponds to changing the adc resolution. How can I change to the 10 bit mode?
Gabriel



Joined: 03 Aug 2009
Posts: 1067
Location: Panama

View user's profile Send private message

PostPosted: Mon Oct 17, 2011 3:17 pm     Reply with quote

#Device ADC=10;
_________________
CCS PCM 5.078 & CCS PCH 5.093
haronraziq



Joined: 25 Aug 2011
Posts: 17

View user's profile Send private message

PostPosted: Mon Oct 17, 2011 3:26 pm     Reply with quote

That's what I thought. Here take a look at my code, I edited my code accordingly (the define is in another file but i did do it), but I still get the same output. It shows zero for an input of .01 volts.

Code:
void displayVoltage(int adc)
{
   char voltage[12];
   sprintf(voltage, "%f", (float)adc * .0048875855);         // Converts adc to text
   glcd_rect(45, 18, 69, 25, YES, OFF);            // Clear the old voltage
   glcd_text57(0, 24, voltage, 1, ON);            // Write the new voltage
}


void main()
{

   int  adc = 0;

   setup_adc_ports(AN0_AN1_AN3);
   setup_adc(ADC_CLOCK_DIV_32);
   set_adc_channel(1);

   delay_us(200);

   glcd_init(ON);

   adc = read_adc();                 // Read a value from the ADC
    displayVoltage(adc);              // Display the reading
}
Display posts from previous:   
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion All times are GMT - 6 Hours
Goto page 1, 2  Next
Page 1 of 2

 
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