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

adc reference voltage

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



Joined: 20 Mar 2010
Posts: 193
Location: Auckland NZ

View user's profile Send private message

adc reference voltage
PostPosted: Fri Jun 15, 2012 2:33 am     Reply with quote

Hi,
I use resistor ladder to drop down the voltage. I use 4x150K to test 15V.

GND<->ADC pin<-><-><->test voltage

What is my problem is the fact that my test of ADC is not linear. When I leave system running on the battery and battery voltage drops down then I have bigger error. E.g. 11.87 is tested as 9.30. I use olimpic average to do test and this works, as voltage refernece I use PIC +5V. Any ideas, hints why it would do it? Higher the difference in tested value from set value the bigger error I get.

Lets say I calibrate my normal running conditions of charged battery to 13.4V with power suplly running. When I turn off power supply and run the board of the battery then down difference during discharging is introducing bigger error depending on the difference value.

thnx for all hints.
Code:


chip 18f4620 ccs 4.114

// Variables ------------------
// ADC
long INT adc_read;
short readadc = 0;
float battery_voltage_test = 0; 
float fbattery_test = 0; 

// adjust value up or down
float battery_voltage_test_adjust = 21.55;
// adjust value up or down end
                                 
// 1 up / 0 down
float badjustup = 0;     
// 1 up / 0 down end

long INT ibattery_test = 0;
                                                                               
int battery_testh = 0;
int battery_testl = 0;

// ================================

// FUSES ==========================
#FUSES H4
#FUSES MCLR                                       
#FUSES BROWNOUT
#FUSES NODEBUG
#FUSES PROTECT    // code protect
#FUSES CPB        // boot block code protect
#FUSES CPD        // data eeprom code protect
#FUSES NOEBTRB    // boot block table code protect
#FUSES NOEBTR     // table code protect
#FUSES WDT2048
#FUSES WDT
#FUSES PUT                                         
#FUSES NOXINST       
#use delay (clock=40M, oscillator=10M)                           

// ================================

// SYSTEM SETUP ===================
void systemsetup(VOID)
{
   setup_wdt (WDT_ON);  //set watch dog timer
   disable_interrupts (GLOBAL);  //clear interrupts
   output_FLOAT (I2CSCL);
   output_FLOAT (I2CSDA);
   set_timer0 (0);  //clear timers
   set_rtcc (0);  //clear timers
   setup_timer_0 (RTCC_INTERNAL|RTCC_8_BIT|T0_DIV_1); //set timer 0 parameters
   setup_adc_ports (AN0_TO_AN5|VSS_VDD); //set AD ports
   setup_adc (ADC_CLOCK_DIV_64|ADC_TAD_MUL_2); //ADC_CLOCK_INTERNAL|
   setup_comparator (NC_NC_NC_NC); //turn off comparators
   enable_interrupts (GLOBAL);  //clear interrupts
   enable_interrupts (INT_ssp);  //enable serial i2c
   enable_interrupts (INT_RTCC); //enable TIMERs
}

// ================================

// READ ADC =======================
void read_analogue_input(UNSIGNED char adcParameter) 
{
   
   // olympic average ----------------------------------------------------------
   
   int a;
   long INT reading,minimum,maximum,average;
   long INT total_reading = 0;
   
   restart_wdt ();
   set_adc_channel (adcParameter);
   
   adc_read = read_adc (); // initial test                 
   reading = adc_read;
   
   total_reading = total_reading+reading;
   minimum = reading;
   maximum = reading;
   
   for (a=0;a<9;a++)
   {       
      adc_read = read_adc ();   
      reading = adc_read;
      total_reading = total_reading+reading;
     
      if (reading < minimum) 
      {
         minimum = reading;
      }
                                           
      if (reading > maximum)
      {
         maximum = reading; 
      }
   }
   
   average = (total_reading-(minimum+maximum))/(8);
   adc_read = average;
   
   restart_wdt ();
                 
} //VOID   

// BATTERY TEST ===================
void battery_testing(VOID)
{
   read_analogue_input (BATTERY_TEST);
   battery_voltage_test = adc_read;
                                                                 
   if (badjustup == 0) {
      fbattery_test = (battery_voltage_test / 20) - battery_voltage_test_adjust;
   }
   else {
      fbattery_test = (battery_voltage_test / 20) + battery_voltage_test_adjust;
   }   

   ibattery_test = fbattery_test * 100;
   battery_testh = ibattery_test / 100;
   battery_testl = ibattery_test - (battery_testh * 100);   
   
   IF (battery_testh < 11)
   {
      // battery low
      outputlowc (BATTERY);
   }
}

// ================================   

_________________
Help "d" others and then you shell receive some help from "d" others.
Markdem



Joined: 24 Jun 2005
Posts: 206

View user's profile Send private message Send e-mail

PostPosted: Fri Jun 15, 2012 3:27 am     Reply with quote

The problem here is the following line.

Code:

 setup_adc_ports (AN0_TO_AN5|VSS_VDD);


You are telling the pic to use the VDD voltage as the reference for the ADC. Remember what the ADCis doing. It is taking the sample voltage and comparing it to the reference range, which in this case is VDD-VSS. If VDD changes, and in your case it will, it will change the ADC result. The solution here is to use a voltage reference that will always feed a know voltage to the ADC as a reference. Have a look at microchip's MCP1541. Remember to change the setup_adc_ports to use a external reference.

Have Fun

Mark
Ttelmah



Joined: 11 Mar 2010
Posts: 19540

View user's profile Send private message

PostPosted: Fri Jun 15, 2012 3:45 am     Reply with quote

Also, look at the input impedance requirements of the PIC ADC. From the data sheet for your PIC:

