breadboard power adapter/Using it/11. Watch the rail with an ESP32
Using it · 11 of 12

Watch the rail with an ESP32

Two 10 kΩ resistors halve the rail, an ESP32's GPIO 34 reads the half, and the sketch prints the rail once a second — with the lowest and highest it saw in between, which is where a sag shows up that a meter never catches.

Why a divider

GPIO 34 on an ESP32 reads voltages up to about 3.1 V, and a pin above 3.3 V is outside what the chip is built for. A 5 V rail is too high to read directly. Two equal resistors in series across the rail meet at exactly half its voltage, and the half is safe to read.

Bringing the rail down to where the ESP32 can read it
4.7 V rail · 2.35 V at the pin
Rail voltage4.7 V
Top resistor
At the pin
2.35 V
Reads up to
6.2 V of rail
Readable. The pin sits at 2.35 V, and the sketch multiplies it back up by 2 to print 4.70 V. The divider itself draws 235 µA from the rail, which nothing will notice.

GPIO 34 is chosen on purpose. It is on ADC1, which keeps working with Wi-Fi on, and it is input only on the classic ESP32, so a mistake in the sketch cannot turn it into an output and drive the rail.

Build it

FromTo
Rail +10 kΩ, first end
10 kΩ, second endthe junction
The junction10 kΩ to rail −, and a wire to GPIO 34
ESP32 GNDRail −

Power the ESP32 from its own USB cable, and plug it in first. The ESP32 and the adapter share ground and nothing else.

What it prints

4.71 V   low 4.69   high 4.73
4.71 V   low 4.52   high 4.73
4.70 V   low 4.69   high 4.72

Once a second, the average of about a thousand readings, then the lowest and highest single readings in that second. The middle line is the interesting one: something drew a burst of current, and for a moment the rail dropped to 4.52 V. A meter averages that away. The low column does not.

Using it on the other boards

On the standard board's 3.3 V side it reads about 3.30 V and barely moves. On the step-down, it reads the voltage you set, and it is how you find the ceiling: turn the trimmer while it prints and watch where the number stops rising.

On the booster, fit a 100 kΩ top resistor instead and set TOP_OHMS to 100000 before turning the booster up. That divides by eleven, so 28 V arrives as about 2.5 V.

The code

bbpwd_rail_watch.ino

Samples the rail a thousand times a second and prints, once a second, the average, the lowest and the highest. A brownout that a meter averages away shows up in the lowest column.

// Watch a breadboard power rail from an ESP32.
//
// Wiring:
//   rail + -> 10k -> junction -> 10k -> rail -
//   junction -> ESP32 GPIO34
//   ESP32 GND -> rail -
//
// Power the ESP32 from its own USB cable, and plug it in
// before the adapter: a live rail should not feed a pin
// on a chip that is still off. Share ground only; do not
// wire the rail to the ESP32's 5V or 3V3 pin as well.
//
// Arduino IDE: Tools > Board > esp32 > ESP32 Dev Module,
// then Tools > Port. No libraries.

const int PIN = 34;            // ADC1, input only
const float TOP_OHMS = 10000;  // 100000 for a booster
const float BOTTOM_OHMS = 10000;
const float SCALE = (TOP_OHMS + BOTTOM_OHMS) / BOTTOM_OHMS;

float lo = 99, hi = 0, sum = 0;
int n = 0;
uint32_t last = 0;

void setup() {
  Serial.begin(115200);
  delay(500);
  Serial.println("rail watch: average, lowest, highest");
}

void loop() {
  float v = analogReadMilliVolts(PIN) / 1000.0 * SCALE;
  sum += v;
  n++;
  if (v < lo) lo = v;
  if (v > hi) hi = v;

  if (millis() - last >= 1000) {
    last = millis();
    Serial.printf("%.2f V   low %.2f   high %.2f\n",
                  sum / n, lo, hi);
    lo = 99;
    hi = 0;
    sum = 0;
    n = 0;
  }
  delay(1);
}

analogReadMilliVolts() applies the chip's own ADC calibration, and the classic ESP32 reads to about 3.1 V at the pin with the core's default setting. Halved, that is about 6.2 V of rail: fine for 3.3 V and 5 V. For a booster, change TOP_OHMS to 100000 and fit a 100 kΩ top resistor, which divides by eleven.

When it does not work

It prints about 0.1 V with the adapter unplugged.

That is the ADC's floor: the ESP32's converter does not read cleanly near zero, and the calibration cannot fix the bottom of its range. Anything under a few tenths of a volt means no voltage on the rail.

It reads 0.1 to 0.2 V different from my meter.

Two 10 kΩ resistors of ordinary 5 % tolerance can be off from each other by several per cent, and the reading is multiplied by two. Measure the rail with a meter once and adjust SCALE to match, or use 1 % resistors.

It always prints the same number, about 6.2 V.

The pin is at the top of what the ADC reads, so the rail is above what a 2:1 divider can bring in range. That happens on a booster. Unplug, change the top resistor to 100 kΩ and TOP_OHMS to 100000, and try again.

The low column dips every few seconds.

Something on the rail pulls a burst of current — a Wi-Fi module transmitting, a servo moving, a relay closing — and the fuse and diode drop a little more while it does. A dip of a tenth or two is normal. A dip under 4.5 V on a 5 V rail is the one that resets things.

Where this goes next

Where to put the meter for each way a rail goes wrong.

When the rail is wrong

Edit this page — content/books/bbpwd/watch-the-rail.mdx

Community

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.

Browse Modules and blocks on the forum