简介:提供一套基于STM32的ATT7022电能计量芯片的完整驱动源码,面向需要采集电压、电流、有功功率、功率因数等电参数的嵌入式开发者,重点解决驱动移植与计量精度校正两大常见难题。压缩包内共2个文件,包含1个C源文件和1个头文件,总大小仅5KB,结构十分紧凑,便于直接加入现有工程使用。代码严格参考官方手册编写,除常规计量参数读取外,还实现了电压电流有效值计算、功率与相位角校正流程,并加入温度系数补偿以减小环境温度变化导致的测量偏移;从底层寄存器读写到上层计量算法均有完整覆盖,每个函数均配详细中文注释,说明参数含义、寄存器配置和计算逻辑,对新手理解ATT7022工作机制非常有帮助。该驱动已在实际项目中验证可用,可直接作为产品开发参考;文件虽少但分工明确,C源码与头文件配合便于移植和二次开发。目前已有684人学习下载,适合正在调试ATT7022芯片或需要快速搭建电能监测功能的开发者。
1. 做三相计量绕不开ATT7022E:这块芯片把采样和计算都替你做了
做三相电表、充电桩计量、电力监控终端的时候,很多人第一反应是自己上互感器、运放和ADC做采样,再在固件里写FFT、算有功无功。ATT7022E这类三相电能计量芯片把这条路直接砍掉:芯片内部完成电压电流采样、有效值计算、有功/无功/视在功率和电能的累加,MCU 只通过 SPI 把结果读回来。对用 C/C++ 写驱动的嵌入式工程师来说,这是一套典型的“驱动全”工作——硬件初始化、SPI读写、寄存器解析、校表流程、数据可靠性处理,全都能在芯片数据手册的约束下自己实现。下面按我调 ATT7022E 的落地顺序,先讲时序和寄存器,再给整套可复用的 C/C++ 驱动骨架,最后把最容易翻车的地方摊开讲。
2. ATT7022E最小系统与SPI读写:先把寄存器读通再谈精度
2.1 最小硬件系统:复位、晶振、SPI引脚和计量通道
ATT7022E的硬件不算复杂,但也不是随便拉几根线就能出数。芯片的计量输入是差分结构,每一相电压通道和电流通道都是独立的,电压通道要配电阻分压网络,电流通道接电流互感器的次级。这里先强调一个原则:分压电阻和采样电阻的精度直接影响整机精度,芯片内部的增益校准只能在你硬件基准正确的前提下做微调。用1%的电阻做分压,校表后还能把误差收回来;用5%的电阻,校表修正范围经常不够覆盖。
最小系统上,我一般按下面这张表把线位确认完再上电:
| 功能 | 引脚 | 连接与注意事项 |
|---|---|---|
| 电源 | AVCC/DVCC | 模拟与数字电源分开走线,各自就近放0.1uF+10uF去耦 |
| 复位 | RESET | 低有效,上电先拉低10ms再释放,等待芯片启动 |
| SPI | CS/SCLK/SDI/SDO | 从机模式,SCLK由MCU提供,线长超过10cm要降速率 |
| 时钟 | XIN/XOUT | 按手册指定频率接晶振,不在手册范围会直接影响计量精度 |
| 电压采样 | 每相电压通道 | 差分输入,配合电阻分压网络 |
| 电流采样 | 每相电流通道 | 差分输入,互感器次级信号 |
复位脚很多人接到MCU的一个GPIO上就算完了,我建议串联一个1k电阻再进芯片,并且在靠近芯片引脚处放一个100nF电容到地,降低上电瞬间的毛刺误复位。ATT7022E上电后需要一段时间让内部的参考电压源起来,我在驱动里复位流程是:拉低复位脚保持10ms,拉高,再延时至少200ms才开始操作SPI。这个延时宁可给足,也别省。数据手册给的典型值是几十毫秒,实际产品里电源纹波大的时候按手册值容易读回乱码,我是因为这个问题翻过一次车才把延时放宽的。
晶振频率必须按手册选,不要图便宜换一个标称频率接近的,计量芯片的时基就是它,频率偏一点点,电能累积误差就会被时间放大。选晶振时负载电容也要按手册,焊上去后用示波器确认起振,再进校表。
2.2 SPI读写时序与命令字:CS、字节序、位宽怎么对
ATT7022E的SPI是标准的从机接口,但有两个地方必须先看手册再写代码:命令字的比特定义,和不同寄存器读取时的字节数。先说不踩坑的通用做法:
- 片选CS在整个读写帧内保持低,帧结束拉高,不要在字节间隙抖动。
- 数据线电平变化在SCLK的哪个边沿被采样,这个要和手册时序图对死,SPI Mode不是猜出来的。
- 先发命令字,再按寄存器位宽读或写数据字节,先发高位字节。
命令字的构造,常见是最高位作为读写标志,其余位是寄存器索引。我习惯把读和写分别定义成宏,这样万一换了手册版本只需要改一个地方:
#define ATT_READ_CMD(addr) (0x80U | ((addr) & 0x7FU)) #define ATT_WRITE_CMD(addr) (0x00U | ((addr) & 0x7FU))这两行的含义是:bit7置1代表读,写时bit7为0,低7位是寄存器地址。不同手册版本对这几位定义可能有差异,移植时对照时序图确认,不要想当然。实际读一个24位计量寄存器的时序就是用CS包住一次完整的收发:先发读命令字,然后连发三个0x00,同时把芯片回送的三个字节存下来。低位寄存器(比如16位校表类)就收两个字节,电能类的累加寄存器如果位宽超过32位,就分帧读取再自己拼起来。每帧之间CS必须释放一次,让芯片把内部的数据总线准备好,连续拉低CS只会读到上一次的旧数据。
下面这段是我在STM32 HAL上的SPI收发底层,平台相关的只有这个文件,上层别碰硬件:
/* att7022e_platform.c */ #include "att7022e_platform.h" #include "spi.h" #include "gpio.h" static void att7022e_cs(uint8_t level) { HAL_GPIO_WritePin(ATT_CS_GPIO_Port, ATT_CS_Pin, level ? GPIO_PIN_SET : GPIO_PIN_RESET); } static uint8_t att7022e_xfer(uint8_t byte) { uint8_t rx = 0; /* 这里务必顺时针为芯片手册要求的SPI模式 */ HAL_SPI_TransmitReceive(&ATT_SPI, &byte, &rx, 1, 10); return rx; } void att7022e_read_bytes(uint8_t cmd, uint8_t *buf, uint8_t len) { att7022e_cs(0); att7022e_xfer(cmd); for (uint8_t i = 0; i < len; i++) { buf[i] = att7022e_xfer(0x00); } att7022e_cs(1); }说明:att7022e_xfer 里的 HAL_SPI_TransmitReceive 同时收发,读的时候主机发0x00只是为了提供SCLK时钟。CS在整个读帧内保持低,len取决于寄存器位宽。SPI句柄 ATT_SPI 在 spi.c 里配置为8位数据位,速率先按1MHz跑通再说,后面再往上提。先按1MHz的原因很实际:线长、布局、MCU引脚翻转速率都会影响时序,跑通后可以拿示波器看波形再提,别一上来就拉满手册标称值。
3. ATT7022E寄存器地图与数据换算:电压、电流、功率、电能怎么从定点转浮点
3.1 寄存器功能分类:先把速查表整理好再写代码
ATT7022E的寄存器不是密密麻麻一个表,而是按功能分成四块:状态寄存器告诉你数据有没有更新、有没有缺相、有没有过压欠压;计量寄存器给出当前电压电流有效值、功率、功率因数、频率;电能寄存器是可累加的累计量;校表寄存器用来调增益、相位和偏置。
| 寄存器类别 | 能读到什么 | 位宽参考 | 读取注意 |
|---|---|---|---|
| 数据更新/状态 | 更新标志、缺相、过压欠压 | 多为16位 | 先读状态再读数据 |
| 电压/电流有效值 | 各相电压电流RMS | 多为24位 | 有符号/无符号按手册 |
| 功率/因数/频率 | 有功、无功、视在功率、PF、Hz | 多为24位 | 功率是有符号数 |
| 电能 | 正向/反向有功、无功累加值 | 32位或更大 | 注意溢出和无符号处理 |
| 校表参数 | 增益、相位、offset、HFConst | 16/24位 | 必须先开校表使能再写 |
对驱动来说,第一步不是急着写代码,而是把这四类里自己用得着的寄存器地址和位宽整理成一张速查表。芯片手册在这一点上给得比较含蓄,寄存器地址表分布在不同章节,我一般做驱动头文件时就把它定义好:
/* att7022e_regs.h */ #define ATT_REG_STATUS 0x01 /* 状态/更新标志,地址以手册为准 */ #define ATT_REG_UA_RMS 0x10 /* A相电压有效值,地址以手册为准 */ #define ATT_REG_IA_RMS 0x11 /* A相电流有效值,地址以手册为准 */ #define ATT_REG_PA 0x12 /* A相有功功率,地址以手册为准 */以上地址值是我组织头文件的习惯写法,真实地址一定要以你手上手册的寄存器表为准。手册版本升级后地址可能微调,凭记忆写地址是驱动移植最常见的翻车原因。全套驱动不是抄一段读函数就完事,寄存器地图才是地基。
读数据还有个通用原则:先看状态寄存器的数据更新标志,标志置位时再读一批计量数据。有些驱动图快,每100ms无脑把电压电流功率全读一遍,读到的可能是这一帧和上一帧混着的。我的做法是读两遍做一致性校验,第一次读完后,第二次再读三个关键寄存器(比如UA、IA、PA),如果两次结果完全一致才采用;不一致就丢弃这一帧。这在干扰较强的工业现场很有效。
3.2 从寄存器原始值到物理量:满量程、符号扩展与电能回绕
芯片返回的是定点数,不是浮点物理量。换算关系通常由满量程决定:当输入电压通道达到你设计的满量程时,寄存器输出一个对应的满量程编码。如果手册给出的编码和你的满量程物理值对得上,系数就出来了。
举个例子,假设电压通道满量程对应430V,寄存器满量程编码32768(16位),那么:
float att7022e_calc_voltage(uint16_t raw) { /* 430.0f是硬件分压网络决定的满量程电压 */ return (float)(int16_t)raw * 430.0f / 32768.0f; }但ATT7022E的有效值寄存器很多是24位,同样原理,把32768换成对应的满量程编码即可。这里的要点:满量程编码是芯片层面的一个常数,而430V是你的分压电阻和芯片内部基准共同决定的,换一批电阻就要重新标定一次。把两个数分开写成宏,不要混在一个魔法数字里:
#define ATT_FS_CODE_U 32768 /* 电压通道满量程编码,查手册 */ #define ATT_FS_VOLT_U 430.0f /* 电压通道满量程物理值,由分压网络决定 */功率和电能也一样。功率寄存器是有符号数,直接用uint32_t拼接出来再当int32_t用,就会把负功率变成很大的正数,翻车概率极高。我一般把“读有符号24位”封装成一个独立函数:
static int32_t att7022e_read_s24(uint8_t addr) { uint8_t buf[3]; uint32_t u; att7022e_read_bytes(ATT_READ_CMD(addr), buf, 3); u = ((uint32_t)buf[0] << 16) | ((uint32_t)buf[1] << 8) | buf[2]; /* 24位有符号数做符号扩展 */ if (u & 0x800000U) { u |= 0xFF000000U; } return (int32_t)u; }说明:读三个字节后按大端拼起来,先当无符号数看最高位,如果是1就补上高8位全1,得到正确的int32_t。这个函数在后续功率、无功、相角读取里都会用到。如果寄存器实际是16位有符号,就把判断位改成0x8000,扩展改成0xFFFF0000。别小看这四行,不写符号扩展,负功率读数会让你白调一整天校表。
电能寄存器比较特殊,它是累加值,持续在涨,不能简单按某一个瞬时系数换算。它和校表参数里的高频脉冲常数绑定:芯片每累积一个脉冲对应的能量,寄存器就加一个步进。所以驱动里电能部分要读成一个64位变量,自行处理32位回绕。比如寄存器是32位无符号,读到从0xFFFFFFFF再变成0x00000000,驱动要判断这一次是否比上一次小且小于一个重置阈值,然后给高32位加1。这个逻辑后面展开,这里先记住结论:电能绝不能用int32_t直接存。
整个换算的最后一公里是校表。出厂芯片的增益是典型值,不是出厂校准值,每一块板子因为电阻精度、互感器误差、焊接差异,都会和标准表差一点。所以驱动的价值不只是把数读出来,还要能改校表寄存器。
4. 用C/C++写一套ATT7022E完整驱动:平台层、协议层、应用层与校表流程
4.1 驱动分层:平台层只留三个口子
写驱动最怕把硬件操作和业务逻辑揉在一起,后期换MCU平台要重写。我习惯分三层:平台层(platform)、协议层(寄存器字节流)、应用层(电压电流功率电能的物理量API)。平台层只暴露三个接口:初始化、CS控制、单字节收发。上层所有代码都不直接碰HAL函数。
/* att7022e_platform.h */ void att7022e_platform_init(void); void att7022e_read_bytes(uint8_t cmd, uint8_t *buf, uint8_t len); void att7022e_write_bytes(uint8_t cmd, const uint8_t *buf, uint8_t len);write_bytes的实现和read对称,只是把数据字节按顺序发出去:
void att7022e_write_bytes(uint8_t cmd, const uint8_t *buf, uint8_t len) { att7022e_cs(0); att7022e_xfer(cmd); for (uint8_t i = 0; i < len; i++) { att7022e_xfer(buf[i]); } att7022e_cs(1); }说明:写操作不需要读,但SPI的MISO线上芯片可能有回显数据,发数据之前先清空接收缓冲,避免脏数据留在里面。协议层不关心cmd的bit定义,那是regs头文件或platform层的事。这一层用C++封装时,可以把三个函数放进一个类里,但底层收发逻辑保持不变,方便在Windows/Linux模拟器上做上位机调试。
4.2 协议层:通用读函数、有符号扩展与数据撕裂防护
协议层主要做两件事:把寄存器地址换算成命令字;把字节流拼成整型并处理符号。上一节已经给了read_s24,这里补一个16位版本和一个电能用的32位版本:
static uint16_t att7022e_read_u16(uint8_t addr) { uint8_t buf[2]; att7022e_read_bytes(ATT_READ_CMD(addr), buf, 2); return ((uint16_t)buf[0] << 8) | buf[1]; } static uint32_t att7022e_read_u32(uint8_t addr) { uint8_t buf[4]; att7022e_read_bytes(ATT_READ_CMD(addr), buf, 4); return ((uint32_t)buf[0] << 24) | ((uint32_t)buf[1] << 16) | ((uint32_t)buf[2] << 8) | buf[3]; }说明:这里假设寄存器位宽分别是16位、32位,和read_s24的24位形成一套。实际调用时,要知道哪个寄存器是几位,查询手册寄存器表。不要把u16的值直接给s24函数读,数据会错位到完全不可信。建议在regs.h里给寄存器宏加上位宽标记,比如ATT_REG_UA_RMS_24,这样调用时不会拿错。
电能读取要单独处理。如果芯片的电能寄存器位宽是32位,读取后要做回绕补偿;如果是更宽的寄存器,一次读可能拆成两帧,此时要在CS释放后立刻拼起来,防止读取过程中电能寄存器进位导致高低字节错位。我的做法是连续读两次:
uint32_t raw1 = att7022e_read_u32(ATT_REG_EP_IMPORT); uint32_t raw2 = att7022e_read_u32(ATT_REG_EP_IMPORT); if (raw1 != raw2) return -1; /* 读取过程中发生了更新,重试 */这属于“数据撕裂”防护。计量寄存器随时在更新,读一帧的中间如果恰好芯片刷新,拿到的高低字节可能来自两个不同的时刻。两帧校验不能完全消除这个问题,但能把异常帧挡在物理量计算之前。
4.3 应用层API:一次读取输出全部计量结果
应用层的价值是让上层业务(显示、上报、存储)不感知寄存器。我一般会定义这样一个结构体:
typedef struct { float ua, ub, uc; /* 相电压 V */ float ia, ib, ic; /* 相电流 A */ float pa, pb, pc; /* 有功功率 W */ float p_total; /* 总有功功率 W */ float freq; /* 频率 Hz */ uint64_t ep_import; /* 正向有功电能 kWh */ uint64_t ep_export; /* 反向有功电能 kWh */ } att7022e_data_t;然后一个函数把一次采样周期需要的数据全读出来:
int att7022e_read_all(att7022e_data_t *d) { int32_t ua = att7022e_read_s24(ATT_REG_UA_RMS); int32_t ia = att7022e_read_s24(ATT_REG_IA_RMS); int32_t pa = att7022e_read_s24(ATT_REG_PA); /* 三相同理,实际代码依次读ub/uc/ib/ic/pb/pc */ d->ua = (float)ua * K_U; /* K_U是标定系数 */ d->ia = (float)ia * K_I; d->pa = (float)pa * K_P; /* 频率等量按同一方式填充 */ return 0; }说明:K_U、K_I、K_P就是上一章说的满量程换算系数,在校表流程里会被修正。注意总有功功率不要简单把三个单相功率直接相加了事,除非你的应用只在乎三相平衡工况。更可靠的做法是读芯片自带的总功率通道,或者按三相四线/三相三线制式分别处理。驱动里提前预留一个p_total字段,但来源要做成可配置的。
校表参数写入和电能回绕扩展的应用层封装,我在量产版本里是单独文件,避免和读数API混在一起。下面讲校表流程,这是整个驱动里最需要“按顺序来”的部分。
4.4 校表流程落地:使能、写参、关闭的固定顺序
校表是ATT7022E驱动里最容易写错的一个环节。芯片的校表寄存器并不是随时可以写的,必须先写校表使能寄存器,把芯片切入校准模式,然后才能在对应地址写入增益、相位、偏置等参数,全部写完后关闭使能。顺序错了,参数不会生效,而且没有任何错误标志,就是一个黑匣子。
void att7022e_cal_enable(void) { uint8_t v = 0x01; att7022e_write_bytes(ATT_WRITE_CMD(ATT_REG_CAL_EN), &v, 1); } void att7022e_cal_disable(void) { uint8_t v = 0x00; att7022e_write_bytes(ATT_WRITE_CMD(ATT_REG_CAL_EN), &v, 1); } void att7022e_cal_write(int32_t value, uint8_t addr, uint8_t width) { uint8_t buf[4]; /* 按大端放进buf,只取width对应的字节数 */ buf[0] = (uint8_t)((uint32_t)value >> 16); buf[1] = (uint8_t)((uint32_t)value >> 8); buf[2] = (uint8_t)((uint32_t)value); att7022e_write_bytes(ATT_WRITE_CMD(addr), buf, width); }说明:att7022e_cal_write里value是有符号的,转成无符号后取低24位,按大端顺序发字节。width传3就是24位,传2就只发两个字节。校表模式下写完参数后,最好再把参数读回来验证一遍,因为这类芯片的寄存器写入有时会因为时序太紧丢字。验证通过后最后关闭校表使能。整个操作里CS每帧都要正常释放,不要为了省时间把两个寄存器写入写进同一帧,芯片内部对校表寄存器的更新需要时间。
标准校表流程我按这个顺序走:
- 给被测板加额定电压、额定电流,功率因数1.0,等待读数趋势收敛。
- 读电压、电流寄存器原始值,和标准表读数比对,计算出增益修正量,写入电压增益、电流增益寄存器。
- 功率因数调到0.5L,校准相位补偿寄存器,让有功功率误差进入要求的范围,然后再回到1.0复验。
- 输入为零(断开电流输入),校准偏置寄存器,消除零点偏移。
- 重复步骤2-4至少三次,直到误差不再变化。
- 关闭校表使能,保存参数到外部EEPROM,上电时驱动负责回写芯片。
注意:校表寄存器值只存在于芯片RAM,掉电会丢,所以驱动里一定要有“上电从EEPROM/NVM回写校表参数”的接口,否则每块板子上电都要重新校表。这个细节在量产时特别关键。
5. ATT7022E驱动避坑实录:上电读零、校表不生效、电能跳变的5个典型问题
5.1 上电后所有寄存器读回0x000000,芯片看起来是“死”的
现象:复位流程走完,读任何寄存器都是全零,MISO波形要么是一条平线,要么全是0xFF。
原因:最常见的两个,一是SPI模式(CPOL/CPHA)和芯片时序图不一致,二是复位后启动时间给太短。还有一个容易被忽略的是CS如果接到了某个默认拉低的引脚上,芯片从开机起就一直被选中,内部状态机根本没起来。
解决:先用示波器看CS、SCLK、MISO三根线在第一次读操作时的波形,确认CS确实是一帧一帧地拉低。把SPI模式对着手册的时序图逐边沿核对,不要靠猜。把复位后的延时提到200ms级别再试。如果MISO上有波形但数据错位,优先检查字节序和命令字位定义。我曾在这上面花过两天,后来发现是SCLK极性配反,读回来的数据整体右移了一位。
5.2 校表寄存器写了没反应,读数纹丝不动
现象:写完增益寄存器,用读命令回读,值还是原来的。
原因:没开校表使能;或者使能寄存器写成功后立刻写参数,但参数地址写错;还有可能是写入的数据长度和寄存器位宽不匹配,高字节被吞掉。
解决:先读回校表使能寄存器,确认已经在校准模式。写参数时用4.4节那个宽度参数,确保24位数据发了3字节而不是2字节。最后在读回验证之前,先做一次完整的关闭使能再读,有些芯片在使能状态下读回的是缓存值。校表不生效不是玄学,绝大多数是命令字或宽度的低级错误。
5.3 电压电流偶发跳变,误差按帧出现
现象:99%的时间数据正常,偶尔某一次的电压或电流值明显偏大偏小,重读一次又正常。
原因:一帧SPI读操作被打断,比如中断服务函数里恰好也用了同一个SPI外设;或者CS由GPIO模拟时,SCLK第一个边沿没等CS电平落地;还有可能是电压/电流差分输入线的共模干扰在强电操作瞬间窜进了芯片。
解决:把ATT7022E的SPI读写做成临界区,读一帧期间关中断;SPI速率先降到1MHz;软件层加一致性校验,连续读两帧,数据相同才使用。强电干扰导致的跳变,主要靠PCB布局——电流互感器的次级线不要和电源线平行走,电压采样电阻的差分走线要等长且靠近芯片。别指望固件滤波能把硬件问题完全兜住。
5.4 电能寄存器不增反减,或者累计误差越来越大
现象:正向有功电能应该只增不减,但驱动读到的值偶尔跳回一个很小的数,然后又涨上来。
原因:一是32位寄存器自然溢出回绕,高32位没做扩展;二是电能寄存器正值和负值切换时,符号处理错乱;三是驱动里用int32_t存,溢出变成了负数。
解决:电能统一用uint64_t保存,每次读取后和上次值比较,若本次值小于上次值且差值超过一个阈值(比如0x80000000),判定发生了一次回绕,给高32位加1。同时把正反向电能分通道记录,不要混在一个变量里减来减去。计量芯片的电能寄存器是补码还是无符号,手册写得很清楚,读代码之前先把这个确认了。
5.5 校表后在批量整机上误差超差,单板校好也没用
现象:单板校表后精度很好,装到整机上误差变大,且误差值随批次有规律地偏。
原因:互感器批次差异和采样电阻批次差异没有进入校表流程的反馈闭环。只校了芯片增益,没有校整机系数。
解决:把校表流程里读出来的增益修正量、整机电压电流系数一起写到EEPROM,批量生产时每块板用自己的参数。换一批互感器时,先抽检10%的板子重新算一次系数,不要默认上一批的参数能继续用。这个坑在量产线上最常见,也是“驱动全”和“驱动能跑”的分水岭:驱动里必须有参数持久化设计。
6. 把ATT7022E驱动升级成产线可用的自动校表模块:一个脚本脚本解决批量标定
既然驱动里的校表流程是固定顺序,量产时就不应该人工拿着标准表读数去算。我后来做产线校表时,MCU驱动留一个校准模式串口命令,PC端脚本读标准表数值和驱动上报的原始寄存器值,算出修正系数,再下发回写。整个过程就是让驱动把下面这段交互跑通:
- UART命令“cal start”:驱动开校表使能,开始输出原始电压电流功率寄存器值。
- 脚本每500ms收集一次,和标准源读数做比例对比。
- 计算增益修正量后,通过UART下发“cal set addr value”。
- 驱动收到后执行写寄存器,再回读验证。
- 全部完成后,“cal save”把参数存入EEPROM。
脚本核心只有几十行,关键思路是“用标准源读数作基准,用比例修正而不是绝对修正”:
if std_value > 0: correction = raw_value / std_valuecorrection保存到驱动软件系数里,或转换成芯片增益寄存器的格式写回,二选一。用比例修正能同时覆盖分压电阻偏差和芯片增益偏差,比只调一个增益寄存器更可靠。验证技巧:校完一台后,把标准源从额定值的80%扫到120%,电压电流功率各记录5个点,误差曲线如果是一条接近水平的线,说明校准参数正确;如果是倾斜的线,说明电压通道还有线性度问题没有暴露,得回去查硬件和晶振。
我自己最开始做ATT7022E驱动时,也是先跑通读数、再补校表,后来在产线被电能累计跳变坑了一轮,才把“读两次校验+64位电能+EEPROM回写”这套补全。现在再接手类似电能计量芯片,我都会先画一版寄存器速查表和校表时序图,再动手写代码。批量产前拿标准源做一遍24小时误差统计,比任何调参都有效。这条路走通之后,你会发现三相计量从硬件到固件都没有黑匣子,剩下的只是耐心。希望帮到你。
本文还有配套的精品资源,点击获取