简介:本资源是一份面向嵌入式初学者与移动电源开发者的应广单片机实战代码包,聚焦移动电源核心功能实现,涵盖按键交互、LED状态指示、充电管理及电池保护等关键模块。压缩包共33个文件,含11个.lb0与11个.lb_目标代码文件(用于烧录与调试)、2个.pj0与2个.pj_工程配置文件、1个.hex可执行镜像、1个.pdk项目定义、1个.h头文件、1个.c主程序源码及配套.prj/.tmp/.pre等工程支持文件,总大小仅140KB,结构紧凑,便于快速导入IDE分析与复现。已有257人学习下载,适合希望理解单片机底层控制逻辑、掌握C语言在电源管理场景中实际应用的学习者。读者可直接基于该工程梳理完整状态机流程、解析ADC采样与GPIO驱动细节,并参考多版本LB文件对比不同固件迭代逻辑,是入门移动电源固件开发的典型参考范例。
1. 项目概述与背景解析
最近在整理老硬盘时,翻出来一个名为“SampleCode_20140701.rar_移动电源_移动电源代码(应广单片机)”的压缩包。这名字一看就很有年代感,2014年的代码,针对的还是应广(PADAUK)单片机。对于很多从那个时代过来的硬件工程师或电子爱好者来说,应广单片机绝对是一个绕不开的名字,尤其是在消费类电子、小家电和像移动电源这类低成本、高量产的方案中。这个压缩包,本质上就是一个基于应广单片机的移动电源参考设计源码。今天,我就以这个“古董”代码为引子,和大家深入聊聊基于8位MCU的移动电源设计核心,以及如何解读、复现乃至优化这类老方案。无论你是想学习移动电源的基本原理,还是手上正好有应广的开发板想练手,或者单纯对那个“万物皆可8位机”的时代感兴趣,这篇文章都能给你带来一些实实在在的参考。
移动电源,或者说充电宝,其核心功能看似简单:给内置的锂电池充电,再将电池的电能升压(或降压)到5V USB标准电压输出。但在2014年前后,智能手机开始普及,市场对移动电源的需求爆发,如何在极低的成本下实现稳定、安全且有一定智能化的充放电管理,就成了众多方案商角逐的战场。应广单片机以其极致的性价比和够用的性能,成为了当时许多中小方案公司的首选。这份代码,就是那个时代技术方案的一个典型切片。它不仅仅是一段代码,更承载了一套完整的硬件设计思路、电源管理逻辑和成本控制哲学。通过拆解它,我们能学到如何在资源受限的MCU上,通过软件巧妙地实现硬件功能,这对于今天从事嵌入式开发,尤其是对功耗和成本敏感的物联网设备开发,依然有很高的借鉴价值。
2. 移动电源核心架构与应广单片机选型解析
2.1 移动电源的经典三模块架构
一个典型的移动电源,无论其主控芯片是简单的专用芯片(ASIC)还是像应广这样的通用MCU,其硬件架构都离不开三个核心模块:充电管理模块、电池保护模块和升压输出模块。软件的所有逻辑,都是围绕服务和协调这三个模块展开的。
充电管理模块负责将外部输入的5V USB电压,转换为适合锂电池的恒定电流/恒定电压(CC/CV)充电曲线。在早期的低成本方案中,这个功能往往由一颗独立的充电管理IC(如TP4056)完成,MCU只负责监测充电状态(如是否接入电源、是否充满)。但在一些更集成或追求极致成本的设计中,MCU会通过PWM控制一个MOSFET和分压电阻网络,配合软件算法来实现简单的恒流恒压充电,这就对MCU的ADC采样精度和定时器控制提出了要求。
电池保护模块是安全底线,通常由一颗专用的电池保护板(如DW01+8205方案)实现,提供过充、过放、过流和短路保护。MCU需要读取保护板的状态(如通过检测某个IO口的电平),并在保护触发时做出相应提示(如LED闪烁报警)。
升压输出模块是整个系统的“发动机”,负责将电池的电压(标称3.7V,范围约3.0V-4.2V)升压到稳定的5V输出。这通常由一个Boost升压芯片及其外围电感、电容、二极管构成。MCU的核心任务之一是控制这个升压电路的开启与关闭(EN引脚),并监测输出状态,比如是否有设备插入(通过检测USB口的D+/D-电平或输出电流)、输出是否过载或短路。
2.2 为什么是应广单片机?
在2014年,面对移动电源这个红海市场,方案商对主控MCU的选择几乎只有一个标准:在满足功能的前提下,成本最低。应广(PADAUK)的8位OTP(One-Time Programmable)单片机正是这方面的“王者”。OTP意味着芯片出厂后程序只能写入一次,无法再次修改,这听起来很不灵活,但却带来了两大优势:一是芯片本身结构简单,封装小(常见为SOP8、SOP16),二是成本可以做到极低,当时一颗SOP8的应广MCU单价可能仅几毛钱人民币。
以这份代码可能针对的应广 PMS150C(SOP8封装)或 PMS154C(SOP14封装)为例,它们通常具备:
- 1K~2K Words的OTP程序存储器:对于移动电源这种逻辑相对固定的控制程序,完全够用。
- 64~128 Bytes的SRAM:需要精打细算地使用变量。
- 最多6个可用的IO口:在SOP8封装下,除去电源引脚,可能只有5-6个IO,每一个都无比珍贵。
- 一个精度尚可的ADC:用于检测电池电压、输入电压、输出电流等模拟量。
- 基本的定时器/计数器:用于产生PWM、进行时间计量和按键消抖。
资源如此紧张,就要求程序员必须具备极强的“挤牙膏”能力,用最精简的代码实现所有功能。例如,一个IO口可能通过分时复用来驱动不同颜色的LED,或者通过ADC测量不同节点的电压时需要快速切换通道并做软件滤波。这份2014年的代码,正是这种“极限编程”的典范。
注意:OTP芯片意味着代码烧录后无法调试和修改。因此,开发流程通常是先在可多次擦写的仿真器或EEPROM版本芯片(如应广的MINIC)上完成全部调试,确认无误后再烧录到OTP芯片中进行量产。拿到这类代码,第一步就是确认它对应的具体芯片型号和开发环境。
3. 代码结构与核心功能逻辑拆解
解压“SampleCode_20140701.rar”后,我们通常会看到几个关键文件:一个或多个.c和.h源文件,可能还有一个.asm汇编文件(应广开发中汇编很常见),以及一个工程文件(如.pj)或简单的编译脚本。代码结构不会很复杂,但非常紧凑。
3.1 主循环与状态机设计
由于资源有限,这类程序几乎不会使用实时操作系统(RTOS),而是采用一个超级循环(Super Loop)配合状态机(State Machine)的设计。主函数main()的结构通常如下所示:
void main() { sys_init(); // 系统初始化:配置IO、ADC、定时器、中断等 while(1) { // 超级循环 key_scan(); // 按键扫描,检测短按、长按 adc_sample(); // ADC采样电池电压、输入电压等 state_machine(); // 核心状态机处理 led_display(); // 根据状态更新LED或数码管显示 delay_ms(10); // 一个简单的延时,控制循环周期 } }核心状态机是程序的灵魂。移动电源的工作状态可以抽象为有限的几种:
- 待机状态(STANDBY):无输入无输出,系统以极低功耗运行,仅维持按键检测。
- 充电状态(CHARGING):检测到USB输入,开启充电电路。根据电池电压,细分为涓流充电、恒流充电、恒压充电等子状态。
- 放电状态(DISCHARGING):检测到负载插入,开启升压输出电路。
- 故障状态(FAULT):如电池过放、输出短路、充电超时等,进入此状态并关闭所有功率电路,通过LED报警。
状态之间的转换由事件触发,例如“插入USB线”、“按下按键”、“负载移除”、“电池电压达到4.2V”等。state_machine()函数内部就是一个大的switch(state)语句,根据当前状态和发生的事件,决定下一个状态并执行相应的动作。
3.2 关键外设驱动与算法实现
1. ADC采样与电池电量计算电池电压的测量是移动电源的“眼睛”。通常通过一个电阻分压网络将电池电压(最高4.2V)分压到MCU的ADC量程内(例如1.2V内部参考电压)。代码中会有类似adc_get_bat_voltage()的函数。 电量计算(俗称“电量显示”)是难点。锂电池的电压与电量(SOC)并非线性关系,且受负载电流、温度影响。在低成本方案中,往往采用简单的电压分段法:
- 电压 >= 4.15V:显示4格电(100%)
- 电压在 3.90V - 4.15V:显示3格电
- 电压在 3.75V - 3.90V:显示2格电
- 电压在 3.60V - 3.75V:显示1格电
- 电压 < 3.60V:显示0格电或闪烁报警 为了读数稳定,需要对ADC值进行软件滤波,比如连续采样多次取平均值。
2. 按键检测与多功能处理通常只有一个按键,通过检测按下时间来实现不同功能:短按(<1秒)查看电量或开启输出,长按(>3秒)开启或关闭输出。代码中会有一个key_scan()函数,它必须在循环中定期被调用,内部使用一个状态机来区分单击、长按和释放,并做好消抖处理。
3. LED/数码管显示驱动为了节省IO,LED驱动常采用扫描方式。例如,用3个IO口控制3个LED来显示4档电量(000-灭,001-1格,011-2格,111-3格,某个特定闪烁模式代表4格或充电中)。如果是数码管,则会用到动态扫描,这对定时器的精度有要求。
4. 充放电控制与保护逻辑
- 充电控制:如果使用MCU直接管理充电,会有一个
charge_control()函数,根据ADC采样的电池电压和设定的充电电流(可能通过另一个ADC通道采样采样电阻上的电压),调整PWM占空比来控制充电MOSFET,模拟CC/CV过程。 - 放电控制:
discharge_control()函数负责控制升压芯片的使能端(EN)。在开启输出前,必须检测电池电压是否高于欠压保护点(如3.3V)。输出开启后,需要持续监测输出电流(通过ADC采样电流采样电阻的压降),一旦过流立即关闭输出。 - 软件保护:作为硬件保护板的补充,软件需要实现二次保护,例如充电超时(超过8小时强制停止)、温度监控(如果MCU有温度传感器或外接NTC)等。
4. 基于现代环境的代码复现与调试要点
如果你手上正好有应广的仿真器(如PFS154的开发板)和MINIC芯片,想实际运行一下这份老代码,或者借鉴其思路用现代MCU(如STM8、STC15、甚至ARM Cortex-M0)重新实现,需要注意以下关键点。
4.1 开发环境搭建与代码移植
应广有自己的集成开发环境,通常是一个比较简易的IDE。你需要先确认代码对应的具体芯片型号(如PMS150C、PMS154C),然后安装对应的编译器。老代码可能会遇到编译器版本兼容性问题。
如果移植到其他平台(如STM32),需要做以下工作:
- 硬件抽象层重写:将代码中所有直接操作应广特殊功能寄存器(SFR)的部分,替换为STM32 HAL库或标准库的函数。例如,应广的
PAC、PA寄存器操作,要改为STM32的GPIO_WritePin,GPIO_ReadPin。 - 外设重新配置:STM32的ADC、定时器、PWM等功能更强大,配置也更复杂。你需要根据移动电源的需求,重新初始化这些外设。比如,STM32的ADC可以配置为连续扫描模式,自动循环采样多个通道,这比应广的单次采样软件切换要高效。
- 逻辑代码复用:状态机、按键扫描算法、电量计算算法、保护逻辑等核心业务代码,是高度独立于硬件的,可以几乎原封不动地移植过来。这是分析老代码最大的价值所在。
4.2 核心功能模块的调试顺序
在复现或调试时,建议按以下顺序逐个模块验证,确保基础牢固:
- 系统时钟与基本IO:先让一个LED闪烁起来,确认MCU最小系统和工作频率正常。
- ADC采样:编写代码读取电池电压分压点的ADC值,并通过串口打印出来(如果MCU支持)。用可调电源模拟电池电压,从3.0V到4.2V变化,检查ADC读数是否线性变化,并校准分压系数。
- 按键检测:实现按键扫描,能稳定识别短按和长按,并通过串口或LED反馈。
- 状态机框架:搭建一个简单的状态机框架,实现待机、充电、放电等状态的空壳子,并通过按键触发状态切换,用串口打印当前状态。
- 充电模块:如果使用独立充电IC,先调试其基本功能(插入USB是否能亮充电灯)。如果是MCU控制充电,则需要用电子负载模拟电池,仔细调试PWM输出和电流采样反馈环,这是一个难点,务必小心避免过充。
- 升压输出模块:这是最需要谨慎对待的部分!先不接电池,用直流电源给升压电路供电,测量空载时输出电压是否为5V。然后接上电子负载,从小电流(如0.1A)开始慢慢增加,观察输出电压是否稳定,并测试过流保护点是否准确。
- 集成与保护测试:将所有模块整合,进行完整的充放电循环测试。重点测试各种边界和异常情况:电池低压保护、输出短路保护、充电器插入/拔出、负载插入/拔出等。
4.3 常见问题排查与实战技巧
在实际动手过程中,你肯定会遇到各种问题。下面是一些常见坑点和解决思路:
问题一:ADC读数跳动大,电量显示不稳定。
- 原因:电源噪声、分压电阻热噪声、ADC参考电压不稳、采样时间不足。
- 解决:
- 在ADC输入引脚靠近MCU处加一个0.1uF的滤波电容。
- 软件上采用多次采样取平均值+软件滤波(如一阶滞后滤波)。
- 确保MCU的AVDD电源干净,最好由LDO单独供电。
- 检查并校准ADC的内部参考电压(如果可用)。
问题二:升压电路效率低,发热严重。
- 原因:电感选型不当(饱和电流不够或DCR太大)、续流二极管正向压降高、MOSFET开关损耗大、布局布线不良导致寄生参数大。
- 解决:
- 选择饱和电流远超最大输出电流的功率电感(通常要留1.5倍余量)。
- 在满足耐压和电流的前提下,优先选用肖特基二极管,其正向压降比普通二极管低。
- 检查升压芯片的开关频率和驱动能力是否与所选MOSFET匹配。
- 布局是开关电源的生命线!务必保证大电流路径(电感-二极管-输出电容)尽可能短而粗,地平面完整。
问题三:轻载时(手机充满后)输出电压偏高,可能损坏设备。
- 原因:许多低成本Boost芯片在轻载时会进入脉冲跳跃模式(PFM),导致输出电压纹波增大,平均电压可能偏高。或者反馈电阻分压网络精度不够。
- 解决:
- 在输出端增加一个假负载电阻(例如1KΩ),强制让芯片在轻载时也有一定电流,维持正常工作模式(PWM)。但这会增加待机功耗,需要权衡。
- 选用在轻载下仍能稳定工作的升压芯片,或带有轻载高效模式的芯片。
- 使用精度为1%的反馈分压电阻。
问题四:长按按键关机后,待机功耗依然很高。
- 原因:升压芯片的使能端(EN)虽然被MCU拉低,但芯片本身静态电流可能较大;或者MCU未进入低功耗模式;又或者某些外围电路(如LED指示电路、电压检测分压电阻)仍在消耗电流。
- 解决:
- 选择待机电流极低的升压芯片(<10uA)。
- 在软件上,当系统进入深度待机时,将MCU本身设置为休眠或停机模式,并通过外部中断(按键或USB插入检测)唤醒。
- 检查所有连接到电池的电路。对于电压检测分压电阻,其阻值应尽可能大(如1MΩ+200KΩ),或者通过一个MOSFET开关在需要测量时才接通。
实操心得:调试开关电源电路,一个可靠的可调直流电源和一台电子负载是必不可少的。调试时,务必先使用直流电源代替电池供电,这样你可以方便地设置限流点,避免电池过放或短路时产生危险。另外,一个热成像仪或至少一个温度枪,能帮你快速定位发热元件,这是优化效率和可靠性的利器。
5. 从老方案到新思路的演进思考
分析这份2014年的代码,我们能清晰地看到当时设计上的取舍:为了成本,牺牲了灵活性(OTP)、性能(8位机)和部分用户体验(简单的电压电量法)。时过境迁,如今移动电源方案已经发生了巨大变化。
技术演进方向:
- 主控芯片升级:32位ARM Cortex-M0内核的MCU(如灵动微、华大等国产芯片)价格已非常亲民,它们提供更丰富的资源(Flash、RAM、外设)、更低的功耗和在线调试能力,使得实现更复杂的快充协议(如QC、PD)、数字电量计、智能温控等成为可能。
- 电量计量精准化:单纯的电压法已被库仑计(电流积分)方案取代,甚至集成高精度库仑计的电池管理IC(如TI的BQ系列)也广泛应用,电量显示准确度大幅提升。
- 快充协议集成:从早期的Apple 2.4A、BC1.2,到高通QC、USB PD,现在主控MCU需要集成或配合专门的协议芯片,与手机/笔记本进行电压电流协商,实现快速充电。
- 双向快充与多口输出:高端移动电源支持输入输出双向快充,并配备多个USB-A/C口,能同时为多台设备充电,这需要更复杂的多路电源管理和协议调度。
对于学习者的价值:尽管方案已变,但底层原理不变。这份老代码就像一本经典的“内功心法”,它教会我们:
- 如何在极度受限的资源下进行系统设计——这是嵌入式工程师的核心能力。
- 状态机在事件驱动型应用中的核心地位——这种编程思想在任何复杂度的系统中都适用。
- 安全与保护逻辑的优先级永远最高——无论功能多炫酷,安全是产品的基石。
- 硬件与软件的紧密协同——理解每一个IO、每一次ADC采样背后的硬件电路,才能写出稳定可靠的代码。
因此,我建议初学者不要轻视这类“过时”的代码。你可以用它来练手,在应广或类似的8位机平台上复现一个基本的移动电源,彻底吃透每一个细节。然后,再尝试用一颗现代的32位MCU去重新实现它,并加入快充协议、OLED显示等新功能。这个过程,会让你对嵌入式系统和电源管理有一个从骨髓到皮肤的全方位理解。这份“SampleCode_20140701.rar”不仅仅是一个压缩包,它更像一个时间胶囊,里面封存着那个时代工程师的智慧与务实,打开它,与过去对话,能更好地照亮你前行的路。
本文还有配套的精品资源,点击获取