View previous topic :: View next topic |
Author |
Message |
Linuxbuilders
Joined: 20 Mar 2010 Posts: 193 Location: Auckland NZ
|
adc reference voltage |
Posted: Fri Jun 15, 2012 2:33 am |
|
|
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
|
|
Posted: Fri Jun 15, 2012 3:27 am |
|
|
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: 19520
|
|
Posted: Fri Jun 15, 2012 3:45 am |
|
|
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
|
|
Posted: Fri Jun 15, 2012 5:26 am |
|
|
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
|
|
Posted: Fri Jun 15, 2012 5:48 am |
|
|
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
|
|
Posted: Fri Jun 15, 2012 6:18 am |
|
|
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
|
|
Posted: Fri Jun 15, 2012 4:09 pm |
|
|
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
|
|
Posted: Fri Jun 15, 2012 8:27 pm |
|
|
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
|
|
Posted: Sat Jun 16, 2012 4:31 am |
|
|
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
|
|
Posted: Sat Jun 16, 2012 4:26 pm |
|
|
thank you _________________ Help "d" others and then you shell receive some help from "d" others. |
|
|
|