Best method for reading Analog Voltage in

Hi guys, I have picked up a project from someone else who left little documentation. The aim is to read values from a Gas Pellistor Sensor. I am more familiar with hardware electronics so I am struggling to work out the best way to convert the analog signal provided to the arduino into a precise voltage. So far I have used two different methods provided by the previous person doing the project however both are slightly incorrect when checked against a DMM;

double TestValue,OutputValue,TestVoltage,OutputVoltage;
double SystemVoltage = 5;
double SystemResolution = 1023;


void setup() {
  // put your setup code here, to run once:
  Serial.begin(9600);
  pinMode(A1,INPUT);
  pinMode(A0,INPUT);
}
void loop() {
  TestValue = analogRead(A0);
  OutputValue = analogRead(A1);
  TestVoltage = ((TestValue * SystemVoltage)/SystemResolution);
  OutputVoltage = ((OutputValue * SystemVoltage)/SystemResolution);
  Serial.print("Test Value: ");
  Serial.println(TestValue);
  Serial.print("Test Measured Voltage: ");
  Serial.println(TestVoltage,4);
  Serial.print("Analog Value: ");
  Serial.println(OutputValue);
  Serial.print("Measured Voltage: ");
  Serial.println(OutputVoltage,4);
  delay(1000);
}

The other method used is referencing the input signal against the 1.1V internal reference built into the arduino, this function was found on a previous forum;

long readVcc() {
  long result;
  // Read 1.1V reference against AVcc
  ADMUX = _BV(REFS0) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1);
  delay(2); // Wait for Vref to settle
  ADCSRA |= _BV(ADSC); // Convert
  while (bit_is_set(ADCSRA,ADSC));
  result = ADCL;
  result |= ADCH<<8;
  result = 1125300L / result; 
  return result;
}

This produces a value of 5022, when i was expecting something like 1100 although i have probably just misunderstood what its actually doing.

This is followed by;

Vcc = readVcc();
val0 = analogRead(Signal);
voltage0 = (val0 / 1024.0) * (Vcc - 0.07);

I dont fully understand the formula used to calculate voltage0, especially the 0.07. It does however produce a relatively close value to the actual value.

Any help would be greatly appreciated, Cheers.

But what is the voltage (range) you want to read?

If it’s below 1,1V you gain in resolution by switching from the default 5V (actually Vcc) to the 1,1V ref. And the 1,1V ref probably is more precise as well where Vcc might be off, especially when powered from USB it will probably not be 5,00V.

Btw, you can reduce any signal <1,1V with the use of a voltage divider. And you don’t need to do register manipulation to set it to the 1,1V reference, simply use analogReference(INTERNAL).

harrygover:

double SystemResolution = 1023;

void loop() {
 TestVoltage = ((TestValue * SystemVoltage)/SystemResolution);
}

Besides the complete misuse of all doubles, division by 1023 is always wrong :wink: Should be 1024.

harrygover:

Vcc = readVcc();

val0 = analogRead(Signal);
voltage0 = (val0 / 1024.0) * (Vcc - 0.07);




I dont fully understand the formula used to calculate voltage0, especially the 0.07. It does however produce a relatively close value to the actual value.

I think this person did some calibration it doesn’t tell you about. (But then again, I have no idea what he does in readVcc() either.) Because like I said, the reference probably has a small error. And if you measure the error and assume it’s static you can compensate for it.

In my opinion the best way to read the voltage:

unsigned int voltage = analogRead(AnalogPin) * 5000ul / 1024;
//or with internal 1,1V ref
unsigned int voltage = analogRead(AnalogPin) * 1100ul / 1024;
//or when you use a 4:1 voltage divider in front when using the 1,1V internal ref
unsigned int voltage = analogRead(AnalogPin) * (4 * 1100ul) / 1024;

In all cases ‘voltage’ will contain the voltage read in mV. I like to stick with integer math instead of floating point because:

  • A float is NOT simple a decimal point
  • integer math is wayyyyyyyyyyyyyyyyyy quicker
  • and it doesn’t mater it’s in mV, just do other calculations in mV as well
  • and if you want to print it in V, just add the decimal point when you print :slight_smile: