Arduino Based Autoranging AC-DC Voltmeter with TRMS

This Arduino project shows how to build a digital voltmeter which can measure up to 600V. This voltmeter can measure AC and DC voltages with automatic switching between the 2 signals, it also can automatically switch between measuring ranges (autoranging).
This Arduino based voltmeter measures the TRMS (true RMS) value of AC voltage signals and calculates its frequency.

A 1602 LCD screen is used to display voltage value, signal type (AC or DC) and frequency (if signal is AC).

No warranty is provided with this project, so do it at your own risk!
No isolation transformer is used between the Arduino board and mains source, please don’t connect the Arduino to your laptop or PC while you’re measuring voltages.
While measuring mains voltage (the Arduino is connected to the mains), there will be a very small current (less than 0.4 mA) that may pass through the Arduino. Even this current is so small which may not harm human body and for safety purpose, please don’t touch the Arduino while you’re measuring mains voltage!

For more safety and better results, the Arduino board should be powered from battery (for example battery of 9 Volts).

AC: Alternating Current.
DC: Direct Current.
TRMS: True Root Mean Square.

Arduino TRMS voltmeter auto-range AC DC

Hardware Required:

  • Arduino UNO board   —-> Atmega328P datasheet
  • 16×2 LCD screen
  • 330 ohms resistor
  • 10k ohms variable resistor or potentiometer
  • 4 x MOC3020 optocoupler (MOC3021, MOC3022, MOC3023, or equivalent)  —-> datasheet
  • 4 x 220 ohm resistor
  • LM4040 – 4.1V (4.096V shunt voltage reference)  —-> datasheet
  • 100 nF capacitor
  • 2 x 0.1 nF capacitor
  • 2 x 1M (Mega) ohms resistor with 1% tolerance or better
  • 220k ohms resistor with 1% tolerance or better
  • 15k ohms resistor with 1% tolerance or better
  • 2 x 4.7k ohms resistor with 1% tolerance or better
  • 4 x 10k ohms resistor with 1% tolerance or better
  • 1k ohms resistor
  • Breadboard
  • Jumper wires

Arduino autoranging AC/DC voltmeter circuit:
Project circuit diagram is shown below.

Arduino autoranging voltmeter with 1602 LCD circuit

Grounded terminals should be externally connected together!

Basically, a voltage of more than 5 Volts can not be directly connected to the Arduino UNO board. To do that we need a step down circuit which downs any input voltage to another one lower than 5V. For an AC voltage we can use a step down transformer, but measurements will not be accurate!

In this project I used voltage divider circuit which consists of 6 resistors as shown in the circuit schematic above (for better results resistors tolerance should be of 1% or lower).
The total resistance of the voltage divider is: 2M + 220k + 15k + 4.7k + 4.7k = 2244.4k Ohms.

For the autoranging purpose I used 4 optoisolators (MOC3020 or equivalent) with triac in one side, this allows current to flow in either directions when the optoisolator LED is triggered.
As shown in the circuit diagram, pin number 4 of each optoisolator (optocoupler) is connected to Arduino analog channel 3 (A3), pin number 6 of each opto-isolator is connected to 1 voltage divider output.
For example, the upper opto-isolator shown in the circuit diagram is connected to largest second resistance of the voltage divider which is equal to: 220k + 15k + 4.7k + 4.7k = 244.4k Ohms. So, voltage divider ration equals to: 2244.4/244.4 = 9.183.

The LM4040-4.1 shunt voltage reference has 2 roles: the fist one is to provide a precise voltage of 4.096V which is then connected to pin AREF of the Arduino board. This voltage is used as positive reference of the ADC module, the negative reference is GND (0V).
The 2nd role is to provide a precise DC bias of 2.048V to the input signal (voltage under measure) which prevents the voltage on Arduino analog channel 3 from going under 0V (negative voltage).

