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;
   
  val = analogRead(average);    // read the input pin
  
  for (int i=0;i<average;i++)
  {  
    val = analogRead(meas_ch);    // read the input pin
    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″]

Leave a Reply

Your email address will not be published. Required fields are marked *