news 2026/9/10 11:05:26

STM32+电阻分压ADC均值滤波实现18650电池电量检测

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
STM32+电阻分压ADC均值滤波实现18650电池电量检测

简介:面向STM32单片机开发者和高校工科学生,这套18650锂电池电量检测系统项目以STM32F103C8T6为主控,采用电阻分压法、均值滤波和ADC采样实现电池电压测量,并据此推算电流与剩余电量,最终在OLED屏上实时显示。所需硬件包括STM32F103C8T6核心板、18650锂电池、10K电阻、104电容与OLED显示屏。工程已通过实际运行验证,功能效果与演示视频一致,源码包含均值滤波处理,可直接复现、用于课程设计或继续扩展。资源压缩包共190个文件、大小6.64MB,以C源文件(.c)、头文件(.h)、Keil工程配置(.uvprojx)和电路原理图PDF为主,同时包含.o/.d等编译中间文件、链接脚本及调试配置,目录层次清晰,便于按模块查阅。已有845人学习下载,既适合毕设/课设快速搭建锂电池监测原型,也可为物联网、智能检测类项目提供ADC采集与滤波算法参考。

1. 18650锂电池电量检测:STM32加上电阻分压与ADC均值滤波就能做出实用系统

18650电池在电动车、储能设备和物联网终端里几乎是标准供电单元,但电量显示却一直是嵌入式开发的痛点。直接读电池电压再对照放电曲线,误差能到20%以上;用库仑计方案精度高,成本也高。标题里的这套系统走的是“电压法”路线:电阻分压把4.2V降到ADC量程内,STM32内置ADC完成采样,再用均值滤波把纹波和开关噪声压下去。整个过程不需要专用电量计芯片,一颗MCU加几个电阻电容就能实现,适合做电池供电产品的原型验证、毕业设计或低成本量产方案。下面从计算逻辑、硬件参数、软件代码到标定方法,拆开讲清楚。

2. 电阻分压法与ADC测量:先算量程、分辨率和采样周期

2.1 电阻分压的计算逻辑:把4.2V安全映射到ADC输入范围

18650满电4.2V,而STM32的ADC输入范围通常是0到3.3V(取决于VDDA和VREF+)。直接用分压电阻把电压按比例缩小,是最省成本的做法。分压网络由R1(上臂)和R2(下臂)串联构成,ADC采样点取自R1与R2的中间节点。

输出电压关系是:

V_adc = V_bat × R2 / (R1 + R2)

分压比 K = R2 / (R1 + R2)。假设选R1=30kΩ、R2=10kΩ,分压比是1/4,4.2V对应1.05V,留出了约3倍的安全余量。这个余量很重要:ADC输入引脚承受过高电压轻则采样失真,重则损坏IO口。另一个约束是输入阻抗。STM32的ADC内部有采样保持电容,外部等效源阻抗过大会导致采样时电容充不满,误差增大。数据手册建议外部阻抗小于10kΩ,因此R1与R2的并联值最好控制在10kΩ以内。上面那个例子并联值是7.5kΩ,满足要求。

电池电压范围分压比R1 (kΩ)R2 (kΩ)4.2V对应ADC输入并联等效阻抗
3.0 - 4.2V1/210102.10V5.0kΩ
3.0 - 4.2V1/320101.40V6.7kΩ
3.0 - 4.2V1/430101.05V7.5kΩ
3.0 - 4.2V1/540100.84V8.0kΩ

分压比不是越小越好。分压比过小会浪费ADC分辨率,比如12位ADC在3.3V参考下每个LSB约0.8mV,但折算回电池端要乘以分压比的倒数,1/4分压时相当于3.2mV/LSB。1/2分压时是1.6mV/LSB。量程余量和分辨率要平衡,对18650这种放电平台较平的电池,我一般选1/3或1/4并配合后级校准。

2.2 ADC采样原理:逐次逼近型ADC的工作流程与转换关系

STM32的ADC是逐次逼近型(SAR ADC)结构,核心思路是用一个DAC不断生成比较电压,通过二分查找逼近输入信号。以12位ADC为例,一次转换需要12次比较,加上采样阶段总共13到15个周期。每次比较都由ADC时钟驱动,所以转换时间和采样周期直接挂钩。

转换结果的数学关系是:

ADC_Value = V_in / V_REF × 4096

这个公式看懂了,后面代码里的换算逻辑就顺了。例如VREF=3.30V,采样点电压为1.05V时,ADC读数理论上接近1303。反过来,由ADC读数算输入电压就是:

V_in = ADC_Value / 4096 × V_REF