The ATmega328P microcontroller has 2 internal clamping diodes on the I/O pins, these diodes are connected from the I/O pin to VCC and GND and they keep all input signals within the operating voltage (-0.5V to VCC + 0.5V). Any voltage higher than VCC + 0.5V will be forced down to VCC + 0.5V and any voltage below GND – 0.5V will be forced up to GND – 0.5V.
As a result, connecting 2-phase voltage of 400V RMS to the above circuit will not do any damage to the ATmega328P microcontroller, even when the voltage divider with lowest ration is selected.

Arduino digital pin 6 is also connected to the common pin of the optoisolators through 10k resistor. Arduino digital pin 7 is connected to +2.048V point through 10k resistor.
Arduino digital pins 6 and 7 are ATmega328P analog comparator inputs (respectively AIN0 and AIN1). The analog comparator is used to detect whether the voltage signal is AC or DC and also for counting AC voltage frequency.

The 16×2 LCD screen (2 rows and 16 columns) is used to display the value of the input voltage, signal type (AC or DC) and AC voltage frequency value, it’s connected to the Arduino board as follows:
RS —> Arduino digital pin 8
E   —> Arduino digital pin 9
D4 —> Arduino digital pin 10
D5 —> Arduino digital pin 11
D6 —> Arduino digital pin 12
D7 —> Arduino digital pin 13
VSS, RW, D0, D1, D2, D3 and K are connected to Arduino GND,
VEE to the 10k Ohms variable resistor (or potentiometer) output,
VDD to Arduino 5V and A to Arduino 5V through 330 ohm resistor.

VEE pin is used to control the contrast of the LCD. A (anode) and K (cathode) are the back light LED pins.

Arduino autoranging AC/DC voltmeter code:
The following Arduino code can measure TRMS value of AC voltages with its corresponding frequency.
Voltage type (AC or DC) is automatically detected, and range is automatically selected (4 ranges).

The following video shows a simple hardware circuit tests:

Discover more from Simple Circuit

Subscribe to get the latest posts sent to your email.

12 thoughts on “Arduino Based Autoranging AC-DC Voltmeter with TRMS”

  1. How does it work and not break?
    at voltage between 0 and 10V
    ch_number = 0 voltage divider 2244.4/244.4 = 9.183
    but if we connect 330V and a divider (9.183) we get 36V to the Arduino port

  2. hi, the circuit didn’t work. I couldn’t find lm4040-4.1. instead, I did it with the lm317 with a voltage close to 4.1 and 2048. Where could the problem be?

  3. I’ve already tried everything. it does not measure voltage. but only frequency 50MHz pleas anybody. can someone please help me

  4. Hi,
    Thanks for the idea shared.
    I copied your circuit seems didn’t get an excepted result.
    Checked the input section circuit, do a roughly calculate, the value from each node seems got just 1/2 reduce from the measuring value? How can input to an Arduino?

  5. Hi,

    First of all: gratulations for your hardware solution!

    May i ask more comment for this lines?

    “for(byte i = 0; i < 50; i++) {
    if ( ACSR & 0x20 )
    (wait some time intul the condition will be true?)

    while ( (per < Periods) && (micros() – current_m < (uint32_t)Time_Out * Periods) ) {
    (I think this is kind of measure period calculaton)

    I use Bascom-Avr, this lines not clear to me to transnlate to basic language.
    Thank you for your help,


  6. I haven’t tested it yet. I want to adapt to measure along with another quantity.
    Question: In the ladder, where is the pin A3 of the Arduino UNO defined as input of the AD converter? Do I want to move to pin A0.

    Ainda não testei. Quero adaptar para medir junto com outra grandeza.
    Pegunta: No ladder, onde está definido pino A3 do Arduino UNO como entrada do conversor AD? Quero passar para o pino A0.

  7. great, your code runs perfectly, I use Arduino Uno as you demonstrated. but what if i use arduino mega 2560? as I know there is no AIN0 pin and only AIN1 on pin D5? thank you for your attention and guidance

Leave a Comment

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.

Scroll to Top