Incorrect Analog Read..

Hi,
I've created a voltage meter to measure the voltages of my main and aux batteries in my 4WD. I'm using a Ruggeduino board to reduce the risk of overloading the board, plus deal with the unfriendly automotive environment.. I've created a voltage divider to measure the battery voltages.. I'm using a voltage divider that allows me to read up to 16v. R1 is 22k and R2 is 10k, thus when the input voltage is 16v the voltage drop across R2 (10K) should be 5v. The issue I'm finding is that when I feed 16v into R1 (22k) the voltage across R2 (10k) is 4.12 v rather than 5v. Disconnecting the analog input pin from the circuit, causes the voltage to come up to 5v as it should. This means that the Arduino is loading the circuit, causing the voltage drop. I didn't think it was supposed to do that i.e. it should have a high impedance. I've checked to ensure I don't have any internal pull up resistors, but to no avail. Is this what is to be expected?

Rgds,
Simmi

It sounds like the analog pin may be "loading" the circuit, ie adding resistance to your divider. Please upload the sketch your using

You might also try connecting the analog pin to your voltage divider through a 1megohm resistor. It the pin is loading the divider that should reduce the load to a negligible value.

If by mistake, you declared analog pin as OUTPUT somewhere in the sketch, post you code to clear this

Thanks..
I'll try the 1Megohm resistor in series with the analog input pin. Anyway, first, I'm attaching a photo of the monitor mounted onto the dash of my 4wd car.. I'm also attaching the schematic of the input for the battery monitoring..

I've worked out that a 16v voltage across the 22k/10k resistors generate around 0.0005 amp current.. Given that the 10k resistor drops 4.12v the extra resistance is in parallel to that. I've worked out that you need a 47k resistor in parallel with the 10k one to drop the voltage down to 4.12v instead of 5v. So the analog input appears to have a 47k DC impedance.

The code to set up and initialise is as follows:

/*
  4WD Car Battery Voltage, Temperature and Charging monitoring.
  The circuit uses two analogoue inputs to monitor the Main Battery and Aux Battery
  The circuit uses one analogoue input to measure the current in/out of the Aux Battery via a CS-200A
  Hall-Effect Current sensor board.
  The circuit also implements a one wire protocol to read the temperature from three Dallas
  DS18B20 Temperature Sensor and display the temperature in degrees celcius.  Two sensors
  monitor the two batteries(Main and Aux), whereas one monitors the outside temperature.
  The code also uses the EEPROM memroy to store the Highest/Lowest temperature read from the outside
  temperature sensor.
 
  The circuit:
   A0 - Main Battery
   A2 - Aux Battery
   A3 - Anaologue Current In
   8 -  Digital Pin for resetting Min/Max Outside Temperature
   6 -  Digital Pin for One Wire Protocol
 * LCD RS pin to digital pin 12
 * LCD Enable pin to digital pin 11
 * LCD D4 pin to digital pin 5
 * LCD D5 pin to digital pin 4
 * LCD D6 pin to digital pin 3
 * LCD D7 pin to digital pin 2
 * LCD R/W pin to ground */

 
 
 
 // include the library code:
 #include <LiquidCrystal.h>
 #include <OneWire.h>
 #include <DallasTemperature.h>
 #include <EEPROM.h>
 
 // One Wire Bus is plugged into digital pin 6 on the Arduino
 #define ONE_WIRE_BUS 6

 // Setup a oneWire instance to communicate with any OneWire devices
 OneWire oneWire(ONE_WIRE_BUS);

 // Pass our oneWire reference to Dallas Temperature. 
 DallasTemperature sensors(&oneWire);
// Assign the addresses of Dallas Temp sensors.

