单片机DIY多功能充电器:恒流恒压、OLED显示、容量估算

📅 发布时间:2026/9/1 7:59:16
单片机DIY多功能充电器:恒流恒压、OLED显示、容量估算 简介面向单片机与嵌入式初学者的多功能充电器设计资料包以Philips 12C5410AD单片机为控制核心面向课程设计、电子竞赛及日常DIY充电方案重点解决电池类型自动识别、充电电压电流检测和过充欠充保护等工程问题。压缩包共11个文件包含C语言源程序low001.c、Keil工程文件uvproj/uvopt/plg、编译中间与结果文件obj、lst、m51、hex以及说明txt能够清晰呈现程序编写、编译到生成烧录文件的全过程工程结构简单适合快速上手。整个资源包仅66KB内容精炼目前已有201人学习下载。资料中单片机利用内置ADC实时采集电池电压和电流通过判断电池初始特征区分镍氢、镍镉、锂离子等类型并据此切换恒流、恒压或涓流充电模式同时设定过充和欠充阈值以确保安全。源码量适中关键逻辑注释清晰便于读者深入理解自动识别和充电控制流程并移植到其它型号单片机。 手头攒了一堆18650、镍氢电池还有一块闲置的12V适配器每次充电都得翻出不同的充电器桌面乱成一团不说关键有些充电器还只能充特定类型的电池。后来我干脆用单片机自己造了一台多功能充电器支持锂电池、镍氢电池、铅酸电池三种电池类型的恒流/恒压充电还带了OLED显示、容量估算和温度保护。这篇就把整个设计思路、硬件选型、软件架构和实测中踩过的坑完整记录下来给想做类似项目的朋友一个可以直接参考的实战方案。这个项目适合有一定单片机基础、又想从点灯进阶到带功率控制的开发者。整个系统不算复杂但把采样放大、Buck降压、状态机、PID调节、多任务调度这些嵌入式常用技术都串了起来做完之后对电源类项目的理解会明显上一个台阶。我会尽量把每个关键决策背后的理由都说清楚让大家不只照着焊还能明白为什么要这么做。1. 为什么是单片机而不是充电管理专用芯片1.1 现成芯片方案的局限市面上充电管理IC非常多比如TP4056、CN3791、BQ24650这些选型得当的话外围电路比单片机方案简单得多。但我一开始就没打算走这条路——专用芯片的充电参数是写死的或者只能通过电阻组合选择有限的几档想做一台通吃的充电器很麻烦。而且锂电池、镍氢、铅酸这三类电池的充电策略完全不同用专用IC就得做三种独立电路成本和体积都兜不住。纯硬件方案还有一个问题调试时一点都不直观。电压电流只能靠万用表点测想看清楚整个充电过程的变化曲线非常痛苦。而单片机方案的好处是参数改固件就能变状态全部可以显示在屏幕上出了问题也能通过日志定位。1.2 单片机方案的技术底座选择单片机做控制核心本质上是把模拟电源控制变成了数字电源控制。充电过程的恒压、恒流、截止判断都交给ADC采样软件算法来处理。这样做最大的优势是灵活想要4.25V截止就改一个宏定义想要100mA的涓流预充就改一个状态跳变阈值不需要动硬件。主控我选了STC8系列属于51内核主频跑到24MHz没问题内置12位ADC和硬件PWM。之所以没用STM32一方面是这个项目需要的资源不多STC8完全够用另一方面51生态的资料太全了很多刚入门的朋友也熟悉51的寄存器操作。至于有些人担心的浮点运算在PI调节器里我全程用定点运算跑起来毫无压力。1.3 功能框架与整体目标这个项目的功能规划我列了一个清单也建议大家在做同类型项目时先列清楚不然一边写代码一边加需求很容易乱。功能项实现说明电池类型选择锂电3.0V~4.2V、镍氢1.2V×N、铅酸12V充电模式预充、恒流CC、恒压CV、截止四段式状态机显示0.96寸OLED显示电压、电流、容量、状态交互单按键循环切换模式长按进入参数设置安全保护电池反接检测、过流保护、NTC温度保护扩展功能放电模式可估算电池实际容量2. 功率电路与采样网络硬件设计的关键决策2.1 Buck降压拓扑与MOS驱动电路充电器的核心功率拓扑我选了Buck降压结构。12V输入输出需要覆盖2V到14.6V的范围最大电流3ABuck是最合理的方案。主开关用一颗N沟道MOS管IRLZ44N逻辑电平型Vgs阈值只有1V左右为什么强调逻辑电平因为驱动电压来自单片机PWM引脚高电平才5V。如果选了普通电平的MOS5V驱动会让管子工作在放大区瞬间发热就能把手摸出水泡。驱动电路上不能直接用单片机IO直驱MOS。单片机IO口驱动能力有限且驱动高边MOS时源极电位会漂移所以中间加了一级三极管推挽驱动。Q1是低边驱动管Q2是高边驱动管两只三极管组成互补推挽结构既能快速充放电栅极电容又能保证栅极驱动电压足够。功率电感这里要注意选饱和电流大于5A的型号否则大电流时电感量塌陷纹波会严重到影响控制环。2.2 采样电路的增益计算与器件选型ADC采样的精度决定了整个充电控制的稳定性。我用0.05Ω、5W的绕线电阻做电流采样电阻满量程3A时压降150mV这电压太小直接送ADC等于把噪声和信号一起采所以必须放大。运放我选LM358搭同相放大电路放大倍数11倍[ V_{out} I \times R_{sense} \times \left(1 \frac{R_f}{R_g}\right) ]算一下3A的时候 Vout 3 × 0.05 × 11 1.65VSTC8的ADC参考电压是2.5V留了约0.85V的余量避免满量程时接近顶格导致失真。放大后的信号经一级RC低通滤波截止频率约1.6kHz再进ADC。电压采样就更直接了。输出端最高14.6V直接接ADC肯定烧引脚用电阻分压网络1/11比例衰减再送ADC引脚。分压电阻用1%精度金属膜串联的均衡电阻有助于减少温漂影响。这里有个细节分压网络的地必须和采样电阻的冷端共用同一个模拟地不能在主功率地线上串接否则采样结果会叠加地线压降误差。2.3 接线保护反接、过流、温度NTC充电器最怕的是接反电池一个反接可能直接烧掉采样电阻和续流二极管。我设计了一个简单有效的反接检测电池接入后经过一个分压网络二极管挡位分压点电压为负利用单片机ADC检测负压通过叠加偏置电压即可判断是否反接。一旦判定反接立即断开充电MOS并报警提示。过流保护方面除了软件在ADC里检测我在硬件上还加了一个熔断器和一只自恢复保险丝双保险。温度探头用10K NTC贴在电池仓旁边接分压电路进ADC当电池温度超过45℃就自动降低充电电流超过55℃强制停机。这个功能做出来后用了不止一次——有次电池是劣质货充电到一半明显发烫NTC直接拉停了。3. 软件架构状态机、PID与时间片调度3.1 三段式充电状态机转换逻辑充电控制的软件核心是一个状态机看起来就这么几种状态但状态跳转条件要写得非常严谨否则会出现充电不满或者过冲的问题。状态进入条件退出条件控制方式待机上电 / 充满检测到电池接入且电压2.8V关闭PWM输出预充电池电压2.8V电池电压升至2.8V100mA恒流恒流充电预充完成电池电压到达目标恒压值电流环PI目标1A恒压充电电压到达4.2V/7.2V/13.8V电流降至设定截止电流电压环PI占空比微调充满截止电流维持5分钟拔掉电池关闭PWM显示充满状态机的好处是逻辑清晰任何时间点都知道系统在干什么也方便加入异常分支比如温度过高随时可以进入保护态。预充阶段是非常容易被忽略的一块过放电池如果直接上大电流充电内部可能有短路析锂风险必须先用小电流让电压慢慢恢复。我设定了一个2.8V阈值低于这个值一律先预充。3.2 PID的工程简化为什么我用改进型PI而不是标准PID充电控制环路本质上是电压环和电流环交叠工作。标准PID有微分项但在这个项目里ADC采样本身有噪声微分项会放大噪声导致PWM占空比抖动反而让输出电压不稳。所以我把D项砍掉只用了PI。实际测试下来动态响应完全够用。具体实现是增量式PI[ \Delta u_k K_p \times (e_k - e_{k-1}) K_i \times e_k ]其中 e_k 是当前误差e_{k-1} 是上次误差。为什么用增量式因为它天然带积分抗饱和能力——如果输出已经限幅下次累加时误差累积不会无限膨胀。我在实现时还加了一组条件输出PWM占空比限制在5%~88%之间防止启动瞬间占空比过冲导致冲击电流。每个控制周期输出前要做一次环路选择电压环算出一个占空比电流环算出一个占空比取两者中较小的那个作为实际输出。这个逻辑在电源控制里叫低选门目的是让系统在任一时刻都被更保守的环路约束不会出现电池已经到达4.2V但电流还没降下来的危险情况。3.3 1ms时基下的多任务调度与实时性很多朋友用51单片机时遇到过一个问题想同时做按键扫描、OLED刷新、ADC采样、充电控制结果一部署就乱套。我这次用的方案是定时器中断产生时基 主循环任务表调度。定时器0配置为1ms中断一次中断服务函数里只做三件事喂软件计数器、置标志位、做一次时间片计数。所有实际任务都放在主循环中根据标志位执行。任务按需要分在不同优先级PD控制环每5ms执行一次温度检测每200ms执行一次OLED刷新每100ms执行一次按键扫描20ms一次。任务表的核心是把实时性要求高的充电控制放在高频执行把显示这类低频任务放在较低频。即使某一帧显示因为耗时掉了几毫秒充电环路也不会被拖慢。这个架构不止适合这个项目后续做其他带多个外设的单片机项目同样可以直接复用。4. OLED显示、按键交互与参数标定4.1 显示界面用一块OLED讲清楚充电状态显示部分我选的0.96寸OLEDSSD1306驱动I2C接口只占两根IO口。界面分三屏按顺序排布第一屏为充电主界面实时显示电压、电流、充电模式和已充入的估算容量第二屏为模式设置界面显示当前选择的电池类型第三屏为系统信息界面显示温度、PID参数校准系数等。关键数据刷新策略是电压电流每100ms刷新一次容量数据1秒刷新一次。OLED刷新频率太高会闪烁太低了让人觉得卡顿100ms这个频率模拟下来观感最自然。I2C驱动这里要注意总线速率设为400kbps更流畅SSD1306本身支持这个速率。4.2 单按键交互短按切换长按设置界面交互只有一个按键这其实比一堆按键更考验逻辑设计。短按在不同显示页面间切换长按2秒进入参数设置。进入设置后短按调整参数值加一档每500ms自动保存到EEPROM长按退出设置。实际操作体验下来设置电池类型最多需要6次短按加1次长按基本10秒内能完成操作。按键抖动处理用的是20ms延时连续确认法没有用外部中断节省引脚。4.3 校准方法没有高精度设备怎么标定ADC转换结果和真实物理量之间一定存在偏差主要来源于采样电阻容差、分压电阻偏差和运放失调电压。如果不对这些偏差做校正显示电压可能偏差0.1V恒压截止点偏差更明显。我的做法是双点标定第一步用一个万用表哪怕是几十块钱的测出充电器空载时的实际输出电压记下 ADC 读数第二步接一个可调电阻负载调整到另一个电压点记录第二组数据。然后软件里建立线性映射[ V_{real} V_{adc} \times K B ]K 和 B 就是标定系数通过两组数据反推出来。得到系数后烧录进EEPROM之后每次开机自动读取。值得注意的是这个校准参数必须在整机老化30分钟后再做因为LM358热漂移会让初始阶段的读数偏移几个毫伏。5. 实测与排坑从炸管到稳定运行的完整过程5.1 纹波导致的ADC抖动差点让我怀疑运放坏了第一版硬件实测时发现一个问题充电电流纹波非常大OLED上显示的电流值在0.8A到1.4A之间快速跳动用示波器测采样点波形上面叠加了很大幅度的开关噪声。排查过程先怀疑是运放的问题换了一颗LM358还是无解。后来仔细看波形才发现噪声不是来自运放而是来自采样点到运放输入这段走线。因为这段线比较长而且旁边就是功率电感开关节点的高频噪声直接耦合进来了。解决方式把采样走线改成紧贴地线的屏蔽结构在PCB上做包地处理同时在运放输入端加了一个1K104的RC低通滤波。改了之后纹波从±300mV降到了±30mV以内ADC跳动基本收敛到1个数字量。5.2 MOS驱动不足的发热逻辑电平MOS也救不了所有问题第二版测试时用小电流0.5A充电MOS管居然烫手。一开始以为是管子质量问题后来量了栅极波形才发现驱动电阻太大了我最初选了100Ω栅极电阻栅极电容充放电时间常数过大导致MOS开关边沿非常缓。开关损耗在100kHz开关频率下直接转化为热量。解决方法是把栅极电阻降到10Ω同时增加了一个三极管推挽驱动级的输出能力把栅极充放电时间从2微秒压到200纳秒。实测满载3A充电一小时散热片温度稳定在60℃左右完全可接受。5.3 电池热插拔导致的反向冲击真正让我吃了一次教训的是电池接入瞬间的问题。第一版程序里充电MOS在待机状态下是关闭的这没问题。但当电池被接入的时候电池电压会反向经过续流电感回路倒灌到Buck的输出电容上瞬间电流把板载电源引脚干短路了一次。后来我加了一个防倒灌二极管在输出回路中同时把单片机上电初始化时的GPIO状态配置为输入模式不输出高电平确保充电MOS默认关闭硬件上和软件上双重防止了热插拔反向冲击。另外一个容易被忽略的细节是MOS管控制充电通路时下管栅极放电如果速度太慢会导致关断瞬间Vds尖峰过高这时候在DS两端并联一个RC吸收电路100pF10Ω实测尖峰从40V压到了22V以下。5.4 延伸玩法放电测容量模式硬件做稳定后我又加了一个放电测容量模式把充电器输出端接一个固定功率电阻用PWM调节放电电流实时记录放电电流和放电时间用安时积分法估算电池真实容量。虽然精度比不上专业电池测试仪但相对误差能做到5%以内对判断18650是否老化非常有参考价值。5.5 稳定性验证结果整套系统调到最终状态后我做了一轮完整的参数测试测试项设计指标实测结果锂电池恒压精度±1%4.19V~4.21V之间满足恒流精度±5%0.96A~1.03A之间满足镍氢充满检测-ΔV或最高温升用最高电压1.45V截止实测正常铅酸浮充电压13.8V13.79V~13.82V之间满足充满截止电流设定50mA48mA~52mA之间满足我个人在实际操作中最大的感受是这类带功率的项目软件只占了四成功夫六成的精力都要花在硬件调试和排查上。尤其是采样、地线、驱动这三块任何一个环节偷懒最后都会在测试阶段找上门。如果大家也想复刻这个项目建议一定先把采样和地线处理好再开始写PID否则你会同时面对多个变量根本无法定位问题根源。本文还有配套的精品资源点击获取