Hackster will be offline on Monday, June 15 from 5pm to 7pm PDT to perform some scheduled maintenance.
Electro BOY
Published © GPL3+

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.

IntermediateFull instructions provided2 hours113
BL0940 AC Energy Monitoring Using Arduino

Things used in this project

Software apps and online services

JLCPCB

Story

Read more

Custom parts and enclosures

Gerber

CPL

BOM

Schematics

Circuit diagram

Code

Calibration code

Arduino
/**
 * BL0940 SPI Calibration + SSD1306 OLED
 *
 * Uses SPI mode exactly like the main example
 * and displays calibration divisors on OLED.
 *
 * Wiring:
 * --------------------------------
 * BL0940:
 *   SCLK   -> D13
 *   RX/SDI -> D11
 *   TX/SDO -> D12
 *   SEL    -> 3.3V
 *   VDD    -> 3.3V
 *   GND    -> GND
 *
 * OLED SSD1306:
 *   SDA -> A4
 *   SCL -> A5
 *   VCC -> 5V
 *   GND -> GND
 */

#include <SPI.h>
#include <Wire.h>
#include <BL0940.h>

#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>

// ---------------- OLED ----------------
#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64
#define OLED_RESET    -1
#define SCREEN_ADDRESS 0x3C

Adafruit_SSD1306 display(
    SCREEN_WIDTH,
    SCREEN_HEIGHT,
    &Wire,
    OLED_RESET
);

// -------------- BL0940 SPI ----------------
// Same as main example
BL0940 meter(-1, 500000);

// ===== Reference Meter Values =====
const float ACTUAL_VOLTAGE = 249.0;
const float ACTUAL_CURRENT = 0.402;
const float ACTUAL_POWER   = 100.0;
// ===================================

void setup()
{
    Serial.begin(115200);

    // OLED Init
    if (!display.begin(SSD1306_SWITCHCAPVCC, SCREEN_ADDRESS)) {

        Serial.println("SSD1306 allocation failed");

        while (1);
    }

    display.clearDisplay();
    display.setTextColor(SSD1306_WHITE);

    display.setTextSize(1);
    display.setCursor(0, 0);
    display.println("BL0940 SPI");
    display.println("Calibration");
    display.println("Initializing...");
    display.display();

    // BL0940 Init (SPI)
    if (!meter.begin()) {

        Serial.println("BL0940 not detected!");

        display.clearDisplay();
        display.setCursor(0, 0);
        display.println("BL0940 ERROR!");
        display.println("Check SPI");
        display.println("SEL HIGH");
        display.display();

        while (1) {
            delay(1000);
        }
    }

    Serial.println("BL0940 initialized.");

    // Stabilization delay
    display.clearDisplay();
    display.setCursor(0, 0);
    display.println("Wait...");
    display.println("Stabilizing");
    display.display();

    delay(3000);

    // Read raw registers
    uint32_t raw_v = meter.readReg(BL0940_REG_V_RMS);
    uint32_t raw_i = meter.readReg(BL0940_REG_I_RMS);
    uint32_t raw_p = meter.readReg(BL0940_REG_WATT);

    // Calculate divisors
    float voltage_div = (float)raw_v / ACTUAL_VOLTAGE;
    float current_div = (float)raw_i / ACTUAL_CURRENT;
    float power_div   = (float)raw_p / ACTUAL_POWER;

    // Serial Output
    Serial.println();
    Serial.println("=== Calibration Divisors ===");

    Serial.print("meter.setVoltageDiv(");
    Serial.print(voltage_div, 1);
    Serial.println(");");

    Serial.print("meter.setCurrentDiv(");
    Serial.print(current_div, 1);
    Serial.println(");");

    Serial.print("meter.setPowerDiv(");
    Serial.print(power_div, 1);
    Serial.println(");");

    // OLED Output
    display.clearDisplay();

    display.setTextSize(2);

    display.setCursor(0, 0);
    display.println("Calibrate");

    display.setTextSize(1);
    display.setCursor(0, 20);
    display.print("VDiv:");
    display.println(voltage_div, 1);

    display.setCursor(0, 36);
    display.print("IDiv:");
    display.println(current_div, 1);

    display.setCursor(0, 52);
    display.print("PDiv:");
    display.println(power_div, 1);

    display.display();
}

