USB Voltage / Current Monitor — RP2040-Zero + SSD1306 OLED

A small Arduino sketch that turns an RP2040-Zero into a USB power monitor. It measures the voltage and current of whatever is plugged into it, calculates power draw, and shows everything on a 128×64 SSD1306 OLED — complete with a cute 7-segment-style "USB score" rated on how close the supply is to an ideal 5 V.

Features

  • Live readings — voltage (V), current (A), power (W) updated every 100 ms
  • USB quality score (0–9) — big 48 px DSEG7 "7SEGGCHAN" digit showing how close the rail is to the ideal 5.0 V (9 = perfect, blink = out of range)
  • Temperature — from the RP2040's internal ADC temperature sensor
  • Uptime counter — MM:SS, wraps after 99 minutes
  • Custom fonts — 7-segment-style DSEG7 fonts plus DejaVu Sans Mono for labels
  • Hand-drawn icons — temperature and clock bitmaps
  • Lean-build options — disable fonts / bitmaps / score to free up flash

Hardware requirements

Part Notes
RP2040-Zero (or any RP2040 board) mcu_model is set in setup.h
SSD1306 OLED, 128×64, I2C address 0x3C, SWITCHCAPVCC
Voltage divider default ratio ÷2, connected to the voltage ADC pin
Current-sense shunt resistor default 50 mΩ, on the current ADC pin
USB thing to measure the whole point :)

Wiring

Default pins (see setup.h to change):

Signal Pin
OLED SDA GP28
OLED SCL GP29
Voltage sense (after divider) A0
Shunt sense (across the shunt) A1

Wire the OLED to 3V3 / GND and the two I2C lines. Connect the voltage divider output to A0 and the shunt's voltage drop to A1.

The display shows "Display Error: Check Connections" on the serial monitor (115200 baud) and halts if the OLED is not found — check SDA/SCL wiring and the 0x3C address first.

How it measures

Readings are taken with the ADC at 12-bit resolution (analogReadResolution(12)):

voltage (V)  = raw / 4095 × 3.3 × voltage_divider
current (A)  = raw / 4095 × 3.3 × (1000 / shunt_resistance_mΩ)
wattage (W)  = current × voltage

Both scale factors live in setup.h:

  • voltage_divider — by how much the input voltage is divided before the ADC (default 2)
  • shunt_resistance — shunt value in milliohms (default 50)

Measurements refresh every 100 ms. Temperature comes from the RP2040's built-in sensor (analogReadTemp()), no external sensor needed.

USB score

calculateUSBScore() grades how close the measured voltage is to an ideal 5.0 V USB rail. Higher is better:

Score Voltage range
9 4.90 – 5.10 V
8 4.80 – 4.90 V or 5.10 – 5.20 V
7 4.70 – 4.80 V or 5.20 – 5.30 V
6 4.60 – 4.70 V or 5.30 – 5.40 V
5 4.40 – 4.60 V or 5.40 – 5.60 V
4 4.20 – 4.40 V or 5.60 – 5.80 V
3 4.00 – 4.20 V or 5.80 – 6.00 V
2 3.70 – 4.00 V or 6.00 – 6.30 V
1 3.50 – 3.70 V or 6.30 – 6.50 V
0 3.00 – 3.50 V or 6.50 – 8.00 V
blink (-) below 3.0 V or above 8.0 V (out of range)

The score is rendered as a big 48 px digit; when out of range it toggles between - and blank every second.

Display layout

┌─────────────────────────────────┐
│ [temp] 25.4 C°  │ [clock] 05:42 │   top: temp + uptime
├─────────────────────────────────┤
│ V: 5.012                        │
│ A: 0.842             │          │
│ W: 4.219             │   9      │   big USB score
│                      │          │
└─────────────────────────────────┘
  • Top row: temperature icon + value, a separator line, clock icon + uptime
  • Left column: W: / A: / V: labels (DejaVu Sans Mono) with DSEG7 7-segment values
  • Right side: the 48 px DSEG7 score digit behind a vertical divider

With use_default_fonts = true the same layout is drawn in the built-in Adafruit 5×7 font (and C replaces C°).

Getting started

  1. Install the Raspberry Pi Pico / RP2040 board package in the Arduino IDE (e.g. Earle Philhower's arduino-pico core, which provides analogReadResolution() / analogReadTemp() and the Pico SDK).
  2. Install the libraries: Adafruit GFX Library and Adafruit SSD1306 (Library Manager).
  3. Copy all files from this folder into a sketch folder named voltage_current_monitor_usb so the .h files sit next to the .ino.
  4. Set your hardware values in setup.h (shunt, divider, pins, features).
  5. Select your board / port and upload.

Required libraries

Library Purpose
Wire I2C (built in)
Adafruit_GFX graphics primitives
Adafruit_SSD1306 OLED driver
<hardware/adc.h> Pico SDK ADC (comes with the arduino-pico core)

Project structure

voltage_current_monitor_usb/
├── voltage_current_monitor_usb.ino   main sketch (loop, display, score, uptime)
├── setup.h                          hardware + feature configuration
├── dseg7_7seggchan_mini_font_48p_regular.h   DSEG7 "7SEGGCHAN" 48 px font (score)
├── dseg7_classic_mini_font_11p_regular.h     DSEG7 Classic mini font (values)
├── DejaVu_Sans_Mono_font_12p_regular.h       label font (as `DialogInput_plain_12`)
└── images.h                         temperature & clock bitmaps

Configuration (setup.h)

Option Default What it does
shunt_resistance 50 shunt value in mΩ — set to match your hardware
voltage_divider 2 divider ratio for the voltage input
VOLTAGE_PIN / CURRENT_PIN A0 / A1 ADC pins
I2C_SDA / I2C_SCL 28 / 29 OLED I2C pins
use_7seggchan true draw the big 48 px score digit
use_default_fonts false use built-in fonts instead of the custom font files (saves flash)
use_bitmaps true draw the temperature / clock icons (saves flash when off)
use_usbscore true compute the 0–9 USB score (requires use_7seggchan)
use_splash / use_version_splash true reserved splash-screen toggles (no splash code in the current sketch yet)

Saving flash: if the sketch is too big, set use_default_fonts = true (and skip the three font #includes) and/or use_bitmaps = false (and skip images.h).

Troubleshooting

  • "Display Error: Check Connections" and it hangs — OLED not found. Check SDA/SCL wiring, 0x3C address, and the pins in setup.h.
  • Voltage reads wrong — verify voltage_divider matches your divider hardware.
  • Current reads wrong — verify shunt_resistance (in mΩ), e.g. 50 = 0.05 Ω.
  • Compilation fails / flash overflow — disable custom fonts and/or bitmaps (see above) and remove the unneeded #includes.
  • Serial monitor — set the baud rate to 115200.

Credits

S
Description
No description provided
Readme
39 KiB
Languages
C 89%
C++ 11%