Improving the voltage measurement performance of an Arduino microcontroller

Most of today’s microcontrollers feature an Analog to Digital Converter (ADC) which is but one component in the analog chain. Closely related circuitry includes an analog multiplexer to select a specific signal to be measured, a sample-and-hold to take a “snapshot” of the voltage to be measured, clock circuitry to run the ADC through its paces, and perhaps one of the most important components the analog voltage reference.

In this short article, we will show how the performance of an Arduino Nano Every microcontroller may be improved by adding an external voltage reference. The lessons are generally applicable to all microcontrollers.

Figure 1: An Arduino Nano Every on a breadboard with an Analog Devices LT1009 shunt voltage reference. Note that the regulator’s trim lead is floating.

What are the default settings for the Arduino Nano Every?

By default, the Arduino is configured to measure voltage relative to the rail. This implies a 5 VDC reference for the Arduino Nano Every with its 5 VDC I/O. This is a good starting point as the analogRead( ) function will return an in-rail voltage reading between 0 and 1023. Here the term in-rail implies an ADC input voltage bounded by ground and the 5 VDC voltage rail. For a contrasting out-of-rail voltage measurement please see this earlier article.

This default connection leaves much to be desired from the standpoint of precision voltage measurement. Again, recall that the performance of an ADC is a direct function of the voltage reference. This statement includes the absolute voltage levels as well undesirable drift and noise.

In this default configuration, the voltage reference is derived from whatever is driving the Arduino’s 5 VDC rail. Many times, this is the USB port from the computer. At other times, it is a battery or voltage regulator. None of these options falls under the umbrella of precision. For example, the USB voltage will vary from computer to computer. Also, with a typical USB cord, the voltage will sag depending on the current draw from your project. The result is an unpredictable voltage measurement that will certainly disagree with your multimeter.

Voltage measurement debugging techniques

For debugging purposes, it is convenient to convert the raw ADC values (binary 0 to 1023) to human readable values between 0.0 and 5.0 VDC (type float). A mapping function provides a convenient conversion method. Unfortunately, Arduino’s map( ) function works on integers. However, it is easily modified to work with floats using this code:

