首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >INA226怎样避免电压电流读成两轮数据

INA226怎样避免电压电流读成两轮数据

原创
作者头像
不脱发的程序猿
发布于 2026-10-19 19:20:26
发布于 2026-10-19 19:20:26
40
举报

一块功率计,电压读得对,电流也读得对,相乘后却可能得到一份不属于任何一轮采样的结果。

问题可能藏在两个 I²C 读取之间。主机读完电压,INA226 恰好更新了结果寄存器;随后读到的电流,已经属于下一轮。给每个寄存器单独加重试,甚至给软件总线加锁,都没有保证它们来自同一轮转换。

对需要成组记录电压、电流的低速监测,这个边界值得单独处理。下面保留一块 STM32F103C8T6 验证板的硬件,重写最小采样固件,让它先完成一轮测量,再把整组数据交给上层。

两个正确读数怎样拼出 24W

先用一个可以复现的合成反例说明问题。

A 轮完整结果为 12V、1A,乘积 12W。B 轮为 5V、2A,乘积 10W。若读取顺序恰好是“读 A 的电压、芯片更新到 B、读 B 的电流”,软件会算出 12×2=24W。

连续模式跨轮读取的合成反例
连续模式跨轮读取的合成反例

图1为合成时序示意,数值用于演示允许发生的读取交错,不是板卡实测波形,也不证明某一块板已经出现该故障。

TI 的 INA226 手册给出了这个分析的依据。连续双量模式先转换分流电压,再转换总线电压;完成所设平均次数及内部计算后,更新对应的输出寄存器。旧结果会保留到下一组完整结果到来,读取数据寄存器不会暂停正在进行的转换。

因此,一次读到完整的 16 位寄存器,与连续几次读取属于同一轮,是两个不同的问题。只在一轮开始前看到 CVRF,也不能阻止连续模式紧接着完成下一轮。

先看这块板到底测了哪里

实际EDA工程重新导出的完整原理图
实际EDA工程重新导出的完整原理图

图2为同一 REV1.0 工程从 EDA 重新导出的原理图。复杂处在下面拆开看,完整源文件随附件提供。

INA226分流电阻及I2C上拉局部
INA226分流电阻及I2C上拉局部

图3保留了 U1、R9、R3/R4 的真实连接。R9 标称 0.005Ω;A0、A1 接地,七位 I²C 地址是 0x40。0x80 是加上读写位后的写地址字节,不能把它原样填进要求七位地址的 HAL 接口。

这张图还有一个容易忽略的细节。VBUS 接 VIN,处在 R9 上游;电流则由流过 R9 的负载支路电流换算得到。这里的 V×I 表示分流器上游、该负载支路对应的功率。它没有扣掉 R9 的损耗,也没有把板上 DC/DC 的自身耗电算进负载支路电流,不能直接叫“负载端精确功率”或“整机总输入功率”。

R3、R4 都是上拉到 3.3V 的 4.7kΩ。新固件把 PB6/PB7 配成开漏,释放高电平时由上拉电阻拉高,并检查 SCL 是否真正变高以及每个字节的 ACK。

同版PCB顶铜及顶层丝印
同版PCB顶铜及顶层丝印

图4为顶层,R9 位于下方输入输出之间,U1 在它上方,R3/R4 紧邻采样与主控区域。排查时要沿着 R9 两侧的取样连接追到 U1,不能只检查负载大电流路径是否连通。

同版PCB底铜及底层丝印
同版PCB底铜及底层丝印

图5为底铜和底丝印的自顶向下透视,与图4使用相同坐标,未作镜像,所以底层文字反向。它不是翻板后的实物照片。两张 PCB 图用于核对布局和连接,不能据铜皮外观推定可持续通过多大电流;丝印中的电压电流范围也没有在本文完成热、电源及保护验收。

把下一轮的开始权交给主机

本次固件只保留采样与串口诊断,不把屏幕菜单也塞进来。转换参数沿用四次平均、总线与分流各 1.1ms,仅把模式改成单次双量触发。

代码语言:c
复制
#define INA_CFG_IDLE 0x4320u
#define INA_CFG_ONCE 0x4323u
#define INA_CAL 1024u

0x4323 的 MODE=011。每次写入都会触发一组测量,即使写入的值和上次相同,也不能省去这次写操作。名义转换时间为 (1.1+1.1)×4=8.8ms,驱动仍要等完成标志,不能延时 8.8ms 后直接假定已经完成。

流程分成三个边界。

第一,触发前核对配置与校准,写配置开启新一轮。初始化先进入关断模式,写入校准值,并关闭本专题没有使用的 ALERT 功能。

