BL0940 AC Energy Monitoring Using Arduino
by Electroveins in Circuits > Arduino
29 Views, 1 Favorites, 0 Comments
BL0940 AC Energy Monitoring Using Arduino
AC power and energy monitoring device this IC used in most of the IoT application, calculate energy consumption in minimal form factor.
Supplies
Components Required
- BL0940 energy metering IC (SOP-14)
- Arduino Uno/Nano
- 1 milliohm (1 mOhm) shunt resistor
- 4 x 300K ohm resistors for the high side of the voltage divider (total 1.2 MOhm)
- 1 x 510 ohm resistor for low side of the voltage divider
- 2 x 2.2 uF capacitors for anti-aliasing filter on VP and IP channels
- 2 x 100 nF (0.1 uF) decoupling capacitors
- 1 x 10 uF electrolytic capacitor
- Custom PCB from JLCPCB
Story:
I have been working with energy metering ICs for a while now. After trying BL0937 which has a pretty straightforward control interface, today I finally got my hands on the BL0940. Both are similar, because they are single-phase energy metering IC but what surprise me the most is its feature set. Unlike the simpler BL0937 ICs in the BL series, the BL0940 gives you voltage, current, active power, energy accumulation, phase angle, power factor and temperature without the need of component calibration, and all data is accessible though UART or SPI.
But for now this tutorial is focused on SPI communication mode. You just pull the SEL pin HIGH for SPI, and the IC switches its entire communication interface. I built a complete Arduino library around this IC with five ready-to-use examples. The total component cost is very low a 1 milliohm shunt resistor, a voltage divider network, and a few capacitors is all you need on the analog front end. This is a open source project you can access the design files through GITHUB, I have made a dedicated PCB from JLCPCB and tested it out with real time energy monitoring in my lab.
What Is BL0940?
The BL0940 is a single-phase energy metering IC, It has two sigma-delta ADCs for simultaneous voltage and current sampling, a digital multiplier for real-time active power computation, and an energy accumulator with pulse output. The IC operates from a 3.3V supply and uses an internal 1.218V reference voltage for all measurements. We can plug a load from 1W to 2500 watts in this with the PCB that I have designed. BL0940 has internal phase angle register with this register you can compute the phase difference between voltage and current, in order to get true power factor as cos(phi) without any extra signal processing. The BL0940 also has a built-in internal temperature sensor and supports an external NTC thermistor on the VT pin.
Here are the key specifications from the datasheet:
- Supply Voltage: 3.0V to 3.6V (typical 3.3V)
- Internal Reference: 1.218V (typ.)
- Differential input (IP/IN), max input +/-200 mV
- Differential input (VP/VN), max input +/-200 mV (after divider)
- UART at 4800 baud (fixed) or SPI up to 900 kHz
- Temperature Sensors: Internal (TPS1) + External NTC (TPS2), 10-bit ADC
- Anti-Creep register
- Energy Pulse Output
- Zero-Crossing Output
Circuit Diagram
I had followed the datasheet, and used the circuit as per the configuration in the documentation. The current sensing path uses a 1 milliohm shunt resistor connected between the IP1 and IN1 pins. At the maximum rated current, the voltage drop across this shunt stays well within the +/-200 mV. The 2.2 uF anti-aliasing capacitor are added across the IP/IN inputs to filter out high-frequency noise from the mains. This is important because the sigma-delta ADC inside the BL0940 can alias at high-frequency harmonics.
Four 300K ohm resistors in series (1.2 MOhm total) form the high side, and a 510 ohm resistor forms the low side. This gives a division ratio of approximately 2354:1, which scales 220V mains down to about 93 mV at the VP pin safely within the ADC input range. For power supply, the BL0940 runs on 3.3V. I have placed a 100 nF ceramic capacitor right next to the VDD pin for high-frequency decoupling, the power is given through the onboard LDO AMS1117 3.3V.
The CF pin outputs energy pulses and can be used for kWh counting or alarm output, while the ZX pin provides a zero-crossing signal synchronized to the mains frequency. Which are not used in this version of the tutorial. All readings are sent to the Serial Monitor, and the library handles all the register-level communication.
Downloads
Understanding the Register Map
Understanding the register map is essential because the library is built entirely around reading these registers:
- I_FAST_RMS (0x00): Measures fast current RMS value (half/full cycle)
- I_WAVE (0x01): Stores instantaneous current waveform data
- V_WAVE (0x03): Stores instantaneous voltage waveform data
- I_RMS (0x04): Measures current RMS over a 400/800 ms window
- V_RMS (0x06): Measures voltage RMS over a 400/800 ms window
- WATT (0x08): Stores active power measurement
- CF_CNT (0x0A): Energy pulse counter register
- CORNER (0x0C): Measures phase angle between voltage and current
- TPS1 (0x0E): Internal temperature sensor reading
- TPS2 (0x0F): External temperature sensor (NTC) reading
Library Design and Conversion:
The BL0940 supports two communication modes, and understanding the protocol is important because the data byte order is different between UART and SPI, I am focusing on SPI because it is more stable and fast, in the library there you can find code for UART also, for the SPI Mode (SEL = HIGH). In SPI mode, the BL0940 uses Mode 1 (CPOL=0, CPHA=1), MSB first, with a maximum clock of 900 kHz. The frame structure is similar to UART but the byte order is reversed, MSB first in SPI mode. The library uses 500 kHz as the default SPI clock for reliable operation.
Both modes use the same checksum formula: the bitwise NOT of the sum of all bytes except the checksum itself. I wrote this library to be as clean and straightforward as possible. Let me walk you through the key design decisions and functions.
Initialization and Verification: The `begin()` function initializes the communication interface and verifies that the BL0940 is responding, for that I have chosen the TPS1 (internal temperature) register for verification because it always returns a valid non-zero value as long as the chip is powered and communicating. If `begin()` returns false, you know immediately that something is wrong with your wiring or the SEL pin configuration.
Measurement Conversion: The raw register values from the BL0940 need to be converted to engineering units using calibration divisors. Here is how the voltage reading works internally:
The `_voltageDiv` is a calibration constant that depends on your specific voltage divider values. The datasheet gives us the formula:
Similar calibration divisors exist for current (default 266.0 for a 1 mOhm shunt) and power (default 1158.2). You can override these with `setVoltageDiv()`, `setCurrentDiv()`, and `setPowerDiv()`.
Calibration Using Load:
The SEL pin must be tied to VDD (3.3V) for SPI mode. Now use a 100W bulb, note down the socket voltage current and compute power manually using multimeter. Then feed the values inside the code like this:
Make the onboard circuit as given here, you have to use the OLED, do not use laptop serial monitor when the IC is plugged in 220V. Laptop is only used to upload the program in the Arduino.
After upload connect the 5V power charger and load as given here, and note down the coefficients that are displayed on the OLED. Note them down and copy in the main working code for calibration.
After upload connect the 5V power charger and load as given here, and note down the coefficients that are displayed on the OLED. Note them down and copy in the main working code for calibration.
Downloads
Working Code:
Here is the main working code after uploading the calibration coefficients see how the reading changes.
Downloads
PCB Overview:
I have kept the PCB minimal and easy to plug, It is kind of breakout board which contain the main IC and supporting electronics, you can plug it with any microcontroller in order to make it working, For now I am using Arduino Nano.
The PCB is simple yet it works, and I have tested it fully, keep in mind the LIVE and NEUTRAL connections, be careful when working with the AC voltage. You can download the files from here, with the working code. I have designed this in EasyEDA and fabricated using JLCPCB, I took me around an hour of soldering work to make it work in real life. If you want a proper soldered solution that works in the first go, I will recommend to go with JLCPCB PCB assembly services, you try them out in lowest prices from here.
Outro:
With all this we can say this is an amazing IC, you can download the main codes from GITHUB. Library works with any Arduino-compatible board that has a serial port or SPI. Whether you are building a commercial smart plug or just experimenting with energy measurement, this project gives you a solid foundation. Library works with any Arduino-compatible board that has a serial port or SPI. This IC find application in IoT related stuff out there, If you want to plan a power supply that deliver 5V directly from 220V see our tutorial on: Smallest 220V to 5V Supply for IOT applications. If you have any questions, suggestions, or want to share your own BL0940 build, please comment below. I would love to see what you make with it.