DIY ELECTRONICSTR

← All projects

Digital Voltmeter

Beginner20 min

A voltmeter that measures between 0 and 5 V with the Arduino's analog input: as you turn the potentiometer, the voltage on pin A0 changes; the 16x2 LCD shows it in volts on its top row (e.g. 3.27 V) and as a bar filling from the left on its bottom row. It teaches how an analog reading (0–1023) turns into volts, how averaging readings steadies them, and how to teach the LCD characters of your own to draw a bar. Install "LiquidCrystal I2C" from the Library Manager.

Get it on Google Play

What you need

Wiring steps

  1. 1

    Connect the power wires

    Connect the power wires

    Plug a red male-male jumper wire into the 5V pin on the Arduino's power header and connect its other end to the breadboard's top red (+) rail; the wire runs round under the breadboard. Plug a black wire into the GND pin on the Arduino's top row, next to pin 13, and connect its other end to the top blue (−) rail. This project uses only the top rails.

    • Arduino 5V → the top red (+) rail (red wire)
    • Arduino GND (top header) → the top blue (−) rail (black wire)
  2. 2

    Plug in and wire the potentiometer

    Plug in and wire the potentiometer

    Plug the potentiometer in with its three legs in row F of the top half, in columns 4, 5 and 6; its body reaches over the gap in the middle. Connect row J of column 4 to the top (−) rail with a short black wire, and row J of column 6 to the top (+) rail with a short red wire. Connect the Arduino's A0 pin to the middle leg's column, row H of column 5, with an orange wire (INPUT_PIN A0); the wire comes round the right of the potentiometer. There are always 5 V between the two outer legs; the middle leg slides somewhere between 0 and 5 V as you turn the knob, and the Arduino measures it.

    • potentiometer left leg → column 4, top half
    • potentiometer middle leg → column 5, top half
    • potentiometer right leg → column 6, top half
    • column 4, top half → the top blue (−) rail (black wire)
    • column 6, top half → the top red (+) rail (red wire)
    • Arduino A0 → column 5, top half (orange wire)
  3. 3

    Connect the LCD

    Connect the LCD

    Push the female ends of male-female wires onto the four pins of the I2C module on the back of the LCD. Connect GND to the top (−) rail, VCC to the top (+) rail, SDA to the top half of column 18 and SCL to the top half of column 19. Then connect the Arduino's A4 pin to the top half of column 18 with a blue male-male wire, and A5 to the top half of column 19 with a yellow one. Over I2C the display talks on just two data wires (SDA and SCL); the code finds it by its address, mostly 0x27.

    • LCD GND → the top blue (−) rail (black wire)
    • LCD VCC → the top red (+) rail (red wire)
    • LCD SDA → column 18, top half (blue wire)
    • LCD SCL → column 19, top half (yellow wire)
    • Arduino A4 → column 18, top half (blue wire)
    • Arduino A5 → column 19, top half (yellow wire)

Arduino sketch

Download the sketch (.ino)Try it on Wokwi

Run the circuit in your browser before buying a part: start the sketch on Wokwi and watch the Serial Monitor.

// To install from the Library Manager:
// "LiquidCrystal I2C"
#include <Wire.h>
#include <LiquidCrystal_I2C.h>

// The analog pin the voltage comes in on
const int INPUT_PIN = A0;
// The Arduino's 5V: with a multimeter,
// write what its 5V pin really measures
const float VREF = 5.00;
// How many readings are averaged
const int SAMPLES = 16;
// Time between measurements (ms)
const unsigned long READ_EVERY = 300;

// I2C address: mostly 0x27, some 0x3F
LiquidCrystal_I2C lcd(0x27, 16, 2);

// The bar's five pieces: boxes with 1-5
// columns filled, as custom LCD chars
void makeBars() {
  for (int level = 0; level < 5; level++) {
    // A row, level+1 columns from left
    byte row = 0;
    for (int col = 0; col <= level; col++) {
      row |= 0x10 >> col;
    }
    byte shape[8];
    for (int y = 0; y < 8; y++) shape[y] = row;
    lcd.createChar(level, shape);
  }
}

// The average reading: steadier numbers
int readAverage() {
  long sum = 0;
  for (int i = 0; i < SAMPLES; i++) {
    sum += analogRead(INPUT_PIN);
  }
  return sum / SAMPLES;
}

// Bottom row: 0-5 V as a 16-box bar;
// 5 steps a box, 80 steps in all
void showBar(int raw) {
  int steps = (long)raw * 80 / 1023;
  lcd.setCursor(0, 1);
  for (int cell = 0; cell < 16; cell++) {
    int fill = steps - cell * 5;
    if (fill >= 5) {
      lcd.write(byte(4));
    } else if (fill > 0) {
      lcd.write(byte(fill - 1));
    } else {
      lcd.print(' ');
    }
  }
}

void setup() {
  lcd.init();
  lcd.backlight();
  makeBars();
  Serial.begin(9600);
}

void loop() {
  int raw = readAverage();
  // A 0-1023 reading, turned into volts
  float volts = raw * VREF / 1023.0;

  lcd.setCursor(0, 0);
  lcd.print("Voltage: ");
  lcd.print(volts, 2);
  // The trailing space clears old text
  lcd.print(" V ");
  showBar(raw);

  Serial.print("Voltage: ");
  Serial.print(volts, 2);
  Serial.print(" V  (A0 = ");
  Serial.print(raw);
  Serial.println(")");
  delay(READ_EVERY);
}

What the Serial Monitor shows

SERIAL MONITOR · 9600 BAUD
Voltage: 0.00 V  (A0 = 0)
Voltage: 1.27 V  (A0 = 260)
Voltage: 2.50 V  (A0 = 512)
Voltage: 3.79 V  (A0 = 776)
Voltage: 5.00 V  (A0 = 1023)

If a wire is loose

SERIAL MONITOR · 9600 BAUD
Voltage: 1.84 V  (A0 = 377)
Voltage: 2.31 V  (A0 = 473)
Voltage: 0.97 V  (A0 = 199)
Voltage: 2.66 V  (A0 = 544)

What you will see

Once the code is uploaded, the LCD's top row shows a value like "Voltage: 2.50 V" and its bottom row a bar filling from the left. Turn the potentiometer to one end and you read close to 0.00 V, to the other end close to 5.00 V; the bar empties and fills with it. The values also go to the Serial Monitor, with A0's raw reading between 0 and 1023 beside them: the Arduino splits 0–5 V into 1024 steps of about 4.9 mV each. If you see 4.95 or 5.07 at the end, the Arduino's 5V is not exactly 5 (the voltage from USB wanders a little); with a multimeter, measure the 5V pin and write it into VREF in the code. If the numbers jump about by themselves, the middle leg's A0 wire is not in place. If the bar fills the wrong way, swap the wires of the two outer legs. If the screen is lit but shows no text, turn the blue trimmer on the back of the I2C module to set the contrast; if there is still nothing, change 0x27 in the code to 0x3F. You can measure an AA battery too: pull the middle leg's wire out of A0, connect the battery's + to A0 and its − to GND; you will see about 1.5 V. Never put more than 5 V on A0: a 9V battery would damage the Arduino.

Similar projects

In the app, tick off every wire, match the parts to your inventory and pick up where you left off.

Get it on Google Play