跳转至

1 exs_bl0939-电能计量芯片

作者:蒋骞 | 最后修改:2026-08-21

声明:

严禁带电操作! 进行任何连接或拆卸前,务必断开电源。

高压危险! 测试220V时,请确保所有接线可靠,并使用隔离变压器及漏电保护器。

本介绍为技术支持页面,操作人员需具备电气安全知识,否则请勿尝试,操作风险由使用者自行承担

一、概述

exs_bl0939 是上海贝岭 BL0939 双路免校准电能计量芯片的 LuatOS 扩展库。 BL0939 内置 3 路 Σ-Δ ADC,可同时测量 2 路电流和 1 路电压, 能够测量电流、电压有效值、有功功率、有功电能量、快速电流有效值、 相角、温度等参数,适用于单相多功能电能表、智能插座、充电桩等场景。

1.1 主要特性

  • 支持 SPI 与 UART 两种通信方式;SPI 模式 1(CPOL=0/CPHA=1), 最高速率 900KHz,写帧发送 6 字节 {0xA5, Addr, DH, DM, DL, CHECKSUM}, 读帧发送 2 字节 {0x55, Addr} 芯片返回 4 字节数据

  • UART 固定波特率 4800bps,N/8/1.5,从模式半双工; 支持"全电参数数据包"模式,一次请求返回 35 字节全部电参量

  • 支持 SOP16L(器件地址固定 5)和 SSOP20L(A4~A1 设地址 0~15)两种封装, UART 多芯片带地址通信

  • 可读取 A/B 双路电流有效值、电压有效值、快速有效值、 有功功率、电能脉冲计数、相角、内部温度、外部温度

  • 支持快速有效值检测(漏电/过流监控), 刷新周期可选半周波或周波,阈值可配

  • 内置温度传感器(内部+外部 VT 引脚),支持温度报警阈值配置

  • CF 引脚可复用为电能脉冲输出、温度报警或 A 通道漏电报警

  • 具有专利防潜动设计,配合外部硬件可确保无电流时噪声不计入电能

  • 支持 SEL 引脚切换 SPI/UART 通信模式(SEL=1 为 SPI,SEL=0 为 UART)

1.2 注意事项

  • 扩展库返回的是芯片寄存器原始值,转换为实际电压、电流、功率 需要外部互感器和分压电阻参数,Demo 中提供示例换算方法

  • 校准系数需在实际硬件上标定后填入 config.calibration, 否则计量精度由芯片出厂参数决定(出厂增益误差小于 1%)

  • 快速有效值阈值需根据实际电流互感器变比和额定电流标定后确定

  • BL0939 的 UART 波特率固定为 4800bps,不可通过软件修改

  • 硬件中断引脚(ZX/I_leak/CF)为芯片直接输出,不在本库统一封装, 需要中断功能的用户可通过 GPIO 监听或轮询状态实现

  • BL0939 的 SPI 不支持片选(CS), setup 中的 cs 参数仅为 LuatOS spi.deviceSetup 所需占位 GPIO, 该 GPIO 不接 BL0939

  • UART 通信模式下,若字节间隔超过 18.5ms,UART 接口自动复位; RX 管脚低电平超过 6.65ms 后拉高也会复位 UART 模块

1.3 硬件连接

SPI 模式接线(SEL 接高电平)

Air780EPM/ADC 模块          BL0939(SSOP20L/SOP16L)
    SPI0_SCK  --------------> SCLK  (SPI 时钟)
    SPI0_MOSI --------------> RX/SDI (SPI 数据输入)
    SPI0_MISO <-------------- TX/SDO (SPI 数据输出,需外部上拉电阻)
    GPIO28    --------------> SEL   (接高电平选择 SPI 模式)
    3.3V      --------------> VDD   (数字电源)
    GND       --------------> GND   (地)

    IP1/IN1   <------------ 电流 A 通道采样(差分输入 ±50mV)
    IP2/IN2   <------------ 电流 B 通道采样(差分输入 ±50mV)
    VP        <------------ 电压采样(差分输入 ±100mV)

UART 模式接线(SEL 接低电平或悬空)

Air780EPM/ADC 模块          BL0939(SSOP20L/SOP16L)
    UART1_TX  --------------> RX/SDI (UART 接收)
    UART1_RX  <-------------- TX/SDO (UART 发送,需外部上拉电阻)
    GPIO28    --------------> SEL   (接低电平选择 UART 模式)
    3.3V      --------------> VDD
    GND       --------------> GND

    SSOP20L 多芯片:A4~A1 接 VDD/GND 设器件地址 0~15
    SOP16L 固定地址:器件地址为 5

