Getting Accurate Values from Arduino Analog Pin Measurements

# Getting Accurate Values from Arduino Analog Pin Measurements

At The Mad Scientist Hut I am currently building a battery capacity data logging system with the Arduino so that I can get discharge curves. I plan on discharging batteries at different load rates and since I would be spending days to many weeks and even months with each battery in discharge,  I did not think it would be very useful if the data was inaccurate . I was not really surprised to find out how far the raw measurement on the analog pin was from the actual value presented to the pin.  I made a quick two point gain and offset calibration that will correct the measurements and make them fairly accurate.  After implementing the gain and offset calibration I compared the values from the Arduino to the Fluke 87 DMM and across the range I was using (1.5V to 0.6V) I saw no more than a 2mV difference from the multimeter compared to readings from the analog pin.

To use the code you will need to define these variables in the beginning of the program:

```int     meas_ch =    0;// channel used for measuring voltage
int     val =        0;//used for averaging the voltage measured
//using the mega 2560 2.56V internal reference with this command
// "analogReference(INTERNAL2V56);"
double  ref =     2.56;//reference voltage
double  Voltage       ;//reported voltage after being averaged
double  average= 1000;//how many measurements to take for averaging
double  gain         ;// gain value for ADC
double  offset       ;// Offset value for ADC```

In the setup() routine I placed this code:

```  gain = 1.0;
offset = 0.0;

//gain = (mv1-mv2)/(fv1-fv2) //fv = force voltage, mv = measure voltage
//offset = fv2 - (gain * mv2)
// example:

//I set a power supply to 1.5V and I used a multimeter to measure the analog pin input
//voltage at 1.5v, running the the readV() routine the analog pin measured 1.534V
//then I set the supply to read on 0.9V the meter and the arduino
//analog pin measured 0.916v
//gain = (1.50 - 0.9)/(1.534 - 0.916);
//offset = 0.90 - (gain*0.916);

```
```// to use this section of code for the first time comment out the gain and offset example
// below, since you will have different values
gain = (1.50 - 0.9)/(1.5406 - 0.921);
offset = 0.90 - (gain*0.921);

```

The following routine is what I use to read the voltage back from the analog pin defined as ‘meas_ch’:

```void readV()
{
Voltage =0.0;

for (int i=0;i<average;i++)
{
Voltage = Voltage +(ref*(double(val)/1023.0));
}

Voltage = (Voltage/average);

Voltage = Voltage*gain+offset;

//to report back to serial port use the following:
//   Serial.print"Volts:");
//   Serial.println(Voltage,3);         // debug value```
``` //to report back to LCD use the following:
//    lcd.setCursor(0, 0);
//    lcd.print("Volts:");
//    lcd.print(Voltage,3);

}```

The following is an example of reading the voltage from the analog pin in the main code: (this code is using the the SD card write logfile.print:

```  readV();

if (Voltage <= 0.6)
{
V_stop++;
}

logfile.print(Voltage,4);

```

In the next blog I will discuss the auto ranging feature that I am adding to the system, so that when I hook up a battery such as a Li-Ion that is at 4V the system will switch in a divider and read the correct voltage.

[wp_bannerize categories=”12,146,4,47,77,58,68,9,102,111,1″]