A voltmeter readout
A digit panel, an Uno and one analog pin: 4.98 across the room. The interesting part is the decimal point, because the obvious way to write it is right for 4.98 and nonsense for 0.05.
The number is easy
analogRead gives 0 to 1023 for 0 to 5 V. Multiply by 5000, divide by 1023, and
you have millivolts. Divide by ten and you have hundredths of a volt: 0 to 500,
which fits three digits.
All of that is one line. The display is the part with a trap in it.
Where the point goes
The obvious call — four digits, a point after the second — is right for 4.98 and wrong everywhere below a volt. Drag the slider down and watch: at 0.05 V the number is 5, the library blanks the three digits it does not need, and the point ends up beside nothing at all.
Leading zeros fix the blanking and give you 00.05, which is readable and ugly.
The proper answer is to tell the library it only owns three of the four digits:
display.showNumberDecEx(centivolts, 0b10000000, true, 3, 1);
// ^ ^ ^
// | | starting at position 1
// | three digits
// leading zeros onNow the three digits always fill their field, the point is always after the
first of them, and 0.05 and 4.98 both read correctly. The mask is
0b10000000 rather than 0b01000000 because it is counted from the start of
this call, not from the left of the display.
Position 0 is never written, which is why setup() calls clear() once. It is
also free real estate: a minus sign, a channel number, or a letter saying which
input is being shown.
Reading it twice
A bare number on a display invites more trust than it deserves. Two habits are worth building in early.
Say when it is stale. If the reading comes from something that can stop — a sensor, a serial feed, another board — show dashes when it has not updated recently rather than leaving the last good value on the panel. The display will hold a two-hour-old reading forever and look exactly as confident as a live one.
Round where the precision is. This shows hundredths of a volt, and an Uno's ADC step is about five thousandths — so the last digit is real, just. A sketch that showed thousandths would be printing noise in a font a metre wide, which is the specific trap of a display this legible.
The code
Reads A0 and shows it as volts to two decimals on a digit panel. The display is written as three digits starting at position 1, which is what keeps the point in the right place for readings under a volt.
// A voltmeter readout: the voltage on A0, to two decimals, on a digit panel.
//
// Wiring, display to board:
// Display GND -> board GND
// Display VCC -> board 5V
// Display CLOCK -> D2
// Display DATA -> D3
// And the thing being measured:
// Potentiometer outer pins -> 5V and GND, wiper -> A0
// (or just a jumper from A0 to 5V, 3V3 or GND to test it)
//
// Arduino IDE: board "Arduino Uno", and "TM1637" by Avishay Orpaz from the
// Library Manager. Nothing else to set.
#include <TM1637Display.h>
#define CLOCK_PIN 2
#define DATA_PIN 3
#define POINT 0b10000000 // after the first of the three digits written
TM1637Display display(CLOCK_PIN, DATA_PIN);
void setup() {
display.setBrightness(4);
display.clear(); // position 0 is never written below
}
void loop() {
long mv = (long)analogRead(A0) * 5000 / 1023; // millivolts, against the 5 V rail
int centivolts = (mv + 5) / 10; // 0 to 500, rounded
// Three digits starting at position 1, leading zeros on, point after the
// first of them. 0.05 and 4.98 both read correctly this way; four digits
// with leading zeros off would blank what it does not need and leave the
// point sitting beside nothing.
display.showNumberDecEx(centivolts, POINT, true, 3, 1);
delay(200);
}It measures against the Uno's own 5 V rail, so it is only as accurate as that rail: a board on USB often sits at 4.8 V, and every reading is then about four percent high. Wire A0 to 5V and whatever it shows is your rail's real voltage — that number is the correction.
When it does not work
That is the truth, not an error. The Uno compares against its own 5 V rail, and a board powered over USB commonly sits between 4.7 and 5.0 V. Whatever it shows with A0 on 5V is your real rail voltage; put that number in place of 5000 in the sketch and everything else lines up.
A floating or high-impedance input picks up noise, and the last digit is worth about 5 mV anyway. Average eight readings before displaying, and leave the display alone unless the value actually changed — it is easier to read a number that is not flickering.
The sketch only ever writes positions 1 to 3, so whatever was in position 0 stays there. That is why setup() calls clear(). If you show something else on that digit later, it will persist until you overwrite it.
Yes, but not with this arithmetic: the ESP32's ADC is 12-bit and not linear across its range. Use analogReadMilliVolts(pin), which applies the chip's own calibration, and drop the multiply-and-divide. The display half of the sketch is unchanged.
The pin cannot read above its reference and nothing warns you. Anything higher needs a voltage divider in front of A0, and then the arithmetic has to scale back up by the same ratio.
The six symptoms, and which half of the problem each of them is in.
When it shows nothing →Edit this page — content/books/tm1637-display/a-voltmeter-readout.mdx
Questions about this product
See what other owners have asked, and read their solutions.
This page covers several products. Choose yours to see the right discussions.
Discuss this article
Ask about this page. The answer stays here, on the page it belongs to, for whoever hits the same wall next.