"The source impedance affects the offset voltage
at the analog input (due to pin leakage current).
The maximum recommended impedance for analog
sources is 2.5 kΩ.".

There is 100nA of leakage internally in the ADC, and as the input impedance rises, this becomes more significant, and the acquisition time also increases. If you are using 3*150K, from 15v, and then 150K to ground, the leakage current, becomes very significant (1/222 the current down the resistor 'tree')....
You are also only allowing 2Tad for the acquisition, while with your source impedance, the required time would be 14.6uSec.

Best Wishes
Mike Walne



Joined: 19 Feb 2004
Posts: 1785
Location: Boston Spa UK

View user's profile Send private message

PostPosted: Fri Jun 15, 2012 5:26 am     Reply with quote

Your source impedance is too high. Maximum recommended is ~10k (or 2k5 depends on which microchip manual you read). The ADC input is effectively in parallel with a 100nA current source. This will give a worst case constant error of ~12mV, so not enough to account for the what you are seeing. Since you're not changing ADC channels aquisition times shouldn't be a problem.

How do you know what your measured voltage is?

I'd suggest that you:-

(1) Reduce your 150k resistors to ~12k.
(2) Simplify your code to the point where you're testing the ADC only, (sending raw ADC values to a PC).

As you let battery discharge measure each of the following:
(a) Battery voltage.
(b) Reference voltage (VDD in your case).
(c) ADC input voltage at PIC pin.

Mike
Linuxbuilders



Joined: 20 Mar 2010
Posts: 193
Location: Auckland NZ

View user's profile Send private message

PostPosted: Fri Jun 15, 2012 5:48 am     Reply with quote

Thank you for all help, I will change resistors and let you know how it goes. If is going about VDD-VCC I use 7805 as supply so battery is able to keep stable 5V as a reference and I imagine that it should not be a problem. Am I correct?
_________________
Help "d" others and then you shell receive some help from "d" others.
Mike Walne



Joined: 19 Feb 2004
Posts: 1785
Location: Boston Spa UK

View user's profile Send private message

PostPosted: Fri Jun 15, 2012 6:18 am     Reply with quote

Using an LM7805 for VDD should not lead to the gross error you're reporting.

Doing the voltage measuring tests I suggested, should show you what's going on. (Either by letting the battery discharge, or using a variable voltage bench power supply.)

Have you got good supply decoupling close to the PIC?

Mike
Linuxbuilders



Joined: 20 Mar 2010
Posts: 193
Location: Auckland NZ

View user's profile Send private message

PostPosted: Fri Jun 15, 2012 4:09 pm     Reply with quote

Mike Walne wrote:
Using an LM7805 for VDD should not lead to the gross error you're reporting.

Doing the voltage measuring tests I suggested, should show you what's going on. (Either by letting the battery discharge, or using a variable voltage bench power supply.)

Have you got good supply decoupling close to the PIC?

Mike


yes I do, it probably will be TAD, I do my work today and post what was the reason of this error. thnx for help
_________________
Help "d" others and then you shell receive some help from "d" others.
Linuxbuilders



Joined: 20 Mar 2010
Posts: 193
Location: Auckland NZ

View user's profile Send private message

PostPosted: Fri Jun 15, 2012 8:27 pm     Reply with quote

Hey,

How do I calculate resistors values in step ladder so I get proper load?

I have changed tad to 15us and changed resistors to 10K and all is good.

When supply is of the battery then it is introducing very small error because of VDD-VCC difference but this is insignificant.

Thank you for all help.
_________________
Help "d" others and then you shell receive some help from "d" others.
Mike Walne



Joined: 19 Feb 2004
Posts: 1785
Location: Boston Spa UK

View user's profile Send private message

PostPosted: Sat Jun 16, 2012 4:31 am     Reply with quote

Quote:
I have changed tad to 15us and changed resistors to 10K and all is good.
I take it that your errors are now acceptable.

Quote:
How do I calculate resistors values in step ladder so I get proper load?

Assume that you're want to measure Vin using a PIC in the circuit below

Code:
                 ---------------  PIC input
                |     
                |         
          R2    |     R1 
Vin ----WWWWW--------WWWWW-----
                               |
                              --- 0V Ground
                               -

The following relations hold:-

Attenuation ratio = (R2 + R1) / R1

Source impedance as seen by PIC = R1 * R2 / (R1 + R2)


For best resolution you want the attenuation ratio to be a minimum.
In other words input to PIC equals Vref at maximum Vin.

I.e. ( Maximum Vin ) / Vref = (R2 + R1) / R1


The PIC input is effectively in parallel with an internal 100nA current source.
For 10 bit accuracy this current has to produce a voltage across the source impedance less than ~Vref/2000. (i.e. about 2.5mV for 5V Vref)
With 10k source impedance this voltage will be 1mV (i.e. well within specification).

For maximum speed the source impedance needs to be a small as possible. Microchip recommends a minimum of 2k5.
(The PIC has an internal resistance of ~1k in series with the reference capacitor, it makes no sense to reduce the source impedance to much less than the suggested 2k5.)

To get your resistance values you can either:-

(1) Make an intelligent guess, work out the source impedance and attenuation ratio with above formulae. Keep refining guess until you get satisfactory results.
(2) Re-arrange formulae above, to get exact values for R1 and R2 directly.
(3) Make R1 equal to desired source impedance. Then R2 = R1 * ( Attenuation Ratio - 1). This method is simplest. The source impedance is slightly on the low side, (which is in the right direction to not cause problems).

Mike
Linuxbuilders



Joined: 20 Mar 2010
Posts: 193
Location: Auckland NZ

View user's profile Send private message

PostPosted: Sat Jun 16, 2012 4:26 pm     Reply with quote

thank you
_________________
Help "d" others and then you shell receive some help from "d" others.
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