The Core Challenge: Safely Interfacing Mains AC with Microcontroller ADCs
To figure out how to measure AC voltage using a microcontroller, you must first accept a hard hardware limitation: microcontroller GPIO pins and internal Analog-to-Digital Converters (ADCs) operate strictly on low-voltage DC (typically 0-3.3V or 0-5V). Connecting 120V or 230V AC mains directly to an Arduino, ESP32, or Raspberry Pi Pico will instantly destroy the silicon and present a severe electrocution hazard.
The direct answer is to use an isolation transformer-based sensor module (like the ZMPT101B) or a dedicated SPI metrology IC (like the Microchip ATM90E26). These components step down the mains voltage, provide galvanic isolation, and output a scaled, DC-biased analog sine wave that the microcontroller's ADC can safely sample. However, building the circuit is only half the battle; verifying that your microcontroller's firmware readings match reality requires rigorous bench testing with a digital multimeter (DMM).
Bench Verification: DMM Setup and Probe Placement for AC Sensor Modules
Before uploading firmware to your ESP32 or Arduino, you must verify the hardware layer. Misadjusted bias potentiometers on ZMPT101B modules are the number one cause of clipped waveforms and inaccurate RMS calculations in firmware. According to Fluke's guide on multimeter safety ratings, using the correct CAT rating is non-negotiable when measuring branch circuits.
Meter Setup Block
- Dial Position: V~ (AC Voltage) for mains input verification; V⎓ (DC Voltage) for checking the sensor's DC bias offset.
- Lead Jacks: Black lead to COM, Red lead to V/Ω/Hz.
- Range: Auto-ranging is preferred. If manual, set to 200V AC for 120V systems, or 600V AC for 230V systems. For DC bias checks, use the 2V or 20V DC range.
- Safety Category: You need a CAT III 600V minimum rating for probing wall outlets and branch circuits. If measuring at the main service panel, CAT IV 600V is required.
Probe Placement Sequence
- Test Point 1 (Mains Input): Place probes across the Live (L) and Neutral (N) screw terminals on the primary side of the ZMPT101B. This establishes your baseline true RMS voltage.
- Test Point 2 (Sensor Analog Out - DC Bias): Switch DMM to DC Voltage. Place the red probe on the sensor module's 'AO' (Analog Out) pin and the black probe on the module's 'GND'. This verifies the op-amp DC offset.
- Test Point 3 (Sensor Analog Out - AC Ripple): Switch DMM to AC Voltage. Keep probes on 'AO' and 'GND'. This measures the peak-to-peak AC ripple scaled down by the transformer.
- Test Point 4 (MCU GPIO): Place probes on the specific microcontroller ADC pin (e.g., ESP32 GPIO 34) and the shared system GND. Readings here must exactly match Test Points 2 and 3.
Expected Readings: Translating Mains RMS to Microcontroller ADC Values
What does a good reading look like numerically? For a standard North American 120V nominal system, acceptable mains voltage ranges from 114V to 126V RMS. The ZMPT101B module scales this down and adds a 1.65V DC bias so the AC waveform swings symmetrically above and below the midpoint, keeping it within the 0-3.3V window of the ESP32 ADC.
If your DC bias is off, the sine wave will clip at 3.3V (ADC reads a flat 4095) or 0V (ADC reads 0), ruining your RMS math. The OpenEnergyMonitor guide on AC voltage sampling heavily emphasizes dialing in this exact bias voltage before writing a single line of code.
| Test Point | DMM Mode | Expected Good Value (120V Nominal) | Bad Value / Fault Condition |
|---|---|---|---|
| Mains Input (L to N) | V~ (AC) | 114.0V - 126.0V AC | < 110V (Brownout) or > 130V (Overvoltage) |
| Sensor AO to GND (Bias) | V⎓ (DC) | 1.60V - 1.70V DC | < 1.2V or > 2.1V (Bias pot misadjusted) |
| Sensor AO to GND (Ripple) | V~ (AC) | 1.00V - 1.30V AC | > 1.65V AC (Waveform will clip at 3.3V rail) |
| ESP32 GPIO 34 to GND | V⎓ (DC) | 1.60V - 1.70V DC | 0.00V (Broken jumper wire or blown GPIO) |
Common Mistakes That Yield Misleading AC Voltage Readings
Even with perfect hardware, firmware implementation errors will give you wildly inaccurate AC voltage readings. Here are the specific mistakes that yield misleading data on the bench:
1. Sampling Below the Nyquist Threshold
AC mains operates at 50Hz or 60Hz. To accurately reconstruct the sine wave and calculate True RMS, you must sample at least twice per cycle, but practically, you need 1,000+ samples per second. If your analogRead() loop is bogged down by delay() calls or heavy Wi-Fi stack processing, you will alias the waveform, resulting in random, fluctuating voltage readouts.
2. Ignoring ESP32 ADC Non-Linearity at the Rails
The ESP32's internal ADC is notoriously non-linear near 0V and 3.3V. According to the Espressif ESP-IDF ADC Oneshot documentation, readings below 0.15V and above 3.1V are highly inaccurate and should be discarded or avoided. If your ZMPT101B bias is set to 1.65V, but your AC ripple is 1.6V, your peaks will hit 3.25V, pushing into the non-linear zone and artificially lowering your calculated RMS voltage.
3. Forgetting to Subtract the DC Offset in Firmware
The ADC reads absolute voltage (0 to 3.3V). To calculate AC RMS, you must first find the DC offset (the center point, usually ~2048 in raw 12-bit ADC values). You must subtract this offset from every sample to center the wave at zero before squaring the values for the RMS calculation. Failing to do this will result in a massive, static DC offset being added to your AC voltage reading.
4. Using ADC2 While Wi-Fi is Active
On the original ESP32, the Wi-Fi and Bluetooth radio share hardware resources with ADC2. If you attempt to measure AC voltage using ADC2 pins (like GPIO 12, 13, 14) while simultaneously transmitting MQTT data over Wi-Fi, the ADC reads will fail or return garbage data. Always use ADC1 pins (GPIO 32, 33, 34, 35, 36, 39) for continuous AC sampling.
FAQ: Measuring AC Voltage with Microcontrollers
Can I use a simple resistor voltage divider to measure AC voltage with an Arduino?
No. A resistor voltage divider provides no galvanic isolation. If a resistor fails open, or if the ground reference shifts, full mains voltage will be routed directly into your microcontroller and any connected USB devices (like your laptop). You must use a transformer-based isolation module (ZMPT101B) or an isolated Hall-effect/opto-isolated sensor to ensure safety.
Why is my ESP32 ADC reading fluctuating wildly when measuring AC voltage?
Wild fluctuations usually stem from one of three issues: 1) Your sampling rate is too low, causing you to catch random points on the sine wave rather than reconstructing it. 2) You are using an ADC2 pin while Wi-Fi is enabled. 3) Your sensor module lacks adequate decoupling capacitors on the 5V/3.3V supply rail, injecting switching noise into the op-amp bias circuit. Add a 100nF ceramic capacitor directly across the sensor's VCC and GND pins.
How do I calculate true RMS AC voltage in microcontroller firmware?
True RMS (Root Mean Square) requires sampling the waveform over at least one full cycle (20ms for 50Hz, 16.6ms for 60Hz). In firmware, subtract the DC bias offset from each raw ADC sample, square the result, accumulate these squared values over the cycle, divide by the total number of samples to find the mean, and finally take the square root. Multiply this final value by your specific calibration constant (derived from comparing DMM readings to raw ADC output) to get the final AC voltage.
What is the safest alternative to the ZMPT101B for measuring mains AC?
For commercial or high-reliability DIY applications, dedicated metrology ICs like the Microchip ATM90E26 or ATM90E32 are vastly superior. These ICs handle the isolation (when paired with proper external CTs/PTs), perform the True RMS math in dedicated hardware silicon, and output precise voltage, current, and power factor data over SPI or UART. They eliminate the analog noise and ADC non-linearity headaches inherent to the ZMPT101B.






