news 2026/9/12 7:30:55

STM32F103读取ACS712电流传感器:原理、代码与滤波实践

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
STM32F103读取ACS712电流传感器:原理、代码与滤波实践

简介:涵盖ACS712、GY-712-5A及20A、30A量程的单片机电流传感器模块开发实例,基于STM32F103和Keil标准库实现,适用于嵌入式物联网项目中的电流检测、数据采集、传感器驱动调试等场景,也适合做STM32外设编程的进阶练习。压缩包共159个文件,大小约4.18MB,内部包含c/h源码、Keil工程文件(uvprojx/uvoptx)、编译生成的hex/axf固件、PDF器件手册,以及重置编译和清理中间文件的批处理脚本,文件类型覆盖开发、编译、烧录、查阅等多个环节,结构清楚。截止目前已有616人学习下载。整套代码均来自实际项目验证,若换成STM32F103系列其他型号,只需在Keil中调整芯片型号与Flash容量;模块接线定义在代码中,配合PDF手册可快速对照实物完成电流采样。工程内注释点出了关键寄存器和采样流程,便于二次开发,适合入门者系统理解标准库工程组织方式,并快速完成电流传感器模块的移植与调试。

1. ACS712 与 STM32F103:电流采集最省事的一对组合

做电机堵转检测时,很多新手直接把 ACS712 的 ADC 原始值当电流用,5A 量程下空载读数不是 0,而是一千五百多。问题出在模块输出的 2.5V 零电流偏置没处理。ACS712 是霍尔效应电流传感器,5A 量程灵敏度 185mV/A,配合 STM32F103 内置 12 位 ADC,是嵌入式物联网项目里最常见的电流采样组合,电机控制、电池放电监测、电源负载分析都会用到。

这套资料带 KEIL 标准库工程,代码里已经把 ADC 初始化、采样滤波、串口输出整理好,拿来改量程和通道就能用。适合做课程设计的在校生,也适合急着评估 ACS712 精度的工程师——不用从寄存器查起,直接看关键代码怎么改参数就行。

2. ACS712 工作原理与量程选型

2.1 霍尔效应与模块内部结构

ACS712 内部真正流过电流的是一条低阻铜排,而不是普通采样电阻。电流从 IP+ 流到 IP- 时,铜排周围产生与电流近似成正比的磁场,封装内的差分霍尔片感应这个磁场,经过放大和温度补偿电路后,从 VIOUT 引脚输出电压。因为测的是磁场而非直接测电压降,ACS712 本身具备电气隔离特性,也不引入明显的插入损耗。

模块支持双向电流测量,以 5A 量程为例,-5A 到 +5A 被映射到以 2.5V 为中心、跨度约 ±0.925V 的电压区间。GY-712-5A 这类模块板只是把芯片引脚转接出来,没有额外信号调理,所以最终精度取决于芯片本身和后面的采样电路。这一点决定了我们在软件里必须做两件事:采零电流基准、做数字滤波。

2.2 量程、灵敏度与关键参数

参数GY-712-5A / ACS712-05BACS712-20AACS712-30A
测量范围±5 A±20 A±30 A
灵敏度185 mV/A100 mV/A66 mV/A
零电流输出(VCC=5V)2.5 V2.5 V2.5 V
通流电阻1.2 mΩ1.2 mΩ1.2 mΩ
典型带宽80 kHz80 kHz80 kHz

选型逻辑很简单:被测电流峰值不超过量程的 70%~80%,然后选灵敏度最高的型号。5A 量程 1A 电流对应 185mV,STM32F103 的 12 位 ADC 在 3.3V 参考下每个 LSB 约 0.806mV,理论分辨率接近 4.4mA;20A 量程每 LSB 对应约 8mA。但芯片输出本身带十几到几十毫伏的噪声,所以实际分辨率要靠软件滤波去逼近。

2.3 为什么这个例程用内置 ADC 而不是外置 ADC

STM32F103 的 ADC1 是 12 位逐次逼近型,ADC 时钟最高 14MHz,单次转换约 1μs 级别。ACS712 带宽 80kHz,对电机电流、电池放电这类几十到几百赫兹的缓变信号,F103 内置 ADC 完全够用。

需要外置 ADC 的场景主要有三种:要真正 16 位以上分辨率、要求主控与采样端电气隔离、多通道需要同步采样。对课程设计和一般物联网节点,外挂 I2C 型高精度 ADC 反而引入总线时序和功耗问题。这个例程固定走 ADC1 + PA1,标准库里 stm32f10x_adc.c 已经写好,改通道只需要动一个宏。

3. KEIL 标准库工程搭建与 ADC1 通道初始化

3.1 工程文件结构和编译前的处理

资料里的文件看起来杂,其实只有几类:ADC.uvprojx 是 KEIL 工程文件,ADC.uvguix 是界面布局配置,ADC.axf 是编译生成的映像文件,ADC_sct.Bak 是分散加载文件备份。还有两个批处理:keilkilll.bat 和 重置KEIL编译.bat,作用都是清理编译中间文件。我拿到例程的第一件事是先跑一遍清理脚本,再重新 Build,避免旧的 .o 和 .axf 残留导致"改了代码不生效"的假象。