// In LC DeviceAddress mainThermometer = { 0x28, 0x45, 0xF6, 0x9A, 0x03, 0x00, 0x00, 0xA4 };
// In LC DeviceAddress outsideThermometer = { 0x28, 0x6F, 0xF5, 0x9A, 0x03, 0x00, 0x00, 0x93 };
// In LC DeviceAddress auxThermometer = { 0x28, 0xA2, 0xDC, 0x9A, 0x03, 0x00, 0x00, 0x4D };

 DeviceAddress mainThermometer = { 0x28, 0x08, 0xC0, 0x9A, 0x03, 0x00, 0x00, 0x83 };
 DeviceAddress outsideThermometer = { 0x28, 0x03, 0xEB, 0x9A, 0x03, 0x00, 0x00, 0xF3 };
 DeviceAddress auxThermometer = { 0x28, 0x37, 0x8E, 0x82, 0x03, 0x00, 0x00, 0x25 };

 // initialize the library with the numbers of the interface pins
 LiquidCrystal lcd(12, 11, 5, 4, 3, 2);
 const int numMainReadings = 10;
 const int numAuxReadings = 10;
 const int numAuxAreadings = 10;
 
 int readingsMain[numMainReadings];
 int readingsAux[numAuxReadings];
 int readingsAuxA[numAuxAreadings];

 int indexMain = 0;
 int indexAux = 0;
 int indexAuxA = 0;
 int mainTotal = 0;
 int auxTotal = 0;
 int auxAtotal = 0;
 int mainAverage = 0;
 int auxAverage = 0; 
 int auxAaverage = 0;
 
 int MainBattSensor = A0;
 int AuxBattSensor = A2;
 int AuxCurrentSensor = A3;
 int AuxCurrentRawValue = 0;
 int AuxCurrentValue = 0;
 int MainBattValue = 0;
 int AuxBattValue = 0;
 float mainBattVolt = 0;
 float auxBattVolt = 0;
 float tempC;

// Ratio is 16v/1024
 float Ratio = 0.015625;                                                                                                                                                                                                                                                     

 long previousMillis = 0;
 long interval = 1000;

 char buf[20]="";
 char tempS[20]="";
 char tempT[20]="";
 float maxTemp = -100;
 float minTemp = 150;
 int buttonState;             // the current reading from the input pin
 int lastButtonState = LOW;   // the previous reading from the input pin
 // the following variables are long's because the time, measured in miliseconds,
 // will quickly become a bigger number than can be stored in an int.
 long lastDebounceTime = 0;  // the last time the output pin was toggled
 long debounceDelay = 50;    // the debounce time; increase if the output flickers
 
 
 //Define new custom LCD characters
 #define UPARROW_CHAR 4
 #define DOWNARROW_CHAR 5
 #define DEGREE_CHAR 6
 
 // EEPROM Addresses
 #define MIN_TEMP_ADDRESS  0x00
 #define MAX_TEMP_ADDRESS  0x01
 #define RESET_MINMAX_PIN  8  // button to reset the stored values in EEPROM

//Matrix for new customer charactes
 byte uparrow[8] = {
  B10100,
  B11100,
  B10100,
  B00001,
  B00001,
  B00001,
  B00000,
 };
 
  byte downarrow[8] = {
  B10000,
  B10000,
  B11000,
  B00010,
  B00101,
  B00101,
  B00010,
 };

 byte degree[8] = {
  B00000,
  B00000,
  B10011,
  B00100,
  B00100,
  B00100,
  B00011,
  B00000
};

 void setup(void) 
 {
  Serial.begin(9600);
   setupLCD();
  
  lcd.createChar(UPARROW_CHAR, uparrow);
  lcd.createChar(DOWNARROW_CHAR, downarrow);
  lcd.createChar(DEGREE_CHAR, degree);
  
  analogReference(DEFAULT);
  
  pinMode( RESET_MINMAX_PIN, INPUT );
  digitalWrite( RESET_MINMAX_PIN, HIGH );  // internal pull-up - switch will pull low to indicate reset
  
  minTemp = EEPROM.read( MIN_TEMP_ADDRESS );
  maxTemp = EEPROM.read( MAX_TEMP_ADDRESS );
 
  // Start up the One Wire library
  sensors.begin();
  // set the resolution to 10 bit (good enough?)
  sensors.setResolution(mainThermometer, 10);
  sensors.setResolution(outsideThermometer, 10);
  sensors.setResolution(auxThermometer, 10);
  
  // initialize all the array readings to 0 for the Main and Aux battery arrays
  
     
  for (int thisMainReading = 0; thisMainReading < numMainReadings; thisMainReading++)
    readingsMain[thisMainReading] = 0;  
  for (int thisAuxReading = 0; thisAuxReading < numAuxReadings; thisAuxReading++)
    readingsAux[thisAuxReading] = 0;    
  
  for (int thisAuxAreading = 0; thisAuxAreading < numAuxAreadings; thisAuxAreading++)
    readingsAuxA[thisAuxAreading] = 0;    
 digitalWrite(MainBattSensor, LOW);
 }


 void loop()

I'll post my results once I've tried the 1 Megohm resistor, but I find it still strange that the analog pin does this..
Rgds,
Simmi

BattMonitor_low_res.jpg

