Introduction: How to Design a Circuit to Make Your Microcontroller Read Any Voltage

Almost any microcontroller can measure analog voltages. Arduino can measure voltages in the range 0 ÷ 5V while ESP32 devices can measure voltages in the range 0 ÷ 3.3V.

But, how to measure voltages in different ranges?

Let see the simplest case: measuring voltages in the range 0 ÷ 10V using Arduino.

A voltage divider (100K + 100K) can be an option. It divides the voltage in half and then a 10V voltage is scaled down to 5V. There is a drawback nonetheless: @10V the current flowing through the voltage divider is 50uA. It might seem small but in some cases it's not acceptable.

The voltage divider cannot help in any way if voltages which are to be read are in the range -10 ÷ 10V. A more complex circuit is therefore required.


Interested in measuring currents?: How to Design a Circuit to Make Your Microcontroller Read Any Current

Step 1: Identify the Circuit and Make the Math Yourself

This Instructable will answer the two following questions: Which is the right circuit to scale and shift the input voltages? How to calculate the right values of the components?

The Signal Conditioning application can be used to avoid wasting time in choosing the right circuit (which depends on input and output ranges) and making many tedious calculations (which might lead to mistakes).

Entering the input voltage range and the output voltage range, the application picks the appropriate OpAmp based circuit to scale and shift the input signal as per requirements and it also calculates the values of the resistors.

Disclaimer: The Signal Conditioning is for sale ... and I am its developer!.

Signal Conditioning is available on the App Store for Mac, iPhone and iPad (here)

With the app you will be able to change the input range and recalculate the circuit in a matter of seconds - no calculations needed!

Often the calculated resistor values do not match the standard values, the application will allow to evaluate the impact on measurements obtained using the standard resistors values instead of the ideal calculated ones.

Step 2: How to Use the Signal Conditioning App

A recap of the problem: how to read a voltage in the range -10V ÷ 10V using Arduino analog inputs which only accept voltages in the range of 0 ÷ 5V.

  • Lets start by running the Signal Conditioning app
  • Go to the Voltage Measurement section
  • In the Input Range enter:
  • Zero Scale: -10
  • Full Scale: 10
  • In the Output Range enter:
  • Zero Scale: 0
  • Full Scale: 5
  • Choose a different Reference Voltage by entering: 2.5 (cheap devices are available for 2.5V reference voltage)
  • The app has already picked the circuit to use and calculated all resistors' values.It is better to increase the value of Rf to 10K to reduce the power consumption . Do not increase it too much as larger resistor values increase the circuit noise (more here) which leads to a loss in precision. Arduino, given its low ADC precision, is not very much impacted by noise but it is still something to keep in consideration.
  • To get an higher input impedance and to avoid overloading the circuit under measurement, it's better to increase the R1 value to 49.9K (i.e., standard E96 value of 1% precision resistors).

The app will compute eventually the values of Rg and R2:

  • Rg: 40K
  • R2: 12.475K (= 12.4K + 75)

Click on Use Calculated Values and by entering the values of the input signal (Vi) the app will subsequently calculate the values at the circuit output. In the same way, entering an output value (Vo) (which can be measured using Arduino) the app is able to calculate the actual voltage at the input circuit.

In case Rg or R2 are not easily obtainable from standard values, standard values can be used instead and the application shows the relative error.

Assume using 12.2K instead of the calculated value. Enter 12.2K in the R2 input field. Now, entering the corresponding values of Vo or Vi the app will calculate the actual values and the relative error:

Vi = 0 -> ideal Vo = 2.5V, rounded Vo: 2.511 (@R2=12.2K) with a relative error of 0.44%.

The app will allow to tweak the resistors values to get the best results in a matter of minutes!

Is the circuit design complete? Unfortunately, not. There are some additional design decisions to make:

  • The adequate OpAmp
  • The OpAmp supply voltage
  • The Voltage Source

Let's go through them one by one.

Step 3: Choosing the OpAmp

The best option would be to choose a input and output rail-to-rail OpAmp with a low offset voltage.

A rail-to-rail OpAmp can accept input voltages up to the supply voltage and the output voltage can go up to the supply voltage without saturating. In other words, rail-to-rail OpAmp operates linearly with input and output voltages up to the supply voltages.

The OpAmp is a differential amplifier, hence when both its inputs are at the same voltage, the output should be 0. The offset voltage is the actual voltage at the output when the inputs have the same voltage.The lower the better.

An OpAmp option would be the OPA197. Yet, many many other OpAmps with even better characteristics are available.

They are not cheap and usually they are not ready to hand.

Let's suppose that a cheap general purpose Operational Amplifier is available: LM324N.

The datasheet states that the output swing is not rail-to-rail and the offset voltage is about 2mV.

Step 4: Choosing the Supply Voltage