1.4 加载方式

-- 扩展库需要 require 加载后才能调用
local exs_bl0939 = require "exs_bl0939"

二、核心示例

2.1 场景一:SPI 模式读取双路电能数据

-- 本示例演示在 Air780EPM 上使用 SPI 初始化 BL0939 并循环读取双路数据
local exs_bl0939 = require "exs_bl0939"

-- 电压/电流转换系数,需根据实际互感器参数计算
local voltage_ratio = 1000  -- 分压比,例如 1000:1
local current_ratio = 1000  -- 电流互感器变比,例如 1000:1

-- 初始化 BL0939,使用 SPI0,SEL 接 GPIO28
local function init_func()
    local result = exs_bl0939.setup({
        mode = "spi",
        spi_id = 0,
        cs = 20,
        sel_pin = 28,
        ac_freq = 50,
        rms_update = 400,
        fast_rms_threshold = 0x7FFF
    })
    if not result then
        log.error("bl0939", "初始化失败")
        return false
    end
    log.info("bl0939", "初始化成功,版本:", exs_bl0939.version())
    return true
end

-- 读取并打印数据
local function read_func()
    local data = exs_bl0939.get_data()
    if not data then
        log.error("bl0939", "读取失败")
        return
    end
    log.info("bl0939", string.format("电压=%.2fV 温度=%.1f°C",
        data.v_rms / voltage_ratio, data.temp))
    log.info("bl0939", string.format("A路 电流=%.3fA 有功=%.2fW 相角=%.1f°",
        data.ia_rms / current_ratio,
        data.a_watt / voltage_ratio / current_ratio,
        data.a_angle))
    log.info("bl0939", string.format("B路 电流=%.3fA 有功=%.2fW 相角=%.1f°",
        data.ib_rms / current_ratio,
        data.b_watt / voltage_ratio / current_ratio,
        data.b_angle))
end

-- 演示任务
local function demo_task_func()
    sys.wait(100)        -- 等待系统稳定,100ms
    if not init_func() then return end
    for i = 1, 10 do
        read_func()
        sys.wait(1000)   -- 每隔 1 秒读取一次
    end
    exs_bl0939.close()
end
sys.taskInit(demo_task_func)

2.2 场景二:UART 模式初始化(SOP16L 固定地址 5)

-- 本示例演示使用 UART 与 BL0939 通信,接线见 1.3 节
local exs_bl0939 = require "exs_bl0939"

local function init_func()
    local result = exs_bl0939.setup({
        mode = "uart",
        uart_id = 1,
        addr = 5,
        sel_pin = 28
    })
    if not result then
        log.error("bl0939", "UART 初始化失败")
        return false
    end
    log.info("bl0939", "UART 初始化成功")
    return true
end

local function read_task_func()
    sys.wait(100)        -- 等待系统稳定,100ms
    if not init_func() then return end
    local data = exs_bl0939.get_data()
    if data then
        log.info("bl0939", "读取成功,电压原始值=", data.v_rms)
    end
    exs_bl0939.close()
end
sys.taskInit(read_task_func)

三、常量解释

扩展库常量,顾名思义是由 exs_bl0939 扩展库中定义的、不可重新赋值或修改的固定值, 在脚本代码中不需要声明,可直接调用;

每个常量对应的常量取值仅做日志打印时查询使用,不要将这个常量取值用做具体的 业务逻辑判断,因为扩展库可能会变更每个常量对应的常量取值;

如果用做具体的业务逻辑判断,一旦常量取值发生改变,业务逻辑就会出错;

3.1 exs_bl0939.CF_FUNC_ENERGY

常量含义:CF 引脚输出电能脉冲(默认),由 MODE[11] 选择 A/B 通道
数据类型:string
注意事项:默认功能,CF 输出对应通道的有功电能脉冲
示例代码:log.info("bl0939", exs_bl0939.CF_FUNC_ENERGY)

3.2 exs_bl0939.CF_FUNC_TEMP_ALERT

常量含义:CF 引脚输出外部温度报警信号
数据类型:string
注意事项:需配合 temp_alert_th 设置报警阈值;当 TPS2 大于等于阈值时 CF 输出高电平
示例代码:log.info("bl0939", exs_bl0939.CF_FUNC_TEMP_ALERT)

3.3 exs_bl0939.CF_FUNC_LEAKAGE_ALERT

常量含义:CF 引脚输出 A 通道漏电/过流报警信号
数据类型:string
注意事项:A 通道报警需占用 CF 引脚;B 通道报警直接由 I_leak 引脚输出,无需占用 CF
示例代码:log.info("bl0939", exs_bl0939.CF_FUNC_LEAKAGE_ALERT)

3.4 exs_bl0939.AC_FREQ_50HZ

常量含义:交流电频率选择 50Hz(默认),适合国内电网
数据类型:number
注意事项:影响快速有效值刷新周期和相角计算
示例代码:log.info("bl0939", exs_bl0939.AC_FREQ_50HZ)

3.5 exs_bl0939.AC_FREQ_60HZ

常量含义:交流电频率选择 60Hz,适合海外电网
数据类型:number
注意事项:50Hz 周波 20ms,60Hz 周波 16.67ms,影响快速 RMS 响应时间
示例代码:log.info("bl0939", exs_bl0939.AC_FREQ_60HZ)

3.6 exs_bl0939.RMS_UPDATE_400

常量含义:有效值寄存器刷新间隔 400ms(默认),响应较快
数据类型:number
注意事项:400ms 刷新一次 IA/IB_RMS 和 V_RMS 寄存器
示例代码:log.info("bl0939", exs_bl0939.RMS_UPDATE_400)

3.7 exs_bl0939.RMS_UPDATE_800

常量含义:有效值寄存器刷新间隔 800ms,数据更平滑
数据类型:number
注意事项:800ms 刷新一次,适合平稳负载场景,减少跳动
示例代码:log.info("bl0939", exs_bl0939.RMS_UPDATE_800)

3.8 exs_bl0939.FAST_RMS_CYCLE_FULL

常量含义:快速有效值按周波刷新(默认),响应时间最长 40ms(50Hz)
数据类型:string
注意事项:周波刷新数据较稳定,适合常规漏电/过流监控
示例代码:log.info("bl0939", exs_bl0939.FAST_RMS_CYCLE_FULL)

3.9 exs_bl0939.FAST_RMS_CYCLE_HALF

常量含义:快速有效值按半周波刷新,响应时间最长 20ms(50Hz)
数据类型:string
注意事项:半周波刷新响应更快但数据跳动较大,适合快速过流保护
示例代码:log.info("bl0939", exs_bl0939.FAST_RMS_CYCLE_HALF)

四、函数详解

4.1 初始化

4.1.1 exs_bl0939.setup(config)

功能

初始化 BL0939 传感器,配置通信接口、SEL 模式切换、交流频率、 RMS 刷新间隔、快速有效值、CF 输出功能等参数, 并写入写保护解锁和基本配置寄存器。

⚠️ 协程限制:必须在 sys.taskInit 创建的协程中调用 原因:初始化过程需要等待芯片稳定并写入寄存器,内部使用 sys.wait 让步 最长等待:约 200ms

参数

config

参数含义:配置参数表
数据类型:table
取值范围:
{
    参数含义:通信方式
    数据类型:string
    取值范围:"spi"(SPI 模式,推荐,速率快)
             "uart"(UART 模式,固定 4800bps,支持多片地址)
    是否必选:否
    注意事项:默认 "spi";SPI 速率快适合高频轮询,
             UART 布线简单仅需两根线且支持隔离通信
    参数示例:"spi"
    config.mode ,

    参数含义:SEL 引脚 GPIO 编号(接 BL0939 SEL,切换 SPI/UART 模式)
    数据类型:number
    取值范围:模块可用 GPIO 编号
    是否必选:是
    注意事项:SEL=1 进入 SPI 模式,SEL=0 进入 UART 模式;
             BL0939 内部下拉,悬空默认为 UART
    参数示例:28
    config.sel_pin ,

    参数含义:SPI 总线 id
    数据类型:number
    取值范围:0 / 1,具体取决于模块硬件 SPI 支持
    是否必选:否
    注意事项:仅在 mode="spi" 时生效;不传时使用默认 SPI 总线
    参数示例:0
    config.spi_id ,

    参数含义:SPI 片选 GPIO 引脚编号(占位,不接 BL0939)
    数据类型:number
    取值范围:模块可用 GPIO 编号
    是否必选:否
    注意事项:仅在 mode="spi" 时生效;BL0939 SPI 不支持片选,
             此 GPIO 仅为 spi.deviceSetup 所需参数,不接 BL0939
    参数示例:20
    config.cs ,

    参数含义:UART 总线 id
    数据类型:number
    取值范围:0 / 1 / 2,具体取决于模块 UART 支持
    是否必选:否
    注意事项:仅在 mode="uart" 时生效;波特率固定 4800bps 不可改
    参数示例:1
    config.uart_id ,

    参数含义:UART 器件地址(A4~A1 引脚决定)
    数据类型:number
    取值范围:0 ~ 15
    是否必选:否
    注意事项:仅在 mode="uart" 时生效;SOP16L 封装固定为 5;
             SSOP20L 由 A4A3A2A1 引脚电平决定,0000~1111 对应 0~15;
             不传时使用默认值 5
    参数示例:5
    config.addr ,

    参数含义:交流电频率选择
    数据类型:number
    取值范围:50(50Hz,国内电网,默认)
             60(60Hz,海外电网)
    是否必选:否
    注意事项:影响快速有效值刷新周期和相角计算;
             50Hz 周波 20ms,60Hz 周波 16.67ms
    参数示例:50
    config.ac_freq ,

    参数含义:有效值寄存器刷新间隔
    数据类型:number
    取值范围:400(400ms,默认,响应较快)
             800(800ms,数据更平滑)
    是否必选:否
    注意事项:刷新间隔影响 IA/IB_RMS 和 V_RMS 的更新速度;
             平稳负载选 800ms,需要快速响应选 400ms
    参数示例:400
    config.rms_update ,

    参数含义:快速有效值阈值(漏电/过流报警阈值)
    数据类型:number
    取值范围:0 ~ 32767,即 0x0000 ~ 0x7FFF
    是否必选:否
    注意事项:取 FAST_RMS 寄存器 Bit[23:9] 与阈值比较,
             大于等于阈值时报警引脚输出高电平;
             阈值需根据实际电流互感器变比和额定电流标定后确定;
             不传时使用默认 0x7FFF(最大值,不报警)
    参数示例:32767
    config.fast_rms_threshold ,

    参数含义:快速有效值刷新周期
    数据类型:string
    取值范围:"full"(周波,默认,响应最长 40ms@50Hz,数据稳定)
             "half"(半周波,响应最长 20ms@50Hz,跳动较大)
    是否必选:否
    注意事项:半周波适合快速过流保护,周波适合常规漏电监控
    参数示例:"full"
    config.fast_rms_cycle ,

    参数含义:CF 引脚输出功能选择
    数据类型:string
    取值范围:"energy"(电能脉冲,默认,MODE[11] 选 A/B 通道)
             "temp_alert"(外部温度报警,CF 复用为温度报警输出)
             "leakage_alert"(A 通道漏电/过流报警,CF 复用为报警输出)
    是否必选:否
    注意事项:B 通道漏电报警直接由 I_leak 引脚输出,不占用 CF;
             选 temp_alert 需配合 temp_alert_th 设置阈值
    参数示例:"energy"
    config.cf_func ,

    参数含义:外部温度报警阈值
    数据类型:number
    取值范围:0 ~ 1023,即 0x000 ~ 0x3FF
    是否必选:否
    注意事项:仅在 cf_func="temp_alert" 时有意义;
             TPS2 寄存器值大于等于阈值时 CF 输出高电平报警;
             不传时使用默认 0x3FF(不报警)
    参数示例:1023
    config.temp_alert_th ,

    参数含义:校准系数表
    数据类型:table
    取值范围:{ {addr, value}, ... } 形式的数组,
             addr 为寄存器地址,value 为写入值
    是否必选:否
    注意事项:仅在需要现场校准时传入;未传入时使用芯片出厂参数;
             校准系数必须由标准源标定后得出,不能随意填写
    参数示例:{ {0x13, 0x10}, {0x15, 0x20} }
    config.calibration
}
是否必选:是
参数示例:
    -- SPI 模式:SEL 接 GPIO28
    exs_bl0939.setup({
        mode = "spi",
        spi_id = 0,
        cs = 20,
        sel_pin = 28,
        ac_freq = 50
    })

    -- UART 模式:SOP16L 固定地址 5
    exs_bl0939.setup({
        mode = "uart",
        uart_id = 1,
        addr = 5,
        sel_pin = 28
    })

返回值

local result = exs_bl0939.setup(config)

result

含义说明:初始化是否成功
数据类型:boolean
取值范围:true(成功),false(失败)
注意事项:失败时请检查接线、SEL 电平、通信参数和供电
返回示例:true

示例

local exs_bl0939 = require "exs_bl0939"
local result = exs_bl0939.setup({
    mode = "spi",
    spi_id = 0,
    cs = 20,
    sel_pin = 28
})
if not result then
    log.error("bl0939", "初始化失败")
    return
end
log.info("bl0939", "初始化成功")