float fmap(float x, float in_min, float in_max, float out_min, float out_max) {
return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;

The code may then be called as:

float val = analogRead(ANALOG_PIN);
float humanReadableVoltage = fmap(val, 0.0, 1023.0, 0.0, 5.0); // Use 5.0 or 3.3 as appropriate for the given voltage rail.

While this is certainly not the most elegant, fast, or energy efficient way to perform a conversion, it works well enough and will allow you to quickly determine if the problem is within the hardware or the software. As a programmer you may want to refactor your code to improve performance. However, as a starting point and debugging tool, this solution is hard to beat.

Tech Tip: All readers should be familiar with the concept of a ratiometric measurement. This term implies that the source (sensor) and the ADC share a common voltage reference. For example, a potentiometer may be connected to the Arduino’s 5 VDC rail along with the ADC’s default configuration. The potentiometer’s wiper is then read by the ADC. In this situation any power supply fluctuations are common to both devices. Consequently, a potentiometer set to 1/4 revolution (binary 256 for a 10-bit ADC) will continue to read the same value even if the rail voltage drifts. Note that there are a few ratiometric sensing applications. An example is an RTD where the sensor’s excitation voltage is shared with the ADC.

Simple way to improve the ADC’s performance

One simple way to improve the voltage measurement performance is to get off the voltage rail. Nearly any other reference will improve the performance. One good solution is to use the microcontrollers internal voltage reference. This is easily accomplished using the statement analogReference(INTERNAL);. This is typically done within the setup( ) function.

Avoid the beginner’s mistake

When the Arduino’s ADC reference is changed, the full-scale input value is also changed. Recall that the default configuration used the 5 VDC rail. In-rail voltage between 0 and 5 VDC were acceptable. With the new internal voltage reference, this range changes. For example, if the internal reference is set to 1.1, VDC the microcontroller now accepts real-world voltage between 0 and 1.1 VDC. The appropriate mapping statement is now:

float val = analogRead(ANALOG_PIN);
float humanReadableVoltage = fmap(val, 0.0, 1023.0, 0.0, 1.1);

Note that any voltage greater than 1.1 VDC will saturate the ADC. After the mapping operation it will be read as 1.1 VDC. Once again, I would refer you to this previous article regarding resistor selection. With the proper pair of precision resistors, you can read voltages greater than 1.1 VDC.

Tech Tip: The Arduino analogReference( ) function is hardware specific. Each microcontroller that falls under the Arduino umbrella has a unique internal construction. That construction goes all the way down to the internal ADC construction and multiplexed options for the ADC’s voltage reference. Depending on the micro, you may be able to choose internal references with 1.1, 2.0, 2.5, and even 2.56 VDC.

Improving performance further using an external reference

A microcontroller’s internal reference is considerably better that using the voltage rail. However, it not perfect. In fact, we could argue that the microcontroller design team carefully balanced the cost vs performance of the analog section. Given the various design constraints we should expect to find an internal voltage reference with good, but not perfect, performance characteristics. To do otherwise would sacrifice the cost for a general-purpose microcontroller.

A dedicated external voltage reference may be used to improve the performance of your microcontroller. One example is the Analog Devices LT1009IZ#PBF as shown in Figure 1. This is shunt regulator provides a 2.5 VDC reference with a +/-0.2 % tolerance.

The voltage reference operates like a Zener diode regulator. Within limitations, the active element consumes whatever current is necessary to maintain a 2.5 VDC output as shown in Figure 2. The shunt resistor is a necessary component. In Figure 2 a 3.6 kΩ resistor was used. In Figure 1 you can see that I used a 1 kΩ 1% resistor. A careful review of Figure 1 and the Arduino Nano Every pinout will show that the shunt regulator is powered from the 3.3 VDC pin. In this application the regulator is consuming 800 uA.

I_{reg} = \dfrac{3.3 \ – \ 2.5}{1000} = 800 \ uA

The chosen 1 kΩ resistor results in slightly more current than the 5.0 VDC application shown in Figure 2. Note that 1% tolerance resistor shown in Figure 1 is not necessary. It was used out of convenience as many such resistors were required for the voltage divider allowing voltages higher than 2.5 VDC to be read by the Arduino.

Note that the trim adjustment is not used in this application. In Figure 1 the adjust wire can be see floating above the breadboard.

In this particular application the LT1009 is over-specified. The limiting factor appears to the 1% tolerance resistors just visible in the background of Figure 1. Also, the 10-bit Arduino ADC is also a limitation. However, with a bit of resistor tweaking, the measured voltages are within 10 mV of those given by a Fluke 87 voltmeter.

** Figure 2**: The LT1009 required a series resistor as shown in this schematic.

** Figure 2**: The LT1009 required a series resistor as shown in this schematic.

Tech Tip: Money is the prime limitation for a voltage reference. From a practical perspective, the high-end cost is constrained by the bit-width of the ADC. The improved voltage reference performance is a wasted resource when it becomes significantly better than the step resolution of the ADC itself. It’s like making continued improvements to a car’s transmission while keeping the old underpowered engine.

Best performance is obtained by using an external ADC

We have reached a point where the bit-width of the internal ADC is the limiting factor. For improved performance, an external ADC with increased bit width is required. As previously mentioned, we have entered a performance vs cost spiral. Increased ADC bit width will require increased performance form the ADC. Depending on the design, we could easily end up purchasing a $20 to $150 dollar solution for the ADC and the voltage reference. As performance further improves, it may be necessary to ovenize the voltage reference to mitigate against normal equipment temperature. One integrated example is Analog Devices LTZ1000 series of ultra precision voltage regulators. You will find this device has a heater element inside the hermetically sealed TO-99 enclosure.


The voltage measurement performance of a microcontroller such as an Arduino may be improved by shifting to an internal or external ADC voltage reference. For the best performance the cost and complexity of the circuit quickly rises with the addition of an external higher bit-width ADC and a corresponding precision voltage reference.

Choose carefully as an over-specified voltage measurement system is like demanding components with 0.001” tolerance when 0.01” components could be used.

Horses for courses.

Best Wishes,


About the Author

Aaron Dahlen, LCDR USCG (Ret.), serves as an application engineer at DigiKey. He has a unique electronics and automation foundation built over a 27-year military career as a technician and engineer which was further enhanced by 12 years of teaching (interwoven). With an MSEE degree from Minnesota State University, Mankato, Dahlen has taught in an ABET accredited EE program, served as the program coordinator for an EET program, and taught component-level repair to military electronics technicians. Dahlen has returned to his Northern Minnesota home and thoroughly enjoys researching and writing articles such as this. LinkedIn | Aaron Dahlen - Application Engineer - DigiKey

1 Like