简介:面向STM32与电能计量应用开发者的完整工程资料,基于STM32F103C8T6搭配HT7036/HT7038芯片,实现了通过I2C接口驱动OLED液晶屏,并利用独立按键切换显示电压、电流等参数的功能,程序已全部调试完成。资源共216个文件,压缩包约6.55MB,涵盖C/H源码头文件、编译生成的O/CRF/D中间文件、UVPROJX工程配置以及HEX/AXF烧录文件等,便于直接打开工程查看或烧录验证。引脚分配明确,OLED使用PA3/PA4的I2C引脚,按键接PA0、PB9、PB0,HT7036通过SPI通信,整体结构清晰,适合作为学习STM32外设驱动和电能采集方案的参考。目前已有1096人浏览学习,适合电子爱好者、嵌入式初学者及项目开发者快速上手并迁移到类似电力监测场景。 前阵子在做一款三相电力参数采集模块,主控选了STM32F103C8T6,计量核心用的是HT7036/HT7038芯片。很多人一听到“电能计量”就发怵,觉得三相电压、电流、有功无功、电能累计这些指标,光算法就能写一大篇。其实用专门的计量芯片来做,事情会简单很多——HT7036/HT7038内部把电压电流采样、FFT运算、功率计算、能量累加全部处理完了,STM32要做的只是通过SPI或者UART把寄存器里的结果读出来,再换算成工程单位。整个项目最费心思的其实是硬件布线、通信时序和校表这三个环节。这篇文章就围绕这个组合,把我实际踩过的坑和总结出来的流程完整梳理一遍,给准备做智能电表、电力监控、配电物联网或者充电桩计费的工程师一个可以直接参考的实操框架,单片机基础薄弱的朋友也能按着步骤把程序跑起来。
1. 方案选型与整体设计思路
1.1 为什么用计量芯片而不是MCU直接采样
用F103C8T6的ADC直接采集三相电压电流,理论上也能算出有效值、功率这些参数,但真正落地会发现几个硬伤。
首先是同步采样问题。三相功率计算要求电压和电流通道在同一时刻采样,F103C8T6的ADC只有一个,逐通道轮询采集会有时间差,在谐波环境下这个时间差会直接导致功率误差。其次是精度问题,普通MCU内置ADC的失调、增益误差已经不小,温度漂移再叠加进去,校准起来非常痛苦。最后是计算量,如果要做真有效值、需要计算到几十次谐波,F103C8T6的Cortex-M3跑FFT会占用大量CPU时间,后续想加Modbus协议、联网功能就很吃力。
HT7036/HT7038这类专用计量芯片把这些工作全部接管了。芯片内部有多路ADC同步采样,加上DSP做滤波、FFT、功率积分,MCU只需要在需要数据的时候去读寄存器即可。而且计量芯片出厂前已经做了大量模拟性能调优,有成熟的设计参考,产品过计量检测时更有把握。
1.2 HT7036与HT7038怎么选
这两颗芯片是同一个系列的三相电能计量芯片,绝大多数寄存器兼容,但定位略有差异。我整理了一张选型对比表,方便你根据项目需求直接拍板。
| 对比项 | HT7036 | HT7038 |
|---|---|---|
| 通信接口 | 以SPI为主 | SPI、UART双接口 |
| 计量精度 | 常规三相计量 | 支持更高精度等级,具体以手册为准 |
| RTC实时钟 | 通常不具备 | 集成RTC,可记录停电时间戳 |
| 温度传感器 | 无 | 集成,可做温度补偿 |
| 典型应用 | 三相参数采集、监控仪表 | 多功能电能表、分时计费终端 |
我的建议是:如果项目只做数据采集和上传,比如电力监控模块、充电桩计费,用HT7036就够了,成本更低;如果要做真正的电能表,尤其是需要分时计费、停电记录、过温保护,那就直接上HT7038。另外HT7038支持UART通信,某些不方便接SPI的场合会灵活很多。
注意:不同批次、不同后缀型号的寄存器地址和精度参数可能存在差异,选型定下后一定要以官方最新数据手册为准,代码里的寄存器地址不要照着别人的工程盲抄。
1.3 为什么F103C8T6够用
STM32F103C8T6这颗芯片在电表行业属于“老黄牛”级别的存在,Cortex-M3内核、72MHz主频、64KB Flash、20KB RAM。HT7036/HT7038的SPI读取频率一般不高,实测1MHz左右就非常稳定,MCU用SPI+DMA方式读取,CPU占用率很低。程序里包含驱动层、Modbus协议栈、简单的数据缓存和应用逻辑,64KB Flash完全装得下。
更重要的是生态成熟,上手资料多,而且国产替代选择非常丰富,GD32F103系列、APM32F103系列都和F103C8T6引脚兼容,很多量产产品已经把主控换成了国产型号,代码几乎不用改。如果后续想在设备上跑FreeRTOS再挂LVGL做彩色屏显示,20KB RAM会有点紧张,这种场景建议直接选F103RCT6(256KB Flash、48KB RAM),而不是在C8T6上硬抠资源。
2. 硬件设计与接口细节
2.1 电压电流采样前端
HT7036/HT7038的模拟输入是差分结构,外部电路的核心任务就是把电网的大电压、大电流转换成芯片输入范围内的微小差分信号。
电压采样我推荐用电阻分压方案,三相电压通过高精度电阻链分压后送入芯片的电压通道。分压电阻必须用温漂低、精度高的金属膜电阻,精度至少0.5%,最好0.1%,否则校准时会发现不同温度下读数飘得厉害。电流采样用电流互感器(CT),次级输出接精密采样电阻,把电流信号转成电压信号,采样电阻建议用低温漂的锰铜电阻或精密电阻。互感器的选择也很关键,变比、精度等级、角差直接影响最终的计量精度,预算允许的情况下尽量选0.1级或0.2级的互感器。
PCB布线时,电压采样线和电流采样线要尽量短,差分走线、包地处理,远离继电器、开关电源等强干扰源。芯片输入引脚前可以加RC低通滤波,但要注意RC滤波会引入相移,后期校相位时需要统一补偿,这个坑后面细说。
2.2 MCU与计量芯片的接线
HT7036/HT7038工作在3.3V,和F103C8T6可以直接电平连接,不需要额外转换。SPI模式接四根线:SCK、MOSI、MISO、CS,另外再接一根RESET复位脚。RESET必须用MCU的GPIO控制,不要直接接RC上电复位,因为程序里需要主动给芯片做复位脉冲。
还有一个很重要的细节是电源处理。计量芯片的模拟电源对纹波非常敏感,开关电源的噪声经常会串进去导致读数跳动。我建议给计量芯片单独用一路LDO供电,并在电源引脚加0.1uF和10uF去耦电容,数字部分和模拟部分用磁珠隔离。如果用UART模式,注意TX和RX交叉连接,即MCU的TX接芯片的RX,MCU的RX接芯片的TX。
2.3 上电复位与启动时序
这个环节最容易翻车。HT7036/HT7038上电后内部需要时间完成自检和时钟稳定,如果复位引脚释放后立刻开始通信,大概率读回一堆0xFF。我的标准流程是:GPIO配置完成后,先把RESET拉低50ms以上,再拉高,然后延时至少100ms,接着连续读取几次芯片版本寄存器或状态寄存器,直到读回有效值才继续初始化。
初始化顺序也很固定:配置SPI外设 → 复位脉冲 → 等待稳定 → 写系统控制寄存器 → 配置计量相关参数 → 开启ADC通道 → 进入正常读取循环。系统控制寄存器的配置项比较多,包括ADC采样率、谐波分析开关、能量累计模式等,建议对照手册逐位确认,不要只抄别人的初始化数组。
3. 软件驱动与数据解析
3.1 SPI通信协议要点
HT7036/HT7038的SPI读写采用命令帧方式,基本格式是:主机先发送寄存器地址,读操作紧接着读回两个字节数据,写操作则发送地址后再跟两个字节数据。芯片一般是大端传输,也就是高字节在前,具体以手册时序图为准。
SPI参数上,时钟极性(CPOL)和相位(CPHA)要严格按照手册配置,很多通信失败案例都是因为把SPI Mode搞错了。速率建议从低往上试,先用100kHz验证通信正常,再逐步提高到1MHz,没必要追求太高,因为计量数据本身并不需要频繁刷新。
读计量数据时还有一个容易忽略的点:瞬时功率、电流有效值这类寄存器是实时更新的,两次读取数值略有不同很正常。但电能累计寄存器是多个字节组合的,读取过程中如果刚好发生进位,可能会读到错误组合。稳妥做法是连续读两次,如果两次结果一致才采用,或者按手册提供的高低字节扩展寄存器方式拼接。
3.2 驱动代码框架
下面是一段SPI读写驱动的框架示例,寄存器地址以你手头芯片手册为准,代码目的是把整个流程串起来。
#define HT703x_CS_LOW() HAL_GPIO_WritePin(HT_CS_GPIO_Port, HT_CS_Pin, GPIO_PIN_RESET) #define HT703x_CS_HIGH() HAL_GPIO_WritePin(HT_CS_GPIO_Port, HT_CS_Pin, GPIO_PIN_SET) // 写寄存器 void HT703x_WriteReg(uint8_t addr, uint16_t data) { HT703x_CS_LOW(); HAL_SPI_Transmit(&hspi1, &addr, 1, 10); uint8_t buf[2]; buf[0] = (data >> 8) & 0xFF; // 高字节 buf[1] = data & 0xFF; // 低字节 HAL_SPI_Transmit(&hspi1, buf, 2, 10); HT703x_CS_HIGH(); } // 读寄存器 uint16_t HT703x_ReadReg(uint8_t addr) { HT703x_CS_LOW(); HAL_SPI_Transmit(&hspi1, &addr, 1, 10); uint8_t buf[2]; HAL_SPI_Receive(&hspi1, buf, 2, 10); HT703x_CS_HIGH(); return (uint16_t)((buf[0] << 8) | buf[1]); }实际项目中可以把“读计量参数”封装成独立函数,比如读电压有效值、读电流有效值、读有功功率、读电能累计值。这些函数内部再套一层互斥保护,防止被不同任务打断。
3.3 数据转换:从原始值到工程单位
芯片读出来的原始值是ADC转换结果,要换算成实际的电压、电流、功率,必须依赖手册给出的比例系数。举个例子,假设电压有效值寄存器原始值为reg_u,手册说明该寄存器分辨率为0.001V/LSB,那么实际电压就是reg_u × 0.001V。电流、功率、电能同理,只是系数不同。
符号处理要特别小心。功率寄存器可能是有符号数,表示电能方向(正向/反向),读出来要转成int16或int32,不能直接当无符号数用。如果芯片寄存器是24位有效数据,还需要自己把高字节做符号扩展,否则负功率会变成很大的正数。建议封装一个统一的转换函数,把“读寄存器 + 符号扩展 + 系数换算”集中处理,这样上层业务代码看到的直接就是float型的电压、电流、功率,逻辑清晰也方便调试。
4. 校表流程与精度调试
4.1 校表的原理和必要性
不要以为芯片接上电就能读出高精度数据。HT7036/HT7038本身有制造误差,模拟前端、互感器、分压电阻也会引入误差,尤其是电流互感器,比差和角差对功率计算影响非常大。校表的本质就是通过软件增益和相位补偿,把系统性误差修正到允许范围内。
校表主要做四个项目:电压增益校准、电流增益校准、有功功率增益校准、相位校准。原理其实就一句话——让芯片读数等于标准源的真实输出值,然后把修正系数写回芯片的校表寄存器。
4.2 一次完整的校表操作
校表需要高精度标准源,或者电能表校验台。流程如下:
- 标准源输出额定电压,比如三相220V,等待读数稳定。
- 读取电压有效值寄存器,计算电压增益 = 标准电压 / 读取值,写入电压增益寄存器。
- 保持电压在额定值,标准源输出基本电流Ib,比如5A,读取电流寄存器,计算电流增益并写入。
- 在功率因数PF=1.0条件下,读取有功功率寄存器,计算功率增益并写入。
- 切换功率因数到0.5L或0.5C,读取功率误差,调整相位补偿寄存器。
- 回读验证:分别在0.1Ib、Ib、Imax,以及PF=1.0、0.5L、0.5C条件下检查误差是否满足目标等级。
校表顺序不能乱,增益和相位会相互影响,先做增益再做相位是通用原则。每校完一项要重新读回确认写入成功,避免出现“看着写了其实没写进去”的尴尬情况。
4.3 误差超标怎么排查
电压准、电流准,但功率不准,大概率是功率增益没校或者没校准到位。小电流下误差偏大,多数是电流互感器在轻载时非线性导致的,可以考虑分段校准或换精度更高的互感器。如果某一相误差明显大于其他两相,重点检查该相的采样电阻、滤波电容、PCB焊接,大概率是硬件问题而不是芯片问题。
还有一个隐蔽的坑:RC低通滤波的相移。滤波电容越大、电阻越大,相位偏移越明显,低功率因数下功率误差会很大。如果产品要求低功率因数下也保持精度,相位补偿必须认真做,而且滤波参数一旦改动,必须重新校表。
5. 常见问题排查实录
5.1 通信异常速查
| 现象 | 可能原因 | 解决思路 |
|---|---|---|
| SPI读回全是0xFF | CS没拉低、RESET处于复位态、SPI模式错误 | 检查CS/GPIO,确认复位脚已经释放,核对CPOL/CPHA |
| SPI读回全是0x00 | MOSI/MISO接反、芯片没供电、晶振没起振 | 检查接线、电源,用示波器看CLK和MOSI波形 |
| 第一次通信正常,掉电后不行 | 上电时序不够,芯片还没准备好 | 加长复位低电平时间,上电后延时至少100ms再通信 |
| 数据偶发错误 | SPI速率过高、传输被打断、总线干扰 | 降速到500kHz,读取期间关中断或用DMA,缩短信号线 |
通信类问题多半是时序细节,用示波器抓一下SCK、CS、MISO波形,基本能定位到具体环节。
5.2 数据异常速查
能量不走、读数跳变、功率为负,这些是最常见的业务层问题。读数全是0,先看电压电流通道有没有接入信号、通道使能有没有开;比值关系固定不对,就是增益系数没配置对;读数随机跳动,重点检查电源纹波和采样滤波。功率为负,大概率是电流互感器次级两根线接反了,交换一下就行,不用怀疑芯片。
电能累计不走,要检查芯片的电能累计功能有没有开启,以及校表常数是否设置正确。很多情况下电能寄存器在累加,但因为系数配置不对,显示出来变化非常小,看起来像“没走”。
5.3 精度相关的疑难杂症
如果按标准流程校完表,高功率因数下精度合格,但低功率因数下超标,优先怀疑相位校准没做透。相位补偿寄存器通常要在0.5L和0.5C两个方向分别测试,取折中值。另外环境温度变化大的场景,可以考虑利用HT7038内置的温度传感器做温漂补偿,对精度要求很高的产品这步不能省。
6. 应用扩展与量产注意
6.1 数据上云与微信小程序展示
本地采集做完了,下一步通常就是远程监控。F103C8T6可以把计量数据打包成Modbus RTU,通过串口发给ESP8266/ESP32这类WiFi模块,再转发到云平台。微信小程序端展示三相电压、电流、功率、电量历史曲线,是比较常见的产品形态。
小程序端我建议走HTTP或者MQTT over WebSocket接后端云服务器,MCU上报周期做成可配置,一般5到60秒一次,避免流量消耗过大。注意MCU侧要处理断线重连和数据缓存,WiFi模块掉电重启后,主控要能自动恢复通信。
6.2 和FreeRTOS、LVGL怎么配合
如果产品需要本地显示屏和操作系统,工程上可以建立三个任务:计量采集任务(每100ms~1s读一次HT703x)、显示刷新任务(每500ms刷新LVGL界面)、通信上报任务(处理Modbus或网络数据)。SPI总线用互斥锁保护,任何时刻只能有一个任务操作计量芯片。
需要提醒的是,F103C8T6的20KB RAM跑FreeRTOS加LVGL确实紧张。LVGL的帧缓冲按最小尺寸分配,或者不启用多缓冲,把内存留给系统调度。真做复杂界面,建议换F103RCT6,成本差异不大,开发体验完全两个档次。
6.3 校准参数存储与固件加密
校准系数是产品出厂前的重要数据,必须掉电保存。可以存到外部EEPROM(比如AT24C02),也可以写到MCU内部Flash末尾扇区,上电时读取并做校验。校准参数丢失会导致批量产品误差超标,这里要花心思。另外开启STM32的读保护功能可以防止固件被读出来,量产阶段建议开启。
不过要提醒一点,开启读保护后,用ST-Link做后续调试可能不方便,需要先做全片擦除才能重新烧写。所以固件调试阶段先别急着加读保护,等产品稳定量产后再统一加上。
踩了几次坑总结下来,这种“主控+专用计量芯片”的组合方案,真正决定项目成败的往往不是芯片本身,而是通信时序、校表流程和电源布线这些容易被轻视的细节。我第一次打板时,SPI速率直接配到2MHz,读数偶尔跳变,查了一整天硬件,最后才发现是定时器中断打断了SPI传输,导致寄存器读到一半的数据“错位”。后来把SPI降速、加了临界区保护,问题立刻消失。电能计量项目没有太多玄学,严格按照手册来,一步一步验证,基本都能稳定跑起来。希望这篇梳理能帮你把从硬件设计到校准量产的完整链路走通。
本文还有配套的精品资源,点击获取