第二,轮询 Mask/Enable,检查同一次读取返回的 CVRF 和 OVF。CVRF 是 bit3,表示转换、平均、乘法都完成;OVF 是 bit2,表示内部运算溢出,电流及功率可能无效。

读取 Mask/Enable 会清除 CVRF。 因此,读到就绪后必须保存这次返回值,不能为了“再确认一下”立即重读,再拿已清除的标志判断超时。配置写入也会清除 CVRF,关断模式写入除外。

第三,就绪后一次读完分流、总线、电流,复查配置和校准。全部成功才更新结果,读完前不启动下一轮。此时结果寄存器不会像连续模式那样自行开始下一组更新。

附件中的采集函数如下,底层回调和结果类型也在同一个工程中。

代码语言:c
复制
ina_result ina_capture(const ina_io *io, ina_sample *out) {
    uint16_t cfg, cal, status, bus, shunt, current;
    uint32_t start = io->millis(io->ctx), ready;
    if (!io->read(io->ctx, 0, &cfg) || !io->read(io->ctx, 5, &cal)) return INA_IO;
    if ((cfg != INA_CFG_IDLE && cfg != INA_CFG_ONCE) || cal != INA_CAL) return INA_CONFIG;
    if (!io->write(io->ctx, 0, INA_CFG_ONCE)) return INA_IO;
    for (;;) {
        if ((uint32_t)(io->millis(io->ctx) - start) >= 30u) return INA_TIMEOUT;
        if (!io->read(io->ctx, 6, &status)) return INA_IO;
        ready = io->millis(io->ctx);
        if ((uint32_t)(ready - start) >= 30u) return INA_TIMEOUT;
        if (status & 8u) break; /* Reading register 6 clears CVRF: retain this returned word. */
        io->sleep_ms(io->ctx, 1);
    }
    if (status & 4u) return INA_OVERFLOW;
    /* One shot is complete. No next conversion is started until this function is called again. */
    if (!io->read(io->ctx, 1, &shunt) || !io->read(io->ctx, 2, &bus) ||
        !io->read(io->ctx, 4, &current) || !io->read(io->ctx, 0, &cfg) ||
        !io->read(io->ctx, 5, &cal)) return INA_IO;
    if (cfg != INA_CFG_ONCE || cal != INA_CAL) return INA_CONFIG;
    if ((uint32_t)(io->millis(io->ctx) - start) >= 30u) return INA_TIMEOUT;
    ina_sample next = {out->seq + 1u, ready, bus, signed16(shunt), signed16(current)};
    *out = next; /* Only successful calls publish a complete sample. Not a thread-safe primitive. */
    return INA_OK;
}

函数先把新值放在局部变量中。通信失败、没有按时完成、溢出或者配置不符,都会提前返回,外部的上一份有效数据不变。成功时才增加 seq,让上层明确知道有没有拿到新数据。

这里的结构体赋值是单线程内的提交点,不是跨中断、跨任务的原子操作。使用 RTOS 时,应由一个任务独占 INA226,并通过队列或受保护的快照向其他任务发布;不能让另一个任务在中途重写配置或触发下一轮。

30ms 是本配置的成功截止线。底层每个寄存器事务另有 5ms 名义软件时限,阻塞时错误返回可能稍晚于截止线,不能把它当成硬实时保证。改变平均次数或转换时间后,应连同截止线一起重算。

校准值不能靠显示顺眼来定

设 Current_LSB=1mA/bit、Rshunt=5mΩ,按手册公式计算:

CAL = 0.00512 ÷ (0.001 × 0.005) = 1024。

这是按名义阻值计算的缩放参数,不是一次实体标定。电阻公差、温漂、焊接和取样压降,需要在有参考仪表的条件下另行处理。

总线电压每位 1.25mV,电流按这里设置为每位 1mA,主机乘积可写成:

代码语言:c
复制
int64_t ina_power_uw(const ina_sample *s) {
    /* 1.25mV/bit * 1mA/bit = 1.25uW/bit^2. Signed, rounded toward zero. */
    return (int64_t)s->bus_raw * s->current_raw * 5 / 4;
}

其中 current_raw 已按有符号 16 位数解释,再参与运算。乘法先提升到 64 位,防止较大数值在中间步骤溢出。这里计算的是主机有符号乘积,没有借用芯片功率寄存器去推断反向功率行为。

还要划清一个测量边界。总线电压与分流电压是顺序转换,四次平均也覆盖一段时间。同一轮不等于同时采样,平均电压乘平均电流也不等于任意动态负载下的平均瞬时功率。 这个改动解决的是寄存器跨轮拼接,适用于低速成组监测;开关瞬态与相位问题需要相应的采样硬件和测试方法。

在这块 STM32 上怎样复现