用 Keil uVision5 打开工程后,第一件事是确认 Device 型号。STM32F103C8 是 64KB Flash,CB 是 128KB,ZET 是 512KB。Options for Target -> Device 里选成板子实际型号,Flash Download 页面里编程算法也要对应。标准库代码对 F103 全系通用,但 Flash 容量配错会直接导致下载失败。

3.2 时钟、GPIO 与 ADC1 初始化代码

void ACS712_ADC_Init(void) { GPIO_InitTypeDef GPIO_InitStructure; ADC_InitTypeDef ADC_InitStructure; // 使能 ADC1 与 GPIOA 时钟,PA1 属于 GPIOA RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1 | RCC_APB2Periph_GPIOA, ENABLE); // PCLK2 = 72MHz,6 分频得到 12MHz ADC 时钟 RCC_ADCCLKConfig(RCC_PCLK2_Div6); // PA1 配置为模拟输入,ADC 引脚不能用复用推挽 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN; GPIO_Init(GPIOA, &GPIO_InitStructure); // 独立模式,单次转换,软件触发,右对齐,1 个通道 ADC_InitStructure.ADC_Mode = ADC_Mode_Independent; ADC_InitStructure.ADC_ScanConvMode = DISABLE; ADC_InitStructure.ADC_ContinuousConvMode = DISABLE; ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None; ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right; ADC_InitStructure.ADC_NbrOfChannel = 1; ADC_Init(ADC1, &ADC_InitStructure); // 规则组第 1 个通道为 ADC_Channel_1,采样时间 55.5 周期 ADC_RegularChannelConfig(ADC1, ADC_Channel_1, 1, ADC_SampleTime_55Cycles5); ADC_Cmd(ADC1, ENABLE); }

时钟分频选 RCC_PCLK2_Div6 是 F103 的常见做法:APB2 总线 72MHz,ADC 时钟不能超过 14MHz,6 分频得到 12MHz,余量充足。如果用 Div4 得到 18MHz,超出上限后转换结果会不稳定。PA1 必须配成 GPIO_Mode_AIN 模拟输入,否则引脚上的施密特触发器会干扰采样。

3.3 采样时间与触发方式的选择依据

采样时间配置总转换周期适用场景
ADC_SampleTime_1Cycles514低阻源、追求最高吞吐
ADC_SampleTime_7Cycles520普通电压信号
ADC_SampleTime_13Cycles526中等阻抗源
ADC_SampleTime_28Cycles541高阻抗传感器
ADC_SampleTime_55Cycles568带噪声的传感器输出
ADC_SampleTime_239Cycles5252极慢变化的直流信号

ACS712 输出阻抗很低,理论上用 1.5 周期采样也读得准。但传感器输出带噪声,较长采样时间等效于在硬件前端做了一次积分低通,能明显压低波形毛刺。例程选 55Cycles5 是合理折中,单通道转换时间约 5.7μs,采样率仍然足够。

触发方式关掉连续转换、只用软件触发,目的是让滤波循环里每一次采样都有明确边界。如果开了连续转换,轮询 EOC 标志时可能拿到的是最新一次结果,循环语义会混乱。

4. 电流换算、滤波与串口验证

4.1 零电流基准为什么不能直接用理论值

理论上 VCC=5V 时零电流输出 2.5V,3.3V 参考下 ADC 读数应该是 2.5V / 3.3V × 4095 ≈ 3102。但芯片本身有零漂,模块供电纹波也会叠加进去。我一般开机后先空载采样 200 到 500 次求平均,把结果存成 zero_adc,后面的换算以它作基准。

#define ACS712_SENSITIVITY 185.0f // mV/A,5A 模块 #define ADC_REF_VOLTAGE 3300.0f // mV,STM32F103 VDDA #define ADC_FULL_SCALE 4095.0f // 空载时调用,返回零电流基准 ADC 值 uint16_t ACS712_CalibrateZero(void) { uint32_t sum = 0; for (uint8_t i = 0; i < 256; i++) { ADC_SoftwareStartConvCmd(ADC1, ENABLE); while (ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC) == RESET); sum += ADC_GetConversionValue(ADC1); } return (uint16_t)(sum / 256); }

4.2 采样均值与电流换算

float ACS712_ReadCurrent(uint16_t zero_adc) { uint32_t sum = 0; float voltage_mv; float zero_mv; float current; for (uint8_t i = 0; i < 32; i++) { ADC_SoftwareStartConvCmd(ADC1, ENABLE); while (ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC) == RESET); sum += ADC_GetConversionValue(ADC1); } // 平均 ADC 值换算成毫伏 voltage_mv = (float)sum / 32.0f / ADC_FULL_SCALE * ADC_REF_VOLTAGE; // 零电流基准同样换成毫伏 zero_mv = (float)zero_adc / ADC_FULL_SCALE * ADC_REF_VOLTAGE; // 减偏置后除以灵敏度,得到安培 current = (voltage_mv - zero_mv) / ACS712_SENSITIVITY; return current; }

这段代码把 ADC 原始值先归一化到毫伏,再统一做减法,最后除以灵敏度。注意 ACS712 测量的是双向电流,换算结果是带符号的 float,正负代表电流方向。整个过程中间变量都用 float,避免整数除法截断;在 32 位 MCU 上浮点运算几十微秒,对采样率没有影响。

4.3 数字滤波方式怎么选

滤波方式窗口抗脉冲能力实时性适用场景
算术平均16~256中等稳态电流监测
滑动平均8~16一般变化较慢的负载
中值滤波5~11电机启动、继电器通断
去极值平均先剔除最大最小再平均中等推荐用于电机回路

电机启动瞬间会有尖峰毛刺,中值滤波能干净地剔除;电源功耗监测则适合滑动平均,因为波形相对平缓。例程的 32 次算术平均是通用起步配置,简单且不容易把有效信号滤掉。改滤波方式时注意窗口越大延迟越大,做堵转保护时迟滞必须留够。

4.4 串口输出与实测验证

验证电流读数最直接的办法是串口打印。例程用 USART1 重定向 printf,接一个 USB-TTL 模块,波特率 115200,串口助手每秒刷新一次即可。如果换成串口 3,注意 USART3 挂在 APB1 总线上,时钟使能要用 RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART3, ENABLE),同时波特率计算的分频基准也从 72MHz 变成 36MHz,这是标准库里串口 1 和串口 3 最容易踩的差异。

