Forum Rule: Always post complete source code & details to reproduce any issue!
Results 1 to 7 of 7

Thread: ADC Troubles (inaccurate and moving around a lot)

  1. #1

    ADC Troubles (inaccurate and moving around a lot)

    I'm just trying to get a simple reading from an ADC pin. However, the value seems to both be wrong and moving around much more than it should be.

    ON TOP:
    const int batteryPin = 16;

    IN SETUP:
    pinMode(batteryPin, INPUT);
    analogReference(DEFAULT);
    analogReadResolution(10);

    IN LOOP:
    display.print(analogRead(batteryPin));

    I have 2.92 volts on the ADC pin. So I should get a reading of 2.92V/3.3V*1024 = 906. Instead, I'm getting in readings that vary between 580 and 700 constantly. Why is this happening?

    I double checked with an oscilloscope and the voltage is very stable. There are no fluctuations on it to speak of. Bypass capacitor is already there.

    Schematically, I have two lithium ion batteries. They have a max voltage of about 4.2V. I have a divider coming off of them - series 500kohm and 1,500kohm. The connection is 4.2V to 500kohm to 1500kohm to ground. The ADC pin is hooked up between the two resistors.

    I have no idea what the problem is. This should be so simple. I'm just trying to read battery voltage so that I can estimate how much charge it has left. Help?

  2. #2
    Senior Member
    Join Date
    Oct 2012
    Location
    Portland OR
    Posts
    711
    Is it possible you have connected your voltage divider to a different pin than you are actually reading? Which physical pin are you using? Is it the one marked 16 (A2) with reference to http://www.pjrc.com/teensy/pinout.html ?
    Last edited by JBeale; 04-11-2013 at 08:10 PM.

  3. #3
    Senior Member
    Join Date
    Oct 2012
    Location
    Portland OR
    Posts
    711

    testing ADC in 10-bit mode

    OH- I just noticed your resistor values, I think that is the issue here.

    I just tried a test, using two 2k resistors as a voltage divider from 3.3V to GND.
    Fluke 179 meter says "3.3V" pin is 3.271 V and ADC input (16 / A2) is 1.632 V.

    Code:
    const int batteryPin = 16;
    
    void setup() {
    delay(2000);
    Serial.begin(115200);
    pinMode(batteryPin, INPUT);
    analogReference(DEFAULT);
    analogReadResolution(10);
    }
    
    void loop() {
    Serial.println(analogRead(batteryPin)); 
    delay(100);
    }

    Here is some sample output from above code:
    Code:
    2x 2k resistor divider output:
    514
    514
    513
    514
    513
    514
    514
    514
    514
    513
    513
    514
    514
    514
    513
    513
    514
    513
    514
    514
    513
    514
    514
    514
    Now I try the same thing again but with a pair of much larger resistors, 2x 1 Megohm. Fluke meter hasn't changed much, at 1.563 V, but the Teensy3 says something quite different, see below. I think the maximum recommended impedance on the ADC input is probably 10k or less. When you go to very high value resistors, you get more noise, and more DC offset due to loading. I'm guessing you want high value R to avoid constant current drain on the battery. One solution is to use small resistors like the 2k values I tried first, but power-switch your battery divider (use a series N-channel FET in between the bottom resistor and ground, and turn it off whenever you are not actively reading it.) That approach is usually cheaper than high-value resistors and an op-amp buffer.

    Code:
    2x 1Meg resistor divider output:
    412
    362
    327
    358
    375
    353
    403
    354
    377
    389
    332
    367
    403
    416
    367
    391
    342
    410
    380
    342
    426
    382
    361
    352
    342
    342
    392
    Last edited by JBeale; 04-11-2013 at 08:43 PM.

  4. #4
    Wow, very interesting. That leaves no doubt about what the problem is. Thank you very much!

  5. #5
    I wonder... would a 1uF cap on the ADC pin to ground help? The idea would be to charge the cap. Since I'm only wanting to detect battery voltage, I only sample that pin once every few minutes at most. Doing the math with RC time constants (500kohm resistor into 1uF cap), it would be 86% charged in 1 second. A 100nF cap would be basically 100% charged in 1 second. I'll try this and see if that works...

    edit: need to leave. will try this tomorrow and update you guys.
    Last edited by kingforger; 04-11-2013 at 09:02 PM.

  6. #6
    Senior Member Constantin's Avatar
    Join Date
    Nov 2012
    Location
    In the yard with a 17' Dia. Ferris Wheel
    Posts
    1,408
    Quote Originally Posted by kingforger View Post
    I wonder... would a 1uF cap on the ADC pin to ground help?
    I'd go with something even smaller... 0.1uF should be fine. The main issue is that you're trying to read a high-impedance load with a SAR-type ADC, which starts by charging a small capacitor (5-10pF) inside the Teensy ADC. Depending on the resolution, consistency, etc. desired, you may need as many as 31 time constants (at 16 bits) to achieve happiness... I'd guess that adding a small external capacitor (0.1uF or 0.01uF) should be fine in this application, provided the signal does not change quickly and you sample infrequently (i.e. allowing the external cap to recharge)

    IIRC, my calculations for 16 bit resolutions indicated a maximum source impedance of around 25kOhm to allow 16 bit measurements at a 6MHz ADC clock rate. So nothing wrong with using large resistors to limit current flow through the resistors, just use a external cap to help charge the SAR ADC sample and hold capacitor.

  7. #7
    Yup, a 0.1uF cap did it! Thanks.

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •