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参数仅为 LuatOSspi.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
-
更新时间:2026-08-20
-
更新内容:
- 初版实现
六、产品支持说明
所有支持 LuatOS 二次开发的模块,具体可以查看选型手册。