What analogRead() actually measures?

Cables, cables...
Cables, cables...

You see that vortex? It’s officially called LCD kits testing station. Just after soldering a module it needs to be connected and examined, if it lights and displays everything properly. There could be a silly text, but it would be too simple.

Therefore among this cable clutter is hidden temperature sensor MCP9700 (actually two) and the LCD simply displays readings from it. Last night I somehow became interested in the temperature Arduino was displaying. It was definitely too high. The difference between 21 and 24 degrees is well distinguished by everyone (the photo was taken at other temperature conditions :) ). There’s no way to blame inaccuracy of measurement for it, because the sensor yet has +/- 2 deg. accuracy.

Moreover, once or twice during a talk with my clients I heard opinions that the sensor shows too much. For this reason I began to grub around and try variety of things.

How voltage converter works

Analog-digital converter is fully described in ATmega328 datasheet on page 250.
In a nutshell: AREF voltage is the voltage powering DAC converter (digital controlled voltage divider) which output is connected to a comparator matching AREF to the voltage on a certain analog input. DAC voltage “starts” from zero and increases until it not excesses measured voltage level.
Thanks to it the measured voltage value is known.

Accuracy of such a measurement stands out from the very beginning. The first thing is resolution (in bits) of DAC. In other words – with which step the voltage is increased. ATmega328 has a 10-bit one.

The second value is AREF voltage. When the number of steps is defined (1023, because of 10 bits), the voltage per step is known. It’s AREF/resolution. ATmega can utilize 3 different AREF sources. It could be internal 1.1V source (don’t know the accuracy), supply voltage (about 5V) or a value given to AREF pin.

Knowing this value is essential to convert digital reading from A/D to a real voltage value. Let’s skip the internal 1.1V source and external 5V AREF for now. We will focus on default AREF value – 5V.

Now, basic knowledge about MCP9700 sensors, exactly about sensitivity, would be useful. It equals 10 mV/deg., so if we want to read what exactly the sensor emits, we have to know the AREF value precisely.

Maybe by an example

Reading from analogRead() has given us 150. We think that the voltage read is 5/1024*150 = 0.7324 V. It’s true, but if AREF equals 5V in fact. And what if it’s 4.9V? Then the real value meant by reading of 150 equals: 0.7178V. The difference – 14.6 mV. For the sensitivity of 10mV/deg. – almost 1.5 degrees!

And how much exactly AREF equals in default setup? Supposedly 5V, but in fact Vcc (supply voltage) provided to ATmega328.

Wait, someone could say Arduino has built-in 5V voltage regulator, so such a high difference shouldn’t exist. It’s true, but only when Arduino is powered by external source, not USB!

As is well known, USB standard tells that supply voltage is 5V, so the voltage regulator doesn’t work, the voltage from USB goes directly to ATmega. The regulator doesn’t work because it needs suitably higher voltage in order to have a “reserve”, so it’s technically impossible to maintain 5V while voltage supplied to the regulator also equals 5V.

In other words, we have to rely on what the computer provides on USB. And here I became suprised, because my notebook gives 4.9V instead of 5V on USB.

Finally – because of that my reading was increased by those 1.5 degrees.

However, when using analogReference(INTERNAL) we will abandon upper ranges of the reading (because maximum reading is 1.1V, what after converting to temperature gives (1.1-0.5)/0.01 = 60 degrees) in order to increase readout accuracy (1.1/1024 = about 1mV – 0.1 degree). Note once again – it’s increasing readout, not mesurement accuracy :) .

That was briefly about what exactly analogRead measures. And, in order to explain why on the photo one readout is 18 degrees, while the another – 10. This isn’t a trick with analogRead – one of the sensors is MCP version A, the another – regular MCP. The one with “A” (supplied with Starter Kit and also sold separately) has +/- 2 accuracy, without “A” – +/- 4 degrees.