int fputc(int ch, FILE *f) { USART_SendData(USART1, (uint8_t)ch); while (USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET); return ch; }

重定向之后,printf("Current: %.2f A\r\n", current) 就能直接在上位机看到数值。验证方法:拿一个 12V 灯泡串在 ACS712 的 IP+ 与 IP- 之间,万用表电流档对照,读数偏差一般在 2% 以内。

5. 量程切换、下载器与 3.3V/5V 电压匹配

5.1 换 20A、30A 模块只需改灵敏度

#define ACS712_SENSITIVITY 100.0f // 20A 模块 #define ACS712_ZERO_VOLTAGE 2500.0f // mV,VCC=5V

换模块后只改这一个宏,换算逻辑不用动。5A 模块全量程输出 2.5V ± 0.925V,20A 模块是 2.5V ± 2V,30A 模块是 2.5V ± 1.98V。

5.2 J-LINK、ST-LINK 与 axf 缺失

KEIL 里 Debug 页面必须与实际下载器一致:J-LINK 选 J-LINK / J-Trace Cortex,ST-LINK 选 ST-Link Debugger。选错会报 No J-Link found 或 Error: Flash Download failed。另外,如果 Build 后发现工程目录下没有 .axf 文件,说明编译并未真正完成,先看 Build Output 里的 Error 数量,再查 Options -> Output 里 Create HEX File 是否勾选。

5.3 5V 输出超过 3.3V ADC 量程的解法

ACS712 必须 5V 供电,它的供电范围下限是 4.5V,直接接 3.3V 不可靠。但 5V 供电时,20A 模块在 10A 以上输出就超过 3.3V 了。F103 的 ADC 输入不能超过 VDDA+0.3V,也就是约 3.6V,超过轻则读数饱和在 4095,重则损伤引脚。我的做法是输出端加电阻分压:R1 取 10kΩ、R2 取 20kΩ,分压比 2/3,满量程 4.5V 降到 3.0V,留出安全余量。软件里把换算电压除以 2/3,同时重新采集一次零电流基准,因为分压后 2.5V 变成了约 1.667V。方向放在分压系数和零基准上,读数才会和实际电流对得上。

本文还有配套的精品资源,点击获取

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/12 7:30:40

Leaflet与Cesium渲染层本质差异与选型决策指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/12 7:30:02

锂电池组SOC均衡控制与Buck-Boost电路设计

1. 项目背景与核心价值锂电池组在电动汽车、储能系统等领域的应用越来越广泛&#xff0c;但电池单体之间的不一致性问题始终是影响系统性能和寿命的关键因素。四节电池组作为最常见的电池模块单元&#xff0c;其均衡控制技术的研究具有典型意义。基于SOC&#xff08;State of C…

作者头像 李华
网站建设 2026/9/12 7:29:46

恶意文件如何被 claude-obsidian 的归档防御逐关击退

恶意文件如何被 claude-obsidian 的归档防御逐关击退 【免费下载链接】claude-obsidian Self-organizing AI second brain for Obsidian Claude Code. Drop any source and Claude reads, links, and files it into one connected knowledge graph of plain Markdown you own.…

作者头像 李华
网站建设 2026/9/12 7:29:31

Rust裸机机器人运行时:MicroDuck的确定性控制与边缘部署

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/12 7:28:59

高校就业管理系统开发实战:ThinkPHP与Laravel混合架构解析

1. 项目背景与核心需求高校就业管理系统是连接学生、企业和学校三方的关键平台。随着高校毕业生人数逐年增加&#xff08;2023年突破1158万人&#xff09;&#xff0c;传统Excel邮件的管理方式已无法满足需求。我们团队基于ThinkPHP和Laravel双框架开发的系统&#xff0c;实现了…

作者头像 李华