尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

STM32F103驱动INA219实现高边电流检测与校准实战

STM32F103驱动INA219实现高边电流检测与校准实战 简介本资源是面向全国大学生电子设计竞赛电赛参赛者与嵌入式初学者的STM32电流检测实战项目聚焦高精度电流/电压监测这一典型赛题需求。项目以STM32F103为主控通过I²C总线驱动INA219传感器实现0–36V电压与0–3.2A电流的实时采集并创新引入数字FIR滤波算法抑制电磁干扰与采样噪声显著提升测量稳定性与精度适用于电源监控、电池管理系统等实际场景。压缩包含221个文件总计6.34MB涵盖核心源码38个.c、40个.h、编译中间文件39个.o、39个.d、工程配置uvprojx、uvoptx、dbgconf、调试输出axf、hex、map、lst及关键外设驱动IIC_SCCB.c、stm32f10x_i2c.c、stm32f10x_tim.c等目录结构完整便于理解工程构建逻辑与模块分工。已有365人学习下载提供可直接编译运行的Keil MDK工程含滤波算法实现、I²C通信封装及数据处理全流程代码是掌握传感器融合与嵌入式信号处理的优质实践范例。 电赛前夜在实验室调板子万用表电流档量程不够还得把表笔串进电路里一个不小心就烧了保险丝。后来换成INA219之后情况一下子舒服了它串在电源正端I2C直接把电流、电压、功率读回来单片机屏幕上实时刷新再也不用对着万用表抠数值。这篇博文主要围绕STM32F103 INA219的组合把我从硬件选型、寄存器配置、软件驱动到校准误区的完整过程写清楚适合正在备赛电赛、或者想给嵌入式项目加一路电流监测的朋友参考。文章不会只贴代码更多的是告诉你每一步为什么这么做、以及哪些坑我已经替你踩过了。1. 为什么在电赛里要专门用一颗INA219芯片测电流1.1 高边检测与低边检测的本质区别很多人在采样电流时第一反应是“在负载和GND之间串一个小电阻然后测电阻两端的电压”。这就是典型的低边电流检测。低边方案在原理上完全没问题但它在实际系统中会引入很糟糕的副作用采样电阻放在地端会让负载的“地”不再真正是0V而是一个被抬高了几十毫伏甚至上百毫伏的参考点。在纯模拟电路里可能无所谓但STM32这类单片机周围往往还有传感器、通信芯片、OLED显示模块它们之间是共地的地电位一旦有偏移I2C通信可能直接乱掉ADC采集也会出现莫名其妙的跳字。INA219走的是高边检测路线采样电阻放在电源正端和负载之间负载的GND仍然和系统地直接相连不会抬高任何模块的地电位。更重要的是高边检测能实时监控到负载到底从电源抽走了多大电流如果电流超出阈值可以直接在软件里关断输出做短路保护或者过流保护。这类保护动作在低边方案里也能做但反应速度和安全性往往不如高边方案。还有一个细节值得说INA219内部不是简单地把采到的差分电压送进一个普通ADC而是经过了可编程增益放大器PGA范围可以从±40mV一路放到±320mV。这意味着小电流测量也能有比较可观的精度不像有些方案小电流时直接被噪声淹没。用一句话总结低边采样是“简单但容易惹事”高边采样是“稍微多花一点心思但系统的地更干净安全性也更高”。电赛作品通常是一个多模块协作的系统地线不干净后面会有一连串连锁问题所以我更推荐高边方案。1.2 采样电阻选型与量程设定市面上常见的GY-INA219模块板载采样电阻通常是一个0.1Ω的合金电阻。0.1Ω这个值不高不低当电流是2A时它上面的压降是0.2V功耗是0.4W。对于大多数电赛题目用的1A~2A电流范围这个阻值是比较合理的。INA219内部电流寄存器是16位有符号数最高位为符号位实际有效位是15位。如果想让满量程电流对应2A附近电流LSB每位代表的安培数通常是2A / 32768 ≈ 61.035uA/LSB但手册和官方库都倾向于选一个“看起来整齐”的数值比如100uA/LSB或者1mA/LSB然后倒推校准寄存器。这里有一点一定要注意如果你把电流量程设置成了2A但实际负载电流瞬时超过了2A读数并不会像普通ADC那样自然饱和而是有可能变成一个看起来完全没规律的负值或者乱跳的值。因为内部寄存器是带符号的超量程之后数据直接溢出。选采样电阻时不要只看阻值还要看功率。0.1Ω的电阻在2A电流下就有0.4W功耗如果你的负载峰值到3A那就要按PI²R算一下功率需求大概是0.9W。电赛现场经常用的是0805贴片电阻额定功率大概在0.125W用在2A场景下完全不够模块上原装的2512封装合金电阻才是比较稳妥的方案。如果你是自己画板子建议直接用2512封装的0.1Ω/1%电阻温漂尽量选低一点。1.3 与“运放ADC”方案的对比为什么要选专用IC用运放搭差分放大电路再去测电流很多教材里都有讲核心是使用仪表放大器或者差分放大器先把采样电阻两侧的小电压放大再送到STM32的内部ADC。这个方案的最大的问题在于STM32F103内部ADC是12位的参考电压是3.3V折算下来1个LSB大约是0.8mV。如果你用的是0.1Ω采样电阻1A电流产生的压降是100mV换算成ADC的LSB大约126个码值看起来够用但当电流只有50mA时对应的压降只有5mVADC读数只有6个LSB左右稍微有一点噪声读出来的电流就是跳来跳去的。而且运放方案还要面对另一堆麻烦用什么型号的运放、失调电压怎么调、共模电压范围够不够、PCB走线要不要包地、要不要加滤波电容。这些在电赛现场都是时间黑洞。INA219把可编程放大器、12位ADC、I2C数字接口、报警比较器全部集成到一个芯片里外部只需要一个采样电阻和两个去耦电容。它测量的是差分电压不是绝对电压所以即使采样电阻两端相对GND的电位都在某个体外范围内也能准确测出差值。对于电赛这种时间紧、变量多的场景拿一块专用IC替代运放手工电路绝对是省时间、降风险的做法。2. 硬件搭建从最小系统到INA219模块的连线细节2.1 STM32F103最小系统与I2C引脚分配先把STM32F103最小系统这块说清楚。市面上的“STM32F103最小系统板”通常已经集成了8MHz晶振、复位电路、BOOT选择、AMS1117-3.3稳压芯片、Type-C或MicroUSB接口以及若干个排针引出所有IO。如果你是自己从零画一块最小系统板核心的几个要素8MHz晶振配合两个20pF电容单片机内部PLL倍频到72MHzVDD每个引脚加上100nF去耦电容VDDA引脚单独接一个1uF电容保证ADC等的模拟电源干净BOOT0下拉到GND让系统从Flash启动NRST引脚的复位电路通常是一个10k上拉电阻加一个按键再加一个100nF电容。对于INA219的I2C通信最简单、最常用的引脚组合是PB6I2C1_SCL和PB7I2C1_SDA。这两个引脚在STM32F103上默认复用为I2C1硬件上还需要外接两个上拉电阻。STM32内部没有上拉使能或者说内部上拉的阻值不足以满足I2C通信的要求所以必须在外部接两个上拉电阻常见阻值100kHz标准模式下用4.7k400kHz快速模式下用2.2k~4.7k。提示电赛现场如果发现I2C通信偶发失败优先检查SDA和SCL两条线上的上拉电阻是否接触良好。尤其是使用杜邦线连接时插拔几次后线阻会变化这是我实际遇到过的。2.2 INA219模块上的A0/A1地址配置与电源接入INA219有两个地址引脚A0和A1通过它们的电平组合决定芯片的I2C地址。默认模块上A0和A1都接地此时地址是0x40。如果你需要同时接两个INA219模块比如一路测电机电流、一路测电池电压就必须把其中一片的A0或A1接到VCC让它的地址变成0x41或者0x42不能两片都用默认地址。关于模块供电市面上大多数INA219模块上带了一个稳压芯片通常是小型的LDO所以VCC可以直接接5V模块会对内部逻辑电路做稳压同时I2C引脚的电平兼容性一般也能和3.3V的单片机互通。不过稳妥起见我还是建议VCC直接接3.3V逻辑电平完全一致少一层电平转换I2C的波形也更干净。接线是最容易出错的地方把每一个物理引脚对应关系写清楚INA219模块引脚接哪里说明VCCSTM32F103的3.3V模块电源也是I2C上拉电源GND系统地GND必须与STM32共地SDAPB7接I2C1的数据线SCLPB6接I2C1的时钟线VIN电源正极连接电源电流从这进VIN-负载正端连接负载电流从这出单独强调一下VIN和VIN-的接法。它俩不是供电引脚而是测量引脚。必须让负载电流真正流过VIN到VIN-之间的采样电阻INA219才能测到电流。如果把VIN和VIN-直接连到电源正极而不经过负载读到的永远是接近0的电流。2.3 电源去耦与采样走线布局如果是在面包板上做实验倒不用太纠结布局但如果是自己画PCB采样电阻的走线值得认真处理。采样电阻两端应该用“开尔文接法”从电阻本体两端各引出一根细走线直接送到INA219的VIN和VIN-引脚附近然后再用细线把这两个点引到芯片。这样做的目的是避免大电流走线上的压降被当作采样电压读到ADC里。PCB上大电流走线的铜箔虽然电阻很低但1A电流流过10cm长、0.5mm宽的走线压降可能就有几十毫伏这直接搞坏了测量精度。芯片的电源引脚旁边要放一个100nF电容优先靠近VCC和GND引脚放置。如果电路板上还有其他大功率器件电机驱动芯片、继电器等建议在INA219的电源输入端再加一个10uF的电解电容能吸收一部分母线电压的跌落和振铃。还有一点SDA和SCL线尽量远离电机的驱动线。电机的PWM驱动线上有大电流快速切换会产生很强的电磁干扰如果I2C线和它平行走线几厘米以上可能会导致通信错误。我自己做电机驱动板的时候I2C线都是和PWM线分两层走交叉时也尽量垂直这个细节能省去很多现场调试的麻烦。3. 读懂INA219的寄存器不踩时序的坑3.1 Configuration寄存器0x00每一个bit都要算清楚INA219操作的核心是先写配置寄存器再写校准寄存器然后不断读取电压、电流和功率寄存器。但很多人一上来就照抄例程的0x019F出了问题又不知道从哪改所以这里把Configuration寄存器的关键bit逐个拆开看。Configuration寄存器是一个16位寄存器各位的含义如下bit位名称作用bit15RST写1复位所有寄存器bit14保留必须写0bit13BNG总线电压量程0 → 16V1 → 32Vbit12PG1/PG0PGA增益00 → ±40mV01 → ±80mV10 → ±160mV11 → ±320mVbit11BADC总线ADC的分辨率和采样模式bit10SADC分流ADC的分辨率和采样模式bit9模式连续/触发、分流/总线/两者以常见的配置值0x019F为例二进制展开0000 0001 1001 1111其中bit13为0表示总线电压量程16Vbit12:11为“11”PGA选择±320mV也就是在0.1Ω采样电阻下的±3.2A电流量程bit10:7为“1001”表示总线ADC是12位分辨率加128次平均bit6:3为“1111”表示分流ADC同样12位加128次平均bit2:0为“111”表示连续测量分流电压和总线电压。这里的“128次平均”很关键相当于芯片内部做了数字滤波对电赛现场的工业噪声有很好的抑制效果。代价是数据更新速度变慢但INA219的采样本来就不是为了做高速电流环平均模式反而更实用。如果想改PGA增益需要注意PGA选±40mV时小电流分辨力更高但量程变小同时Calibration寄存器的值要重新算。不要以为配置值随便改一下就行改了PGA不改校准值读出来的电流会差好几倍。3.2 Calibration寄存器与电流LSB的关系校准寄存器0x05的值决定了电流寄存器每变化一个数字到底代表多大的电流。手册给出的公式是cal trunc(0.04096 / (current_LSB × R_shunt))其中current_LSB是你期望的每位电流分辨率单位是A/LSB。举个例子如果我期望每个LSB代表100uA采样电阻是0.1Ω那么0.04096 / (0.0001 × 0.1) 0.04096 / 0.00001 4096所以cal 4096。写入0x05寄存器后电流寄存器的原始值乘以0.0001A就是实际电流。这样算出来的好处是电流值可以直接通过移位或者整数运算再转到显示层不需要频繁使用浮点数。功率寄存器的换算稍微特殊一点功率寄存器0x03的原始值乘以20再乘以current_LSB才等于实际功率单位瓦特。也就是说在0.100mA/LSB的设置下功率寄存器的每个字代表2mW。曾经看到有人把功率寄存器直接乘current_LSB结果功率只有实际值的一半这就是没乘20导致的。注意如果PGA增益设置改变或者电流量程预期改变务必重新计算cal。这个寄存器一旦写错虽然通信一切正常但读出来的所有电流值、功率值都会系统性偏大或偏小属于最隐蔽的“貌似正常实则全错”问题。3.3 I2C读写注意事项INA219使用的I2C时序很简单先向从机设备地址如0x40发送要访问的寄存器指针然后再读或写数据。但有几个细节很容易被忽略读寄存器时地址字节是7位从机地址左移1位加上读写位。在HAL库中hdev.Address要填的是0x40的左移版也就是0x80可以直接填0x40然后在HAL_I2C_Mem_Read里传参不同写法要对照你使用的库定义千万别地址搞错否则一直返回超时。一次读取两个字节时高位在前、低位在后需要自行合并value (uint16_t)((buf[0] 8) | buf[1])。写配置寄存器时如果先写寄存器指针再写两个字节数据两段之间需要一点延时或者在HAL库中直接用HAL_I2C_Mem_Write接口这样一个函数就能完成不用手动管Start/Stop信号。关于STM32F103的硬件I2C这里专门提一句很多老工程师对F103的硬件I2C有心理阴影。在我使用HAL库的过程中只要初始化正确加上超时重试机制硬件I2C基本能稳定工作。但如果你的工程是标准库写的使用硬件I2C时偶尔会遇到总线忙死锁的情况如果你不想在这种问题上浪费电赛备赛时间最简单粗暴的方案是用两个普通GPIO软件模拟I2C时序。INA219是I2C从设备对时序要求不算苛刻软件模拟稳定可靠代码量也不大。这里用HAL库硬件I2C的方式继续讲但软件模拟代码作为备选也是好选择。4. 软件实现HAL库下用I2C驱动INA219的完整过程4.1 初始化流程复位、配置、校准三件事在开始写代码之前先看一下整体初始化顺序开启I2C1外设时钟配置PB6、PB7为复用开漏输出模式设置上拉电阻设置I2C时钟频率为100kHz使能I2C向寄存器0x00写入0x019F完成配置向寄存器0x05写入校准值4096可以读取一遍所有寄存器验证是否读到正常数据。这里提供一个完整的HAL库初始化函数框架#include stm32f1xx_hal.h I2C_HandleTypeDef hi2c1; void MX_I2C1_Init(void) { hi2c1.Instance I2C1; hi2c1.Init.ClockSpeed 100000; hi2c1.Init.DutyCycle I2C_DUTYCYCLE_2; hi2c1.Init.OwnAddress1 0; hi2c1.Init.AddressingMode I2C_ADDRESSINGMODE_7BIT; hi2c1.Init.DualAddressMode I2C_DUALADDRESS_DISABLE; hi2c1.Init.OwnAddress2 0; hi2c1.Init.GeneralCallMode I2C_GENERALCALL_DISABLE; hi2c1.Init.NoStretchMode I2C_NOSTRETCH_DISABLE; if (HAL_I2C_Init(hi2c1) ! HAL_OK) { Error_Handler(); } } #define INA219_ADDR 0x40 #define INA219_REG_CFG 0x00 #define INA219_REG_CAL 0x05 void INA219_Init(void) { uint8_t cfg_data[2]; uint8_t cal_data[2]; // 修正寄存器值 0x019F16V量程、PGA±320mV、12bit128平均、连续测量 cfg_data[0] 0x01; cfg_data[1] 0x9F; HAL_I2C_Mem_Write(hi2c1, INA219_ADDR 1, INA219_REG_CFG, I2C_MEMADD_SIZE_8BIT, cfg_data, 2, 100); // 校准值 4096对应100uA/LSB cal_data[0] 0x10; cal_data[1] 0x00; HAL_I2C_Mem_Write(hi2c1, INA219_ADDR 1, INA219_REG_CAL, I2C_MEMADD_SIZE_8BIT, cal_data, 2, 100); }4.2 封装读取函数电压、电流、功率一次读清初始化完成后读取数据就很简单了。唯一容易出错的地方是有符号数的处理。INA219的分流电压寄存器和电流寄存器都是有符号16位当电流反向流动时寄存器值会是负数对应的二进制是0xFFFF开头。如果直接按无符号十六进制转十进制会得到65535这种大数。正确的做法是判断最高位如果最高位为1则用原值减65536。我这里以电流为例int16_t INA219_ReadRaw(uint8_t reg) { uint8_t buf[2]; HAL_I2C_Mem_Read(hi2c1, INA219_ADDR 1, reg, I2C_MEMADD_SIZE_8BIT, buf, 2, 100); int16_t val (int16_t)((buf[0] 8) | buf[1]); return val; } float INA219_ReadBusVoltage(void) { // 总线电压寄存器 bit15:3 是有效位最低位代表4mV int16_t raw INA219_ReadRaw(0x02); return (float)(raw 3) * 0.004f; } float INA219_ReadCurrent(void) { // 电流寄存器直接用乘以LSB 0.0001 int16_t raw INA219_ReadRaw(0x04); return (float)raw * 0.0001f; } float INA219_ReadPower(void) { // 功率寄存器原始值 * 20 * 0.0001 int16_t raw INA219_ReadRaw(0x03); return (float)raw * 0.002f; }有一个细节读总线电压时手册说寄存器低3位为0实际数据是bit15:3。所以先右移3位再乘4mV得到的才是正确的母线电压。如果你不右移直接乘数据会偏大到没有意义。4.3 连续采集与去抖动处理电赛现场常见的负载是直流电机、继电器、发热丝这类设备。电机启动时电流尖峰很大稳定时电流又比较平稳如果直接拿原始电流值去控制逻辑可能会有误判。INA219本身支持128次平均这是第一个滤波手段软件层面建议再加一个简单的滑动平均比如每50ms读取一次缓存最近20个值取平均值作为当前电流。关于读取速度INA219在平均模式下一次完整的电流和功率读取大概需要几毫秒到几十毫秒不等对于电赛的监测需求完全足够。不建议为了提高刷新率把ADC分辨率降到9位除非你要做的是高频电流保护那样的话更推荐直接使用INA219的中断比较功能Alert引脚而不是靠单片机轮询。下面这段代码是滑动平均的简单实现适用于裸机环境#define SAMPLE_NUM 20 float current_buf[SAMPLE_NUM]; uint8_t current_index 0; float get_current_average(void) { float current INA219_ReadCurrent(); current_buf[current_index] current; current_index (current_index 1) % SAMPLE_NUM; float sum 0; for (uint8_t i 0; i SAMPLE_NUM; i) { sum current_buf[i]; } return sum / SAMPLE_NUM; }5. 校准精度为什么手册公式算出来的电流不准5.1 误差来源拆解很多人烧录完程序读到的电流值和万用表实测值对不上第一反应是程序写错了。实际情况是INA219本身和采样电阻都存在误差这些误差叠加起来电流读数出现百分之几的偏差非常正常。误差来源可以分成三类采样电阻的阻值误差模块上原装电阻一般是1%精度但如果是自己焊的普通贴片电阻误差可能到5%。而Calibration寄存器里的校准值是基于“标称阻值”算的电阻实际值如果不是0.100Ω电流读数就会等比例偏大或偏小。INA219的增益误差和偏移误差数据手册中给出的典型增益误差大约在0.5%~1%之间零点偏移误差通常在几微伏级别。对于小电流测量偏移误差的影响会比较明显。温度漂移电流流过采样电阻会发热发热后阻值变化。金属膜电阻的温漂可能是几十ppm/℃而合金电阻通常好得多。如果长时间过大电流采样电阻阻值变化读数也会慢慢漂。理解这些来源之后就能意识到手册算出来的校准值只是一个“初始化值”真正想要电赛得分更高、数据更可信还是要做一次实测校准。5.2 两步标定法零电流偏移和增益校正校准分两步。第一步是零电流校准系统上电负载保持断开状态此时INA219读到的电流理论上应该是0但实际可能读到几mA甚至十几mA这个值就是零点偏移。把它记录下来后续每次读取实际电流时先减掉它。第二步是增益校准找一个稳定负载比如一个大功率电阻或者电子负载让电流稳定在一个已知值I_ref用万用表或者前级电源读数作为参考。同时记录INA219读出并经零点校正后的电流值I_raw然后计算增益修正系数gain I_ref / I_raw之后每次读取就用I_real (I_raw - offset) × gain如果条件允许最好选两个标定点分别在量程的30%和80%附近这样能同时修正线性度上的一些偏差。电赛现场时间比较紧张一个点也够用但要知道这是折中方案。将修正系数固化到程序里之前建议多测几组不同电流的数据确认修正后的曲线是否平直。如果修正曲线的斜率不断变化说明采样电阻可能已经严重发热或者选用的电阻本身就不是高精度类型这时候要考虑换电阻。5.3 用OLED/串口显示电流的联动调试电赛现场很少有人只接一路电流检测而不看数据。最常用的调试方式是借助STM32F103的串口把测量到的电压、电流、功率打印到串口助手或者接一块0.96寸I2C OLED屏幕直接显示出来。有一个常见的坑OLED模块的I2C地址通常是0x3CINA219的地址是0x40地址不同可以挂在同一条I2C总线上。但OLED初始化时如果频繁拉低SDA线会占用总线一段时间如果此时INA219也在连续测量软件轮询可能会有延迟。我的建议是显示刷新频率不需要太高OLED每200ms刷新一次即可电流数据的采集放在定时器中断里保证采样周期稳定不因为显示刷新而抖动。6. 我做这套方案时踩过的四个坑6.1 多片INA219共用同一个I2C地址有一年电赛我需要在电机电源端和主控电源端各测一路电流于是第一版直接放了两片INA219模块代码里读的都是0x40地址结果两路数据完全一样排查了半天才发现第二片芯片的A0、A1没设置成不同地址。解决方法是第二片INA219把A0引脚接VCC或者接SDA让它工作在0x41地址。代码里定义两个不同的从机地址读取函数加一个地址参数就可以分别读取两路数据了。类似这种问题如果前期布局时没规划好后期就只能飞线改地址麻烦但能解决。6.2 母线电压过高导致读回全FFFF电赛电源类题目中输入电压经常是12V、24V甚至更高。INA219的Configuration寄存器里bit13控制总线电压量程0是16V档1是32V档。如果你用的是16V档并且母线电压实际是24V那么读回来的总线电压寄存器就会饱和表现出来就是0x7FF0之类的大数或者各种非预期数据。我建议在配置寄存器时如果题目没有明确说明电压一定低于16V就直接选32V档也就是把bit13置1。这样虽然低电压时的分辨率从4mV/LSB变成8mV/LSB但对大多数电赛应用影响不大。电流检测部分不受这个档位影响PGA的范围还是由bit12:11决定。6.3 电机负载下的瞬时峰值干扰带电机负载时电流波形不是一条直线而是在平均值附近叠加脉动。电机换向时瞬间电流可能接近堵转电流。INA219的PGA如果设置在±40mV在0.1Ω采样电阻下对应最大电流只有0.4A电机稍微一启动就超量程电流寄存器就会乱跳甚至变成负值读者很容易误判成“短路了”或者“芯片烧了”。所以我强烈建议在摸清负载电流范围之前先把PGA设为±320mV档也就是配置值的“11”。如果发现小电流时分辨率不够比如待机电流只有10mA读数经常在0到20mA之间乱跳再考虑把PGA调低到±160mV或±80mV同时注意相应更新校准值。6.4 地线噪声对测量结果的影响还有一个容易被忽视的问题ESP32、STM32这类单片机板子上的GND并不一定非常干净特别是与其他大电流模块直接共地时。INA219是高边检测芯片它本身测的是VIN和VIN-之间的差分电压对GND电平的波动有一定的共模抑制能力。但如果采样电阻两端的走线绕过了一大段地线或者VIN、VIN-两根线不对称共模噪声就会转变成差模误差。解决方法是把VIN和VIN-两根线尽量从采样电阻两端“单独引出”短而粗不要跟负载大电流线混在一起走参考前面提到的开尔文接法。如果实在没法布线可以使用双绞线或者加一组RC滤波再进芯片引脚效果会好很多。7. 电赛现场扩展把电流检测模块变成子系统7.1 与PWM输出联动做限流保护电赛题经常需要控制电机转速PWM输出是标配。当负载电流超过设定阈值时把PWM关闭或者占空比降到安全值是一个简单但非常实用的保护策略。利用STM32F103的定时器产生PWM比如TIM3_CH1输出到电机驱动芯片的EN或PWM引脚。在电流检测模块里判断如果连续N次读取到的电流超过阈值就调用HAL_TIM_PWM_Stop停止输出或者把比较寄存器CCR的值改小。这个保护动作完全不需要外部硬件纯软件可以实现响应速度通常在几十毫秒级别适合电赛这种对实时性要求不是特别苛刻的场景。如果要更快响应可以借助INA219的Alert引脚。连接方式是芯片内部有一个比较器当电流或总线电压超过设定阈值时Alert引脚会拉低触发STM32的外部中断然后立即关断PWM。这种方式可以在几百微秒内完成保护动作但需要额外配置Alert相关的寄存器电赛现场时间充裕的话值得尝试。7.2 把监测数据通过CAN/SPI上报电赛作品如果是“主板 驱动板”的结构那么驱动板上的电流检测数据需要回传给主板做显示和控制。STM32F103自带的CAN外设和SPI外设都能胜任这个任务。如果走CAN总线可以参考标准CAN例程把电流、电压、功率打包成一个8字节数组周期发送。CAN协议有ACK机制比串口更可靠适合距离较长、干扰较大的场景。如果走SPI一般是一个MCU做主机另一个做从机从机把INA219数据写入SPI发送缓冲区主机周期读取。注意SPI从机发送时不能像串口一样随时发起必须等主机发起CLK所以从机端要维护一个“准备好新数据”的寄存器标志位。7.3 现场调参建议与故障预案电赛现场调电流检测模块我的顺序一般是先单独读总线电压确认能否读到电源电压值。如果这个值不对说明I2C地址、硬件连接、模块供电至少有一个有问题先解决掉再说下一步。再读分流电压寄存器观察负载断开时是否为0。不为0先做零点校正。再读电流寄存器对比万用表或者电源自带电流显示的数值判断增益偏差是否在可接受范围。确认显示输出的曲线稳定没有明显的跳变和异常尖峰。现场调试时一定要备两个额外的上拉电阻2.2k和4.7k各若干和至少一片备用INA219模块。I2C上拉电阻不匹配在实验室可能不明显到了赛场换了一套杜邦线、接触电阻变化后通信失败的概率会明显上升。芯片本身也不贵万一模块上的合金电阻意外断开或者芯片烧了换个模块比当场换芯片快得多。提示无论做哪类题目建议在程序里加一个“自检模式”开机后读一次INA219寄存器如果两个寄存器的值都是0xFFFF或者读不到ACK就在OLED/串口上明确提示“INA219无响应”而不是让系统傻傻地继续运行。这个小小的自检在电赛现场往往能帮你节省半小时的排查时间。把一路电流检测做成一个稳定可靠的子系统后续无论接到哪个题目上都能给主控提供干净的数据。我在实际项目中体会最深的一点是INA219这类带数字接口的传感器真正的难点不是通信协议而是你对量程、校准和误差来源有没有足够的敬畏心。把所有数据源都过一遍校准、加一层滤波、留好自检入口测量结果才会真的可信系统也才有底气带更复杂的控制逻辑。本文还有配套的精品资源点击获取
返回列表