采样周期是从外部输入到内部采样保持电容充电的时间。STM32F103的ADC时钟最高14MHz,采样时间可配为1.5、7.5、13.5、28.5、41.5、55.5、71.5、239.5个周期。外部源阻抗越大,需要的采样时间越长。分压电阻网络阻抗在kΩ级别时,建议采样时间至少选13.5周期以上。热词里频繁出现的“adc采样周期”,在实际项目中通常就卡在这几个配置项上。

2.3 均值滤波算法:为什么单次采样直接拿来用会出问题

电池供电的系统里,ADC采到的电压不仅仅是电池电动势。负载开关瞬间会产生毛刺,PWM调光或电机驱动会叠加周期性纹波,电源芯片开关噪声也会耦合进来。单次采样的瞬时值可能偏离真实电压几百毫伏。

均值滤波的思路是多次采样后取平均,让随机噪声互相抵消。常见做法有两种:简单滑动平均和去极值平均。前者代码量小,但对尖峰脉冲敏感;后者把排序后最大和最小的若干值剔除,再对剩余值取平均,抗干扰能力明显更好。对18650电压检测这类变化缓慢的信号,8次采样去首尾后取平均已经能满足1%以内的电压精度。这里先不做代码展开,第4章会给出完整实现。

3. 硬件电路设计:分压电阻选型与电压电流采样网络

3.1 电压采样电路:电阻精度、功率与RC低通滤波

电阻分压看起来简单,工程细节全在选型上。分压电阻要选1%精度或更高的金属膜电阻,普通5%碳膜电阻的温漂和初始误差会让标定变得困难。功率方面,R1上的电流是V_bat / (R1 + R2),4.2V下用30kΩ+10kΩ方案电流只有0.105mA,单个电阻功耗微瓦级,0805封装完全够用。但要注意阻值不能选太大,否则并联等效输出阻抗过高,会影响ADC采样保持电容的充电速度。

ADC输入引脚前串联一颗100Ω到1kΩ的限流电阻,并在引脚对地并联一颗100nF电容,组成一阶RC低通滤波。RC截止频率大约在1.6kHz(以1kΩ+100nF计算),能滤掉大部分高频开关噪声,同时限流电阻还能保护ADC引脚免受静电冲击。这个电容的另一个作用是提供电荷池,弥补采样瞬间ADC采样电容抽取的电荷,减少电压跌落。

实际画PCB时还要注意分压电阻的参考地要和STM32的模拟地AGND单点连接,避开数字电路的地环路。如果板上有DCDC,分压采样点要远离电感,必要时在分压节点加一个10nF电容专门滤DCDC开关频率。

3.2 电流采样方案:低值采样电阻加运放放大

标题明确包含电流检测,工程上常见做法是采样电阻加差分运放。在电池负极或正极串联一颗低阻值精密电阻,比如10mΩ,满载1A时压降只有10mV。这个信号太小,必须放大。用INA180这类专用电流检测放大器,增益可选20、50、100倍,单芯片就能完成放大和电平转换,不需要负电源,非常适合3.3V单电源系统。预算更紧时可以用LM358等通用运放搭差分放大电路,但要注意输入共模范围和失调电压。

以10mΩ采样电阻、50倍增益为例,1A电流对应的输出电压是0.01V × 50 = 0.5V,ADC读数约621。如果最大测量电流设计为2A,则ADC满量程对应的电压是1.0V,精度够用。采样电阻的功率按 I²R 计算,2A持续电流对应40mW,选用额定功率0.25W的2512封装电阻有充足余量。开尔文接法(四线制)能避免焊盘铜箔带来的附加电阻误差,电流走线从电阻两端独立引出,不要和功率走线共用一段铜箔。

3.3 ADC参考电压与VREF引脚处理

STM32的VREF+引脚直接决定ADC量化精度。VREF等于VDDA时,如果VDDA上有纹波,这部分噪声会原样叠加到采样结果上。测量精度要求高的系统,用独立的3.3V LDO给VDDA和VREF供电,并在引脚附近放1μF和100nF两级去耦电容。测量要求再高一些,可以外接REF3030这类精密基准源,把VREF稳定在3.0V。外接基准后所有换算公式中的V_REF要同步修改,否则标定系数全部偏掉。

4. STM32软件实现:从ADC通道配置到均值滤波C代码

4.1 用STM32CubeMX初始化ADC与DMA多通道采集

STM32标准库更新慢,现在新项目基本都是HAL库配合CubeMX生成初始化代码。配置ADC时需要确定三个关键参数:分辨率、对齐方式和采样时间。分辨率选12位,右对齐(ADC_DATAALIGN_RIGHT),采样时间根据分压网络阻抗选择。如果电压和电流各占一个通道,还需要确认ScanConvMode和连续转换模式。多通道用DMA搬运结果,避免CPU逐个轮询浪费主循环时间。

4.1.1 CubeMX关键参数表
配置项推荐值说明
ADC1 ChannelIN1(电压)/ IN2(电流)对应具体引脚
ResolutionADC_RESOLUTION_12B12位逐次逼近
ScanConvModeENABLE多通道需开启扫描
ContinuousConvModeENABLE连续采样配合DMA
DMA Continuous RequestsENABLEDMA循环模式
Number Of Conversion2两个通道轮流转换
Sampling Time28.5 Cycles适配kΩ级源阻抗

4.2 HAL库ADC采样代码与换算公式

生成初始化代码后,主逻辑分为三步:启动DMA、读取结果、换算真实值。DMA采用循环模式,写入长度为N的数组,硬件自动完成N次转换后从头开始。下面给出一个完整的电压采样实现,电流通道按同样方式处理。

#define VREF 3.30f #define ADC_FULL_SCALE 4096.0f #define VOLT_DIVIDER 4.0f /* 分压比倒数 */ uint16_t dma_buf[8]; /* DMA直接写入的原始数据 */ float voltage_mv; /* 启动ADC的DMA连续采集 */ void Battery_ADC_Start(void) { HAL_ADC_Start_DMA(&hadc1, (uint32_t *)dma_buf, 8); } /* 对8次采样做去极值平均,再由ADC值换算电池电压 */ float Battery_GetVoltage(void) { uint16_t tmp[8]; uint32_t sum = 0; memcpy(tmp, dma_buf, sizeof(tmp)); /* 冒泡排序,剔除最大值和最小值 */ for (int i = 0; i < 7; i++) { for (int j = 0; j < 7 - i; j++) { if (tmp[j] > tmp[j + 1]) { uint16_t t = tmp[j]; tmp[j] = tmp[j + 1]; tmp[j + 1] = t; } } } for (int i = 1; i < 7; i++) { sum += tmp[i]; } /* 6次平均值换算成毫伏 */ return (float)(sum / 6) / ADC_FULL_SCALE * VREF * VOLT_DIVIDER * 1000.0f; }

代码里先做排序再掐头去尾,防止DMA写了一半产生的半新半旧数据影响平均结果。相加后除以6取平均值,得到的是ADC原始值的均值,最后再统一乘上电压换算系数。分压比倒数写成宏定义,换硬件改一处就够了。

4.3 均值滤波的C语言实现与窗口大小选择

上面的代码用的是固定8点去极值平均,对18650这种缓变信号足够了。如果采样点增多,排序开销会明显增加,可以考虑优化:先用简单的滑动平均做一次粗滤波,超过阈值突变时才做去极值处理。这样既保留抗尖峰能力,又降低CPU占用。

滤波窗口大小需要根据纹波频率来定。ADC采样时钟频率和采样周期决定了采样速率,假设单次转换耗时20μs,8次采样间隔约160μs,对应约6.25kHz的重复频率。高于这个频率的噪声会被平均掉,低于这个频率的纹波则无法滤除。对工频50Hz及谐波干扰效果有限,这时要结合硬件RC滤波,把低通截止频率压到几百Hz。热词里的“c语言adc值滤波函数”指的就是这一层处理逻辑,代码量不大,关键在窗口长度是否匹配实际噪声频段。

4.4 电流采样与功率计算

电流通道换算公式与电压通道类似,但多一个增益系数。假设采样电阻10mΩ,运放增益50倍,则:

电流(A) = ADC_Value / 4096 × VREF / (增益 × R采样)

功率等于电压乘以电流,两条采样链路的时序要尽量同步。DMA循环模式在这时体现出优势:电压和电流是同一个ADC按通道顺序转换的,间隔只有一次转换时间,基本可以认为是同步采样。拿到两组数据后直接乘起来,再配合定时器累加就能估算瓦时数。不过严格说电压法估算容量误差偏大,更适合看瞬时功率和粗略剩余电量,做高精度库仑计还是得用电流积分方案。

5. 标定与实战:三点校准消除器件误差叠加

5.1 三点校准法校准分压比与ADC零偏

理论计算值和实测值之间有三层误差:分压电阻精度、VREF实际电压、ADC本身的偏移和增益误差。单点校准只能纠正比例误差,无法处理零点偏移。更稳妥的做法是三点校准,对应18650的3.0V、3.7V、4.2V三个典型点。用可调电源精确输出这三个电压,读回ADC换算值,建立分段线性映射表。中间段的非线性特征都能被照顾到。

