基于STM32F103C8T6单片机驱动ACS712模块进行电流检测
-
- [一、ACS712 模块简介](#一、ACS712 模块简介)
-
- 1.1产品简介
- [1.2 模块特性](#1.2 模块特性)
- [1.3 引脚定义](#1.3 引脚定义)
- 二、硬件连接
-
- [2.1 单片机接线](#2.1 单片机接线)
- [2.2 电流检测端及分压接线](#2.2 电流检测端及分压接线)
- [2.3 实物接线](#2.3 实物接线)
- 三、软件代码
-
- [3.1 AD.c](#3.1 AD.c)
- [3.2 主程序](#3.2 主程序)
- 四、测试现象
-
- [4.1 理想数据](#4.1 理想数据)
- [4.2 实测数据](#4.2 实测数据)
- 五、常见问题
-
- [Q1: 读数一直为 0?](#Q1: 读数一直为 0?)
- [Q2: 读数跳变很大?](#Q2: 读数跳变很大?)
- [Q3: 负电流显示?](#Q3: 负电流显示?)
- [Q4: 精度不够?](#Q4: 精度不够?)
一、ACS712 模块简介
1.1产品简介
在嵌入式开发中,电流检测是一个常见需求。本文详细介绍如何使用 STM32F103C8T6 驱动 ACS712 霍尔效应电流传感器 ,并完成1-5A电流的实测验证。
ACS712 是一款基于霍尔效应的电流传感芯片,用来测量直流或交流电流。它通过内部导体感应电流产生的磁场,再由霍尔元件转换成与电流成比例的模拟电压输出(一般以 Vcc/2 为零点)。该芯片具有电气隔离、安全性高、响应速度快 的特点,常见量程有 ±5A、±20A、±30A,广泛用于电源监测、电机控制和过流检测等场景。


1.2 模块特性
- 工作电压:5V DC(不可以用3.3V供电,输出不稳定误差大,官方手册工作电压在4.5-5.5V之间)
- 输出类型:模拟电压输出
- 零点电压:VCC/2 = 2.5V(无电流时)
- 灵敏度 :185mV/A(5A 版本)
ACS712 不同量程的灵敏度不同,可以看下表:

1.3 引脚定义
| 引脚 | 功能 | 连接 |
|---|---|---|
| VCC | 电源正极 | 接 5V |
| OUT | 模拟输出 | 接 STM32 PA0(ADC 输入) |
| GND | 电源负极 | 共地 |
| IP+ | 电流输入 | 检测电路电流输入 |
| IP- | 电流输出 | 检测电路电流输出 |
二、硬件连接
2.1 单片机接线
| ACS712 | STM32F103C8T6 | OLED |
|---|---|---|
| VCC(外部电源接5V) | -- | -- |
| OUT | 分压后接到PA0 | -- |
| GND(外部电源接地) | GND | GND |
| -- | 3.3V | VCC |
| -- | PB8 | SCL |
| -- | PB9 | SDA |
2.2 电流检测端及分压接线

①这里检测电路和板子供电的5V建议分开供电。
②在PA0对地之间可以加个0.1uF的独石电容,增加稳定性。
③加分压电路的原因:5A电流时,OUT输出电压理论值3.425V已经超过STM32的采样电压3.3V了,因此需要加分压电路。
2.3 实物接线

三、软件代码
STM32F103C8T6驱动ACS712电流检测(标准库代码)。
3.1 AD.c
c
#include "stm32f10x.h" // Device header
/**
* 函 数:AD初始化
* 参 数:无
* 返 回 值:无
*/
void AD_Init(void)
{
/*开启时钟*/
RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE); //开启ADC1的时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); //开启GPIOA的时钟
/*设置ADC时钟*/
RCC_ADCCLKConfig(RCC_PCLK2_Div6); //选择时钟6分频,ADCCLK = 72MHz / 6 = 12MHz
/*GPIO初始化*/
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure); //将PA0引脚初始化为模拟输入
/*规则组通道配置*/
ADC_RegularChannelConfig(ADC1, ADC_Channel_0, 1, ADC_SampleTime_55Cycles5); //规则组序列1的位置,配置为通道0
/*ADC初始化*/
ADC_InitTypeDef ADC_InitStructure; //定义结构体变量
ADC_InitStructure.ADC_Mode = ADC_Mode_Independent; //模式,选择独立模式,即单独使用ADC1
ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right; //数据对齐,选择右对齐
ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None; //外部触发,使用软件触发,不需要外部触发
ADC_InitStructure.ADC_ContinuousConvMode = DISABLE; //连续转换,失能,每转换一次规则组序列后停止
ADC_InitStructure.ADC_ScanConvMode = DISABLE; //扫描模式,失能,只转换规则组的序列1这一个位置
ADC_InitStructure.ADC_NbrOfChannel = 1; //通道数,为1,仅在扫描模式下,才需要指定大于1的数,在非扫描模式下,只能是1
ADC_Init(ADC1, &ADC_InitStructure); //将结构体变量交给ADC_Init,配置ADC1
/*ADC使能*/
ADC_Cmd(ADC1, ENABLE); //使能ADC1,ADC开始运行
/*ADC校准*/
ADC_ResetCalibration(ADC1); //固定流程,内部有电路会自动执行校准
while (ADC_GetResetCalibrationStatus(ADC1) == SET);
/*开始校准*/
ADC_StartCalibration(ADC1);
while (ADC_GetCalibrationStatus(ADC1) == SET);
}
/**
* 函 数:获取AD转换的值
* 参 数:无
* 返 回 值:AD转换的值,范围:0~4095
*/
uint16_t AD_GetValue(void)
{
/*开始转换*/
ADC_SoftwareStartConvCmd(ADC1, ENABLE); //软件触发AD转换一次
while (ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC) == RESET); //等待EOC标志位,即等待AD转换结束
return ADC_GetConversionValue(ADC1); //读数据寄存器,得到AD转换的结果
}
3.2 主程序
c
/**********************************************
***基于STM32F103C8T6单片机驱动ACS712模块进行电流检测***
注意:启动时电流必须是0A电流,程序会在启动时获取0电流下的零点值带入后面的计算;
如果启动不是零点值,需要在重新启动读取0电流值计算才可以读数正确(或者自己更换后面计算的V_zero数值)
| ACS712 |STM32F103C8T6 | OLED|
| VCC(外部电源接5V) | -- | -- |
| OUT | 分压后接到PA0 | -- |
| GND(外部电源接地) | GND | GND |
| -- | 3.3V | VCC |
| -- | PB8 | SCL |
| -- | PB9 | SDA |
**********************************************/
#include "stm32f10x.h" // Device header
#include "Delay.h"
#include "OLED.h"
#include "AD.h"
uint16_t ADValue; //定义AD值变量
float Voltage,Vsensor,Current; //定义电压,电流变量
float sum = 0;
float V_zero; //定义零点电压变量
int main(void)
{
/*模块初始化*/
OLED_Init(); //OLED初始化
AD_Init(); //AD初始化
/*显示静态字符串*/
OLED_ShowString(1, 1, "ADValue:"); //ad采样值
OLED_ShowString(2, 1, "Voltage:0.00V"); //读取电压值
OLED_ShowString(3, 1, "Vsensor:0.00V"); //OUT输出实际电压值
OLED_ShowString(4, 1, "Current:0.00A"); //转换出来的电流值
for(int i=0;i<20;i++)
{
sum += AD_GetValue();
}
ADValue = sum / 20;
sum = 0;
V_zero = (float)ADValue / 4095 * 3.3 * 2.0f;//获取无电流下的零点电压值
while (1)
{
/*滤波处理*/
for(int i=0;i<20;i++)
{
sum += AD_GetValue();
}
ADValue = sum / 20; //获取AD转换的平均值
sum = 0;
// ADValue = AD_GetValue(); //获取AD转换的值
Voltage = (float)ADValue / 4095 * 3.3; //将AD值线性变换到0~3.3的范围,表示电压
Vsensor = Voltage * 2.0f;
Current = (Vsensor - V_zero) / 0.185f; //获取读出的电压,换算成电流
OLED_ShowNum(1, 9, ADValue, 4); //显示AD值
OLED_ShowNum(2, 9, Voltage, 1); //显示读取电压值的整数部分
OLED_ShowNum(2, 11, (uint16_t)(Voltage * 100) % 100, 2); //显示读取电压值的小数部分
OLED_ShowNum(3, 9, Vsensor, 1); //显示OUT电压值的整数部分
OLED_ShowNum(3, 11, (uint16_t)(Vsensor * 100) % 100, 2); //显示OUT电压值的小数部分
OLED_ShowNum(4, 9, Current, 1); //显示电流值的整数部分
OLED_ShowNum(4, 11, (uint16_t)(Current * 100) % 100, 2); //显示电流值的小数部分
Delay_ms(300); //延时300ms,手动增加一些转换的间隔时间
}
}
四、测试现象
4.1 理想数据

4.2 实测数据

五、常见问题
Q1: 读数一直为 0?
- 检查 ACS712 供电是否正常
- 检查 OUT 引脚是否连接到 PA0
- 确认 ADC 通道配置正确
Q2: 读数跳变很大?
- 增加采样次数(建议 10-20 次平均)
- 添加软件滤波(滑动平均/中值滤波)
- 检查电源是否稳定
Q3: 负电流显示?
- 空载时零点电压可能不是精确 VCC/2
- 运行校准程序获取实际零点
- 检查电流方向是否正确
Q4: 精度不够?
- ACS712 本身精度约±3%
- 高精度需求建议使用 INA219 等专用芯片
- 校准实际灵敏度参数
如果觉得有帮助,欢迎点赞👍 收藏⭐ 关注📌!
有问题或者需要资料请在评论区留言~