Hey all I am trying to use the Arduino as a measuring device and I need it to as precise as possible. I am measuring it in the low mV range and so I put 1.05V (measured with DMM) on the AREF pin. The resolution should be 1.02mV but I measured at least 10 times with different resistors (all of them also measured with the DMM to make the analytic calculation better) and I'm missing at least 2.5mV in all of them and those 2.5mV (or actually 2.04V) are very important to me. I am using this sketch which is very basic :
float voltage ;
void setup() {
 Serial.begin(9600);
 analogReference(EXTERNAL);
}
void loop() {
 voltage = analogRead(A0);
 voltage = voltage * 1.02 / 1023 ;
 voltage = voltage * 1000 ;
 Serial.print(voltage, 8);
 Serial.println ("mV") ;
 delay(500);
}
I tried to use the internal reference but it didn't change much. I also tried from 3 different Arduinos (two Uno and one Nano, all of them are clones) and it was the same. Am I doing a stupid mistake ? or is it just not possible for some reason ?
Thank you all very much
This is the wiring with an example for a bad measurement :
analogRead returns an int.
If you want the result in millivolts, do the calculation in millivolts.
And divide by 1024, not 1023 (INCOMING!)
Eight places of decimals with a float is optimistic.
Thank you for your answer.
But if I define "voltage" as a float it doesn't really matter that analogRead is an int no ? This is my new sketch :
float voltage ;
void setup() {
 Serial.begin(9600);
 analogReference(EXTERNAL);
}
void loop() {
Â
 voltage = float (analogRead(A0)) * 1020 / 1024 ;
 Serial.print(voltage, 4);
 Serial.println ("mV") ;
 delay(500);
}
But I get again the same result (4.98mV instead of 6.72mV). Have I followed your advice right ?
Yeah, it was 1010 before. I know it's inconsistent here but I have around 20 measurements and it's all messed up when I write it here. It was consistent on the moment I did and wrote the measurements and their results. Sorry for the inconvenience
Something I made: averageRead.ino with correction for the half-bit.
When using the average of many samples, the noise will help to get a better result. The hardware of the ADC of the Arduino Uno and Nano are only accurate for the 10-bits, but with the average one or two more bits resolution can be achieved.
Using the voltage regulator of 3.3V as reference (with resistor divider) is not accurate. I think that the internal voltage reference is better, although its value can be between 1.0 and 1.2V.
Can you calculate everything with real units ? For example the 'voltage' should be the Voltage, in my opinion
I searched in the datasheets couldn't find it. What I found was that it is better to connect an impedance with less than 10KOhm for an optimal measurement. some people on the internet say it is 100MOhm.
I understand why the milliVolt thing bothering you guys, sorry, I totally forgot that when I uploaded it here. Sorry.
Thank you for your sketch, Koepel. It raised the voltage to V = 8.5mV +- 0.3mV (analytic 9.68mV). I am going to have now another series of measuring and see if that's good enough, thank you
Edit :
Ok, I have a deviation of maximum 1.5mV which can do the job for me. Thank you all
If your grounding is not perfect then the current used by the Arduino board itself can lift the signal of the analog measurement. I have that in a project where I put the voltage divider on a shield and also the power supply is on that shield. Try to measure 0V, and put the offset in the sketch.
The input impedance for a digital input is very high, it can almost not be expressed in a number. But the input impedance is not a resistor to ground, it is a impedance to something and that something can by anything.
The analog input impedance is also very high, but the ADC requires a little charge. With a circuit impedance of 10k, then there is enough for that charge. When the circuit impedance is 100k, everything still works, but it is less accurate. That can be solved with a small capacitor between the analog input and GND. Perhaps 1nF or 10nF is enough for that charge that the ADC needs.
When you have noise from the 50Hz / 60Hz mains voltage, that can be hard to get rid of. If you take 1000 samples and still have voltage that changes, then you have low frequency noise.
I wanted a highly accurate ADC process for a project, so I used a TL431 to create a precision voltage reference. I applied that to one ADC pin, and used its measurement to calibrate the ADC conversion process before every read of the sampled voltage. It improved consistence a lot.
Also, I think the ADC processes don't maintain perfect linearity all the way to zero.
You should use the voltage reference for AREF, unless the voltage is too low. There is a minimum voltage for AREF, I can not find it in the datasheet at the moment.
Hi,
Have you measured the actual volts at the analog input?
I see you quote "analytical" values, but have you used your DMM to check those "analytical" values?
Can you also print the raw analog input values please.
Can you please post a picture of your testing project so we can see your component layout?
Have you tried a 0.1uF or even a 10uF capacitor between the analog input pin and gnd?
As previously said wiring , impedances , resistor tolerances are all important .
If you use the internal reference which is approx 1.1volts , then the resolution is. 1.1/1024=1.07mV
( If you use a voltage divider on the input to give a higher span then the resolution is less by that factor ( a 5volt full scale input resolves to 5/1024) )
If your input is 1.5mV then it will read 1.07 or 2.14 ideally , but could be another 1.07mV out.
Be careful that you maths is not throwing away resolution , dividing by 1000 , then multiplying by a similar number may well do that .
With any voltmeter made from an Arduino , you need to calibrate it .
Hey, thank you guys so much for all of your answers, I definitely learned from that. I added my wiring and my measurements. I calculated the analytical value of the voltage through the voltage divider (R / R+98.5KOhm). IThe values from the Arduino are Umeasured (I had an fluctuation of +-0.3mV from the value I wrote, which is the average one).
I need to measure a very small force and we plan to use a strain gauge and convert the force to a voltage. Calculation showed that the voltage in the Wheatstone Bridge should be 3mV-50mV.
I used the sketch of Koepel (thanks again) :
void setup()
{
 Serial.begin( 9600);
 analogReference(INTERNAL);
}
void loop()
{
 float average = averageRead( A0);
 float voltage = average / 1024.0 * 1.08;
 float milliVoltage = voltage * 1000.0 ;
 Serial.println( milliVoltage);
 delay( 300);
}
const int nSamples = 20; Â // Usually from 5 to 10000
float averageRead( int pin)
{
 unsigned long total = 0;
 for ( int i = 0; i < nSamples; i++)
 {
  total += (unsigned long) analogRead( pin);
 }
 total += nSamples / 2;  // add half a bit
 return ( float( total) / float( nSamples));
}
I measured 20 times to make the average. I didn't raise it because I wanted to use as less clock signals as possible (the measured force will be fast, around couple of milli seconds. Do you think it's even possible ?). I will try again with 1000 tries just to see and update here. I will also add a capacitor to see how it goes.
Thank you guys for the the tips and advises. I will read it all and learn more, do the new experiments and come back here