analogRead(), how to get finer resolution (UNO)

Is it possible to get finer resolution from the analog read pins on the UNO?

For example, I'm using analogReference(EXTERNAL) to set an external voltage reference, and my analog input pin will read a maximum of 1V difference relative the reference. I want the entire 10bit analog scale to span 1V, instead of the default 5V. Essentially I want 1mV per level, instead of the default 4.9mV per level. Is this possible with the UNO?

Assuming that it is a 0 to 1 V signal, you can set the internal 1.1 V reference.

Thanks for the reply. I'm actually reading the voltage across a Wheatstone bridge. So initially both points are 2.5v, but the voltages will diverge by up to 1V. Point A will vary between 2.5v and 2v, and point B will vary between 2.5v and 3v. I need to read the difference between the two. So I'm using point A as the voltage reference, and reading point B with an analog pin. This gives me the difference, and seems to be working OK.

Where I'm stuck is trying to get 1mV resolution. I'm still stuck at the 4.9mV resolution. With the UNO's 10-bit ADC you get 1023 levels, so for the entire 5v range you get 5v/1023 = 4.9mV resolution. What I need is 1v/1023, for 1mV resolution. But I don't know if it's possible to rescale the UNO's ADC such that the entire 10-bit range can be used for only a 1v range?

Feed the bridge to a differential amplifier.


You can use the internal bandgap reference, for 1.1V/1023 = 1.07mV resolution.
Likely have to run your voltages thru an op-amp to offset them down 2V.

Or, use an external higher-bit count ADC, with 14 or 16 bit resolution and I2C or SPI interface.

Or a diff amp and stay with the slow internal ADC.

The Arduino will always start at 0 V.

Thanks for the reply. I'm actually reading the voltage across a Wheatstone bridge.

This is an important bit of information that should have been in the first post.

All measurements that done by the Uno's ADC are implicitly referenced to GND. This is typically called a "single-ended" signal, as opposed to a "differential" one. The "reference" of the ADC simply sets what voltage will result in a full scale (0x3FF) output of the ADC conversion, it does not change the negative reference point.

In order to measure the voltage between two arbitrary points, there are some options:

  1. Read both points separately, and subtract them in software to get the differential measurement.

  2. Use a differential amplifier to change the differential signal into a single-ended one.

  3. Use a differential input ADC. Some microcontrollers have them built in (like the ATtiny85 and ATtiny84), or you can get an external one.

Thank you guys very much for the replies, this helps a ton. I'm going to give it a shot using a differential amplifier with single ended output and see what kind of a gain I can get.

I didn't realize that the voltage reference didn't actually set a reference voltage for the comparison, but just set the top of the scale for the adc. I should have read the analogReference() info a little more carefully (it's right there in the first sentence). This explains why my output was always pegged at 1023, lol.

There is anther alternative use an Arduino Zero. It is more expensive but it can read 12bits.

If you can not use the internal aref as suggested, then another approach to enhancing the Arduino's ADC resolution would be to use dithering & oversampling. I've described a couple of approaches to generating a dither signal in detail at:

You can use an external adc like this one. It has a programmable gain amplifier.

ADS1115 16-Bit ADC - 4 Channel with Programmable Gain Amplifier

Thanks everyone for the replies. For simplicity, I just picked up a load cell amplifier on a breakout board: