0

let's consider this simple piece of code:

void setup() {   
    Serial.begin (9600); 
}

void loop() {  
    int code = analogRead (A2);   
    double voltage = code *5/1024;   

    Serial.print("Voltage is  ");   
    Serial.println(voltage);   
    delay (500); 
}

It is simply the A/D conversion of a voltage applied between A2 and GND. Unfortunately I saw that this reading is not so accurate. Precisely, if I use a battery of 3.5V, on the serial monitor I will see the value voltage = 3.00. If I use a battery of 1.5V, I will see 1.00 V.

This means that the program works correctly, but it is not accurate. Which is the reason for this and how can I solve it? I do not understand the reason for this since the resolution of Arduino as ADC is equal to 5/1024 = 4.88 mV, so I think that we may have a quantizazion error of 4.88mV, and not of 0.5V.

stevieb
  • 157
  • 10
Kinka-Byo
  • 3,340
  • 2
  • 19
  • 58
  • You should try taking 10-20 readings and averaging them, I'm sure your accuracy will improve... You don't have to wait between readings. I'm not sure but I hope that whoever wrote the Arduino analog library made `analogRead` a blocking call on a conversion complete. – Ron Beyer Sep 21 '19 at 02:08
  • What board are you using? is there anything between the pin and the arduino? – Voltage Spike Sep 21 '19 at 02:10
  • Do you get any results that are not X.00? Is your calculation being done using integer math and then converted to a double? Write out the raw values for code and do the calculation by hand to verify. – Dean Franks Sep 21 '19 at 02:11

1 Answers1

8

The problem is how your calculation is being expressed. The calculation for voltage will be done using integer math and then the result is converted to a double, resulting in the values you report. Corrected code:


void setup() {
Serial.begin (9600); }

void loop() {
int code = analogRead (A2);
double voltage = (double)code * 5.0 / 1024.0;
Serial.print("Voltage is ");
Serial.println(voltage);
delay (500); }
Dean Franks
  • 3,441
  • 2
  • 13
  • 19
  • Thank you! Now I got 1.42V on my measurement of a battery of 1.5V. perfect. Only a general question: so is the problem of my code the fact that inside operations not all variables are double? It seems to me that if there is an integer (although all other operands are double), the result will have the accuracy of an integer (also if I declare the result as a double). Is it correct? – Kinka-Byo Sep 21 '19 at 03:03
  • @Kinka-Byo There's no need, with one of the operands to be double it's computed as double. Beware that `(double)code * 5.0 / 1024.0` are two operations, `(double)code * 5.0` and `(result) / 1024.0` you can leave it as `code * 5.0 / 1024` as the result of the first operation is already a double, but if you leave `code * 5 / 1024.0` the first part would be computed as integer (in fact it would work but because the first op is a multiplication and it will not give any decimals even if it's a double).. – Gusman Sep 21 '19 at 04:16
  • @Gusman you are correct, I do little enough work with Arduino to know what the evaluation rules are so I used the sledge hammer solution. It should also be noted that a better solution would be to leave everything as an integer and calculate the number of millivolts instead of the number of volts. That would be orders of magnitude faster on the arduino. – Dean Franks Sep 21 '19 at 16:27
  • Yep, that's right, integer operations are way faster as the ATMEGA328 doesn't has a FP unit. Or at least using a float instead of a double would speed it up, using 64 bit precission floating point is unnecessary in this case as the error from the ADC will be bigger than the float's instrinsic one. – Gusman Sep 21 '19 at 18:09