void loop()
{
    // Nothing required
}

Main program

Arduino
/**
 * BL0940 SPI Mode + SSD1306 OLED Display
 * (Calibrated Version)
 *
 * Calibration Values Applied:
 *   Voltage Div = 15988.6
 *   Current Div = 568427.9
 *   Power Div   = 1421.1
 *
 * OLED: SSD1306 128x64 I2C
 *
 * Wiring (Arduino Uno/Nano):
 * --------------------------------
 * BL0940:
 *   SCLK   -> D13
 *   RX/SDI -> D11
 *   TX/SDO -> D12
 *   SEL    -> 3.3V
 *   VDD    -> 3.3V
 *   GND    -> GND
 *
 * OLED SSD1306:
 *   VCC -> 5V
 *   GND -> GND
 *   SDA -> A4
 *   SCL -> A5
 */

#include <SPI.h>
#include <Wire.h>
#include <BL0940.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>

// OLED settings
#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64
#define OLED_RESET    -1
#define SCREEN_ADDRESS 0x3C

Adafruit_SSD1306 display(
    SCREEN_WIDTH,
    SCREEN_HEIGHT,
    &Wire,
    OLED_RESET
);

// BL0940 SPI object
BL0940 meter(-1, 500000);

void setup()
{
    Serial.begin(115200);

    // OLED Init
    if (!display.begin(SSD1306_SWITCHCAPVCC, SCREEN_ADDRESS)) {

        Serial.println("SSD1306 allocation failed");

        while (1);
    }

    display.clearDisplay();
    display.setTextColor(SSD1306_WHITE);

    display.setTextSize(1);
    display.setCursor(0, 0);
    display.println("BL0940 Energy");
    display.println("Initializing...");
    display.display();

    // BL0940 Init
    if (!meter.begin()) {

        Serial.println("BL0940 not detected!");

        display.clearDisplay();
        display.setCursor(0, 0);
        display.println("BL0940 ERROR!");
        display.println("Check SPI");
        display.println("SEL HIGH");
        display.display();

        while (1) {
            delay(1000);
        }
    }

    // ===== Apply Calibration =====
    meter.setVoltageDiv(15988.6);
    meter.setCurrentDiv(568427.9);
    meter.setPowerDiv(1421.1);
    // =============================

    Serial.println("BL0940 initialized.");
    Serial.println("Calibration Applied.");

    display.clearDisplay();
    display.setCursor(0, 0);
    display.println("Calibration");
    display.println("Applied!");
    display.display();

    delay(1500);
}

void loop()
{
    float voltage = meter.getVoltage();
    float current = meter.getCurrent();
    float power   = meter.getPower();
    float energy  = meter.getEnergy();
    float temp    = meter.getInternalTemp();

    if (meter.lastReadOk()) {

        // Serial Output
        Serial.print("V=");
        Serial.print(voltage, 1);

        Serial.print("V  I=");
        Serial.print(current, 3);

        Serial.print("A  P=");
        Serial.print(power, 1);

        Serial.print("W  E=");
        Serial.print(energy, 4);

        Serial.print("kWh  T=");
        Serial.print(temp, 1);
        Serial.println("C");

        // OLED Display
        display.clearDisplay();

        // Large Voltage Display
        display.setTextSize(2);
        display.setCursor(0, 0);

        display.print("V:");
        display.print(voltage, 1);
        display.println("V");

        // Small Text
        display.setTextSize(1);

        display.setCursor(0, 22);
        display.print("I: ");
        display.print(current, 3);
        display.println(" A");

        display.setCursor(0, 34);
        display.print("P: ");
        display.print(power, 1);
        display.println(" W");

        display.setCursor(0, 46);
        display.print("E: ");
        display.print(energy, 4);
        display.println("kWh");

        display.setCursor(0, 56);
        display.print("T:");
        display.print(temp, 1);
        display.print("C");

        display.display();

    } else {

        Serial.println("Read error!");

        display.clearDisplay();
        display.setCursor(0, 0);
        display.println("Read Error!");
        display.display();
    }

    delay(1000);
}

Library for BL0940

Credits

Electro BOY
60 projects • 70 followers
Electronics is my passion. I am not professional, Always learning something new. I am good at soldering, designing pcb, Arduino programing.

Comments