4.2 数据读取

4.2.1 exs_bl0939.get_data()

功能

读取 BL0939 全部测量数据,包括 A/B 双路电流有效值、电压有效值、 快速有效值、有功功率、电能脉冲计数、相角、温度等。 UART 模式优先使用全电参数数据包(35 字节一次返回),SPI 模式逐寄存器读取。

⚠️ 协程限制:必须在 sys.taskInit 创建的协程中调用 原因:SPI/UART 读取需要多帧通信,内部使用 sys.wait 让步 最长等待:UART 数据包约 150ms,SPI 逐寄存器约 200ms

参数

返回值

local data = exs_bl0939.get_data()

data

含义说明:传感器测量数据
数据类型:table 或 nil
取值范围:
    data.ia_rms       - A 通道电流有效值原始值,24-bit 无符号整数
    data.ib_rms       - B 通道电流有效值原始值,24-bit 无符号整数
    data.v_rms        - 电压有效值原始值,24-bit 无符号整数
    data.ia_fast_rms  - A 通道快速有效值原始值,24-bit 无符号整数
    data.ib_fast_rms  - B 通道快速有效值原始值,24-bit 无符号整数
    data.a_watt       - A 通道有功功率原始值,24-bit 有符号整数
    data.b_watt       - B 通道有功功率原始值,24-bit 有符号整数
    data.cfa_cnt      - A 通道电能脉冲计数原始值,24-bit 无符号整数
    data.cfb_cnt      - B 通道电能脉冲计数原始值,24-bit 无符号整数
    data.a_angle      - A 通道相角,单位 °,范围 -180.0 ~ 180.0
    data.b_angle      - B 通道相角,单位 °,范围 -180.0 ~ 180.0
    data.tps1         - 内部温度寄存器原始值,10-bit 无符号整数
    data.tps2         - 外部温度寄存器原始值,10-bit 无符号整数
    data.temp         - 内部温度换算值,单位 °C
注意事项:原始值需根据外部采样电路参数换算为实际物理量;
          有功功率为有符号数,正值表示正功(用电),负值表示负功(发电);
          电能脉冲计数为代数和累积,正功加负功减
返回示例:{ia_rms=123456, ib_rms=7890, v_rms=234567, temp=35.5, a_watt=250}

示例

local exs_bl0939 = require "exs_bl0939"
local data = exs_bl0939.get_data()
if data then
    log.info("bl0939", string.format("温度=%.1f°C", data.temp))
    log.info("bl0939", string.format("A路电流原始值=%d 有功=%d", data.ia_rms, data.a_watt))
    log.info("bl0939", string.format("B路电流原始值=%d 有功=%d", data.ib_rms, data.b_watt))
end

4.3 参数配置

4.3.1 exs_bl0939.reset()

功能

对 BL0939 执行软复位,写入 0x5A5A5A 到 SOFT_RESET 寄存器, 复位用户区寄存器为默认值。复位后需重新调用 setup 才能继续读取数据。

⚠️ 协程限制:必须在 sys.taskInit 创建的协程中调用 原因:复位后需要等待芯片恢复,内部使用 sys.wait 让步 最长等待:约 100ms

参数

返回值

local result = exs_bl0939.reset()

result

含义说明:复位是否成功
数据类型:boolean
取值范围:true(成功),false(失败)
返回示例:true

示例

exs_bl0939.reset()  -- 复位用户区寄存器
-- 复位后需重新调用 setup
exs_bl0939.setup({mode = "spi", spi_id = 0, cs = 20, sel_pin = 28})

4.4 资源释放

4.4.1 exs_bl0939.close()

功能

释放 SPI/UART 总线和 GPIO 资源,关闭 BL0939 扩展库。

参数

返回值

local result = exs_bl0939.close()

result

含义说明:是否成功释放资源
数据类型:boolean
取值范围:true(成功),false(失败)
返回示例:true

示例

exs_bl0939.close()

4.5 版本信息

4.5.1 exs_bl0939.version()

功能

获取扩展库版本号。

参数

返回值

local version = exs_bl0939.version()

version

含义说明:扩展库版本号
数据类型:string
取值范围:版本号字符串,格式为 yyyymmddhhmm
返回示例:202608200000

示例

log.info("bl0939", "版本:", exs_bl0939.version())

五、版本更新说明

版本号:202608200000

  1. 更新时间:2026-08-20

  2. 更新内容:

    • 初版实现

六、产品支持说明

所有支持 LuatOS 二次开发的模块,具体可以查看选型手册

搜索