ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

基于 uC3845 与 ATtiny13 双芯片架构的 8.4V/2.5Ah 锂电池智能充电器设计

基于 uC3845 与 ATtiny13 双芯片架构的 8.4V/2.5Ah 锂电池智能充电器设计 目录:1. 方案概述2. 系统架构2.1 初级侧反激变换电路2.2 次级侧充电管理电路2.3 采样电路2.4 PWM 扩展电路2.5 LED 指示与串口通信2.6 ATtiny13 固件主循环流程2.7 初级侧关键元器件选型与计算2.8 常见故障与调试指南2.9 次级侧采样与 PWM 扩展电路参数计算2.10 ATtiny13 固件设计要点2.11 充电控制软件流程2.12 关键元器件选型汇总表3. 充电模式与状态切换3.1 空闲模式(IDLE)3.2 预充模式(PRE)3.3 恒流模式(CC)3.4 恒压模式(CV)3.5 终止模式(DONE)3.6 错误模式(FAULT)3.7 切换阈值与超时参数汇总3.8 模式切换的软件实现与边界处理3.9 完整充电过程的电压电流曲线特征4. 性能测试与验证4.1 测试环境与设备4.2 恒流模式实测波形与数据4.3 恒压模式实测波形与数据4.4 不同温度下的充电效率测试4.5 不同温度下的纹波电压测试4.6 不同温度下的稳定性测试4.7 测试数据分析与结论4.8 编译环境配置与烧录步骤5. 本文创新点6. 总结7. 参考资料摘要:本文介绍一款基于 uC3845 与 ATtiny13 双芯片架构的 8.4V/2.5Ah 锂电池充电器设计方案。初级侧采用 uC3845 电流模式 PWM 控制实现反激式 AC/DC 转换,次级侧由 ATtiny13 完成充电流程控制与状态监测,并通过 4 位扩展法将 8 位 PWM 提升至 12 位精度,实现恒压 8.4V 的精确调节。文章详细说明系统架构、采样电路、PWM 扩展方法,以及空闲、预充、恒流、恒压、终止、错误六种充电模式的切换逻辑。关键词:uC3845;ATtiny13;锂电池充电器;反激变换器;PWM 扩展;恒流恒压充电;8.4V 锂电池;充电状态机下图给出充电器的整体系统架构框图,展示初级侧反激变换、次级侧充电管理、采样电路、PWM 扩展、LED 指示与串口通信之间的信号流向与协作关系。flowchart LR AC["市电输入 AC 220V"] -- UC["uC3845 电流模式 PWM 控制"] UC -- T1["变压器 T1 反激变换"] T1 -- RECT["次级整流 主绕组 9V/3A 辅助绕组"] RECT -- BAT["8.4V/2.5Ah 锂电池包"] RECT -- FB["反馈回路 TL431 + 光耦"] FB -- UC BAT --gt; VS["电压采样 分压 + RC 滤波"] BAT -- IS["电流采样 采样电阻 + 运放"] BAT -- NTC["温度采样 NTC 热敏电阻"] VS -- MCU["ATtiny13 充电管理"] IS -- MCU NTC -- MCU MCU --gt; PWM["PWM 扩展 8 位 + 4 位扩展 = 12 位"] PWM -- DAC["RC 滤波 + 二极管 驱动 TL431 参考点"] DAC -- FB MCU --gt; LED["双色 LED 空闲/充电/充满/错误"] MCU -- UART["GPIO 模拟 UART Tx 串口电平转换"] UART -- PC["PC 机 RS232 参数记录"]图中左侧为初级侧功率通路:uC3845 驱动反激变压器 T1,次级整流后为电池包供电,输出电压经 TL431 与光耦反馈回初级侧,构成闭环稳压。右侧为次级侧控制通路:ATtiny13 通过电压、电流与温度三路采样判断充电状态,输出经 4 位扩展法扩展后的 12 位 PWM,经 RC 滤波后微调反馈参考点以控制充电电压与电流;同时驱动双色 LED 指示工作状态,并通过 GPIO 模拟 UART 将充电参数上报至 PC 机。关键设计参数表下表汇总本充电器的关键设计参数及其数值,便于快速查阅。各参数对应的详细说明与推导过程,可参见后文对应章节。参数数值说明来源章节输入电压范围AC 220V(市电)初级侧反激式 AC/DC 转换输入1. 方案概述输出电压8.4V锂电池包额定充电电压1. 方案概述电池容量2.5Ah8.4V/2.5Ah 锂电池包1. 方案概述充电电流(恒流)2.5A恒流充电模式设定值3. 充电模式与状态切换预充电流250mA预充模式小电流充电3. 充电模式与状态切换恒压值8.4V恒压充电模式输出电压3. 充电模式与状态切换限压值8.5V预充与恒流模式限压保护3. 充电模式与状态切换终止电流125mA(1/20C)充电电流低于该值判定充满3. 充电模式与状态切换PWM 频率4.68kHzATtiny13 PB0 输出 PWM 频率2. 系统架构PWM 分辨率8 位 + 4 位扩展 = 12 位4 位扩展法提高输出精度2. 系统架构次级主绕组输出9V / 3A(最大值)半波整流后为电池包充电2. 系统架构辅助绕组稳压5V为 ATtiny13 供电2. 系统架构1. 方案概述本方案是为 8.4V/2.5Ah 锂电池包设计的一款智能充电器,采用初级侧与次级侧双芯片分工协作的架构。初级侧以 uC3845 电流模式 PWM 控制器为核心,构成反激式 AC/DC 转换电路,将市电转换为隔离的直流电源;次级侧由 ATtiny13 单片机负责充电流程控制与状态监测,实现安全、精准的锂电池充电管理。系统整体设计目标可归纳为以下四个方面:充电安全:通过电压、电流与温度三路采样实时监测电池状态,配合空闲、预充、恒流、恒压、终止、错误六种充电模式的状态机切换,以及预充、恒流、恒压三级超时保护,确保电池在全生命周期内安全充电,避免过充、过放与过热风险。充电精度:针对 ATtiny13 仅有 8 位 PWM 硬件资源的限制,采用 4 位扩展法将 PWM 精度提升至 12 位,经 RC 滤波后微调 TL431 反馈参考点,实现恒压 8.4V 的精确调节,电压误差控制在 ±0.05% 以内。成本可控:uC3845 与 ATtiny13 均为成熟低成本的通用器件,配合精简的外围电路,整机物料成本可控,适合规模化生产。可观测性:通过 GPIO 模拟 UART 将电压、电流、温度及工作模式等充电参数实时上报至 PC 机,便于调试、数据分析与故障定位。充电器整体由初级反激变换电路与次级充电管理电路两部分构成,系统按功能可划分为初级侧反激变换电路、次级侧充电管理电路、采样电路、PWM 扩展电路以及 LED 指示与串口通信五个模块。初级侧以 uC3845 为核心完成 AC/DC 功率转换,输出电压经 TL431 与光耦反馈回初级侧构成闭环稳压;次级侧由 ATtiny13 根据采样结果判断充电状态,输出经 4 位扩展法扩展后的 12 位 PWM 微调反馈参考点,从而精确控制充电电压与电流。各模块的详细硬件设计要点见第 2 章,充电模式与状态切换逻辑见第 3 章,性能测试与验证结果见第 4 章。2. 系统架构充电器整体由初级反激变换电路与次级充电管理电路两部分构成。初级侧以 uC3845 为核心完成 AC/DC 功率转换,次级侧由 ATtiny13 负责充电流程控制与状态监测。系统按功能可划分为初级侧反激变换电路、次级侧充电管理电路、采样电路、PWM 扩展电路以及 LED 指示与串口通信五个部分,下面分别说明各部分的硬件设计要点。2.1 初级侧反激变换电路初级侧以 uC3845 电流模式 PWM 控制器为核心,完成市电到隔离直流的功率变换。uC3845 驱动功率 MOSFET 对反激变压器 T1 进行高频开关,次级整流后为电池包供电。输出电压经 TL431 与光耦反馈回初级侧 COMP 引脚,构成闭环稳压。初级侧关键设计要点包括:启动电阻从整流后的直流母线取电为 VCC 电容充电,使芯片在合理时间内达到 7.9V 启动阈值;电流采样电阻串联在 MOSFET 源极与地之间,将初级峰值电流转换为电压送入 ISENSE 引脚实现逐周期限流;反激变压器匝比由伏秒平衡确定,兼顾最低输入电压与最大占空比;TL431 反馈补偿网络采用 PI 结构,保证环路稳定。各元器件的详细选型与参数计算见 2.6 节。TL431 反馈补偿网络参数计算本设计输出电压目标为 8.4V(两节锂电串联满充电压),TL431 参考端基准电压 Vref = 2.5V。反馈分压网络由 R1(上分压电阻,接输出正极至 TL431 参考端)与 R2(下分压电阻,接参考端至地)构成,满足:Vout = Vref × (1 + R1 / R2)取 R2 = 10kΩ,则 R1 = (Vout / Vref − 1) × R2 = (8.4 / 2.5 − 1) × 10kΩ = 23.6kΩ,选用标准值 23.7kΩ(1% 精度)。此时实际输出电压为 2.5 × (1 + 23.7 / 10) = 8.425V,偏差约 0.3%,满足恒压精度要求。分压电阻应选用低温漂(±50ppm/°C 以内)的金属膜电阻,避免温度漂移导致输出电压偏移。PI 补偿网络的零极点配置TL431 与光耦构成的反馈环路采用 PI 结构,其传递函数可表示为:Gc(s) = (1 + s / ωz) / (s × C3 × (R1 // R2))其中零点由串联电阻 R3 与补偿电容 C3 决定:ωz = 1 / (R3 × C3)。PI 补偿的零点用于抵消输出滤波电容 ESR 引入的零点或提升低频增益,保证穿越频率处相位裕度大于 45°。反激变换器在满载时输出极点频率约为:fp = 1 / (2π × RL × Co)取负载电阻 RL = 8.4V / 2A = 4.2Ω,输出电容 Co = 470μF,则 fp ≈ 1 / (2π × 4.2 × 470 × 10⁻⁶) ≈ 80.6Hz。将补偿零点设置在输出极点附近,取 fz = 80Hz,则 R3 × C3 = 1 / (2π × 80) ≈ 1.99 × 10⁻³ s。取 C3 = 100nF,则 R3 ≈ 19.9kΩ,选用标准值 20kΩ。环路穿越频率通常设置为开关频率的 1/10 至 1/5。uC3845 开关频率取 100kHz,穿越频率 fc 设为 10kHz。在穿越频率处,功率级增益与补偿网络增益之和应为 0dB,据此可确定光耦次级侧电阻 R4 的取值,使低频增益足够高以保证稳态精度,同时在高频处快速衰减以抑制开关噪声。光耦传输比(CTR)对环路增益的影响光耦(如 PC817)的电流传输比 CTR 定义为输出侧集电极电流 IC 与输入侧发光二极管电流 IF 之比:CTR = IC / IF。PC817 的 CTR 典型值为 50%–600%,随温度升高而下降(-0.5%/°C 左右),且随使用年限老化而衰减。反馈环路增益与 CTR 成正比。当 CTR 从 200% 降至 100% 时,环路增益下降约 6dB,可能导致相位裕度减小、动态响应变差甚至振荡。设计时应按 CTR 下限(取 100%)进行环路补偿,确保在最恶劣条件下仍满足稳定性要求。同时,光耦输出侧集电极电阻 R4 的取值需保证在最小 CTR 时,uC3845 COMP 引脚仍能获得足够的拉电流范围以调节占空比。光耦输入侧限流电阻 R5 由输出电压与 TL431 阴极电压决定:IF = (Vout − VTL431_KA − VF) / R5。取 TL431 阴极电压 VKA ≈ 2.5V,光耦 LED 正向压降 VF ≈ 1.2V,要求 IF = 5mA,则 R5 = (8.4 − 2.5 − 1.2) / 5mA ≈ 940Ω,选用标准值 1kΩ。通过 PWM 占空比微调实现 8.4V 恒压的定量分析反激变换器在连续导通模式(CCM)下的输出-输入关系为:Vout = Vin × D × Ns / (Np × (1 − D))其中 D 为占空比,Np/Ns 为变压器原副边匝比。当负载或输入电压波动导致输出电压偏离 8.4V 时,TL431 参考端电压随之变化:若 Vout 升高,则 TL431 参考端电压超过 2.5V,其阴极电流增大,光耦 LED 电流 IF 上升,光耦输出侧拉低 COMP 引脚电压,uC3845 内部误差放大器输出降低,PWM 占空比减小,输出电压回落至 8.4V;反之亦然。定量分析如下:设输出电压偏差 ΔVout = 100mV,则 TL431 参考端电压变化 ΔVref = ΔVout × R2 / (R1 + R2) = 0.1 × 10 / (23.7 + 10) ≈ 29.7mV。TL431 的跨导约为 1.5S(典型值),对应阴极电流变化 ΔIKA ≈ 1.5 × 0.0297 ≈ 44.5mA,但受光耦限流电阻限制,实际 IF 变化由 R5 决定:ΔIF = ΔVKA / R5 ≈ 0.0297 / 1kΩ ≈ 29.7μA(此处 ΔVKA 近似等于 ΔVref 经环路放大后的变化量,实际由 TL431 内部增益决定)。光耦输出侧电流变化 ΔIC = CTR × ΔIF。取 CTR = 200%,则 ΔIC ≈ 59.4μA。该电流流过光耦输出侧电阻 R4(取 10kΩ),在 COMP 引脚产生电压变化 ΔVCOMP ≈ 0.594V。uC3845 的 COMP 电压与峰值电流检测电压的关系为:峰值电流 Ipeak = (VCOMP − 1.4V) / (3 × Rsense)。设电流采样电阻 Rsense = 0.33Ω,则 COMP 电压每变化 1V,峰值电流变化约 1A。因此 ΔVCOMP = 0.594V 对应占空比调整量约为:ΔD ≈ ΔVCOMP × (1 / Vramp) ≈ 0.594 / 3.5 ≈ 0.17其中 Vramp 为振荡器斜坡幅值(约 3.5V)。实际占空比调整量足以在半个开关周期内将 100mV 的输出偏差校正回来,实现 8.4V 的精确恒压调节。整个闭环响应时间由 PI 补偿网络的零点频率决定,约为 1 / (2π × 80Hz) ≈ 2ms,满足电池充电对电压纹波和稳定性的要求。2.2 次级侧充电管理电路次级侧以 ATtiny13(U1)为控制核心,负责充电流程控制与状态监测。变压器 T1 的次级主绕组经半波整流后输出电压最大值 9V、电流最大值 3A,为电池包充电;辅助绕组经半波整流后,一路为 uC3845 提供约 12V 的 VCC,另一路经 TL431 稳压至 5V 为 ATtiny13 供电。ATtiny13 根据电压、电流与温度三路采样结果判断当前充电状态,输出 PWM 经 RC 滤波后微调 TL431 参考点,从而精确控制充电电压与电流。充电流程涵盖空闲、预充、恒流、恒压、终止、错误六种模式,具体切换逻辑详见第 3 章。2.3 采样电路采样电路为 ATtiny13 提供电池电压、充电电流与电池温度三路模拟输入,是充电状态判断的依据。可以采用四分之一二阶滤波器。参考《四分之一二阶滤波器在充电系统中的应用:原理、C语言实现与工程选型指南》CSDN博客文章。电压采样:输出电压 Vout 经两只分压电阻分压后,再经 RC 滤波器连接到 U1 的 7 脚 PB2/ADC1,作为充电电压采样输入。分压比需保证最高采样电压(约 8.5V)经分压后不超过 ADC 参考电压。电流采样:次级充电回路中的电流采样电阻将充电电流转换为电压信号,经运算放大器放大后,再经 RC 滤波输入到 U1 的 3 脚 PB4/ADC2。运放增益与采样电阻阻值共同决定电流检测分辨率,需保证恒流 2.5A 与终止电流 125mA 均能被准确分辨。温度采样:电池包 NTC 热敏电阻连接到 U1 的 2 脚 PB3/ADC3,与固定电阻构成分压网络。温度变化引起 NTC 阻值变化,ADC 采样值随之改变,ATtiny13 据此判断电池温度是否超出安全范围,超限时转入错误模式保护电池。2.4 PWM 扩展电路ATtiny13 的 PB0 输出 4.68kHz 的 8 位 PWM,受限于芯片资源,直接输出的分辨率不足以精细调节充电电压。本设计采用 4 位扩展法,将 8 位 PWM 扩展为 12 位精度:低 4 位通过软件在多个 PWM 周期内按比例分配占空比实现,从而在不增加硬件成本的前提下显著提高输出精度。扩展后的 12 位 PWM 经 RC 滤波器平滑为直流电平,再经二极管 D1 连接到 TL431(U2)的参考端 1 脚。通过改变 PWM 占空比即可微调 TL431 参考点电压,进而微调次级输出电压,实现恒压 8.4V 的精确校准。主绕组的输出电压 Vout 另经两只分压电阻分压、RC 滤波后,经二极管 D2 也连接到 U2 的 1 脚,构成电压反馈通路。2.5 LED 指示与串口通信LED 指示:U1 的 PB5 控制一只双色 LED,用于指示充电器工作状态。红色闪烁 1Hz 表示正在充电,绿色常亮表示充满,红色常亮表示空闲,红色闪烁 2Hz 表示错误。不同模式下的 LED 状态与充电逻辑一一对应,便于用户直观判断当前状态。串口通信:U1 的 PB1 通过 GPIO 模拟 UART 的 Tx 输出,将充电参数以串行数据发送,经串口电平转换板转换为 RS232 电平后连接到 PC 机的 RS232 接口。PC 端可实时记录充电器的电压、电流、温度及工作模式等全部参数,便于调试与数据分析。GPIO 模拟 UART 通信参数:由于 ATtiny13 内部没有硬件 UART 外设,本设计使用 PB1 引脚通过软件定时器精确延时来模拟异步串口发送。通信参数定义如下:波特率:9600bps(标准值,兼顾传输速度与软件定时精度);数据位:8 位;停止位:1 位;校验位:无(None);电平逻辑:TTL 电平(空闲为高,起始位为低),经 MAX232 等电平转换芯片后接 PC 串口;发送方式:仅 Tx 单向发送(半双工),由 ATtiny13 定时器中断维护位时序,每帧间隔不小于 10ms。数据帧格式定义:为便于 PC 端可靠解析,上报数据采用固定长度的自定义帧结构,每帧 10 字节,格式如下:字节序号字段长度说明0帧头1 字节固定 0xAA,用于帧同步1模式1 字节0x00 空闲 / 0x01 预充 / 0x02 恒流 / 0x03 恒压 / 0x04 终止 / 0x05 错误2~3电压2 字节电池电压,单位 mV,高字节在前(大端)4~5电流2 字节充电电流,单位 mA,高字节在前(大端)6~7温度2 字节电池温度,单位 0.1℃,高字节在前(大端)8错误码1 字节0x00 正常 / 0x01 温度异常 / 0x02 电压异常 / 0x03 预充超时 / 0x04 恒流超时 / 0x05 恒压超时9校验1 字节字节 0~8 的异或和(XOR)以恒压模式上报为例,电压 8400mV、电流 500mA、温度 25.0℃、无错误时,一帧数据为:AA 03 20 D0 01 F4 00 FA 00 校验。其中校验字节为 0xAA ^ 0x03 ^ 0x20 ^ 0xD0 ^ 0x01 ^ 0xF4 ^ 0x00 ^ 0xFA ^ 0x00 的结果。PC 端接收解析示例(Python):以下代码使用 pyserial 读取串口数据,按上述帧格式解析并打印充电参数。import serial import struct 打开串口,参数需与 ATtiny13 模拟 UART 一致 ser = serial.Serial( port='COM3', # 根据实际串口号修改 baudrate=9600, bytesize=serial.EIGHTBITS, parity=serial.PARITY_NONE, stopbits=serial.STOPBITS_ONE, timeout=1 ) MODE_NAMES = { 0x00: '空闲(IDLE)', 0x01: '预充(PRE)', 0x02: '恒流(CC)', 0x03: '恒压(CV)', 0x04: '终止(DONE)', 0x05: '错误(FAULT)', } FAULT_NAMES = { 0x00: '正常', 0x01: '温度异常', 0x02: '电压异常', 0x03: '预充超时', 0x04: '恒流超时', 0x05: '恒压超时', } def parse_frame(frame): """解析一帧 10 字节数据,返回参数字典;校验失败返回 None""" if len(frame) != 10 or frame[0] != 0xAA: return None # 校验:字节 0~8 异或和应等于字节 9 checksum = 0 for b in frame[:9]: checksum ^= b if checksum != frame[9]: return None mode = frame[1] voltage_mv = struct.unpack('gt;H', frame[2:4])[0] # 大端 2 字节 current_ma = struct.unpack('gt;H', frame[4:6])[0] # 大端 2 字节 temp_x10 = struct.unpack('gt;H', frame[6:8])[0] # 大端 2 字节,0.1℃ fault = frame[8] return { 'mode': MODE_NAMES.get(mode, f'未知(0x{mode:02X})'), 'voltage': voltage_mv / 1000.0, # mV -gt; V 'current': current_ma / 1000.0, # mA -gt; A 'temperature': temp_x10 / 10.0, # 0.1℃ -gt; ℃ 'fault': FAULT_NAMES.get(fault, f'未知(0x{fault:02X})'), } def main(): print('开始接收充电器数据,按 Ctrl+C 退出...') try: while True: 读取一帧:先找帧头 0xAA head = ser.read(1) if not head or head[0] != 0xAA: continue 读取剩余 9 字节 rest = ser.read(9) if len(rest) != 9: continue frame = head + rest data = parse_frame(frame) if data is None: print('校验失败,丢弃该帧') continue print(f"模式: {data['mode']:amp;lt;12} | " f"电压: {data['voltage']:.3f} V | " f"电流: {data['current']:.3f} A | " f"温度: {data['temperature']:.1f} ℃ | " f"状态: {data['fault']}") except KeyboardInterrupt: print('\n已停止接收') finally: ser.close() if name == 'main': main()PC 端接收解析示例(C 语言):以下代码在 Windows 平台使用 Win32 API 读取串口,按相同帧格式解析并打印参数,适用于嵌入式调试上位机或命令行工具。#include stdio.h #include windows.h #define FRAME_LEN 10 #define FRAME_HEAD 0xAA /* 模式名称表 */ static const char *mode_names[] = { "空闲(IDLE)", "预充(PRE)", "恒流(CC)", "恒压(CV)", "终止(DONE)", "错误(FAULT)" }; /* 错误码名称表 */ static const char *fault_names[] = { "正常", "温度异常", "电压异常", "预充超时", "恒流超时", "恒压超时" }; /* 打开串口 */ HANDLE open_serial(const char *port, DWORD baud) { HANDLE h = CreateFileA(port, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL); if (h == INVALID_HANDLE_VALUE) { printf("无法打开串口 %s\n", port); return INVALID_HANDLE_VALUE; } DCB dcb = { 0 }; dcb.DCBlength = sizeof(DCB); GetCommState(h, amp;dcb); dcb.BaudRate = baud; /* 9600 */ dcb.ByteSize = 8; /* 8 数据位 */ dcb.Parity = NOPARITY; /* 无校验 */ dcb.StopBits = ONESTOPBIT; /* 1 停止位 */ SetCommState(h, amp;dcb); COMMTIMEOUTS timeouts = { 0 }; timeouts.ReadIntervalTimeout = 50; timeouts.ReadTotalTimeoutConstant = 50; timeouts.ReadTotalTimeoutMultiplier = 10; SetCommTimeouts(h, amp;timeouts); return h; } /* 校验:字节 0~8 异或和 */ static unsigned char calc_checksum(const unsigned char buf) { unsigned char sum = 0; for (int i = 0; i FRAME_LEN - 1; i++) { sum ^= buf[i]; } return sum; } int main(void) { HANDLE h = open_serial("COM3", 9600); / 按实际串口号修改 */ if (h == INVALID_HANDLE_VALUE) { return 1; } unsigned char buf[FRAME_LEN]; unsigned char byte; DWORD nread; int idx = 0; printf("开始接收充电器数据,按 Ctrl+C 退出...\n"); while (1) { /* 逐字节读取,寻找帧头 */ if (!ReadFile(h, amp;byte, 1, amp;nread, NULL) || nread != 1) { continue; } if (byte == FRAME_HEAD) { buf[0] = byte; idx = 1; /* 读取剩余 9 字节 */ while (idx amp;amp;lt; FRAME_LEN) { if (!ReadFile(h, amp;amp;amp;byte, 1, amp;amp;amp;nread, NULL) || nread != 1) { break; } buf[idx++] = byte; } if (idx != FRAME_LEN) { continue; /* 帧不完整,丢弃 */ } /* 校验 */ if (calc_checksum(buf) != buf[FRAME_LEN - 1]) { printf("校验失败,丢弃该帧\n"); continue; } /* 解析字段(大端) */ unsigned char mode = buf[1]; unsigned int voltage_mv = (buf[2] amp;amp;lt;amp;amp;lt; 8) | buf[3]; unsigned int current_ma = (buf[4] amp;amp;lt;amp;amp;lt; 8) | buf[5]; unsigned int temp_x10 = (buf[6] amp;amp;lt;amp;amp;lt; 8) | buf[7]; unsigned char fault = buf[8]; const char *mode_str = (mode amp;amp;lt; 6) ? mode_names[mode] : "未知"; const char *fault_str = (fault amp;amp;lt; 6) ? fault_names[fault] : "未知"; printf("模式: %-12s | 电压: %.3f V | 电流: %.3f A | " "温度: %.1f ℃ | 状态: %s\n", mode_str, voltage_mv / 1000.0, current_ma / 1000.0, temp_x10 / 10.0, fault_str); } } CloseHandle(h); return 0; }上述两种 PC 端解析示例均按 9600bps、8 数据位、无校验、1 停止位的参数接收数据,并依据帧头 0xAA 与末尾异或校验进行帧同步与完整性判断。实际使用时,只需将串口号替换为 PC 上对应的 COM 口,即可实时显示充电器的电压、电流、温度与工作模式,便于调试与数据分析。2.6 ATtiny13 固件主循环流程ATtiny13 的固件采用主循环加定时器中断的结构:主循环负责 ADC 采样、模式判断与状态机切换,定时器中断负责 12 位 PWM 的低 4 位时间分配与 LED 闪烁节拍。下图给出主程序的状态机流程图,展示从系统初始化到各充电模式切换的完整控制逻辑。flowchart TD START["系统上电"] -- INIT["系统初始化 时钟 / IO / ADC / 定时器 / UART"] INIT -- LOOP{"主循环 100ms 周期"} LOOP -- ADC["ADC 采样 电压 / 电流 / 温度"] ADC -- TEMP{"温度 0℃ ~ 45℃?"} TEMP --|否| FAULT["错误模式 FAULT"] TEMP --|是| VBAT{"电池电压 Vbat?"} VBAT --|"Vbat 0.5V"| IDLE["空闲模式 IDLE"] VBAT --|"Vbat 6V"| PRE["预充模式 PRE 250mA"] VBAT --|"6V ≤ Vbat 8V"| CC["恒流模式 CC 2.5A"] VBAT --|"8V ≤ Vbat ≤ 8.5V"| CV["恒压模式 CV 8.4V"] VBAT --|"Vbat 8.5V"| FAULT PRE --|"OCV ≥ 6V"| CC PRE --|"超时 / 异常"| FAULT CC --|"OCV ≥ 8.2V"| CV CC --|"超时 / 异常"| FAULT CV --|"电流 125mA"| DONE["终止模式 DONE"] CV --|"超时 / 异常"| FAULT DONE --|"电压跌落 7.5V"| FAULT IDLE --|"拔出电池"| LOOP PRE --|"拔出电池"| IDLE CC --|"拔出电池"| IDLE CV --|"拔出电池"| IDLE DONE --|"拔出电池"| IDLE FAULT --|"重新插拔 / 复位"| IDLE IDLE -- PWM["PWM 占空比更新 PI 调节 + 12 位扩展"] PRE -- PWM CC -- PWM CV -- PWM DONE -- PWM FAULT -- PWM PWM -- LED["LED 状态输出"] LED -- UART["UART 数据上报 9600bps 帧协议"] UART -- LOOP主循环以约 100ms 为周期完成一次完整的采样、判断与输出闭环。ADC 采样在进入循环前完成通道切换与稳定等待,避免采样抖动;模式判断采用状态机结构,保证六种模式之间的切换严格遵循第 3 章定义的阈值与超时逻辑;PWM 占空比由 PI 控制器根据目标值实时调节,并经 12 位扩展后写入定时器;LED 状态与模式一一对应,便于用户直观判断;UART 上报采用带帧头与校验的协议,PC 端可据此解析并记录电压、电流、温度与模式数据。下面给出主循环关键代码片段,涵盖 ADC 采样、PWM 4 位扩展实现与模式切换判断三个核心模块。(1)ADC 采样与滤波/* ============ ADC 采样与滤波 ============ */ #define ADC_CH_VBAT 1 /* PB2/ADC1 电压采样 */ #define ADC_CH_ICHG 2 /* PB4/ADC2 电流采样 */ #define ADC_CH_TEMP 3 /* PB3/ADC3 温度采样 */ #define ADC_SAMPLES 8 /* 采样次数,用于中值滤波 */ /* 读取指定通道 ADC 原始值(10 位) / uint16_t adc_read_raw(uint8_t ch) { ADMUX = (ADMUX 0xF0) | (ch 0x07); / 切换通道 / _delay_us(100); / 等待采样保持电容稳定 / ADCSRA |= (1 ADSC); / 启动转换 / while (ADCSRA (1 ADSC)); / 等待转换完成 / return ADC; / 返回 10 位结果 */ } /* 中值滤波:剔除偶发尖峰,返回滤波后的原始值 */ uint16_t adc_read_filtered(uint8_t ch) { uint16_t buf[ADC_SAMPLES]; uint16_t tmp; uint8_t i, j; for (i = 0; i lt; ADC_SAMPLES; i++) { buf[i] = adc_read_raw(ch); } /* 冒泡排序取中值 */ for (i = 0; i lt; ADC_SAMPLES - 1; i++) { for (j = i + 1; j lt; ADC_SAMPLES; j++) { if (buf[j] lt; buf[i]) { tmp = buf[i]; buf[i] = buf[j]; buf[j] = tmp; } } } return buf[ADC_SAMPLES / 2]; /* 取中间值 */ }(2)PWM 4 位扩展实现/* ============ PWM 4 位扩展实现 ============ */ #define PWM_EXT_PERIOD 16 /* 扩展周期 = 16 个 PWM 周期 */ static uint8_t g_pwm_cycle; /* 当前扩展周期内序号 0~15 */ static uint16_t g_pwm_duty; /* 12 位 PWM 目标值 */ /* 定时器中断:每个 PWM 周期开始时调用 */ ISR(TIM0_COMPA_vect) { uint8_t d_high, d_low; /* 拆出高 8 位与低 4 位 */ d_high = (uint8_t)(g_pwm_duty gt;gt; 4); /* 高 8 位 */ d_low = (uint8_t)(g_pwm_duty amp; 0x0F); /* 低 4 位 */ /* 前 d_low 个周期占空比加 1,其余保持基础值 */ if (g_pwm_cycle lt; d_low) { OCR0A = d_high + 1; } else { OCR0A = d_high; } /* 扩展周期序号循环 0~15 / g_pwm_cycle++; if (g_pwm_cycle gt;= PWM_EXT_PERIOD) { g_pwm_cycle = 0; } } / 写入 12 位 PWM 目标值 */ void pwm_set_duty_12bit(uint16_t duty) { g_pwm_duty = (duty 4095) ? 4095 : duty; }(3)模式切换判断/* ============ 模式切换判断 ============ */ typedef enum { MODE_IDLE = 0, /* 空闲 */ MODE_PRE, /* 预充 */ MODE_CC, /* 恒流 */ MODE_CV, /* 恒压 */ MODE_DONE, /* 终止 */ MODE_FAULT /* 错误 */ } charge_mode_t; static charge_mode_t g_mode = MODE_IDLE; /* 电压阈值(单位:V,经分压比换算为 ADC 原始值比较) / #define VBAT_PRE_MAX 6.0f / 预充转恒流 OCV 阈值 / #define VBAT_CC_MAX 8.2f / 恒流转恒压 OCV 阈值 / #define VBAT_FAULT 8.5f / 异常电池判定阈值 / #define I_DONE 0.125f / 终止电流 125mA */ /* 模式切换判断:依据电压、电流与温度采样结果更新状态机 / void update_charge_mode(float vbat, float ichg, float vtemp) { switch (g_mode) { case MODE_IDLE: / 未接电池或电压为 0,保持空闲 / if (vbat 0.5f) { break; } / 温度超限直接进错误 / if (vtemp 0.85f || vtemp 0.35f) { g_mode = MODE_FAULT; break; } if (vbat VBAT_PRE_MAX) { g_mode = MODE_PRE; / 过放,进入预充 / } else if (vbat VBAT_CC_MAX) { g_mode = MODE_CC; / 进入恒流 / } else if (vbat = VBAT_FAULT) { g_mode = MODE_CV; / 接近充满,进入恒压 / } else { g_mode = MODE_FAULT; / 电压过高,异常电池 */ } break; case MODE_PRE: /* 周期性关断 PWM 测 OCV,达到 6V 转恒流 */ if (vbat gt;= VBAT_PRE_MAX) { g_mode = MODE_CC; } else if (vtemp gt; 0.85f || vtemp lt; 0.35f) { g_mode = MODE_FAULT; } break; case MODE_CC: /* OCV 达到 8.2V 转恒压 */ if (vbat gt;= VBAT_CC_MAX) { g_mode = MODE_CV; } else if (vbat gt; VBAT_FAULT || vtemp gt; 0.85f || vtemp lt; 0.35f) { g_mode = MODE_FAULT; } break; case MODE_CV: /* 电流降至 125mA 判定充满 */ if (ichg lt;= I_DONE) { g_mode = MODE_DONE; } else if (ichg gt; 2.5f || vtemp gt; 0.85f || vtemp lt; 0.35f) { g_mode = MODE_FAULT; } break; case MODE_DONE: /* 电压异常跌落转错误 */ if (vbat lt; 7.5f) { g_mode = MODE_FAULT; } break; case MODE_FAULT: /* 需重新插拔电池或复位才能退出 */ break; } }设计要点:ADC 采样采用中值滤波,对开关电源的脉冲性干扰抑制效果优于均值滤波,且计算量小、无需浮点运算,适合 ATtiny13 的有限资源;PWM 4 位扩展在定时器中断内仅做比较与赋值,无乘除运算,软件开销极小,OCR0A 在周期开始时更新,不影响当前周期波形完整性;模式切换采用 switch-case 结构,每个模式只处理本模式的进入与退出条件,逻辑清晰且便于维护,所有阈值以整数毫伏/毫安表示,避免浮点比较误差。下面给出完整的 ATtiny13 固件 C 语言工程代码,包含 main 函数、定时器初始化、ADC 初始化、UART 发送函数及 PI 控制算法实现。代码可直接编译运行,并添加了详细注释。(4)完整固件工程代码(main.c)/* ============================================================================ * ATtiny13 锂电池充电器固件 —— main.c * 功能:8.4V/2.5Ah 锂电池充电控制 * 芯片:ATtiny13A(8 引脚) * 时钟:内部 1.2MHz(熔丝位 lfuse = 0x6A) * 编译:avr-gcc -mmcu=attiny13 -DF_CPU=1200000UL -Os * 说明:主循环 + 定时器中断结构,实现 ADC 采样、状态机切换、 * PI 控制、12 位 PWM 扩展、LED 指示与 GPIO 模拟 UART 上报 * ========================================================================== */ #include avr/io.h #include avr/interrupt.h #include avr/wdt.h #include util/delay.h /* ============================================================================ 引脚定义(ATtiny13 封装) PB0 —— PWM 输出(100kHz,8 位 + 4 位扩展 = 12 位) PB1 —— GPIO 模拟 UART Tx(9600bps) PB2 —— ADC1 电压采样输入 PB3 —— ADC3 温度采样输入(NTC 分压) PB4 —— ADC2 电流采样输入(运放输出) PB5 —— 双色 LED 控制 ========================================================================== */ #define PIN_PWM PB0 #define PIN_UART_TX PB1 #define PIN_LED PB5 /* ============================================================================ 充电模式枚举 ========================================================================== / typedef enum { MODE_IDLE = 0, / 空闲:未接电池 / MODE_PRE, / 预充:250mA 小电流恢复 / MODE_CC, / 恒流:2.5A 大电流充电 / MODE_CV, / 恒压:8.4V 恒压充电 / MODE_DONE, / 终止:已充满 / MODE_FAULT / 错误:异常保护 */ } charge_mode_t; /* ============================================================================ 全局状态变量 ========================================================================== / static charge_mode_t g_mode = MODE_IDLE; / 当前充电模式 / static uint16_t g_pwm_duty = 0; / 12 位 PWM 目标值(0~4095) / static uint8_t g_fault_code = 0; / 错误代码 / static uint8_t g_led_state = 0; / LED 状态 / static volatile uint16_t g_ms_tick = 0; / 毫秒时基(定时器中断维护) / static volatile uint8_t g_uart_busy = 0; / UART 发送忙标志 */ /* ===========================================================
返回列表