Since the output has to swing between -10V and 10V, the OpAmp has to be powered with a dual voltage. Datasheet states that the output voltage can be up to Vp - 1.4V, the supply voltage has to be at least -12V ÷ 12V to have some margin.

Step 5: Dual Voltage From a Single Voltage

What if the dual voltage is not available? The simplest way to generate the dual voltage is starting with a single voltage and using the shown circuit to make a virtual ground (VGND).

The voltage divider splits the voltage in two and the OpAmp acts as a buffer, keeping it stable and (almost) independent from the current drained.

Step 6: Voltage Reference

Many chips are available to provide a precise and stable voltage reference. A cheap alternative with a reasonable precision could be the LM236-2.5V (datasheet) (be careful some datasheets report wrong pins' positions).

Even though the chip should provide an exact 2.5V, the output voltage could be different. The shown circuit can be used to trim the voltage at exactly 2.5V.

To make the reference voltage independent from the supplied current, a voltage follower can be added as shown in the second figure.

Using a good multimeter connected between +2.5V and Vgnd, rotate the trimmer until the multimeter shows exactly 2.5 volt.

For better results:

  • turn the power on and allow the circuit to stabilize for at least half an hour
  • use a multi-turn potentiometer


It is worth noting that precision and temperature stability of voltage source is essential for getting precise results. For example the AD584KNZ provides much better temperature stability at a very much higher cost.

Step 7: The Complete Circuit

The complete circuit diagram is shown in the picture. Note that the two decoupling capacitors should be placed as near as possible to the supply pins of the LM324N.

Important Note:

The resistors' values shown in the circuit diagram are only for Arduino boards which accept up to 5V at their analog inputs (Uno, Nano, Mega, etc.). Other Arduino boards like Zero, Mkr, Nano 33, etc. accept only up to 3.3V.

In the latter case, the tutorial is valid but the output range values entered into Signal Conditioning have to be changed accordingly. Check out the boards specs before connecting the Arduino board.

Step 8: Unused Amplifiers

In the circuit, only three out of four available amplifiers are used. To avoid the risk of oscillations and instability, best practice suggests not to leave unused amplifier unconnected. The picture shows how to safely connect the unused amplifier.

Step 9: Power Supply

Everything seems fine so far, but the circuit has to be powered with 24V which is not a voltage that can be obtained from a wall power adapter.

A simple boost DC-DC (AKA step-up or boost) converter can be used to generate the 24V from a lower voltage. Boost converters can be easily bought on-line for a few dollars (e.g., google "MT3608" but any other boost DC-DC converter will still do the job).

The picture shows how to connect the DC-DC converter, the conditioning circuit and the Arduino board.

Important Note: the gain & shift circuit has two different grounds:

  • GND: which refers to the 24V voltage and has to be connected to the DC-DC converter;
  • VGND: which has to be connected to Arduino.

Don't mess up with the two grounds, otherwise both the Arduino and the signal conditioning circuit could be damaged.

Keep in mind that DC-DC converter are intrinsically noisy and may affect the precision of your measurements. For optimal measuring results use a linear dual power supply to power up the conditioning circuit.

Step 10: Testing the Circuit Using Arduino

Arduino ADC normally uses the supply voltage as reference. This makes the measurements not very precise, because the actual supply voltage is not 5V and it can get lower depending on other circuits wired to Arduino.

A simple solution is measuring the actual supply voltage (between ground and V5 pin) and using that voltage in the conversion formula.

Alternatively, an external 5V reference voltage can be used (wired to external pin) or even better an external ADC with a higher resolution. ADS1115 can also be an option.

The provided code shows how to get the measured voltage staring from the ADC reading.

In the Arduino code using the exact value of the actual resistors, instead of the calculated values, provides better readings.

Connecting a AAA battery to the circuit input, the measured voltage should show on the console, possibly with a minus sign depending on where the battery's positive pole is connected.

The device can directly read any voltage in the range -10V ÷ 10V.

Step 11: Different Input Range / Different Out Range?

Using the Signal Conditioning app, changing to a different input range or a different output range means just entering new numbers and replacing the resistors with the new ones calculated by the app.

Step 12: Reading the Measurements Without Using the Arduino IDE Console

Arduino and the signal conditioning circuit can be used as an additional bench instrument (you can never have enough!). To do that, there are a couple of options:

  1. Add a Display to directly read the measurements (plenty of tutorials available online)
  2. Use a macOS or iOS application wireless connected to the microcontroller. Take a look at these other tutorials:
  3. Control Arduino from your iOS Device and Apple Watch
  4. Cheap IOT Device in Minutes and Without Writing Any Code Using Raspberry Pico Pi W

Using Arduino Manager a wireless measurements device can be created in minutes just adding a cheap bluetooth BLE adapter like HM-10 or HM-19, but there are many other options in terms of microcontrollers and communication devices that can be used. Check it out.