STM32引脚与串口所在的同版原理图局部
STM32引脚与串口所在的同版原理图局部

图6中 PB6=SCL、PB7=SDA,USART1 PA9 为 TX、PA10 为 RX。最小固件使用内部 HSI 8MHz,SysTick 提供 1ms 计时,不依赖外部晶体,也不驱动屏幕。

构建只需要 Python 3.12 和 Zig 0.13.0,无第三方 Python 包。解压附件,进入 firmware 目录,将命令末尾改为本机 Zig 路径:

代码语言:txt
复制
python build.py C:/Tools/zig-0.13.0/zig.exe

脚本先编译并运行主机测试,再生成 STM32F103C8 的 ELF、BIN,核对 Flash 地址、初始栈和复位向量。本次生成的 Flash 镜像为 3084 字节。附件包含启动文件、链接脚本、I²C 适配器、核心驱动和测试,不需要从文章片段自行拼工程。

准备烧录时,用 ST-Link 连接 PA13/SWDIO、PA14/SWCLK、地和 3.3V 电压参考,BOOT0 为低;在 STM32CubeProgrammer 中确认目标后下载 ELF 并校验。若使用 BIN,基址填 0x08000000。具体接线及前提见附件 README。

串口使用 9600、8N1,PA9 接 3.3V 逻辑 USB-UART 的 RX,并共地。不要用 USB-UART 的 3.3V 引脚给整块功率板供电。正常采集会输出 OK、递增 seq 和带单位的数值;失败则输出错误码与 last_seq,不把旧值冒充新读数。

本文没有验收原板 DC/DC、LDO 和高电流负载路径。复现固件应使用供电已经验收的板卡;独立搭台可用已验证供电的 3.3V STM32F103C8 与 INA226 板,先确认实际分流电阻和上拉电压,再从低压限流小负载核对缩放及方向。不同分流电阻必须重算 CAL,不能直接套用二进制。

故意让它出错,比只看正常打印更有用

主机模型测试和目标构建的实际运行日志
主机模型测试和目标构建的实际运行日志

图7由本次实际运行日志重排,属于主机模型与交叉构建结果,没有连接实体板。

测试模型复现了连续模式的 24W 跨轮反例。改用单次触发后,同一组合成输入交付 B 轮的 10W。随后逐一让 13 个采集通信操作失败,检查错误上报和上一份有效数据是否保留;初始化中的 5 个操作也逐一注入失败。

另外覆盖了旧 CVRF 清除后重触发、只消费一次就绪返回字、永不就绪、OVF、配置或校准失配、读取中复位、32 位毫秒回绕、负电流及 64 位功率中间量。这些测试检验驱动在约定模型下的行为,不能替代逻辑分析仪检查开漏边沿、ACK 与实际转换时序。

上板排查可以沿着错误码走:I/O 错误先查地址、上拉、地线与被拉低的总线;配置错误检查芯片是否复位、是否被其他代码改写;超时先核对转换参数与时钟;OVF 则检查校准和输入量程。不要把“错误时仍有上次读数”误当作采集还在正常更新,seq 和状态要一起看。

低速功率监测里,一份数据最先需要交代的,是它从哪一轮来。先把转换边界和失败行为讲清楚,后面的显示、记录和报警才有可靠的输入。

资料与工程

最小工程及同版硬件源文件:下载完整工程,附件名 ina226-one-shot-v1.0.0.zip。独立固件按 MIT 提供;原理图、PCB 源文件及其派生图片按项目 GPL-3.0 保留,硬件作者 HumphreyLin。许可文本与必要声明见附件。

硬件项目 https://oshwhub.com/HumphreyLin/INA226gong-shuai-ji-yan-zheng-ba 。上游固件仅作核验,未复制进附件,仓库 https://gitee.com/humphreylin/INA226-program ,核对版本 d3aaa39061824052b58e9e10e1437a3cb78f7715,其 LICENSE 为 AGPL-3.0。

技术依据为 TI INA226 SBOS547C 第6.3.1、6.5.1、7.1.1、7.1.5及7.1.7节 https://www.ti.com/document-viewer/INA226/datasheet ,以及 ST RM0008 Rev21、PM0056 Rev7。硬件图从同版 EDA 工程重新导出,只作裁剪和保真缩放;时序图为明确标注的合成示意。已完成主机故障模型测试与目标构建,未进行实体板烧录、精度、温升或功率额定验证。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

目录
  • 两个正确读数怎样拼出 24W
  • 先看这块板到底测了哪里
  • 把下一轮的开始权交给主机
  • 校准值不能靠显示顺眼来定
  • 在这块 STM32 上怎样复现
  • 故意让它出错,比只看正常打印更有用
  • 资料与工程
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档