typedef struct { float adc_voltage; /* 校准点ADC原始换算值 */ float real_voltage; /* 万用表实测电压 */ } CalPoint; const CalPoint cal_table[3] = { {2.98f, 3.00f}, {3.68f, 3.70f}, {4.19f, 4.20f}, }; float Cal_GetRealVoltage(float adc_voltage) { if (adc_voltage <= cal_table[0].adc_voltage) return cal_table[0].real_voltage; if (adc_voltage >= cal_table[2].adc_voltage) return cal_table[2].real_voltage; for (int i = 0; i < 2; i++) { if (adc_voltage >= cal_table[i].adc_voltage && adc_voltage <= cal_table[i + 1].adc_voltage) { float ratio = (adc_voltage - cal_table[i].adc_voltage) / (cal_table[i + 1].adc_voltage - cal_table[i].adc_voltage); return cal_table[i].real_voltage + ratio * (cal_table[i + 1].real_voltage - cal_table[i].real_voltage); } } return cal_table[2].real_voltage; }

记录校准点时每档电压稳定5秒后再读数,多次测量取平均。万用表示值为基准,换算后的电压值全部落在±30mV以内才算合格。如果偏差超过50mV,优先检查VREF引脚电压和分压电阻阻值是否与标称一致。

5.2 采样周期与滤波参数的配合调整

采样周期不是越大越好。采样时间延长会增加每次转换的周期数,降低采样率,对均值滤波来说反而让窗口覆盖的时间范围变长。信号变化缓慢,窗口拉长没有大问题;但若系统同时在做PWM调光,过长的窗口会把几百毫秒的负载变化平滑掉,电量显示反而迟钝。经验法则是让滤波窗口覆盖至少一个完整纹波周期。比如负载纹波频率200Hz,周期5ms,单次采样周期按STOP条件选最长的239.5个周期,ADC时钟14MHz时单次约17.4μs,8点采样窗口约139μs,明显不够。这时要么增加采样数量到32次以上,要么在分压输出端加大RC滤波电容,让硬件先把高频成分滤掉,ADC再采样时已经是干净信号。

5.3 工程落地的几个细节

烧录调试时频繁遇到的“error: no stm32 target found”,多半不是代码问题,而是板子复位电路把SWD引脚拉住了,或者目标板供电不足导致连接不稳。先按住复位键再点连接,连接成功瞬间松开,能解决大部分恼人的连接失败。连不上的情况下先量VDDA有没有3.3V。

量产时VREF用内部参考还是外部基准决定一致性。内部参考在不同芯片间有±5%的离散,批量产品建议每片板子都做一次两点校准;外部基准源贵一点,但换来的是换芯片不需要重新标定。GD32、APM32等国产替代芯片可以直接跑STM32的HAL工程,ADC寄存器布局兼容,但外设时钟树配置有差异,直接烧录后ADC数值可能整体偏大或偏小,这时重新检查RCC配置中的ADC时钟分频系数,再用第5.1节的标定逻辑校正一次即可。

测量精度和速度永远是矛盾的两端,这个系统把优先级放在精度上,核心收益全部来自硬件分压网络和软件均值滤波的配合。调采样周期时,先用示波器确认纹波频率,再回头算窗口长度,比盲目加大采样次数更省事。

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

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

diagram-design:逻辑表达的工程化设计方法论

1. “diagram-design”不是一张图&#xff0c;而是一套工程化表达语言“diagram-design”这个词最近在前端、产品、架构和教学类项目里高频出现&#xff0c;但它既不是某个新出的 npm 包&#xff0c;也不是某家公司的私有工具代号——它本质上是一套围绕“可视化逻辑表达”展开…

作者头像 李华
网站建设 2026/9/10 11:03:10

多 GPU JAX 训练如何开启 PGLE,让集合通信与计算重叠

多 GPU JAX 训练如何开启 PGLE&#xff0c;让集合通信与计算重叠 【免费下载链接】jax Composable transformations of PythonNumPy programs: differentiate, vectorize, JIT to GPU/TPU, and more 项目地址: https://gitcode.com/GitHub_Trending/ja/jax 在多 GPU 上跑…

作者头像 李华
网站建设 2026/9/10 11:01:02

CANN/GE内核工具使用说明

一、工具用途 【免费下载链接】ge GE&#xff08;Graph Engine&#xff09;是面向昇腾的图编译器和执行器&#xff0c;提供了计算图优化、多流并行、内存复用和模型下沉等技术手段&#xff0c;加速模型执行效率&#xff0c;减少模型内存占用。 GE 提供对 PyTorch、TensorFlow 前…

作者头像 李华
网站建设 2026/9/10 10:59:38

嵌入式QT车载影音系统C++源码:从工程结构到真机部署

简介&#xff1a;这是一套面向嵌入式与Qt开发学习者的车载影音系统完整工程&#xff0c;基于C在Qt/Embedded环境下实现&#xff0c;涵盖天气、视频、音乐、地图四大功能模块。天气模块通过HTTP请求并解析JSON数据展示未来5天预报&#xff1b;视频与音乐模块调用mplayer进程并支…

作者头像 李华