Well, I just tried the 1Mohm resistor in series with the analog input. The voltage over the 10K resistor is now 5v so that is great, however the voltage drop over the 1Mohm resistor is 2.235v so the reading is incorrect. This indicates that the current going through the 1Mohm resistor is around 2.2Micro amps. Thus the bigger the series resistor, the bigger the voltage drop across it. With the 16v and the 32k (22k+10k) resistors, the current is around 500 Microamps through the 22k resistor, but then it is split across the 10k and the internal resistance of the analog pin. I calculate that current to be around 18 microamps, which isn't much, but manages to drop the voltage down by almost a whole volt.
This would indicate I need to use lower value resistors overall i.e. increase the current, so proportionally the current into the analog pin has less significance.. Any other ideas?
Rgds,
Simmi

Well, looking at the results of your measurements, I think that problem could be related to zener diodes installed in parallel to each port on the board.
Of course, it makes board vandal-proof protected, but also increases input current, especially when input voltage goes above 4V.

Eureka!! :slight_smile: Of course. I had forgotten about those.. It is consistent with my measurements.. i.e. the closer to the 5v the worse it was. Thanks for pointing this out..
So my option is to remove the zener diodes, or change the resistance divider to 3.3v and use that as the reference voltage on the Arduino.. That way I never get close to the zener diode barrier..
Rgds,
Simmi

What Zener diodes, I don't see them on the schematic?

I`m using the Ruggeduino version of the Uno board. It has 5.1 zener diodes on all the i/o pins, plus a 220ohm resetable fuse resistor. I chose that specially made board as it handles higher voltages and has lots of protection components like the Zener diode. The schematic is of the std Uno board I used initially.
Rgds simmi

Well I've decided to use the 3.3v as the reference voltage.. I've put the 3.3v to the Aref pin and put in a resistor divider where r1 is 47k and R2 is 12.2k.. This gives me just about 3.3v when I've got a 16v input. Close enough.. That way I can retain the zener diodes and still protect the input from over voltages if they occur.. It is now working fine. I only have 5% resistors, so I'll put in 1% ones so the two channels track closely..
Rgds,
Simmi

In case you need 1% or better accuracy, I'd check on thermal non ? stability of leakage current of this zeners. I can't see part number on the schem, would be interesting have a look in their data specification on this matter.

The zeners on the board have a marking of Z2W. This appears to be bzx84c5v1. The diode has three legs on its SMD casing.. Reds simmi

Hmm, I download a data sheet from here: BZX84C5V1 Datasheet pdf - 350mW ZENER DIODE 3.3 VOLTS THRU 33 VOLTS 5% TOLERANCE - Central Semiconductor
Fairchild, as I don't know manufacturer, probably, its doesn't really matter. Chart "5.1 Zener Voltage vs. Temperature" makes me uncomfortable, zener optimized for best thermal stability at 5 mA, with lower current it getting worse, even chart doesn't show below 1mA, but extrapolation would lead to 100-200 % may be more offset. What I'd suggest, you have to buffer input with OPA and use a res. divider, or better set another zener in series battery<->zener<->resistor<->ground , about 11.2 V, so when bat. goes up to 16, input will see from res. to ground 4.8V. In this case you wouldn't be able to measure below 11.2V.

It's all working now fine. I didn't need high accuracy.. I'm using 3.3v for the current sensor and the battery voltage sensing. The 1% 47k and 12.2k (10k+2.2k) resistor divider seems to work fine. When I have 16v input, the voltage across the 12.2k is 3.3v. Because it's 3.3v it doesn't trigger the zener diode as it only starts conducting around 4v. For the temperature sensors Dallas DS1820 I use the 5v line. I had them on the 3.3v but that didn't work, i.e. they just shoed 0 degrees and wouldn't read the bus. Now it's working fine. Thanks for the help.. Simmi

3.3v it doesn't trigger the zener diode as it only starts conducting around 4v

False assumption, zener start to conduct at "0" V.
Current passing in your res. divider is only 16 / 60k = 55 uA.

You are of course right. The Zener always presents a parallel resistance across the input impedance of the analog input, plus the R2 (12.2k) resistor. I've measured the voltage across R2 and then lifted off the analog input to see if there are any differences.. Up to around 1.5v I can't measure them to three decimal places, but at 3.30v when disconnecting the analog pin the voltage rises to 3.41v Thus the difference is around 0.11v. My multimeter isn't all that accurate, so this is the difference it sees. That does account for the slight increase in differences at the higher voltages. It's accurate enough for my purposes at present. This implies that using a Zener on the analog inputs to protect the input also destroys any accuracy in the analog to digital conversion. Thanks again..
Simmi