9 Essential Steps to Build a DIY 3-in-1 AC Meter (Arduino • Voltage • Current • Power)
This DIY electronics project shows you how to design and build a 3-in-1 AC Meter using an Arduino Nano, an OLED display, an LM358 IC, and a 100 A/50 mA current transformer. With this project, you can measure voltage, current, and power from AC mains and display real-time results on a compact OLED screen. The guide includes a complete bill of materials with buy links, a clear circuit diagram, PCB layout tips, and a step-by-step assembly process.
Beginners and experienced engineers will both benefit from learning how to condition signals, safely step down mains values, and process data with Arduino code. The project also explains calibration and testing methods to ensure reliable accuracy. By the end, you’ll have a professional DIY tool for monitoring household or lab AC loads, perfect for education, research, and practical electrical projects.
Introduction (3-in-1 AC Meter)
I’ve built and fielded a lot of mains-measurement gadgets over the years, and the core challenge never changes: scale and safety. We’re measuring ~230 VAC and up to triple-digit amps on the primary, yet the Arduino wants millivolts around a 0–5 V window. This project solves that with:
- A high-impedance resistive divider and RC network to scale the mains voltage.
- To obtain a clear, isolated current signal, a 2000:1 current transformer (CT) with a calculated burden resistor is used.
- An LM358 stage to bias and condition both channels for the ADC.
- Sampling firmware that computes Vrms, Irms, real power (P), apparent power (S), and power factor (PF).
- A crisp OLED display for live readouts.
What This Build Measures (3-in-1 AC Meter)
- Voltage (Vrms) — true RMS mains voltage.
- Current (Irms) — via CT sensing, isolated from mains.
- Real Power (P, watts) is calculated by averaging and multiplying the synchronized instantaneous voltage and current.
- Bonus values (derived in code): Apparent power (S = Vrms×Irms), power factor (PF = P/S), and energy (Wh) if you add accumulation.
Materials for the Project (3-in-1 AC Meter)
Component | Quantity | Description / Purpose | Buy Link |
---|---|---|---|
Arduino Nano | 1 | Main microcontroller to sample, process, and display measurements | Buy Link |
OLED Display (0.96″, SSD1306, I²C) | 1 | 128×64 screen to show Voltage, Current, Power, PF | Buy Link |
Current Transformer 100 A / 50 mA (2000:1) | 1 | Isolated current sensing of AC load | Buy Link |
LM358 IC | 1 | Dual op-amp for signal conditioning & biasing | Buy Link |
47 Ω Resistor (1%) | 1 | CT burden resistor | Buy Link |
2.2 kΩ Resistor (1%) | 1 | Voltage divider (bottom leg) | Buy Link |
4.7 kΩ Resistor (1%) | 1 | Voltage divider (bottom leg) | Buy Link |
10 kΩ Resistors (1%) | 3 | Mid-rail bias network, pull-downs | Buy Link |
470 kΩ Resistors (1%) | 6 | High-voltage divider chain (scales mains voltage) | Buy Link |
2-pin Terminal Blocks | 2 | One for AC input, one for CT secondary | Buy Link |
Perfboard | 1 | For assembling the circuit | Buy Link |
Jumper wires | — | Connections between components | Buy Link |
Download Circuit Diagram
How the Circuit Works (Block-by-Block)
1) Voltage Sensing & Scaling
- Goal: Convert 230 VAC (≈325 Vpk) to a small, safe waveform for the ADC.
- Divider idea: Six 470 kΩ in series form ~2.82 MΩ on the top leg. The bottom leg uses 4.7 kΩ + 2.2 kΩ = 6.9 kΩ to ground.
- Approx. ratio: 2.82 MΩ : 6.9 kΩ ≈ 409:1.
- Peak at ADC (pre-bias) ≈ 325 V / 409 ≈ 0.79 Vpk (≈0.56 Vrms). Perfect headroom for conditioning.
- RC filter: Place ~100 nF film cap across the bottom leg to reduce HF noise; keep the time constant short enough to preserve the 50/60 Hz shape.
- Protection: Add 220 Ω series + 5 V TVS near the MCU pin. Always include a fuse and MOV on the line side, and enforce creepage/clearance.
Isolation note: This divider is not isolated. The CT provides isolation for current, but voltage scaling here is live-referenced. Use an isolated AC transformer if you require full galvanic isolation for voltage.
2) Current Sensing with CT (100 A/50 mA, 2000:1)
- CT principle: Primary current induces a scaled secondary current (50 mA at 100 A primary).
- Burden resistor (47 Ω): Converts secondary current to voltage. At 50 mA RMS, Vburden ≈ 0.05 A × 47 Ω ≈ 2.35 Vrms (≈3.32 Vpk). That’s a healthy signal that we’ll attenuate/condition before the ADC.
- RC filtering: 100 nF across burden tamps HF spikes. Keep CT leads twisted; avoid open-circuiting a powered CT (large voltages can develop).
3) Mid-Rail Bias & LM358 Conditioning
- The Arduino’s ADC reads 0–5 V. We bias signals around Vref/2 ≈ 2.5 V using two 10 kΩ resistors (5 V–2.5 V–GND) and decouple with 10 µF.
- LM358 (two channels):
- Voltage channel: Buffer the divided mains waveform and shift it around 2.5 V (AC-couple through a cap to the 2.5 V rail, then buffer). Optional small gain (<×2) if needed.
- Current channel: First attenuate the CT burden voltage if necessary (simple divider), then AC-couple to the 2.5 V bias and buffer. Optionally add a small anti-alias RC at the output.
- Outputs go through 220 Ω into A0 (voltage) and A1 (current).
4) Sampling & Math
- Sampling rate: ≥ 2 kS/s per channel for 50 Hz is fine (40+ samples per cycle). I prefer 3–4 kS/s to reduce quantization and timing errors.
- Synchrony: Use timer-driven ISR to interleave A0/A1 reads with fixed spacing. Store into circular buffers.
- RMS & Power:
- Vrms=1N∑v(n)2V_\text{rms}=\sqrt{\frac{1}{N}\sum v(n)^2}Vrms=N1∑v(n)2
- Irms=1N∑i(n)2I_\text{rms}=\sqrt{\frac{1}{N}\sum i(n)^2}Irms=N1∑i(n)2
- P=1N∑v(n)⋅i(n)P=\frac{1}{N}\sum v(n)\cdot i(n)P=N1∑v(n)⋅i(n) (real power)
- S=Vrms⋅IrmsS=V_\text{rms}\cdot I_\text{rms}S=Vrms⋅Irms, PF=P/S\text{PF}=P/SPF=P/S
- Calibration constants:
- KV (V per ADC count) from your voltage divider.
- KI (A per ADC count) from CT ratio and burden.
- Offset trims for both channels (remove bias error).
5) Display
- Use an I²C OLED (SSD1306). Show:
- Line 1: Vrms (e.g., 229.7 V)
- Line 2: Irms (e.g., 4.12 A)
- Line 3: Real Power (e.g., 945 W)
- Line 4: PF (e.g., 0.96 lag)
Schematic Narrative (Text-Based)
- Mains L/N → Fuse → MOV across L-N → Voltage divider: L → series chain of 6×470 kΩ → node Vdiv → (4.7 kΩ + 2.2 kΩ) → N. A 100 nF across 6.9 kΩ. From Vdiv, AC-couple via small cap into LM358 stage biased at 2.5 V. LM358 out → 220 Ω → A0. TVS near A0 to ground/5 V.
- CT secondary → burden 47 Ω → 100 nF across burden. Tap across burden → attenuator (if needed) → AC-couple into 2.5 V bias → LM358 buffer → 220 Ω → A1. TVS near A1.
- Bias rail: 10 kΩ–10 kΩ divider from 5 V to GND gives 2.5 V node. 10 µF to ground for stability. Feed both AC-coupled channels here.
- Power: Arduino 5 V powers LM358 and OLED. Decouple LM358 with 100 nF at Vcc.
Design Calculations (Walk-Through)
Voltage Divider Scaling
- Top: 6×470 kΩ = 2.82 MΩ
- Bottom: 4.7 kΩ + 2.2 kΩ = 6.9 kΩ
- Ratio: 2.82 M / 6.9 k ≈ 409
- Peak output (pre-conditioning): 325 V / 409 ≈ 0.79 Vpk
- Divider current at peak: 325 V / 2.82 M ≈ 115 µA → low dissipation, cool resistors.
If your mains is 120 VAC, the numbers still work; you’ll simply get a smaller ADC swing (plenty of headroom).
CT Burden & Headroom
- Secondary at full scale: 50 mA RMS.
- With 47 Ω, Vburden ≈ 2.35 Vrms (3.32 Vpk).
- After AC-coupling and buffering around 2.5 V, ensure peaks stay < 0.5–4.5 V at the ADC. If you see clipping, add a simple divider (e.g., 10 kΩ / 10 kΩ) before the coupling cap, or reduce burden to 22–33 Ω (then adjust KI in firmware).
ADC & Quantization
- 10-bit ADC @5 V → 4.88 mV/LSB. With our gains, that’s adequate. For tighter accuracy, average multiple mains cycles and compensate for phase shift (see below).
Phase Shift Compensation
- The RC networks and CT magnetics introduce small phase lags. For better real power:
- Measure time offset between zero crossings of voltage and current waveforms (in samples).
- Either delay one channel in software or apply a small phase correction factor when computing v(n)i(n)v(n)i(n)v(n)i(n).
- Even a 1–2° correction can clean up PF and P.
Step-by-Step Build Guide (3-in-1 AC Meter)
Step 1
First connect Arduino.
Step 2
Then connect LM358 IC. And connect its pin number one to A0 pin of Arduino. Its pin number two to A7 pin of Arduino. Its pin number eight to 5V pin of Arduino And its pin number four to ground.
Step 3
Now connect a 10k resistor and connect its one pin to pin number one of the IC and its other pin to pin number two of the IC.
Step 4
Now connect another 10k resistor and connect its one pin to pin number two of the IC and its other pin to ground.
Step 5
Now connect 47 ohm resistor and connect its one pin to pin number three of the IC and its other pin to ground.
Step 6
Now connect the current transformer and connect its one pin to pin number three of the IC and its other pin to ground.
Step 7
Now connect a 10k resistor and connect its one pin to pin number seven of the IC and its other pin to pin number six of the IC.
Step 8
Now connect a 4.7K resistor and connect its one pin to pin number six of the IC and its other pin to ground.
Step 9
Now connect a 2.2k 2k resistor and connect its one pin to pin number five of the IC and its other pin to ground.
Step 10
Now connect a two pin terminal block.
Step 11
Now connect a 470k resistor and connect its one pin to pin
number five of the IC.
Step 12
Now connect another 470k resistor and connect its one pin to remaining pin of the previous 470k resistor.
Step 13
Now connect another 470k resistor and connect its one pin to remaining pin of the 470k resistor and its other pin to pin number one of the two pin terminal block.
Step 14
Now connect another 470k resistor and connect its one pin to ground.
Step 15
Now connect another 470k resistor and connect its one pin to previous 470k resistor.
Step 16
Now connect another 470k resistor and connect its one pin to remaining pin of the previous 470k resistor and its other pin to pin number two of the two pin terminal block.
Step 17
Now connect the OLED display and connect its VCC pin to 5 volt pin of Arduino. Its ground pin to ground its SDA pin to A4 pin of Arduino and its Sccl pin to A5 pin of Arduino.
Step 18
Now connect a push button and connect its one pin to pin D2 of Arduino and its other pin to ground.
Step 19
Now connect another push button and connect its one pin to pin D3 of Arduino and its other pin to ground.
Step 20
Now connect another push button and connect its one pin to D4 pin of Arduino and its other pin to ground. So we have completed all the connections.
Step 21
Now let’s upload the code to Arduino and test the project.
Arduino Code
Display Layout (Suggested)
- Top-left: V: 229.8 V
- Top-right: I: 2.31 A
- Bottom-left: P: 531 W
- Bottom-right: PF: 0.97
Use large font for V and P; small font for I and PF. Add icons or units glyphs for readability.
Accuracy Tips (3-in-1 AC Meter)
- Use 1% resistors (you already are) and match the 470 kΩ chain as best as possible.
- Keep analog leads short and away from mains.
- Add a dedicated analog ground star-point returning to the Arduino AGND pin.
- Average over multiple windows to steady the numbers.
- If noise persists, lower ADC input impedance by buffering with LM358 at gain ≈1 and keeping source resistance to the ADC < 10 kΩ.
Common Pitfalls & Fixes
- OLED flicker/noise: Decouple 5 V at the display with 100 nF + 10 µF.
- ADC clipping: Verify peaks < 0.5–4.5 V. Reduce gain or attenuate CT channel.
- PF looks wrong on non-resistive loads: Implement phase correction and ensure synchronized sampling.
- CT reads zero: Ensure you clamped around one conductor only.
- Hot resistors: If your mains runs high, check divider dissipation; with 2.82 MΩ the chain runs cool, but inspect anyway.
FAQs
Q1. Can I power the Nano from USB while measuring mains?
Yes, but keep the USB ground isolated from exposed metal. The voltage divider is live-referenced; treat the entire analog side as potentially at mains potential unless you use an isolated front-end.
Q2. Will the LM358 be accurate at high frequency?
We’re measuring 50/60 Hz, well within LM358’s bandwidth. For harmonics analysis, consider a faster, lower-noise op-amp.
Q3. Do I need true RMS code if I only care about sine loads?
For purely resistive loads you could estimate, but the code already computes RMS/real power; keep it—modern loads are rarely perfect sine.
Q4. Can I extend this to energy (kWh)?
Yes. Integrate P(t) over time and divide by 3600 to get Wh, then kWh.
Q5. What display alternatives work?
A 16×2 LCD (I²C) works fine. Update less often to keep readings stable.
Q6. Can I use different CT ratios?
Absolutely. Recalculate the burden so your maximum expected secondary current produces ~1–2 Vrms before conditioning.
Q7. How do I improve isolation?
Replace the resistive divider with an isolation PT (potential transformer) or use an isolated ADC module. Keep the CT for current.