voltmeter/A build, and a wrong number/11. A low-battery warning
A build, and a wrong number · 11 of 12

A low-battery warning

A 9 V battery on the terminal, a TK01 XL LED on a second pin, and a sketch that lights it below 7.5 V. The one idea worth having is hysteresis: the light comes on below 7.5 V and goes out only above 7.7 V, so a reading that wobbles across the line does not make it flicker.

Two blocks, two pins

The voltmeter's SIG goes to the analog pin, as before. The TK01's SIGNAL goes to a second, digital pin: D9 on an Uno, GPIO 4 on an ESP32, GPIO 5 on an ESP32-S3, GP15 on a Pico. Both blocks' GND pins go to your board's GND. The battery goes on the terminal, minus on the left screw.

The battery here is only being watched. Your board runs from USB, so the only current the battery supplies is the block's own 0.24 mA.

Why the obvious sketch flickers

The obvious sketch is one line: LED on if the reading is under 7.5 V, off if not. It works until the battery gets near 7.5 V, and then it flickers. A battery drifts down over hours, and each reading wobbles a few hundredths of a volt either way. For as long as the battery sits near the line, some readings land under it and some over.

A warning that does not flicker
Hysteresis
Last reading
-
Warning
off
Times it switched
0
Press run. The readings fall from about 7.8 V to about 7.2 V, wobbling a few hundredths of a volt either way as unaveraged readings do.

Hysteresis: two lines instead of one

The fix is two thresholds. The warning turns on below 7.5 V, and turns off only above 7.7 V. Between the two, it stays as it was. No wobble is 0.2 V wide, so once the battery has crossed 7.5 V the light stays on, and it goes out only when somebody fits a battery that really is fuller.

The name for this is hysteresis, and most thermostats use it. In the sketch it is the warning variable, remembered from one pass of loop() to the next, and the two if tests that each look at it before changing it. The averaging from the last article helps too: sixteen readings wobble a quarter as much, so 0.2 V is a wide margin.

The threshold itself is a choice. An alkaline 9 V battery starts a little above 9 V, and many devices give up on one somewhere around 7 V, so 7.5 V warns with some life left. To flash the warning rather than light it steadily, without a delay that stops the readings, see blinking without stopping.

The code

The calibrated sketch plus a TK01 on LED_PIN. warning turns on below LOW_V and off only above LOW_V + HYSTERESIS; between the two it keeps whatever it was.

voltmeter_low_battery.ino
/*
  Voltmeter - low-battery warning                        TK09 / /p/tk09

  Wiring. Count from the square pad on the TinkerBlock board, terminal
  at the top, header at the bottom:

    GND    -> GND
    NC     -> nothing   (both NC pins are unconnected on the board)
    SIG    -> A0 on an Uno, GPIO 34 on an ESP32, GPIO 4 on an
              ESP32-S3, GP26 on a Raspberry Pi Pico

  Terminal: left screw to the battery's minus, right screw to its plus.

  TK01 XL LED, counted from its own square pad:
    GND    -> GND
    SIGNAL -> D9 on an Uno, GPIO 4 on an ESP32, GPIO 5 on an
              ESP32-S3, GP15 on a Pico

  Arduino IDE
    Tools > Board                 your board, e.g. ESP32S3 Dev Module
    Tools > Port                  the one that appears when you plug in
    Tools > USB CDC On Boot       Enabled   (ESP32-S3 only)
    No library needed.
*/

// The pin SIG is wired to. Uno: A0. ESP32: 34. ESP32-S3: 4. Pico: 26.
const int SIG_PIN = A0;
// The pin the TK01 is on. Uno: 9. ESP32: 4. ESP32-S3: 5. Pico: 15.
const int LED_PIN = 9;

// Uno: 5.0 and 1023. Pico: 3.3 and 1023. The ESP32s do not use these.
const float VREF = 5.0;
const float ADC_MAX = 1023.0;

const float SCALE = 5.0;        // the terminal is 5 x SIG
const float CAL = 1.000;        // multimeter / sketch
const int SAMPLES = 16;

const float LOW_V = 7.5;        // warn below this
const float HYSTERESIS = 0.2;   // and stop only above LOW_V + this

bool warning = false;

float sigVolts() {
  float sum = 0;
  for (int i = 0; i < SAMPLES; i++) {
#if defined(ARDUINO_ARCH_ESP32)
    sum += analogReadMilliVolts(SIG_PIN) / 1000.0;
#else
    sum += analogRead(SIG_PIN) * VREF / ADC_MAX;
#endif
  }
  return sum / SAMPLES;
}

void setup() {
  Serial.begin(115200);
  pinMode(LED_PIN, OUTPUT);
}

void loop() {
  float battery = sigVolts() * SCALE * CAL;

  if (!warning && battery < LOW_V) {
    warning = true;
  } else if (warning && battery > LOW_V + HYSTERESIS) {
    warning = false;   // only a real recovery, such as a new battery
  }
  digitalWrite(LED_PIN, warning ? HIGH : LOW);

  Serial.print("battery ");
  Serial.print(battery, 2);
  Serial.println(warning ? " V  LOW" : " V");
  delay(1000);
}

Set CAL from the previous article first, or the threshold is only as good as the uncalibrated reading. LED_PIN is the TK01 book's pin on each board, except on an ESP32-S3, where GPIO 4 is already SIG and the LED moves to GPIO 5.

When it does not work

Why warn at 7.5 V?

It is a choice, not a property of the battery. A fresh alkaline 9 V battery starts a little above 9 V, and many devices give up on one somewhere around 7 V. 7.5 V warns with some life left. For a 12 V lead-acid battery, somewhere around 11.8 V at rest is a common warning point.

The LED flickers near the threshold even with the sketch as written.

The wobble is bigger than the 0.2 V hysteresis. Check the terminal screws are tight and the header's GND is wired, then raise HYSTERESIS or SAMPLES. A battery under a changing load also sags and recovers, which looks exactly like a wobble.

Can the LED share the analog pin's side of the board?

It needs its own pin. SIG_PIN reads the voltmeter; LED_PIN drives the TK01. On an ESP32-S3 the analog pin is GPIO 4, so the LED moves to GPIO 5. Both blocks' GND pins go to your board's GND.

The battery lasts less than I expected with this running.

The block draws about 0.24 mA from the battery it measures, all the time. If the battery also powers your board, add the board's own current: tens of milliamps for an Uno or an ESP32, which will flatten a 9 V battery in hours, not months.

Where this goes next

Zero, stuck at the top, or wandering: where to look first.

When the number is wrong

Edit this page — content/books/voltmeter/a-low-battery-warning.mdx

Community

Questions about this product

See what other owners have asked, and read their solutions.

Ask a question ↗

Voltmeter

Loading 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.

Browse Modules and blocks on the forum