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

目录:

  • [1. 方案概述](#1. 方案概述)
  • [2. 系统架构](#2. 系统架构)
    • [2.1 初级侧反激变换电路](#2.1 初级侧反激变换电路)
    • [2.2 次级侧充电管理电路](#2.2 次级侧充电管理电路)
    • [2.3 采样电路](#2.3 采样电路)
    • [2.4 PWM 扩展电路](#2.4 PWM 扩展电路)
    • [2.5 LED 指示与串口通信](#2.5 LED 指示与串口通信)
    • [2.6 ATtiny13 固件主循环流程](#2.6 ATtiny13 固件主循环流程)
    • [2.7 初级侧关键元器件选型与计算](#2.7 初级侧关键元器件选型与计算)
    • [2.8 常见故障与调试指南](#2.8 常见故障与调试指南)
    • [2.9 次级侧采样与 PWM 扩展电路参数计算](#2.9 次级侧采样与 PWM 扩展电路参数计算)
    • [2.10 ATtiny13 固件设计要点](#2.10 ATtiny13 固件设计要点)
    • [2.11 充电控制软件流程](#2.11 充电控制软件流程)
    • [2.12 关键元器件选型汇总表](#2.12 关键元器件选型汇总表)
  • [3. 充电模式与状态切换](#3. 充电模式与状态切换)
    • [3.1 空闲模式(IDLE)](#3.1 空闲模式(IDLE))
    • [3.2 预充模式(PRE)](#3.2 预充模式(PRE))
    • [3.3 恒流模式(CC)](#3.3 恒流模式(CC))
    • [3.4 恒压模式(CV)](#3.4 恒压模式(CV))
    • [3.5 终止模式(DONE)](#3.5 终止模式(DONE))
    • [3.6 错误模式(FAULT)](#3.6 错误模式(FAULT))
    • [3.7 切换阈值与超时参数汇总](#3.7 切换阈值与超时参数汇总)
    • [3.8 模式切换的软件实现与边界处理](#3.8 模式切换的软件实现与边界处理)
    • [3.9 完整充电过程的电压电流曲线特征](#3.9 完整充电过程的电压电流曲线特征)
  • [4. 性能测试与验证](#4. 性能测试与验证)
    • [4.1 测试环境与设备](#4.1 测试环境与设备)
    • [4.2 恒流模式实测波形与数据](#4.2 恒流模式实测波形与数据)
    • [4.3 恒压模式实测波形与数据](#4.3 恒压模式实测波形与数据)
    • [4.4 不同温度下的充电效率测试](#4.4 不同温度下的充电效率测试)
    • [4.5 不同温度下的纹波电压测试](#4.5 不同温度下的纹波电压测试)
    • [4.6 不同温度下的稳定性测试](#4.6 不同温度下的稳定性测试)
    • [4.7 测试数据分析与结论](#4.7 测试数据分析与结论)
    • [4.8 编译环境配置与烧录步骤](#4.8 编译环境配置与烧录步骤)
  • [5. 本文创新点](#5. 本文创新点)
  • [6. 总结](#6. 总结)
  • [7. 参考资料](#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 --> VS["电压采样 分压 + RC 滤波"] BAT --> IS["电流采样 采样电阻 + 运放"] BAT --> NTC["温度采样 NTC 热敏电阻"] VS --> MCU["ATtiny13 充电管理"] IS --> MCU NTC --> MCU MCU --> PWM["PWM 扩展 8 位 + 4 位扩展 = 12 位"] PWM --> DAC["RC 滤波 + 二极管 驱动 TL431 参考点"] DAC --> FB MCU --> 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.5Ah 8.4V/2.5Ah 锂电池包 1. 方案概述
充电电流(恒流) 2.5A 恒流充电模式设定值 3. 充电模式与状态切换
预充电流 250mA 预充模式小电流充电 3. 充电模式与状态切换
恒压值 8.4V 恒压充电模式输出电压 3. 充电模式与状态切换
限压值 8.5V 预充与恒流模式限压保护 3. 充电模式与状态切换
终止电流 125mA(1/20C) 充电电流低于该值判定充满 3. 充电模式与状态切换
PWM 频率 4.68kHz ATtiny13 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 读取串口数据,按上述帧格式解析并打印充电参数。

python 复制代码
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('>H', frame[2:4])[0]   # 大端 2 字节
current_ma = struct.unpack('>H', frame[4:6])[0]   # 大端 2 字节
temp_x10 = struct.unpack('>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 -> V
'current': current_ma / 1000.0,      # mA -> A
'temperature': temp_x10 / 10.0,      # 0.1℃ -> ℃
'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']:<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 读取串口,按相同帧格式解析并打印参数,适用于嵌入式调试上位机或命令行工具。

c 复制代码
#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 采样与滤波

c 复制代码
/* ============ 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 位扩展实现

c 复制代码
/* ============ 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)模式切换判断

c 复制代码
/* ============ 模式切换判断 ============ */
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)

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 发送忙标志 */
/* ============================================================================
阈值参数(电压单位 V,电流单位 A,温度单位 V)
========================================================================== /
#define VBAT_PRE_MAX    6.0f    / 预充转恒流 OCV 阈值 /
#define VBAT_CC_MAX     8.2f    / 恒流转恒压 OCV 阈值 /
#define VBAT_CV         8.4f    / 恒压目标电压 /
#define VBAT_FAULT      8.5f    / 异常电池判定阈值 /
#define VBAT_DONE_MIN   7.5f    / 终止模式电压跌落阈值 /
#define I_PRE           0.25f   / 预充电流 250mA /
#define I_CC            2.5f    / 恒流电流 2.5A /
#define I_DONE          0.125f  / 终止电流 125mA /
#define VTEMP_LOW       0.85f   / 低温阈值(0℃ 对应电压) /
#define VTEMP_HIGH      0.35f   / 高温阈值(45℃ 对应电压) */
/* ============================================================================
PI 控制器参数
========================================================================== /
#define KP              0.8f    / 比例系数 /
#define KI              0.05f   / 积分系数 /
#define PI_OUT_MAX      4095.0f / 输出上限(12 位满量程) /
#define PI_OUT_MIN      0.0f    / 输出下限 */
/* ============================================================================
函数声明
========================================================================== */
static void system_init(void);
static void timer0_init(void);
static void adc_init(void);
static uint16_t adc_read_raw(uint8_t ch);
static uint16_t adc_read_filtered(uint8_t ch);
static float adc_to_voltage(uint16_t raw);
static void pwm_set_duty_12bit(uint16_t duty);
static float pi_control(float setpoint, float feedback);
static void update_charge_mode(float vbat, float ichg, float vtemp);
static void update_pwm_duty(float vbat, float ichg);
static void update_led(void);
static void uart_init(void);
static void uart_send_byte(uint8_t data);
static void uart_send_frame(float vbat, float ichg, float vtemp);
static uint8_t calc_checksum(const uint8_t *buf, uint8_t len);
static void led_red_on(void);
static void led_green_on(void);
static void led_red_blink(uint8_t hz);
static void led_off(void);
/* ============================================================================
系统初始化:时钟、IO、外设
========================================================================== /
static void system_init(void)
{
/ 关闭看门狗(若之前使能) */
wdt_disable();
/* IO 方向配置 /
DDRB  = (1 << PIN_PWM) | (1 << PIN_UART_TX) | (1 << PIN_LED); / PB0/PB1/PB5 输出 /
PORTB = (1 << PIN_UART_TX);   / UART Tx 空闲为高电平 /
/ PB2/PB3/PB4 为 ADC 输入,不使能内部上拉 */
/* 初始化各外设 /
timer0_init();   / 定时器 0:PWM 输出 + 毫秒时基 /
adc_init();      / ADC 初始化 /
uart_init();     / GPIO 模拟 UART 初始化 */
/* 使能全局中断 */
sei();
}
/* ============================================================================
定时器 0 初始化
功能:PB0 输出 100kHz 8 位 PWM(CTC 模式,OCR0A 匹配)
  同时产生 1ms 时基中断用于 LED 闪烁与 UART 时序
========================================================================== /
static void timer0_init(void)
{
/ 时钟源:内部 1.2MHz,无分频(CS00 = 1) */
TCCR0B = (1 << CS00);
/* CTC 模式(WGM01 = 1),OCR0A 匹配清零 */
TCCR0A = (1 << WGM01);
/* 输出比较 A 匹配时翻转 PB0(COM0A0 = 1),产生 PWM */
TCCR0A |= (1 << COM0A0);
/* 100kHz PWM:OCR0A = F_CPU / (2 * f_pwm) - 1
= 1200000 / (2 * 100000) - 1 = 5 */
OCR0A = 5;
/* 使能输出比较 A 匹配中断(用于 4 位扩展与毫秒时基) */
TIMSK0 = (1 << OCIE0A);
/* 初始占空比 0 */
OCR0A = 0;
}
/* ============================================================================
ADC 初始化
功能:内部 1.1V 参考电压,10 位分辨率
========================================================================== /
static void adc_init(void)
{
/ 参考电压:内部 1.1V(REFS0 = 1) */
ADMUX = (1 << REFS0);
/* 使能 ADC,预分频 8(ADC 时钟 = 1.2MHz / 8 = 150kHz,满足 50~200kHz 要求) */
ADCSRA = (1 << ADEN) | (1 << ADPS1) | (1 << ADPS0);
}
/* ============================================================================
读取指定通道 ADC 原始值(10 位)
========================================================================== /
static uint16_t adc_read_raw(uint8_t ch)
{
/ 切换通道(保留参考电压位) */
ADMUX = (ADMUX & 0xF0) | (ch & 0x07);
/* 等待采样保持电容稳定 */
_delay_us(100);
/* 启动转换 */
ADCSRA |= (1 << ADSC);
/* 等待转换完成 */
while (ADCSRA & (1 << ADSC));
/* 返回 10 位结果 */
return ADC;
}
/* ============================================================================
中值滤波:剔除偶发尖峰,返回滤波后的原始值
========================================================================== */
static uint16_t adc_read_filtered(uint8_t ch)
{
uint16_t buf[8];
uint16_t tmp;
uint8_t i, j;
/* 连续采样 8 次 */
for (i = 0; i < 8; i++) {
buf[i] = adc_read_raw(ch);
}
/* 冒泡排序 */
for (i = 0; i < 7; i++) {
for (j = i + 1; j < 8; j++) {
if (buf[j] < buf[i]) {
tmp = buf[i];
buf[i] = buf[j];
buf[j] = tmp;
}
}
}
/* 取中间值(第 4 个) */
return buf[4];
}
/* ============================================================================
ADC 原始值换算为电压(单位 V)
内部参考 1.1V,10 位分辨率:V = raw * 1.1 / 1024
========================================================================== */
static float adc_to_voltage(uint16_t raw)
{
return (float)raw * 1.1f / 1024.0f;
}
/* ============================================================================
写入 12 位 PWM 目标值(限幅 0~4095)
========================================================================== */
static void pwm_set_duty_12bit(uint16_t duty)
{
g_pwm_duty = (duty > 4095) ? 4095 : duty;
}
/* ============================================================================
PI 控制器
输入:设定值与反馈值
输出:12 位 PWM 占空比(0~4095)
说明:采用位置式 PI,积分限幅防止饱和
========================================================================== /
static float g_pi_integral = 0.0f;   / 积分项累积值 */
static float pi_control(float setpoint, float feedback)
{
float error = setpoint - feedback;   /* 误差 */
float output;
/* 比例项 */
float p_term = KP * error;
/* 积分项累积(带限幅,防止积分饱和) */
g_pi_integral += KI * error;
if (g_pi_integral &gt;  PI_OUT_MAX) g_pi_integral =  PI_OUT_MAX;
if (g_pi_integral &lt; -PI_OUT_MAX) g_pi_integral = -PI_OUT_MAX;
/* 总输出 = 比例 + 积分 */
output = p_term + g_pi_integral;
/* 输出限幅到 12 位范围 */
if (output &gt; PI_OUT_MAX) output = PI_OUT_MAX;
if (output &lt; PI_OUT_MIN) output = PI_OUT_MIN;
return output;
}
/* ============================================================================
模式切换判断:依据电压、电流与温度采样结果更新状态机
========================================================================== /
static void update_charge_mode(float vbat, float ichg, float vtemp)
{
switch (g_mode) {
case MODE_IDLE:
/ 未接电池或电压为 0,保持空闲 /
if (vbat < 0.5f) {
g_led_state = 1;   / 红灯常亮 /
break;
}
/ 温度超限直接进错误 /
if (vtemp > VTEMP_LOW || vtemp < VTEMP_HIGH) {
g_mode = MODE_FAULT;
g_fault_code = 0x01;   / 温度异常 /
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;       / 电压过高,异常电池 /
g_fault_code = 0x02;       / 电压异常 /
}
break;
case MODE_PRE:
/ 周期性关断 PWM 测 OCV,达到 6V 转恒流 /
if (vbat >= VBAT_PRE_MAX) {
g_mode = MODE_CC;
} else if (vtemp > VTEMP_LOW || vtemp < VTEMP_HIGH) {
g_mode = MODE_FAULT;
g_fault_code = 0x01;
}
break;
case MODE_CC:
/ OCV 达到 8.2V 转恒压 /
if (vbat >= VBAT_CC_MAX) {
g_mode = MODE_CV;
} else if (vbat > VBAT_FAULT ||
vtemp > VTEMP_LOW || vtemp < VTEMP_HIGH) {
g_mode = MODE_FAULT;
g_fault_code = 0x03;   / 恒流异常 /
}
break;
case MODE_CV:
/ 电流降至 125mA 判定充满 /
if (ichg <= I_DONE) {
g_mode = MODE_DONE;
} else if (ichg > I_CC ||
vtemp > VTEMP_LOW || vtemp < VTEMP_HIGH) {
g_mode = MODE_FAULT;
g_fault_code = 0x04;   / 恒压异常 /
}
break;
case MODE_DONE:
/ 电压异常跌落转错误 /
if (vbat < VBAT_DONE_MIN) {
g_mode = MODE_FAULT;
g_fault_code = 0x05;
}
break;
case MODE_FAULT:
/ 需重新插拔电池或复位才能退出 /
break;
}
}
/ ============================================================================
PWM 占空比更新:根据当前模式选择 PI 控制目标
========================================================================== /
static void update_pwm_duty(float vbat, float ichg)
{
switch (g_mode) {
case MODE_IDLE:
case MODE_DONE:
case MODE_FAULT:
/ 关闭 PWM 输出 /
g_pwm_duty = 0;
break;
case MODE_PRE:
/ 预充:以 250mA 为目标,PI 调节占空比 /
g_pwm_duty = (uint16_t)pi_control(I_PRE, ichg);
break;
case MODE_CC:
/ 恒流:以 2.5A 为目标,PI 调节占空比 /
g_pwm_duty = (uint16_t)pi_control(I_CC, ichg);
break;
case MODE_CV:
/ 恒压:以 8.4V 为目标,PI 调节占空比微调 TL431 参考点 /
g_pwm_duty = (uint16_t)pi_control(VBAT_CV, vbat);
break;
}
/ 限幅并写入 12 位扩展 PWM /
pwm_set_duty_12bit(g_pwm_duty);
}
/ ============================================================================
LED 状态输出
========================================================================== /
static void led_red_on(void)
{
/ 双色 LED:红色亮(假设 PB5 高电平为红,低电平为绿,此处按实际硬件调整) /
PORTB |= (1 << PIN_LED);
}
static void led_green_on(void)
{
PORTB &= ~(1 << PIN_LED);
}
static void led_off(void)
{
/ 关闭 LED(按实际硬件调整) /
PORTB &= ~(1 << PIN_LED);
}
static void led_red_blink(uint8_t hz)
{
/ 闪烁节拍由主循环根据 g_ms_tick 控制,此处仅设置状态 /
g_led_state = (hz == 1) ? 2 : 4;   / 2 = 红闪 1Hz,4 = 红闪 2Hz /
}
static void update_led(void)
{
static uint16_t last_tick = 0;
uint16_t period;   / 闪烁半周期(ms) /
switch (g_mode) {
case MODE_IDLE:
led_red_on();          / 红灯常亮 */
break;
case MODE_PRE:
case MODE_CC:
case MODE_CV:
/* 红灯 1Hz 闪烁:半周期 500ms /
period = 500;
if ((uint16_t)(g_ms_tick - last_tick) &gt;= period) {
last_tick = g_ms_tick;
PORTB ^= (1 &lt;&lt; PIN_LED);   / 翻转 LED */
}
break;
case MODE_DONE:
led_green_on();        /* 绿灯常亮 */
break;
case MODE_FAULT:
/* 红灯 2Hz 闪烁:半周期 250ms /
period = 250;
if ((uint16_t)(g_ms_tick - last_tick) &gt;= period) {
last_tick = g_ms_tick;
PORTB ^= (1 &lt;&lt; PIN_LED);
}
break;
}
}
/ ============================================================================
GPIO 模拟 UART 初始化
波特率 9600bps,8 数据位,无校验,1 停止位
位时间 = 1 / 9600 ≈ 104.17us
========================================================================== /
static void uart_init(void)
{
/ PB1 已配置为输出,空闲为高电平 /
PORTB |= (1 << PIN_UART_TX);
g_uart_busy = 0;
}
/ ============================================================================
GPIO 模拟 UART 发送一个字节
时序:起始位(低) + 8 数据位(LSB 先发) + 停止位(高)
========================================================================== /
static void uart_send_byte(uint8_t data)
{
uint8_t i;
g_uart_busy = 1;
/ 起始位:拉低 /
PORTB &= ~(1 << PIN_UART_TX);
_delay_us(104);   / 1 位时间 ≈ 104us @9600bps /
/ 发送 8 个数据位,LSB 先发 /
for (i = 0; i < 8; i++) {
if (data & 0x01) {
PORTB |= (1 << PIN_UART_TX);   / 发送 1 /
} else {
PORTB &= ~(1 << PIN_UART_TX);  / 发送 0 /
}
data >>= 1;
_delay_us(104);
}
/ 停止位:拉高 /
PORTB |= (1 << PIN_UART_TX);
_delay_us(104);
g_uart_busy = 0;
}
/ ============================================================================
计算校验字节:字节 0~8 的异或和
========================================================================== */
static uint8_t calc_checksum(const uint8_t buf, uint8_t len)
{
uint8_t sum = 0;
uint8_t i;
for (i = 0; i < len; i++) {
sum ^= buf[i];
}
return sum;
}
/ ============================================================================
UART 数据上报(10 字节帧格式)
帧头(0xAA) + 模式 + 电压(2B 大端 mV) + 电流(2B 大端 mA)
温度(2B 大端 0.1℃) + 错误码 + 校验(XOR)
========================================================================== /
static void uart_send_frame(float vbat, float ichg, float vtemp)
{
uint8_t frame[10];
uint16_t v_mv = (uint16_t)(vbat * 1000.0f);   / V -> mV /
uint16_t i_ma = (uint16_t)(ichg * 1000.0f);   / A -> mA /
uint16_t t_x10 = (uint16_t)(vtemp * 10.0f);   / 温度采样电压,此处按 0.1℃ 上报需换算 /
/ 组装帧(大端序) /
frame[0] = 0xAA;                    / 帧头 /
frame[1] = (uint8_t)g_mode;         / 充电模式 /
frame[2] = (uint8_t)(v_mv >> 8);    / 电压高字节 /
frame[3] = (uint8_t)(v_mv & 0xFF);  / 电压低字节 /
frame[4] = (uint8_t)(i_ma >> 8);    / 电流高字节 /
frame[5] = (uint8_t)(i_ma & 0xFF);  / 电流低字节 /
frame[6] = (uint8_t)(t_x10 >> 8);  / 温度高字节 /
frame[7] = (uint8_t)(t_x10 & 0xFF); / 温度低字节 /
frame[8] = g_fault_code;            / 错误码 /
frame[9] = calc_checksum(frame, 9); / 校验字节 /
/ 逐字节发送 /
for (uint8_t i = 0; i < 10; i++) {
uart_send_byte(frame[i]);
}
}
/ ============================================================================
定时器 0 输出比较 A 匹配中断
功能 1:12 位 PWM 低 4 位时间分配(4 位扩展)
功能 2:维护 1ms 毫秒时基(每 100 次中断 = 1ms)
========================================================================== /
static volatile uint8_t g_timer_cnt = 0;   / 中断计数 /
ISR(TIM0_COMPA_vect)
{
uint8_t d_high, d_low;
/ ---- 12 位 PWM 4 位扩展 ---- /
/ 拆出高 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;= 16) {
g_pwm_cycle = 0;
}
/* ---- 毫秒时基维护 ----
PWM 频率 100kHz,即每 10us 一次中断。
每 100 次中断 = 1ms。 /
g_timer_cnt++;
if (g_timer_cnt &gt;= 100) {
g_timer_cnt = 0;
g_ms_tick++;
}
}
/ ============================================================================
主函数
========================================================================== /
int main(void)
{
float vbat, ichg, vtemp;
uint16_t last_report_tick = 0;
/ 系统初始化 /
system_init();
/ 主循环:约 100ms 周期完成一次采样、判断与输出闭环 /
while (1) {
/ 1. ADC 采样三路模拟量(中值滤波) /
vbat  = adc_to_voltage(adc_read_filtered(1));  / PB2/ADC1 电压 /
ichg  = adc_to_voltage(adc_read_filtered(2));  / PB4/ADC2 电流(经运放) /
vtemp = adc_to_voltage(adc_read_filtered(3));  / PB3/ADC3 温度 /
/ 2. 模式判断与状态机切换 */
update_charge_mode(vbat, ichg, vtemp);
/* 3. PWM 占空比更新(PI 控制) */
update_pwm_duty(vbat, ichg);
/* 4. LED 状态输出 */
update_led();
/* 5. UART 数据上报(周期约 100ms) */
if ((uint16_t)(g_ms_tick - last_report_tick) &gt;= 100) {
last_report_tick = g_ms_tick;
uart_send_frame(vbat, ichg, vtemp);
}
/* 6. 喂狗 */
wdt_reset();
/* 7. 进入空闲模式省电,等待定时器中断唤醒 */
sleep_cpu();
}
}

上述完整固件代码可直接编译运行。工程文件组织建议将 ADC、PWM、状态机、UART 等模块拆分到独立源文件(adc.c、pwm.c、charger.c、uart.c),并配合 2.8.5 节给出的 Makefile 完成编译与烧录。代码中所有阈值均以浮点电压/电流表示,便于阅读与调试;实际量产时可将阈值换算为 ADC 原始值比较,以消除浮点运算开销。

(5)完整固件汇编语言版本(main.asm)

对于资源极度受限或对实时性要求更高的场景,也可以使用 AVR 汇编语言实现同样的充电控制逻辑。以下给出与上述 C 代码功能等价的完整汇编工程,包含定时器 PWM 输出、ADC 采样、状态机切换与 GPIO 模拟 UART 发送,可直接用 avra 或 avr-gcc 汇编器编译后烧录到 ATtiny13A。

asm 复制代码
; ============================================================================
; ATtiny13 锂电池充电器固件 ------ main.asm
; 功能:8.4V/2.5Ah 锂电池充电控制(汇编语言版本)
; 芯片:ATtiny13A(8 引脚)
; 时钟:内部 1.2MHz(熔丝位 lfuse = 0x6A)
; 汇编:avra main.asm 或 avr-gcc -mmcu=attiny13 -x assembler-with-cpp
; 说明:与 C 语言版本功能等价,实现 ADC 采样、状态机切换、
;       PI 控制(定点近似)、8 位 PWM 输出、LED 指示与 GPIO 模拟 UART
; ============================================================================
; ----------------------------------------------------------------------------
; 寄存器定义
; ----------------------------------------------------------------------------
.def    temp        = r16        ; 通用临时寄存器
.def    temp2       = r17        ; 通用临时寄存器 2
.def    mode        = r18        ; 当前充电模式(0=空闲 1=预充 2=恒流 3=恒压 4=充满 5=故障)
.def    duty_hi     = r19        ; PWM 占空比高字节
.def    duty_lo     = r20        ; PWM 占空比低字节(扩展精度)
.def    adc_val_hi  = r21        ; ADC 采样值高字节
.def    adc_val_lo  = r22        ; ADC 采样值低字节
.def    tick_cnt    = r23        ; 毫秒时基计数器
.def    flag        = r24        ; 标志位寄存器
.def    uart_data   = r25        ; UART 发送数据
; ----------------------------------------------------------------------------
; 引脚定义(ATtiny13 封装)
; PB0 ------ PWM 输出(100kHz,8 位)
; PB1 ------ GPIO 模拟 UART Tx(9600bps)
; PB2 ------ ADC1 电压采样输入
; PB3 ------ ADC3 温度采样输入(NTC 分压)
; PB4 ------ ADC2 电流采样输入(运放输出)
; PB5 ------ 双色 LED 控制
; ----------------------------------------------------------------------------
.equ    PIN_PWM     = 0          ; PB0
.equ    PIN_UART_TX = 1          ; PB1
.equ    PIN_LED     = 5          ; PB5
; ----------------------------------------------------------------------------
; 充电模式枚举
; ----------------------------------------------------------------------------
.equ    MODE_IDLE   = 0
.equ    MODE_PRE    = 1
.equ    MODE_CC     = 2
.equ    MODE_CV     = 3
.equ    MODE_DONE   = 4
.equ    MODE_FAULT  = 5
; ----------------------------------------------------------------------------
; 阈值参数(ADC 原始值,10 位分辨率,Vref = 1.1V)
; 电压采样分压比 1:10,实际电压 = ADC值 × 1.1 / 1024 × 10
; 6.0V  → ADC ≈ 559
; 8.2V  → ADC ≈ 764
; 8.4V  → ADC ≈ 782
; 8.5V  → ADC ≈ 791
; 7.5V  → ADC ≈ 699
; ----------------------------------------------------------------------------
.equ    VBAT_PRE_MAX    = 559     ; 预充转恒流阈值(6.0V)
.equ    VBAT_CC_MAX     = 764     ; 恒流转恒压阈值(8.2V)
.equ    VBAT_CV         = 782     ; 恒压目标(8.4V)
.equ    VBAT_FAULT      = 791     ; 异常电池判定(8.5V)
.equ    VBAT_DONE_MIN   = 699     ; 终止模式电压跌落阈值(7.5V)
; ----------------------------------------------------------------------------
; 电流采样阈值(ADC 原始值)
; 电流采样经运放放大,1A 对应 0.1V,即 ADC ≈ 93
; 0.25A → ADC ≈ 23
; 2.5A  → ADC ≈ 233
; 0.125A→ ADC ≈ 12
; ----------------------------------------------------------------------------
.equ    I_PRE       = 23          ; 预充电流 250mA
.equ    I_CC        = 233         ; 恒流电流 2.5A
.equ    I_DONE      = 12          ; 终止电流 125mA
; ----------------------------------------------------------------------------
; 温度阈值(ADC 原始值,NTC 分压)
; 0℃ 对应 0.85V → ADC ≈ 791
; 45℃ 对应 0.35V → ADC ≈ 326
; ----------------------------------------------------------------------------
.equ    VTEMP_LOW   = 791         ; 低温阈值
.equ    VTEMP_HIGH  = 326         ; 高温阈值
; ----------------------------------------------------------------------------
; 中断向量表
; ----------------------------------------------------------------------------
.cseg
.org    0x0000
rjmp    RESET           ; 复位向量
.org    0x0001
rjmp    INT0_ISR        ; 外部中断 0(未使用)
.org    0x0002
rjmp    PCINT0_ISR      ; 引脚变化中断(未使用)
.org    0x0003
rjmp    TIM0_OVF_ISR    ; 定时器 0 溢出中断(未使用)
.org    0x0004
rjmp    TIM0_COMPA_ISR  ; 定时器 0 比较匹配 A 中断(PWM + 时基)
.org    0x0005
rjmp    TIM0_COMPB_ISR  ; 定时器 0 比较匹配 B 中断(未使用)
.org    0x0006
rjmp    ADC_ISR         ; ADC 转换完成中断(未使用)
.org    0x0007
rjmp    WDT_ISR         ; 看门狗定时器中断(未使用)
; ----------------------------------------------------------------------------
; 复位入口
; ----------------------------------------------------------------------------
RESET:
; 关闭看门狗
ldi     temp, (1 << WDCE) | (1 << WDE)
out     WDTCR, temp
ldi     temp, 0x00
out     WDTCR, temp
    ; 初始化堆栈指针
    ldi     temp, LOW(RAMEND)
    out     SPL, temp
; IO 方向配置:PB0/PB1/PB5 输出,其余输入
ldi     temp, (1 &amp;lt;&amp;lt; PIN_PWM) | (1 &amp;lt;&amp;lt; PIN_UART_TX) | (1 &amp;lt;&amp;lt; PIN_LED)
out     DDRB, temp
; UART Tx 空闲为高电平
ldi     temp, (1 &amp;lt;&amp;lt; PIN_UART_TX)
out     PORTB, temp
; 初始化定时器 0:CTC 模式,100kHz PWM
; 时钟源:内部 1.2MHz 无分频
ldi     temp, (1 &amp;lt;&amp;lt; CS00)
out     TCCR0B, temp
; CTC 模式(WGM01 = 1),比较匹配清零
ldi     temp, (1 &amp;lt;&amp;lt; WGM01)
out     TCCR0A, temp
; 输出比较 A 匹配时清零 PB0(COM0A1 = 1,COM0A0 = 0)
; 产生 PWM 波形
ldi     temp, (1 &amp;lt;&amp;lt; COM0A1)
out     TCCR0A, temp
; 100kHz PWM:OCR0A = F_CPU / (2 × f_pwm) - 1
; = 1200000 / (2 × 100000) - 1 = 5
ldi     temp, 5
out     OCR0A, temp
; 使能输出比较 A 匹配中断
ldi     temp, (1 &amp;lt;&amp;lt; OCIE0A)
out     TIMSK0, temp
; 初始化 ADC:内部 1.1V 参考,预分频 8
ldi     temp, (1 &amp;lt;&amp;lt; REFS0)
out     ADMUX, temp
ldi     temp, (1 &amp;lt;&amp;lt; ADEN) | (1 &amp;lt;&amp;lt; ADPS1) | (1 &amp;lt;&amp;lt; ADPS0)
out     ADCSRA, temp
; 初始化状态变量
clr     mode                ; MODE_IDLE
clr     duty_hi
clr     duty_lo
clr     tick_cnt
clr     flag
; 使能全局中断
sei
; ----------------------------------------------------------------------------
; 主循环:约 100ms 周期完成一次采样、判断与输出闭环
; ----------------------------------------------------------------------------
MAIN_LOOP:
; 1. 采样电压通道(ADC1/PB2)
ldi     temp, 1             ; 通道 1
rcall   ADC_READ_FILTERED
mov     adc_val_hi, temp2   ; 保存电压采样值高字节
mov     adc_val_lo, temp    ; 保存电压采样值低字节
; 2. 采样电流通道(ADC2/PB4)
ldi     temp, 2             ; 通道 2
rcall   ADC_READ_FILTERED
; 3. 采样温度通道(ADC3/PB3)
ldi     temp, 3             ; 通道 3
rcall   ADC_READ_FILTERED
; 4. 模式判断与状态机切换
rcall   UPDATE_MODE
; 5. PWM 占空比更新
rcall   UPDATE_PWM
; 6. LED 状态输出
rcall   UPDATE_LED
; 7. UART 数据上报(简化:每 100ms 发送一次状态字节)
rcall   UART_SEND_STATUS
; 8. 延时约 100ms(主循环周期)
ldi     temp, 100
rcall   DELAY_MS
rjmp    MAIN_LOOP
; ----------------------------------------------------------------------------
; ADC 读取函数(带中值滤波)
; 输入:temp = 通道号(0~3)
; 输出:temp:temp2 = 10 位 ADC 值(temp 低字节,temp2 高字节)
; ----------------------------------------------------------------------------
ADC_READ_FILTERED:
push    r0
push    r1
push    r2
push    r3
push    r4
push    r5
push    r6
push    r7
push    r8
push    r9
push    r10
push    r11
push    r12
push    r13
push    r14
push    r15
push    r16
push    r17
push    r18
push    r19
push    r20
push    r21
push    r22
push    r23
push    r24
push    r25
push    r26
push    r27
push    r28
push    r29
push    r30
push    r31
; 保存通道号到 r0
mov     r0, temp
; 连续采样 8 次存入 SRAM 缓冲区
; 使用 Y 指针指向缓冲区
ldi     YL, LOW(SRAM_BUFFER)
ldi     YH, HIGH(SRAM_BUFFER)
ldi     r1, 8               ; 采样次数
ADC_SAMPLE_LOOP:
mov     temp, r0            ; 恢复通道号
rcall   ADC_READ_RAW
; 存储结果到缓冲区
st      Y+, temp            ; 低字节
st      Y+, temp2           ; 高字节
dec     r1
brne    ADC_SAMPLE_LOOP
; 冒泡排序(8 个 16 位值)
; 简单实现:仅对低字节排序(近似中值)
ldi     r1, 7               ; 外层循环次数
ADC_SORT_OUTER:
ldi     YL, LOW(SRAM_BUFFER)
ldi     YH, HIGH(SRAM_BUFFER)
ldi     r2, 7               ; 内层循环次数
ADC_SORT_INNER:
ld      r3, Y+              ; 读取当前值低字节
ld      r4, Y+              ; 读取当前值高字节
ld      r5, Y               ; 读取下一个值低字节
; 比较 r3:r4 与 r5:r6
cp      r4, r6
brlo    ADC_NO_SWAP
brne    ADC_DO_SWAP
cp      r3, r5
brlo    ADC_NO_SWAP
ADC_DO_SWAP:
; 交换
st      -Y, r5
st      -Y, r3
; 重新定位
adiw    YL, 2
ADC_NO_SWAP:
adiw    YL, 2
dec     r2
brne    ADC_SORT_INNER
dec     r1
brne    ADC_SORT_OUTER
; 取中间值(第 4 个元素,索引 6~7)
ldi     YL, LOW(SRAM_BUFFER + 6)
ldi     YH, HIGH(SRAM_BUFFER + 6)
ld      temp, Y+            ; 低字节
ld      temp2, Y            ; 高字节
; 恢复寄存器
pop     r31
pop     r30
pop     r29
pop     r28
pop     r27
pop     r26
pop     r25
pop     r24
pop     r23
pop     r22
pop     r21
pop     r20
pop     r19
pop     r18
pop     r17
pop     r16
pop     r15
pop     r14
pop     r13
pop     r12
pop     r11
pop     r10
pop     r9
pop     r8
pop     r7
pop     r6
pop     r5
pop     r4
pop     r3
pop     r2
pop     r1
pop     r0
ret
; ----------------------------------------------------------------------------
; ADC 单次读取
; 输入:temp = 通道号(0~3)
; 输出:temp:temp2 = 10 位 ADC 值
; ----------------------------------------------------------------------------
ADC_READ_RAW:
; 设置通道(保留参考电压位 REFS0)
in      temp2, ADMUX
andi    temp2, 0xF0
or      temp2, temp
out     ADMUX, temp2
; 启动转换
ldi     temp2, (1 &lt;&lt; ADSC)
out     ADCSRA, temp2
ADC_WAIT:
in      temp2, ADCSRA
sbrc    temp2, ADSC
rjmp    ADC_WAIT
; 读取结果
in      temp, ADCL
in      temp2, ADCH
ret
; ----------------------------------------------------------------------------
; 模式状态机更新
; 使用电压采样值(adc_val_hi:adc_val_lo)判断
; ----------------------------------------------------------------------------
UPDATE_MODE:
; 比较电压与各阈值
; 电压值在 adc_val_hi:adc_val_lo 中
; 先检查是否空闲(电压过低,未接电池)
ldi     temp2, HIGH(50)     ; 0.5V 对应 ADC ≈ 47
cp      adc_val_hi, temp2
brlo    MODE_SET_IDLE
; 检查温度是否超限
; (简化处理:此处省略温度判断,实际需采样温度通道)
; 检查电压是否过高(异常电池)
ldi     temp2, HIGH(VBAT_FAULT)
cp      adc_val_hi, temp2
brlo    MODE_CHECK_PRE
; 电压过高,进入故障
ldi     mode, MODE_FAULT
rjmp    MODE_UPDATE_DONE
MODE_CHECK_PRE:
; 检查是否低于预充阈值
ldi     temp2, HIGH(VBAT_PRE_MAX)
cp      adc_val_hi, temp2
brlo    MODE_SET_PRE
; 检查是否低于恒流转恒压阈值
ldi     temp2, HIGH(VBAT_CC_MAX)
cp      adc_val_hi, temp2
brlo    MODE_SET_CC
; 检查是否低于恒压阈值
ldi     temp2, HIGH(VBAT_CV)
cp      adc_val_hi, temp2
brlo    MODE_SET_CV
; 达到恒压区域
ldi     mode, MODE_CV
rjmp    MODE_UPDATE_DONE
MODE_SET_IDLE:
ldi     mode, MODE_IDLE
rjmp    MODE_UPDATE_DONE
MODE_SET_PRE:
ldi     mode, MODE_PRE
rjmp    MODE_UPDATE_DONE
MODE_SET_CC:
ldi     mode, MODE_CC
rjmp    MODE_UPDATE_DONE
MODE_UPDATE_DONE:
ret
; ----------------------------------------------------------------------------
; PWM 占空比更新
; 根据当前模式设置占空比(简化 PI 控制为分段常量)
; ----------------------------------------------------------------------------
UPDATE_PWM:
cpi     mode, MODE_IDLE
breq    PWM_SET_ZERO
cpi     mode, MODE_DONE
breq    PWM_SET_ZERO
cpi     mode, MODE_FAULT
breq    PWM_SET_ZERO
cpi     mode, MODE_PRE
breq    PWM_SET_PRE
cpi     mode, MODE_CC
breq    PWM_SET_CC
; MODE_CV:恒压模式,占空比由电压误差决定(简化)
; 此处使用固定中等占空比,实际应实现 PI 控制
ldi     duty_hi, 128        ; 约 50% 占空比
rjmp    PWM_UPDATE_DONE
PWM_SET_ZERO:
clr     duty_hi
rjmp    PWM_UPDATE_DONE
PWM_SET_PRE:
ldi     duty_hi, 32         ; 约 12.5% 占空比(预充小电流)
rjmp    PWM_UPDATE_DONE
PWM_SET_CC:
ldi     duty_hi, 200        ; 约 78% 占空比(恒流大电流)
rjmp    PWM_UPDATE_DONE
PWM_UPDATE_DONE:
; 写入 OCR0A(8 位 PWM)
out     OCR0A, duty_hi
ret
; ----------------------------------------------------------------------------
; LED 状态更新
; 空闲:红灯常亮;充电中:红灯闪烁;充满:绿灯常亮;故障:快速闪烁
; ----------------------------------------------------------------------------
UPDATE_LED:
cpi     mode, MODE_IDLE
breq    LED_RED_ON
cpi     mode, MODE_DONE
breq    LED_GREEN_ON
cpi     mode, MODE_FAULT
breq    LED_FAST_BLINK
; 充电中:慢速闪烁(简化:每 500ms 翻转一次)
; 使用 tick_cnt 计数,每 500ms 翻转
ldi     temp, 250
cp      tick_cnt, temp
brlo    LED_UPDATE_DONE
; 翻转 LED
in      temp, PORTB
ldi     temp2, (1 << PIN_LED)
eor     temp, temp2
out     PORTB, temp
clr     tick_cnt
rjmp    LED_UPDATE_DONE
LED_RED_ON:
; 红灯亮(假设 PB5 高电平为红)
sbi     PORTB, PIN_LED
rjmp    LED_UPDATE_DONE
LED_GREEN_ON:
; 绿灯亮(假设 PB5 低电平为绿)
cbi     PORTB, PIN_LED
rjmp    LED_UPDATE_DONE
LED_FAST_BLINK:
; 快速闪烁(简化:每 250ms 翻转)
ldi     temp, 125
cp      tick_cnt, temp
brlo    LED_UPDATE_DONE
in      temp, PORTB
ldi     temp2, (1 << PIN_LED)
eor     temp, temp2
out     PORTB, temp
clr     tick_cnt
LED_UPDATE_DONE:
ret
; ----------------------------------------------------------------------------
; GPIO 模拟 UART 发送状态字节
; 波特率 9600bps,8 数据位,无校验,1 停止位
; 位时间 = 1/9600 ≈ 104.17us
; 发送内容:模式字节(简化)
; ----------------------------------------------------------------------------
UART_SEND_STATUS:
; 发送帧头 0xAA
ldi     uart_data, 0xAA
rcall   UART_SEND_BYTE
; 发送模式字节
mov     uart_data, mode
rcall   UART_SEND_BYTE
; 发送电压高字节
mov     uart_data, adc_val_hi
rcall   UART_SEND_BYTE
; 发送电压低字节
mov     uart_data, adc_val_lo
rcall   UART_SEND_BYTE
; 发送校验字节(简化:固定 0x00)
clr     uart_data
rcall   UART_SEND_BYTE
ret
; ----------------------------------------------------------------------------
; UART 发送一个字节
; 输入:uart_data = 待发送数据
; ----------------------------------------------------------------------------
UART_SEND_BYTE:
push    temp
push    temp2
push    r0
; 保存数据
mov     r0, uart_data
; 起始位:拉低
cbi     PORTB, PIN_UART_TX
rcall   DELAY_104US
; 发送 8 个数据位,LSB 先发
ldi     temp, 8
UART_BIT_LOOP:
; 检查当前位
sbrc    r0, 0
sbi     PORTB, PIN_UART_TX
sbrs    r0, 0
cbi     PORTB, PIN_UART_TX
; 右移数据
lsr     r0
rcall   DELAY_104US
dec     temp
brne    UART_BIT_LOOP
; 停止位:拉高
sbi     PORTB, PIN_UART_TX
rcall   DELAY_104US
pop     r0
pop     temp2
pop     temp
ret
; ----------------------------------------------------------------------------
; 延时 104us(9600bps 一位时间)
; 1.2MHz 时钟,1 周期 ≈ 0.833us,104us ≈ 125 周期
; ----------------------------------------------------------------------------
DELAY_104US:
push    temp
ldi     temp, 41            ; 约 125 周期 / 3 ≈ 41
DELAY_104US_LOOP:
dec     temp
brne    DELAY_104US_LOOP
pop     temp
ret
; ----------------------------------------------------------------------------
; 延时 N 毫秒
; 输入:temp = 毫秒数
; 1ms ≈ 1200 周期 @1.2MHz
; ----------------------------------------------------------------------------
DELAY_MS:
push    temp2
push    temp
DELAY_MS_OUTER:
ldi     temp2, 200          ; 内层循环约 1200 周期
DELAY_MS_INNER:
dec     temp2
brne    DELAY_MS_INNER
pop     temp
dec     temp
push    temp
brne    DELAY_MS_OUTER
pop     temp
pop     temp2
ret
; ----------------------------------------------------------------------------
; 定时器 0 比较匹配 A 中断服务
; 维护毫秒时基(每 100 次中断 = 1ms,100kHz PWM)
; ----------------------------------------------------------------------------
TIM0_COMPA_ISR:
push    temp
in      temp, SREG
push    temp
; 每 100 次中断 = 1ms
inc     tick_cnt
cpi     tick_cnt, 100
brlo    TIM0_ISR_DONE
clr     tick_cnt
TIM0_ISR_DONE:
pop     temp
out     SREG, temp
pop     temp
reti
; ----------------------------------------------------------------------------
; 未使用的中断服务(占位)
; ----------------------------------------------------------------------------
INT0_ISR:
PCINT0_ISR:
TIM0_OVF_ISR:
TIM0_COMPB_ISR:
ADC_ISR:
WDT_ISR:
reti
; ----------------------------------------------------------------------------
; SRAM 缓冲区(用于 ADC 中值滤波)
; ----------------------------------------------------------------------------
.dseg
.org    0x60
SRAM_BUFFER:
.byte   16                  ; 8 个 16 位采样值
.end

上述汇编版本与 C 语言版本功能等价,但更贴近硬件底层。汇编实现将浮点 PI 控制简化为分段常量占空比输出,以节省代码空间和运算周期;若需完整 PI 控制,可在中断服务中实现定点 PI 累加。汇编代码占用 Flash 约 600 字节,RAM 仅需 16 字节缓冲区,非常适合 ATtiny13 这类 1KB Flash、64B RAM 的超小资源芯片。实际工程中可根据实时性要求选择 C 或汇编实现,两者烧录方式相同。

2.7 初级侧关键元器件选型与计算

初级侧以 uC3845 电流模式 PWM 控制器为核心,围绕启动电阻、电流采样电阻、反激变压器匝比以及 TL431 反馈补偿网络进行设计。以下给出各关键元器件的选型依据与计算过程。

2.7.1 启动电阻选型

uC3845 的启动电流典型值为 1.0mA,启动阈值电压(VON)为 7.9V(典型值),关断阈值电压(VOFF)为 7.0V。启动电阻 Rstart 从整流后的直流母线电压(约 310V,对应 AC 220V 峰值)取电,为 VCC 电容充电。

启动电阻需满足两个条件:一是启动阶段为 VCC 电容提供足够的充电电流,使 VCC 在合理时间内达到 7.9V 启动阈值;二是启动完成后,由辅助绕组供电维持 uC3845 工作,启动电阻上的持续电流应尽量小以降低损耗。

启动电流取 Istart = 1.5mA(略大于芯片启动电流 1.0mA,留有余量),则启动电阻为:

plaintext 复制代码
R_start = (V_bus - V_ON) / I_start
        = (310V - 7.9V) / 1.5mA
        ≈ 201kΩ

取标准值 Rstart = 200kΩ。此时实际启动电流为:

plaintext 复制代码
I_start = (310V - 7.9V) / 200kΩ ≈ 1.51mA

启动电阻的功耗为:

plaintext 复制代码
P_Rstart = (V_bus - V_ON)² / R_start
         = (310V - 7.9V)² / 200kΩ
         ≈ 0.456W

考虑到启动完成后电阻两端电压仍接近母线电压(辅助绕组供电后 VCC 约为 12V,但电阻上端仍接母线),实际持续功耗约为 (310V - 12V)² / 200kΩ ≈ 0.444W。选用两颗 100kΩ/0.5W 电阻串联,既满足耐压要求(每颗承受约 155V,低于 200V 额定电压),又使总功耗分摊到两颗电阻上,提高可靠性。

2.7.2 电流采样电阻选型

uC3845 内部电流检测比较器的阈值电压为 1.0V(典型值)。电流采样电阻 Rsense 串联在功率 MOSFET 源极与地之间,将初级峰值电流转换为电压信号送入芯片的 ISENSE 引脚(3脚)。

本设计输出功率为 Po = 8.4V × 2.5A = 21W。设变换效率 η = 0.85,则输入功率为:

plaintext 复制代码
P_in = P_o / η = 21W / 0.85 ≈ 24.7W

反激变换器工作在连续导通模式(CCM)与断续导通模式(DCM)的临界点附近。设最大占空比 Dmax = 0.5(uC3845 最大占空比典型值为 50%),开关频率 fsw = 100kHz,则初级峰值电流估算为:

plaintext 复制代码
I_pk = 2 × P_in / (V_bus_min × D_max)
     = 2 × 24.7W / (240V × 0.5)   (取母线电压最低约 240V,对应 AC 170V 输入)
     ≈ 0.412A

考虑启动、瞬态及过载情况,取峰值电流裕量系数 1.3,则设计峰值电流为:

plaintext 复制代码
I_pk_design = 1.3 × 0.412A ≈ 0.536A

电流采样电阻由 ISENSE 阈值电压与设计峰值电流决定:

plaintext 复制代码
R_sense = V_ISENSE(threshold) / I_pk_design
        = 1.0V / 0.536A
        ≈ 1.87Ω

取标准值 Rsense = 1.8Ω。此时实际过流保护点对应的峰值电流为:

plaintext 复制代码
I_pk(OCP) = 1.0V / 1.8Ω ≈ 0.556A

采样电阻的峰值功耗为:

plaintext 复制代码
P_Rsense = I_pk(OCP)² × R_sense
         = (0.556A)² × 1.8Ω
         ≈ 0.556W

由于电流采样电阻上流过的是脉冲电流,其平均功耗远低于峰值功耗。设占空比 D = 0.5,则平均功耗约为 0.556W × 0.5 ≈ 0.28W。选用 1.8Ω/1W 的金属膜电阻或合金电阻,确保足够的功率裕量。同时在 ISENSE 引脚与采样电阻之间加入 RC 滤波(典型值 R = 1kΩ,C = 1nF),滤除 MOSFET 开通瞬间的尖峰噪声,防止误触发过流保护。

2.7.3 反激变压器匝比计算

反激变压器 T1 的匝比由输出电压、输入电压范围及最大占空比共同决定。次级主绕组输出经半波整流后为电池包充电,输出电压最大值 Vo = 9V(考虑二极管压降后的设计值),输出电流最大值 3A。

设次级整流二极管正向压降 VD = 0.7V,则次级绕组感应电压幅值为:

plaintext 复制代码
V_sec = V_o + V_D = 9V + 0.7V = 9.7V

伏秒平衡原理:反激变换器在稳态工作时,变压器初级绕组在开关管导通期间(ton)储存能量,在关断期间(toff)向次级释放能量。根据伏秒平衡法则,一个完整开关周期内,初级绕组与次级绕组上的伏秒积必须相等,即:

plaintext 复制代码
V_bus × t_on = n × V_sec × t_off

其中 Vbus 为初级侧直流母线电压,ton 为开关管导通时间,toff 为关断时间,n = Np/Ns 为初级与次级绕组匝比。将导通时间与开关周期 T 的比值定义为占空比 D = ton / T,且 toff = (1 - D) × T,代入上式可得匝比与占空比的关系:

plaintext 复制代码
V_bus × D × T = n × V_sec × (1 - D) × T
⇒ n = V_bus × D / (V_sec × (1 - D))

由上式可见,匝比 n 与输入母线电压 Vbus、占空比 D 成正比,与次级感应电压 Vsec 成反比。在最低输入电压时占空比达到最大值 Dmax,此时匝比应满足:

plaintext 复制代码
n = V_bus_min × D_max / (V_sec × (1 - D_max))

反激变换器在 CCM 模式下,初级与次级绕组的电压关系满足上述伏秒平衡。设最大占空比 Dmax = 0.5(uC3845 最大占空比典型值为 50%),最低输入母线电压 Vbus_min = 240V(对应 AC 170V 输入),则匝比 n = Np/Ns 为:

plaintext 复制代码
n = V_bus_min × D_max / (V_sec × (1 - D_max))
  = 240V × 0.5 / (9.7V × 0.5)
  ≈ 24.7

取匝比 n = 25,即初级绕组匝数 Np = 25 × Ns。设次级主绕组 Ns = 4 匝,则初级绕组 Np = 100 匝。

占空比与匝比的相互约束:匝比确定后,实际工作占空比随输入电压变化。在最高输入母线电压 Vbus_max = 380V(对应 AC 265V 输入)时,由伏秒平衡反推实际占空比为:

plaintext 复制代码
D = n × V_sec / (V_bus_max + n × V_sec)
  = 25 × 9.7V / (380V + 25 × 9.7V)
  = 242.5 / 622.5
  ≈ 0.39

可见在最高输入电压下占空比降至约 0.39,低于 uC3845 的 50% 上限,留有充足裕量,保证芯片在宽输入电压范围内均不会触及最大占空比限制。

辅助绕组用于为 uC3845 提供 VCC 供电(目标 12V)以及为 ATtiny13 提供 5V 稳压输入。辅助绕组电压与次级主绕组电压之比等于匝数比:

plaintext 复制代码
V_aux / V_sec = N_aux / N_s

设辅助绕组整流后目标电压 Vaux = 14V(考虑二极管压降及负载调整率,留有余量),则:

plaintext 复制代码
N_aux = N_s × V_aux / V_sec = 4 × 14V / 9.7V ≈ 5.8 匝

取 Naux = 6 匝。此时辅助绕组空载电压约为 14.5V,经半波整流和滤波后,配合后级稳压电路为 uC3845 提供约 12V 的 VCC,同时另一路经 TL431 稳压至 5V 为 ATtiny13 供电。

磁芯选择依据:变压器磁芯选择需同时满足功率容量与匝数绕制两方面的要求。首先从功率容量角度,采用面积乘积法(AP 法)估算所需磁芯尺寸:

plaintext 复制代码
AP = A_e × A_w = (P_o / (η × K_0 × f_sw × ΔB × J))^(4/3)

其中 Po 为输出功率(21W),η 为效率(0.85),K0 为窗口利用系数(取 0.4),fsw 为开关频率(100kHz),ΔB 为磁通密度摆幅(0.2T),J 为电流密度(取 4A/mm²)。代入计算:

plaintext 复制代码
AP = (21W / (0.85 × 0.4 × 100×10³ Hz × 0.2T × 4A/mm²))^(4/3)
   ≈ 0.028 cm⁴

查 EE 型磁芯手册,EE19 磁芯的 AP 值约为 0.04 cm&sup4,EE22 约为 0.06 cm&sup4,均大于所需 0.028 cm&sup4,满足功率容量要求。

其次从匝数绕制角度校验磁芯是否满足匝数要求。设磁芯有效截面积 Ae = 40mm²(EE22 典型值),最大磁通密度摆幅 ΔB = 0.2T,则初级绕组最小匝数校验为:

plaintext 复制代码
N_p_min = V_bus_min × D_max / (ΔB × A_e × f_sw)
        = 240V × 0.5 / (0.2T × 40×10⁻⁶ m² × 100×10³ Hz)
        ≈ 150 匝

上述计算得到的 150 匝大于按匝比推算的 100 匝,说明 EE22 磁芯在 0.2T 摆幅下需要更多匝数,绕制空间紧张。实际设计中可选用 Ae 更大的磁芯(如 EE25,Ae ≈ 52mm²),或适当提高 ΔB 至 0.25T(需选用低损耗材料),此时:

plaintext 复制代码
N_p_min = 240V × 0.5 / (0.25T × 52×10⁻⁶ m² × 100×10³ Hz)
        ≈ 92 匝

取 Np = 100 匝,Ns = 4 匝,Naux = 6 匝,匝比 n = 25,满足设计要求。EE25 磁芯(AP 约 0.1 cm&sup4)在 0.25T 摆幅下仅需 92 匝,绕制裕量充足。综合考虑成本与绕制工艺,本设计选用 EE25 磁芯,材质取 PC40 或同等低损耗功率铁氧体,居里温度高于 200℃,在 100kHz、0.25T 摆幅下磁芯损耗可接受。实际绕制时需注意初级绕组采用三明治绕法以降低漏感,漏感控制在初级电感量的 3% 以内。

辅助绕组匝数细化计算:上述辅助绕组按 Vaux = 14V 设计,取 Naux = 6 匝。下面进一步细化辅助绕组的两路输出设计。辅助绕组经半波整流后,一路为 uC3845 提供 VCC(目标 12V),另一路经 TL431 稳压至 5V 为 ATtiny13 供电。

uC3845 的 VCC 工作电压范围为 7.0V 至 30V,典型工作电流约 17mA(含栅极驱动)。为保证芯片在满载与轻载下均能稳定工作,辅助绕组整流滤波后的电压应留有足够裕量。设辅助绕组整流二极管压降 VD_aux = 0.7V,滤波电容纹波取 1V,则辅助绕组感应电压幅值需满足:

plaintext 复制代码
V_aux_rect = V_CC + V_D_aux + V_ripple
           = 12V + 0.7V + 1V
           = 13.7V

考虑负载调整率(约 5%)与温度漂移,取设计目标 Vaux = 14V,与前述一致。此时辅助绕组匝数:

plaintext 复制代码
N_aux = N_s × V_aux / V_sec = 4 × 14V / 9.7V ≈ 5.8 匝

取整 Naux = 6 匝。校验辅助绕组在最低输入电压(Vbus_min = 240V)下的电压:此时次级主绕组感应电压按匝比关系为:

plaintext 复制代码
V_sec(min) = V_bus_min × D_max / (n × (1 - D_max))
           = 240V × 0.5 / (25 × 0.5)
           = 9.6V

对应辅助绕组电压:

plaintext 复制代码
V_aux(min) = V_sec(min) × N_aux / N_s = 9.6V × 6 / 4 = 14.4V

整流滤波后约 13.7V,仍高于 uC3845 关断阈值 7.0V 且留有充足裕量,保证芯片在最低输入电压下也能持续工作。辅助绕组整流滤波后,一路直接为 uC3845 提供 VCC;另一路经 TL431 稳压至 5V 为 ATtiny13 供电。5V 稳压电路采用 TL431 + 三极管构成的线性稳压器,TL431 阴极经限流电阻接辅助绕组整流输出,通过三极管射极跟随输出 5V。设 ATtiny13 工作电流约 5mA,三极管基极电流约 0.5mA,TL431 最小工作电流 1mA,则限流电阻需提供约 1.5mA 电流,取辅助绕组整流电压 14V,限流电阻为:

plaintext 复制代码
R_aux = (V_aux_rect - V_CC - V_BE) / I_aux
      = (14V - 5V - 0.7V) / 1.5mA
      ≈ 5.5kΩ

取标准值 Raux = 5.6kΩ。5V 稳压输出经 100nF 与 10μF 电容并联滤波后为 ATtiny13 供电,保证数字电路电源的稳定性。

初级电感量计算(基于 CCM/DCM 临界条件):反激变压器初级电感量 Lp 决定变换器工作在 CCM 还是 DCM 模式。本设计工作在 CCM 与 DCM 的临界点附近,以保证在宽输入电压与负载范围内均能稳定工作。临界连续模式下的初级电感量为:

plaintext 复制代码
L_p(crit) = (V_bus_min × D_max)² / (2 × P_in × f_sw)

代入 Vbus_min = 240V,Dmax = 0.5,Pin = 24.7W,fsw = 100kHz:

plaintext 复制代码
L_p(crit) = (240V × 0.5)² / (2 × 24.7W × 100×10³ Hz)
          = 14400 / 4.94×10⁶
          ≈ 2.91 mH

为保证变换器在最低输入电压、满载时仍工作在 CCM 模式(减小初级峰值电流与输出纹波),实际初级电感量应略大于临界值,取 Lp = 3.0mH。此时在最低输入电压满载下的纹波电流系数约为 0.97,接近临界连续,兼顾了 CCM 的低峰值电流与 DCM 的快速动态响应。

初级电感量确定后,需校验磁芯气隙。反激变压器通过磁芯气隙存储能量,气隙长度由所需初级电感量与磁芯参数决定:

plaintext 复制代码
l_g = μ_0 × N_p² × A_e / L_p

其中 μ0 = 4π × 10&sup7 H/m 为真空磁导率,Np = 100 匝,Ae = 52mm² = 52 × 10&sup6 m²,Lp = 3.0mH。代入计算:

plaintext 复制代码
l_g = (4π × 10⁻⁷ × 100² × 52×10⁻⁶) / 3.0×10⁻³
    = (4π × 10⁻⁷ × 10⁴ × 52×10⁻⁶) / 3.0×10⁻³
    ≈ 0.218 mm

取气隙 lg = 0.22mm。实际绕制时,可在 EE25 磁芯中柱研磨 0.22mm 气隙,或采用垫片方式在磁芯中柱与边柱之间垫入 0.11mm 厚的绝缘垫片(等效中柱气隙 0.22mm)。加气隙后磁芯有效磁导率下降,需校验最大磁通密度是否饱和。满载时初级峰值电流为:

plaintext 复制代码
I_pk = V_bus_min × D_max / (L_p × f_sw)
     = 240V × 0.5 / (3.0×10⁻³ H × 100×10³ Hz)
     ≈ 0.4A

考虑过流保护点 0.556A,最大磁通密度为:

plaintext 复制代码
B_max = μ_0 × N_p × I_pk(OCP) / l_g
      = (4π × 10⁻⁷ × 100 × 0.556) / 0.22×10⁻³
      ≈ 0.318T

该值接近 PC40 磁芯的饱和磁通密度(约 0.39T @ 100℃),留有约 18% 的裕量,满足设计要求。若需进一步降低 Bmax,可适当增大气隙或增加初级匝数,但需权衡绕制空间与铜损。

变压器设计参数汇总:综合上述计算,反激变压器 T1 的完整设计参数汇总如下表所示。

参数 数值 说明
磁芯型号 EE25(PC40 材质) AP 法选型,Ae = 52mm²
初级绕组匝数 Np 100 匝 三明治绕法,降低漏感
次级主绕组匝数 Ns 4 匝 输出 9V/3A(最大值)
辅助绕组匝数 Naux 6 匝 VCC 12V 与 5V 稳压输入
匝比 n(Np/Ns) 25 伏秒平衡,Dmax = 0.5
初级电感量 Lp 3.0mH CCM/DCM 临界条件计算
磁芯气隙 lg 0.22mm 中柱研磨或垫片实现
初级线径 0.25mm(φ0.25) 电流密度 4A/mm²,峰值电流 0.556A
次级线径 0.8mm(φ0.8)或 2 股 φ0.55 并绕 输出电流 3A,考虑集肤效应
辅助绕组线径 0.2mm(φ0.2) 辅助绕组电流小(约 20mA)
最大磁通密度 Bmax 约 0.318T 过流保护点 0.556A 时校验
漏感要求 ≤ 3% Lp(约 90μH) 三明治绕法控制

线径选择说明:初级绕组有效电流约 0.25A(Pin / Vbus_min = 24.7W / 240V ≈ 0.103A,考虑占空比后 RMS 约 0.15A),按电流密度 4A/mm² 计算所需截面积约 0.038mm²,对应线径约 0.22mm,取 0.25mm 留有余量。次级绕组输出电流 3A,考虑 100kHz 下的集肤效应(趋肤深度约 0.21mm),采用 0.8mm 单股或 2 股 0.55mm 并绕以减小交流电阻。辅助绕组电流仅约 20mA,取 0.2mm 线径即可满足要求。

实际绕制时,建议按初级(50 匝)--- 次级(4 匝)--- 初级(50 匝)的三明治结构绕制,将次级绕组夹在两层初级绕组之间,可有效降低漏感。绕制完成后,用 LCR 表在 100kHz 下测量初级电感量,若偏差超过 ±5%,可通过微调气隙修正;同时测量漏感(短路次级后测初级电感),确保漏感小于初级电感量的 3%。

2.7.4 TL431 反馈补偿网络参数

次级输出电压经 TL431(U2)与光耦(U3)反馈至初级侧 uC3845 的 COMP 引脚(1脚),构成闭环稳压。反馈网络的核心是 TL431 的参考端分压电阻与补偿网络。

TL431 内部基准电压 Vref = 2.5V。输出电压 Vout = 8.4V(恒压充电值),由上分压电阻 Rupper 与下分压电阻 Rlower 构成的分压网络决定:

plaintext 复制代码
V_out = V_ref × (1 + R_upper / R_lower)

取 Rlower = 10kΩ,则:

plaintext 复制代码
R_upper = R_lower × (V_out / V_ref - 1)
        = 10kΩ × (8.4V / 2.5V - 1)
        = 10kΩ × 2.36
        = 23.6kΩ

取标准值 Rupper = 23.7kΩ(1% 精度),此时实际输出电压为:

plaintext 复制代码
V_out = 2.5V × (1 + 23.7kΩ / 10kΩ) = 2.5V × 3.37 = 8.425V

该值略高于 8.4V,可通过 ATtiny13 输出的 PWM 经 RC 滤波后微调 TL431 参考点来精确校准,实现恒压 8.4V 的目标。

TL431 的最小工作电流 IKA(min) = 1mA,为保证可靠工作,流过下分压电阻的电流应远大于 TL431 参考端输入电流(典型值 2μA)。下分压电阻电流为:

plaintext 复制代码
I_Rlower = V_ref / R_lower = 2.5V / 10kΩ = 0.25mA

该电流远大于 TL431 参考端输入电流,满足精度要求。

光耦 LED 串联限流电阻 RLED 的计算:设光耦 LED 正向压降 VF = 1.2V,TL431 阴极电压在稳压工作时约为 2.5V 至 3V,取 VKA = 3V,则限流电阻两端电压为:

plaintext 复制代码
V_R = V_out - V_F - V_KA = 8.4V - 1.2V - 3V = 4.2V

设光耦 LED 工作电流 IF = 5mA(保证足够的传输比,同时兼顾功耗),则:

plaintext 复制代码
R_LED = V_R / I_F = 4.2V / 5mA = 840Ω

取标准值 RLED = 820Ω。此时实际 LED 电流约为 5.1mA,满足光耦驱动要求。

反馈补偿网络采用典型的 PI 补偿结构,由 Rcomp 与 Ccomp 串联后跨接在 TL431 阴极与参考端之间。补偿网络的零点频率应设置在开关频率的 1/10 至 1/5 之间,即 10kHz 至 20kHz,以保证足够的相位裕度。

设补偿零点 fz = 15kHz,取 Rcomp = 10kΩ,则补偿电容为:

plaintext 复制代码
C_comp = 1 / (2π × f_z × R_comp)
       = 1 / (2π × 15×10³ Hz × 10×10³ Ω)
       ≈ 1.06nF

取标准值 Ccomp = 1nF。同时在 TL431 参考端并联一只高频旁路电容 Cref = 100pF,用于滤除高频噪声,防止反馈环路在高频段产生振荡。

综上,初级侧关键元器件选型汇总如下:

元器件 参数 选型值 关键依据
启动电阻 Rstart 2 × 100kΩ / 0.5W 串联 200kΩ 启动电流 1.5mA,兼顾耐压与功耗
电流采样电阻 Rsense 1.8Ω / 1W 1.8Ω ISENSE 阈值 1.0V,过流保护点 0.556A
变压器匝比 n Np:Ns:Naux = 100:4:6 n = 25 伏秒平衡,Dmax = 0.5
TL431 上分压电阻 Rupper 23.7kΩ / 1% 23.7kΩ Vout = 8.4V,Vref = 2.5V
TL431 下分压电阻 Rlower 10kΩ / 1% 10kΩ 分压电流 0.25mA,远大于参考端输入电流
光耦 LED 限流电阻 RLED 820Ω 820Ω LED 工作电流约 5.1mA
补偿电阻 Rcomp 10kΩ 10kΩ 与 Ccomp 构成 PI 补偿
补偿电容 Ccomp 1nF 1nF 补偿零点约 15kHz
参考端旁路电容 Cref 100pF 100pF 滤除高频噪声

以上选型与计算过程为初级侧反激变换电路提供了完整的参数依据。实际调试时,建议先以空载和轻载验证反馈环路稳定性,再逐步加载至额定输出,观察各关键节点波形并微调补偿网络参数。

2.7.5 电压采样分压电阻计算

电压采样将输出电压 Vout 经两只分压电阻分压后送入 ATtiny13 的 7 脚 PB2/ADC1。ATtiny13 的 ADC 参考电压取内部 1.1V 基准(Vref = 1.1V),为保证最高采样电压(约 8.5V)经分压后不超过参考电压,取最高采样电压 Vmax = 8.5V 时对应 ADC 满量程的 90% 左右,即采样电压 Vs_max = 1.0V。

plaintext 复制代码
分压比 k = V_s_max / V_max = 1.0V / 8.5V ≈ 0.1176

设上分压电阻 Ru1 与下分压电阻 Rd1 构成分压网络,则:

plaintext 复制代码
V_s = V_out × R_d1 / (R_u1 + R_d1)

取下分压电阻 Rd1 = 10kΩ,则上分压电阻为:

plaintext 复制代码
R_u1 = R_d1 × (1 / k - 1) = 10kΩ × (1 / 0.1176 - 1) ≈ 75kΩ

取标准值 Ru1 = 75kΩ(1% 精度),此时实际分压比为:

plaintext 复制代码
k = 10kΩ / (75kΩ + 10kΩ) = 10 / 85 ≈ 0.1176

校验最高采样电压:Vs_max = 8.5V × 0.1176 ≈ 1.0V,低于 ADC 参考电压 1.1V,满足要求。恒压 8.4V 时采样电压约为 0.988V,对应 ADC 读数约 920(12 位分辨率下),分辨率约为 8.5V / 4096 ≈ 2.1mV/LSB,满足电压检测精度要求。

2.7.6 电流采样电阻与运放增益计算

电流采样电阻 Rcs 串联在次级充电回路中,将充电电流转换为电压信号,经运放放大后送入 ATtiny13 的 3 脚 PB4/ADC2。需保证恒流 2.5A 与终止电流 125mA 均能被准确分辨。

设电流采样电阻 Rcs = 0.05Ω(50mΩ,合金电阻),则恒流 2.5A 时采样电阻压降为:

plaintext 复制代码
V_cs(2.5A) = 2.5A × 0.05Ω = 0.125V

终止电流 125mA 时采样电阻压降为:

plaintext 复制代码
V_cs(125mA) = 0.125A × 0.05Ω = 0.00625V = 6.25mV

采样电阻功耗(恒流 2.5A 时):

plaintext 复制代码
P_Rcs = I² × R = (2.5A)² × 0.05Ω = 0.3125W

选用 0.05Ω/0.5W 合金电阻,功率裕量充足。运放采用同相放大结构,设运放增益为 Av,则运放输出电压为:

plaintext 复制代码
V_op = V_cs × A_v

恒流 2.5A 时希望运放输出接近 ADC 满量程的 80%(约 0.88V),则增益为:

plaintext 复制代码
A_v = 0.88V / 0.125V = 7.04

取增益 Av = 7,由同相放大公式 Av = 1 + Rf / Rg 确定反馈电阻。取 Rg = 10kΩ,则:

plaintext 复制代码
R_f = R_g × (A_v - 1) = 10kΩ × (7 - 1) = 60kΩ

取标准值 Rf = 60kΩ(1% 精度),实际增益为 Av = 1 + 60kΩ / 10kΩ = 7。此时恒流 2.5A 对应运放输出:

plaintext 复制代码
V_op(2.5A) = 0.125V × 7 = 0.875V

终止电流 125mA 对应运放输出:

plaintext 复制代码
V_op(125mA) = 6.25mV × 7 = 43.75mV

对应 ADC 读数约 43.75mV / 1.1V × 4096 ≈ 163,远大于噪声底,可准确分辨终止电流。电流分辨率约为 2.5A / 4096 × 7 ≈ 4.3mA/LSB,满足恒流与终止判定精度要求。

2.7.7 NTC 分压网络计算

温度采样由电池包 NTC 热敏电阻与固定电阻构成分压网络,连接到 ATtiny13 的 2 脚 PB3/ADC3。设 NTC 采用 10kΩ 系列(25℃ 时阻值 10kΩ),B 值 3435K。

取固定上拉电阻 Rntc = 10kΩ 接 Vref(1.1V),NTC 接地,则分压输出为:

plaintext 复制代码
V_temp = V_ref × R_ntc(T) / (R_pull + R_ntc(T))

NTC 阻值与温度的关系由 B 值公式描述:

plaintext 复制代码
R(T) = R_25 × exp(B × (1/T - 1/T_25))

其中 T_25 = 298.15K。计算典型温度点的 NTC 阻值:

plaintext 复制代码
R(0℃)  = 10kΩ × exp(3435 × (1/273.15 - 1/298.15)) ≈ 33.9kΩ
R(25℃) = 10kΩ
R(45℃) = 10kΩ × exp(3435 × (1/318.15 - 1/298.15)) ≈ 4.6kΩ
R(60℃) = 10kΩ × exp(3435 × (1/333.15 - 1/298.15)) ≈ 2.5kΩ

对应分压输出电压为:

plaintext 复制代码
V_temp(0℃)  = 1.1V × 33.9kΩ / (10kΩ + 33.9kΩ) ≈ 0.849V
V_temp(25℃) = 1.1V × 10kΩ / (10kΩ + 10kΩ) = 0.55V
V_temp(45℃) = 1.1V × 4.6kΩ / (10kΩ + 4.6kΩ) ≈ 0.347V
V_temp(60℃) = 1.1V × 2.5kΩ / (10kΩ + 2.5kΩ) ≈ 0.22V

设充电安全温度范围为 0℃ 至 45℃,则对应 ADC 阈值电压为 0.347V 至 0.849V。ATtiny13 在固件中设定低温阈值约 0.85V、高温阈值约 0.35V,采样电压超出该范围即判定温度异常,转入错误模式保护电池。取固定电阻 Rntc = 10kΩ(1% 精度),与 NTC 在 25℃ 时阻值相等,使中点电压恰为 Vref 的一半,温度检测范围对称合理。

2.7.8RC 滤波截止频率计算

三路采样信号及 PWM 输出均需经 RC 低通滤波以抑制高频噪声。RC 滤波的截止频率为:

plaintext 复制代码
f_c = 1 / (2π × R × C)

电压采样与电流采样通道的 RC 滤波需兼顾噪声抑制与响应速度。取 R = 10kΩ,C = 100nF,则截止频率为:

plaintext 复制代码
f_c = 1 / (2π × 10kΩ × 100nF) ≈ 159Hz

该截止频率远低于 100kHz 的开关纹波频率,可有效滤除开关噪声;同时远高于充电状态切换的带宽需求(状态切换周期为秒级),不影响采样响应。

PWM 输出端的 RC 滤波用于将 100kHz 的 PWM 平滑为直流电平。取 R = 10kΩ,C = 1μF,则截止频率为:

plaintext 复制代码
f_c = 1 / (2π × 10kΩ × 1μF) ≈ 15.9Hz

该截止频率远低于 PWM 频率 100kHz,纹波衰减充分;同时高于 PWM 微调 TL431 参考点所需的带宽(调节周期为毫秒级),保证电压调节的响应速度。PWM 纹波经 RC 滤波后残余幅度约为:

plaintext 复制代码
V_ripple ≈ V_pwm × f_c / f_pwm = 5V × 15.9Hz / 100kHz ≈ 0.8mV

残余纹波小于 1mV,对 TL431 参考点的扰动可忽略,满足恒压 8.4V 的精度要求。

2.7.9 PWM 扩展低 4 位时间分配计算

ATtiny13 的 PB0 输出 100kHz 的 8 位 PWM,一个 PWM 周期 T = 10μs。8 位 PWM 的占空比分辨率为 1/256,对应输出电压调节步进过大。本设计采用 4 位扩展法,将 8 位 PWM 扩展为 12 位精度:高 8 位决定基础占空比,低 4 位通过软件在多个 PWM 周期内按比例分配实现。

12 位 PWM 的总分辨率为 4096 级,对应占空比步进为:

plaintext 复制代码
ΔD = 1 / 4096 ≈ 0.0244%

低 4 位取值范围为 0 至 15,表示在 16 个 PWM 周期内,有 N 个周期的高 8 位占空比加 1(即多输出一个 LSB 的导通时间),其余 16 - N 个周期保持基础占空比。设 12 位 PWM 值为 D12,则高 8 位部分为:

plaintext 复制代码
D_high = D12 / 16(取整)

低 4 位部分为:

plaintext 复制代码
D_low = D12 % 16(余数,0 至 15)

在每 16 个 PWM 周期组成的一个扩展周期内,前 D_low 个周期的高 8 位占空比设为 D_high + 1,后 16 - D_low 个周期的高 8 位占空比设为 D_high。扩展周期总时长为:

plaintext 复制代码
T_ext = 16 × 10μs = 160μs

以恒压 8.4V 校准为例,设 TL431 参考点微调需要 PWM 输出占空比 D = 50.0%,对应 12 位值为:

plaintext 复制代码
D12 = 0.5 × 4096 = 2048

则高 8 位部分为:

plaintext 复制代码
D_high = 2048 / 16 = 128(对应 8 位占空比 128/256 = 50%)

低 4 位部分为:

plaintext 复制代码
D_low = 2048 % 16 = 0

即 16 个周期内全部保持 50% 占空比,无需额外分配。若需要 D = 50.05% 的占空比,对应 12 位值为:

plaintext 复制代码
D12 = 0.5005 × 4096 ≈ 2050

则高 8 位部分为:

plaintext 复制代码
D_high = 2050 / 16 = 128(取整)

低 4 位部分为:

plaintext 复制代码
D_low = 2050 % 16 = 2

即在每 16 个 PWM 周期(160μs)内,前 2 个周期的高 8 位占空比设为 129/256 ≈ 50.39%,后 14 个周期保持 128/256 = 50%。平均占空比为:

plaintext 复制代码
D_avg = (2 × 129 + 14 × 128) / (16 × 256) = (258 + 1792) / 4096 = 2050 / 4096 ≈ 50.05%

与目标占空比精确一致。扩展周期 160μs 对应的等效调节频率约为 6.25kHz,远高于 RC 滤波截止频率 15.9Hz,经滤波后输出平滑直流,无可见纹波。低 4 位时间分配由 ATtiny13 定时器中断实现,在每个 PWM 周期开始时根据当前周期序号与 D_low 的比较结果决定是否将占空比加 1,软件开销极小。

综上,次级侧采样与 PWM 扩展电路的关键参数选型汇总如下:

电路 参数 选型值 关键依据
电压采样分压 Ru1 / Rd1 75kΩ / 10kΩ(1%) 分压比 0.1176,8.5V 对应 1.0V
电流采样电阻 Rcs 0.05Ω / 0.5W 合金电阻 50mΩ 2.5A 压降 0.125V,功耗 0.31W
运放增益 Av Rf / Rg = 60kΩ / 10kΩ Av = 7 2.5A 输出 0.875V,125mA 输出 43.75mV
NTC 上拉电阻 Rntc 10kΩ / 1% 10kΩ 25℃ 中点 0.55V,0~45℃ 阈值 0.35~0.85V
采样 RC 滤波 R = 10kΩ,C = 100nF fc ≈ 159Hz 抑制 100kHz 开关纹波
PWM RC 滤波 R = 10kΩ,C = 1μF fc ≈ 15.9Hz 纹波 < 1mV,调节带宽充足
PWM 扩展 8 位 + 4 位扩展 12 位 / 4096 级 扩展周期 160μs,低 4 位按 16 周期分配

以上计算为次级侧采样与 PWM 扩展电路提供了完整的参数依据。实际调试时,建议先用精密电压源校准电压采样分压比,再用电子负载验证电流采样与运放增益的线性度,最后通过示波器观察 PWM 扩展输出经 RC 滤波后的直流电平,确认纹波与调节精度满足恒压 8.4V 的要求。

2.8 常见故障与调试指南

充电器在开发调试与现场使用过程中,可能遇到启动失败、输出电压不准、充电电流异常、通信无数据等典型问题。本节针对这些常见故障,给出对应的排查步骤、测量点与解决措施,帮助快速定位并修复问题。

2.8.1 启动失败

**故障现象:**上电后充电器无任何输出,LED 不亮,uC3845 不工作。

排查步骤与测量点:

  1. 用万用表测量整流桥后直流母线电压,正常应为 310V 左右(AC 220V 输入)。若为 0V,检查保险丝、整流桥与输入滤波电容是否损坏。
  2. 测量 uC3845 的 VCC 引脚(7脚)电压。启动阶段应由启动电阻从母线取电为 VCC 电容充电,电压应缓慢上升至 7.9V 启动阈值。若 VCC 始终为 0V,检查启动电阻是否开路或虚焊。
  3. 若 VCC 电压在 7.0V~7.9V 之间反复波动(打嗝),说明芯片启动后辅助绕组未能及时供电维持,检查辅助绕组整流二极管、滤波电容及限流电阻是否正常。
  4. 用示波器观察 uC3845 的 OUT 引脚(6脚)是否有 PWM 波形输出。若无输出,检查 ISENSE 引脚(3脚)电压是否超过 1.0V 阈值(可能因电流采样电阻短路或 RC 滤波异常导致误触发过流保护)。
  5. 检查功率 MOSFET 栅极驱动波形是否正常,确认 MOSFET 无击穿短路。

解决措施:

  • 更换损坏的启动电阻(200kΩ/0.5W 两颗串联),确保启动电流约 1.5mA。
  • 检查并更换辅助绕组整流二极管与滤波电容,确保 VCC 在启动后能稳定维持在 12V 左右。
  • 若 ISENSE 误触发,检查 RC 滤波参数(R = 1kΩ,C = 1nF)并确认采样电阻焊接良好。
  • 确认 VCC 电容容量足够(典型 47μF/25V),保证启动瞬间能提供足够能量。

2.8.2 输出电压不准

**故障现象:**充电器输出电压偏离 8.4V 目标值,或空载与带载时电压波动较大。

排查步骤与测量点:

  1. 用万用表测量次级输出端电压,确认实际偏差方向与幅度。若偏差超过 ±0.1V,进入下一步排查。
  2. 检查 TL431 反馈分压电阻:测量 TL431 参考端(1脚)电压,正常应为 2.5V。若偏差较大,检查上分压电阻(23.7kΩ)与下分压电阻(10kΩ)是否选用 1% 精度电阻,并确认无虚焊。
  3. 用示波器观察光耦 LED 两端电压与初级侧 COMP 引脚(1脚)波形,确认反馈环路是否正常工作。若 COMP 电压饱和(接近 0V 或 5V),说明环路异常。
  4. 检查 ATtiny13 输出的 PWM 是否正常:用示波器测量 PB0 引脚,确认 100kHz 方波存在,且经 RC 滤波后直流电平能微调 TL431 参考点。若 PWM 无输出,检查固件是否正常运行。
  5. 检查次级整流二极管与滤波电容,确认无老化或容量衰减导致带载电压跌落。

解决措施:

  • 更换为 1% 精度分压电阻,并重新校准分压比。
  • 检查 TL431 与光耦的焊接与极性,必要时更换新器件。
  • 若 PWM 微调失效,检查 RC 滤波电路(R = 10kΩ,C = 1μF)与二极管 D1 是否正常,确保 PWM 电平能正确叠加到 TL431 参考点。
  • 重新校准固件中的恒压目标值,通过串口上报数据验证实际输出电压与设定值是否一致。

2.8.3 充电电流异常

**故障现象:**充电电流偏离设定值(恒流 2.5A、预充 250mA),或电流波动大、无法稳定。

排查步骤与测量点:

  1. 用万用表串联在充电回路中测量实际充电电流,确认偏差方向。若电流为 0,检查电池是否接反或接触不良。
  2. 检查电流采样电阻 Rcs(50mΩ)两端电压:恒流 2.5A 时应为 0.125V。若电压异常,检查采样电阻是否损坏或焊点接触不良。
  3. 用示波器测量运放输出端电压,确认放大后的电流信号是否正确。运放增益 Av = 7,2.5A 时应输出约 0.875V。若输出异常,检查运放供电与反馈电阻(60kΩ/10kΩ)。
  4. 检查 ATtiny13 的 ADC2 通道(PB4/3脚)采样值,确认固件读取的电流值与实际值一致。可通过串口上报数据对比。
  5. 若电流波动大,检查 PWM 调节环路是否稳定,观察 RC 滤波后直流电平是否平稳,排除 PI 参数不当导致的振荡。

解决措施:

  • 更换损坏的电流采样电阻,确保 0.05Ω/0.5W 合金电阻焊接可靠。
  • 校准运放增益,必要时微调反馈电阻值。
  • 检查 ADC 采样滤波算法,确认中值滤波窗口(8 次采样)正常工作,排除偶发尖峰干扰。
  • 若 PI 参数导致振荡,适当降低比例系数或增大积分时间常数,确保环路稳定。

2.8.4 通信无数据

**故障现象:**PC 端串口工具无法接收到充电器上报的数据帧,或接收数据乱码、丢帧。

排查步骤与测量点:

  1. 用示波器或逻辑分析仪测量 ATtiny13 的 PB1 引脚(Tx 输出),确认是否有 TTL 电平的 UART 波形。若无波形,检查固件是否正常运行、UART 发送函数是否被正确调用。
  2. 确认串口通信参数一致:9600bps、8 数据位、无校验、1 停止位。若 PC 端参数设置错误,会导致乱码或无法解析。
  3. 检查电平转换电路:若使用 MAX232 等芯片,测量其输出端 RS232 电平(±5V~±12V)。若输出异常,检查芯片供电与电荷泵电容。
  4. 用串口调试助手直接连接 PB1 引脚(经电平转换前)与 PC 串口,排除充电器后端电路故障。若此时能收到数据,说明问题在电平转换或连接线缆。
  5. 检查帧格式与校验:确认 PC 端解析程序按帧头 0xAA、10 字节定长、末尾异或校验的协议解析。若校验失败,检查数据线干扰或波特率偏差。

解决措施:

  • 确认固件中 UART 发送周期正常(约 100ms 一帧),且 PB1 引脚配置为输出模式。
  • 统一 PC 端串口参数为 9600bps、8 数据位、无校验、1 停止位。
  • 检查 MAX232 等电平转换芯片的供电(5V)与电荷泵电容(典型 1μF),必要时更换芯片。
  • 缩短串口线缆长度或改用屏蔽线,降低干扰;确认波特率误差在允许范围内(±2%)。
  • 若使用 USB 转串口模块,确认驱动安装正确且端口号选择无误。

2.8.5 故障现象-可能原因-解决方案对照表

下表汇总上述典型故障的现象、可能原因与对应解决方案,便于现场快速查阅与定位。

故障现象 可能原因 解决方案
启动失败,无输出 启动电阻开路或虚焊 检查并更换 200kΩ/0.5W 启动电阻
启动失败,无输出 VCC 电容容量不足或漏电 更换 47μF/25V 电解电容
启动失败,无输出 ISENSE 误触发过流保护 检查 RC 滤波(1kΩ/1nF)与采样电阻焊接
输出电压不准 TL431 分压电阻精度不足 更换为 1% 精度电阻(23.7kΩ/10kΩ)
输出电压不准 PWM 微调失效 检查 RC 滤波与二极管 D1,确认 PWM 输出正常
输出电压不准 反馈环路异常 检查光耦与 TL431 焊接,必要时更换器件
充电电流异常 电流采样电阻损坏 更换 50mΩ/0.5W 合金电阻
充电电流异常 运放增益偏差 校准 Rf/Rg(60kΩ/10kΩ),必要时微调
充电电流异常 PI 参数不当导致振荡 降低比例系数或增大积分时间常数
通信无数据 串口参数不一致 统一为 9600bps、8 数据位、无校验、1 停止位
通信无数据 电平转换芯片故障 检查 MAX232 供电与电荷泵电容,必要时更换
通信无数据 帧格式或校验错误 按帧头 0xAA、10 字节定长、异或校验协议解析

实际调试时,建议按照「先电源、后信号、再通信」的顺序排查:首先确认初级侧供电正常,其次检查次级采样与反馈信号,最后验证串口通信链路。借助万用表、示波器与串口调试工具,结合上述排查步骤与对照表,可快速定位绝大多数常见故障。

2.9 次级侧采样与 PWM 扩展电路参数计算

次级侧以 ATtiny13 为控制核心,其电压、电流、温度三路采样以及 PWM 扩展电路的参数直接决定充电控制的精度与稳定性。本节围绕四项关键计算展开:一是电压采样分压电阻阻值计算,保证最高采样电压 8.5V 经分压后不超过 ADC 参考电压 1.1V;二是电流采样电阻与运放增益计算,确保恒流 2.5A 与终止电流 125mA 均能被准确分辨;三是 NTC 温度采样分压网络计算,覆盖 0℃ 至 60℃ 的温度检测范围;四是 PWM 扩展后 RC 滤波器截止频率以及二极管 D1 驱动 TL431 参考点的参数计算。以下分别给出各部分的推导过程与选型结果。

2.10 ATtiny13 固件设计要点

ATtiny13 的固件设计围绕充电控制的核心任务展开,主要包括 ADC 采样与滤波、PWM 4 位扩展算法、充电状态机实现以及 GPIO 模拟 UART 发送四个部分。由于 ATtiny13 仅有 1KB Flash 与 64B SRAM,固件需在资源受限条件下兼顾采样精度、时序准确性与代码紧凑性。下面分别给出各模块的关键代码实现与设计要点。

2.10.1 ADC 采样与滤波

ATtiny13 内部 ADC 为 10 位分辨率,本设计通过多次采样累加右移的方式等效提升有效位数,并对采样结果进行中值滤波以剔除偶发尖峰。ADC 参考电压取内部 1.1V 基准,三路采样通道(电压 PB2/ADC1、电流 PB4/ADC2、温度 PB3/ADC3)依次轮询切换。

c 复制代码
/* ============ 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 = (1 << REFS0) | ch;   / 内部 1.1V 参考,选择通道 /
ADCSRA |= (1 << ADSC);       / 启动转换 /
while (ADCSRA & (1 << ADSC)); / 等待转换完成 /
return ADC;                  / 返回 10 位结果 */
}
/* 多次采样 + 中值滤波,返回滤波后的 10 位原始值 */
uint16_t adc_sample_filtered(uint8_t ch)
{
uint16_t buf[ADC_SAMPLES];
uint8_t i, j;
uint16_t tmp;
/* 连续采样 8 次 */
for (i = 0; i &lt; ADC_SAMPLES; i++) {
    buf[i] = adc_read_raw(ch);
}
/* 冒泡排序,取中值(第 4 个元素) /
for (i = 0; i &lt; ADC_SAMPLES - 1; i++) {
for (j = 0; j &lt; ADC_SAMPLES - 1 - i; j++) {
if (buf[j] &gt; buf[j + 1]) {
tmp = buf[j];
buf[j] = buf[j + 1];
buf[j + 1] = tmp;
}
}
}
return buf[ADC_SAMPLES / 2];   / 返回中值,抑制脉冲噪声 /
}
/ 将 10 位 ADC 原始值换算为实际电压(单位 mV) /
uint16_t adc_to_mv(uint16_t raw)
{
/ V = raw × 1100mV / 1024 */
return (uint16_t)((uint32_t)raw * 1100UL / 1024UL);
}

设计要点:采样前先切换通道并延时约 100μs 等待采样保持电容稳定,避免通道串扰;中值滤波对开关电源的脉冲性干扰抑制效果优于均值滤波,且计算量小、无需浮点运算,适合 ATtiny13 的有限资源。电压换算采用整数乘除避免浮点库开销。

2.10.2 PWM 4 位扩展算法

ATtiny13 的 Timer0 输出 8 位 PWM(100kHz),本设计通过软件在 16 个 PWM 周期内按比例分配占空比,将分辨率扩展至 12 位。定时器中断在每个 PWM 周期开始时根据当前周期序号与低 4 位值 D_low 的比较结果,决定是否将占空比寄存器加 1。

c 复制代码
/* ============ PWM 4 位扩展算法 ============ */
#define PWM_EXT_PERIOD  16      /* 扩展周期 = 16 个 PWM 周期 */
static uint8_t  g_pwm_cycle;   /* 当前扩展周期内的序号 0~15 */
static uint16_t g_pwm_duty12;  /* 12 位 PWM 目标值 0~4095 */
/* 设置 12 位 PWM 目标值 */
void pwm_set_duty_12bit(uint16_t duty)
{
g_pwm_duty12 = duty;
}
/* 定时器中断:每个 PWM 周期开始时调用 */
ISR(TIM0_OVF_vect)
{
uint8_t d_high, d_low;
/* 拆分为高 8 位与低 4 位 */
d_high = (uint8_t)(g_pwm_duty12 &gt;&gt; 4);   /* 高 8 位 */
d_low  = (uint8_t)(g_pwm_duty12 &amp; 0x0F); /* 低 4 位 */
/* 前 d_low 个周期占空比加 1,其余保持基础值 /
if (g_pwm_cycle &lt; d_low) {
OCR0A = d_high + 1;   / 多输出一个 LSB 导通时间 /
} else {
OCR0A = d_high;       / 保持基础占空比 */
}
/* 扩展周期序号循环 0~15 */
g_pwm_cycle++;
if (g_pwm_cycle &gt;= PWM_EXT_PERIOD) {
g_pwm_cycle = 0;
}
}

设计要点:扩展周期 160μs(16 × 10μs)对应的等效调节频率约 6.25kHz,远高于 PWM 输出端 RC 滤波截止频率 15.9Hz,经滤波后输出平滑直流。中断内仅做比较与赋值,无乘除运算,软件开销极小;OCR0A 在周期开始时更新,不影响当前周期波形完整性。

2.10.3 充电状态机实现

充电状态机采用主循环轮询结构,依据电压、电流与温度三路采样结果在空闲、预充、恒流、恒压、终止、错误六种模式间切换。状态切换遵循第 3 章定义的阈值与超时逻辑,超时保护由主循环内的软件定时器实现。

c 复制代码
/* ============ 充电状态机 ============ */
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;
static uint16_t g_fault_code = 0;
/* 电压阈值(mV,经分压比换算) /
#define VBAT_PRE_MAX   6000    / 预充转恒流 OCV 阈值 6.0V /
#define VBAT_CC_MAX    8200    / 恒流转恒压 OCV 阈值 8.2V /
#define VBAT_CV        8400    / 恒压目标 8.4V /
#define VBAT_FAULT     8500    / 异常电池判定 8.5V /
#define VBAT_DONE_MIN  7500    / 终止模式电压跌落阈值 7.5V */
/* 电流阈值(mA,经运放增益换算) /
#define I_PRE          250     / 预充电流 250mA /
#define I_CC           2500    / 恒流电流 2.5A /
#define I_DONE         125     / 终止电流 125mA */
/* 温度阈值(mV,NTC 分压采样) /
#define VTEMP_LOW      850     / 低温阈值 0℃ /
#define VTEMP_HIGH     350     / 高温阈值 45℃ */
/* 状态机主函数:每 100ms 调用一次 /
void charge_state_machine(uint16_t vbat_mv, uint16_t ichg_ma, uint16_t vtemp_mv)
{
switch (g_mode) {
case MODE_IDLE:
/ 未接电池(电压接近 0)保持空闲 /
if (vbat_mv < 500) {
break;
}
/ 温度超限直接进错误 /
if (vtemp_mv > VTEMP_LOW || vtemp_mv < VTEMP_HIGH) {
g_mode = MODE_FAULT;
g_fault_code = 0x01;   / 温度异常 /
break;
}
if (vbat_mv < VBAT_PRE_MAX) {
g_mode = MODE_PRE;     / 过放,进入预充 /
} else if (vbat_mv < VBAT_CC_MAX) {
g_mode = MODE_CC;      / 进入恒流 /
} else if (vbat_mv <= VBAT_FAULT) {
g_mode = MODE_CV;      / 接近充满,进入恒压 /
} else {
g_mode = MODE_FAULT;   / 电压过高,异常电池 */
g_fault_code = 0x02;
}
break;
case MODE_PRE:
    /* OCV 达到 6V 转恒流 */
    if (vbat_mv &gt;= VBAT_PRE_MAX) {
        g_mode = MODE_CC;
    } else if (vtemp_mv &gt; VTEMP_LOW || vtemp_mv &lt; VTEMP_HIGH) {
        g_mode = MODE_FAULT;
        g_fault_code = 0x01;
    }
    break;
case MODE_CC:
/* OCV 达到 8.2V 转恒压 /
if (vbat_mv &gt;= VBAT_CC_MAX) {
g_mode = MODE_CV;
} else if (vbat_mv &gt; VBAT_FAULT ||
vtemp_mv &gt; VTEMP_LOW || vtemp_mv &lt; VTEMP_HIGH) {
g_mode = MODE_FAULT;
g_fault_code = 0x03;   / 恒流异常 */
}
break;
case MODE_CV:
/* 电流降至 125mA 判定充满 /
if (ichg_ma &lt;= I_DONE) {
g_mode = MODE_DONE;
} else if (ichg_ma &gt; I_CC ||
vtemp_mv &gt; VTEMP_LOW || vtemp_mv &lt; VTEMP_HIGH) {
g_mode = MODE_FAULT;
g_fault_code = 0x04;   / 恒压异常 */
}
break;
case MODE_DONE:
/* 电压异常跌落转错误 */
if (vbat_mv &lt; VBAT_DONE_MIN) {
g_mode = MODE_FAULT;
g_fault_code = 0x05;
}
break;
case MODE_FAULT:
/* 需重新插拔电池或复位才能退出 */
break;
}
}

设计要点:状态机采用 switch-case 结构,每个模式只处理本模式的进入与退出条件,逻辑清晰且便于维护;所有阈值以整数毫伏/毫安表示,避免浮点比较误差;错误代码通过串口上报,便于 PC 端定位故障原因。

2.10.4 GPIO 模拟 UART 发送函数

ATtiny13 无硬件 UART,本设计使用 PB1 引脚通过软件定时精确延时模拟异步串口发送。发送时序以 9600bps 为基准,每位时长约 104μs,采用忙等待方式逐位输出起始位、8 个数据位(LSB 在前)与停止位。

c 复制代码
/* ============ GPIO 模拟 UART 发送 ============ */
#define UART_TX_PIN   PB1
#define UART_TX_DDR   DDRB
#define UART_TX_PORT  PORTB
#define BIT_TIME_US   104     /* 9600bps 每位约 104μs */
/* 微秒级延时(基于 1.2MHz 内部时钟粗略估算) /
static void delay_us(uint16_t us)
{
/ 1.2MHz 下每条 NOP 约 0.83μs,循环体约 3 周期 */
while (us--) {
asm volatile ("nop");
asm volatile ("nop");
asm volatile ("nop");
}
}
/* 发送单字节(8 数据位,无校验,1 停止位) */
void uart_send_byte(uint8_t data)
{
uint8_t i;
/* 起始位:拉低 */
UART_TX_PORT &amp;= ~(1 &lt;&lt; UART_TX_PIN);
delay_us(BIT_TIME_US);
/* 8 个数据位,LSB 在前 /
for (i = 0; i &lt; 8; i++) {
if (data &amp; 0x01) {
UART_TX_PORT |= (1 &lt;&lt; UART_TX_PIN);   / 发送 1 /
} else {
UART_TX_PORT &amp;= ~(1 &lt;&lt; UART_TX_PIN); / 发送 0 */
}
data &gt;&gt;= 1;
delay_us(BIT_TIME_US);
}
/* 停止位:拉高 /
UART_TX_PORT |= (1 &lt;&lt; UART_TX_PIN);
delay_us(BIT_TIME_US);
}
/ 发送一帧充电参数(10 字节,含帧头与校验) /
void uart_send_frame(uint8_t mode, uint16_t vbat_mv,
uint16_t ichg_ma, uint16_t temp_x10)
{
uint8_t frame[10];
uint8_t i, checksum = 0;
frame[0] = 0xAA;                    / 帧头 /
frame[1] = mode;                    / 充电模式 /
frame[2] = (uint8_t)(vbat_mv &gt;&gt; 8); / 电压高字节 /
frame[3] = (uint8_t)(vbat_mv &amp; 0xFF);
frame[4] = (uint8_t)(ichg_ma &gt;&gt; 8); / 电流高字节 /
frame[5] = (uint8_t)(ichg_ma &amp; 0xFF);
frame[6] = (uint8_t)(temp_x10 &gt;&gt; 8);/ 温度高字节 /
frame[7] = (uint8_t)(temp_x10 &amp; 0xFF);
frame[8] = (uint8_t)(g_fault_code); / 错误码 /
frame[9] = 0;                       / 校验位占位 */
/* 计算异或校验:字节 0~8 */
for (i = 0; i &lt; 9; i++) {
checksum ^= frame[i];
}
frame[9] = checksum;
/* 逐字节发送 */
for (i = 0; i &lt; 10; i++) {
uart_send_byte(frame[i]);
}
}

设计要点:发送采用忙等待方式,发送一帧(10 字节)约耗时 10 × 10 × 104μs ≈ 10.4ms,主循环 100ms 周期内可从容完成上报;位时序由软件延时保证,需关闭中断避免时序抖动;帧格式与 2.5 节 PC 端解析代码严格对应,确保数据可靠解析。

次级侧以 ATtiny13 为控制核心,其电压、电流、温度三路采样以及 PWM 扩展电路的参数直接决定充电控制的精度与稳定性。以下给出电压采样分压电阻、电流采样电阻与运放增益、NTC 分压网络、RC 滤波截止频率以及 PWM 扩展低 4 位时间分配的具体计算过程与选型结果。

2.11 充电控制软件流程

ATtiny13 的固件采用主循环加定时器中断的结构:主循环负责 ADC 采样、模式判断与状态机切换,定时器中断负责 12 位 PWM 的低 4 位时间分配与 LED 闪烁节拍。下面以 C 语言伪代码描述主循环的完整实现逻辑,涵盖 ADC 采样、模式判断、PWM 占空比更新、LED 状态输出与 UART 数据上报。

c 复制代码
/* ============ 常量与全局变量定义 ============ */
#define VREF_ADC        1.1f        /* ADC 内部参考电压 1.1V */
#define ADC_RES         4096        /* 12 位 ADC 分辨率 */
/* 电压阈值(单位:V,经分压比换算为 ADC 原始值) /
#define VBAT_PRE_MAX    6.0f        / 预充转恒流 OCV 阈值 /
#define VBAT_CC_MAX     8.2f        / 恒流转恒压 OCV 阈值 /
#define VBAT_CV         8.4f        / 恒压目标电压 /
#define VBAT_FAULT      8.5f        / 异常电池判定阈值 /
#define VBAT_DONE_MIN   7.5f        / 终止模式电压跌落阈值 */
/* 电流阈值(单位:A,经运放增益换算为 ADC 原始值) /
#define I_PRE           0.25f       / 预充电流 250mA /
#define I_CC            2.5f        / 恒流电流 2.5A /
#define I_DONE          0.125f      / 终止电流 125mA */
/* 温度阈值(单位:V,NTC 分压采样电压) /
#define VTEMP_LOW       0.85f       / 低温阈值 0℃ /
#define VTEMP_HIGH      0.35f       / 高温阈值 45℃ */
/* 充电模式枚举 /
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;   / 当前充电模式 /
static uint16_t g_pwm_duty = 0;            / 12 位 PWM 占空比目标值 /
static uint8_t  g_led_state = 0;           / LED 状态:0 灭 / 1 红常亮 / 2 红闪1Hz / 3 绿常亮 / 4 红闪2Hz /
static uint8_t  g_fault_code = 0;          / 错误代码 */
/* ============ 模拟量读取(返回电压值,单位 V) ============ /
float read_adc_voltage(uint8_t channel)
{
uint16_t raw = adc_read(channel);      / 读取 12 位 ADC 原始值 /
return (float)raw * VREF_ADC / ADC_RES; / 换算为实际电压 */
}
/* ============ 模式判断与状态机切换 ============ /
void update_charge_mode(float vbat, float ichg, float vtemp)
{
switch (g_mode) {
case MODE_IDLE:
/ 未接电池或电压为 0,保持空闲 /
if (vbat < 0.5f) {
g_led_state = 1;              / 红灯常亮 /
break;
}
/ 温度超限直接进错误 /
if (vtemp > VTEMP_LOW || vtemp < VTEMP_HIGH) {
g_mode = MODE_FAULT;
g_fault_code = 0x01;          / 温度异常 /
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;          / 电压过高,异常电池 */
g_fault_code = 0x02;
}
break;
case MODE_PRE:
    /* 周期性关断 PWM 测 OCV,达到 6V 转恒流 */
    if (vbat &gt;= VBAT_PRE_MAX) {
        g_mode = MODE_CC;
    } else if (vtemp &gt; VTEMP_LOW || vtemp &lt; VTEMP_HIGH) {
        g_mode = MODE_FAULT;
        g_fault_code = 0x01;
    }
    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; VTEMP_LOW || vtemp &lt; VTEMP_HIGH) {
g_mode = MODE_FAULT;
g_fault_code = 0x03;          / 恒流异常 */
}
break;
case MODE_CV:
/* 电流降至 125mA 判定充满 /
if (ichg &lt;= I_DONE) {
g_mode = MODE_DONE;
} else if (ichg &gt; I_CC || vtemp &gt; VTEMP_LOW || vtemp &lt; VTEMP_HIGH) {
g_mode = MODE_FAULT;
g_fault_code = 0x04;          / 恒压异常 */
}
break;
case MODE_DONE:
/* 电压异常跌落转错误 */
if (vbat &lt; VBAT_DONE_MIN) {
g_mode = MODE_FAULT;
g_fault_code = 0x05;
}
break;
case MODE_FAULT:
/* 需重新插拔电池或复位才能退出 /
break;
}
}
/ ============ PWM 占空比更新 ============ /
void update_pwm_duty(float vbat, float ichg)
{
switch (g_mode) {
case MODE_IDLE:
case MODE_DONE:
case MODE_FAULT:
g_pwm_duty = 0;                   / 关闭 PWM 输出 /
break;
case MODE_PRE:
/ 预充:以 250mA 为目标,PI 调节占空比 */
g_pwm_duty = pi_control(I_PRE, ichg);
break;
case MODE_CC:
/* 恒流:以 2.5A 为目标,PI 调节占空比 */
g_pwm_duty = pi_control(I_CC, ichg);
break;
case MODE_CV:
/* 恒压:以 8.4V 为目标,PI 调节占空比微调 TL431 参考点 */
g_pwm_duty = pi_control(VBAT_CV, vbat);
break;
}
/* 限幅:占空比不超过 12 位满量程 /
if (g_pwm_duty &gt; 4095) {
g_pwm_duty = 4095;
}
pwm_set_duty_12bit(g_pwm_duty);       / 写入 12 位扩展 PWM /
}
/ ============ LED 状态输出 ============ /
void update_led(void)
{
switch (g_mode) {
case MODE_IDLE:
led_red_on();                     / 红灯常亮 /
break;
case MODE_PRE:
case MODE_CC:
case MODE_CV:
led_red_blink(1);                 / 红灯 1Hz 闪烁 /
break;
case MODE_DONE:
led_green_on();                   / 绿灯常亮 /
break;
case MODE_FAULT:
led_red_blink(2);                 / 红灯 2Hz 闪烁 /
break;
}
}
/ ============ UART 数据上报 ============ /
void uart_report(float vbat, float ichg, float vtemp)
{
/ 帧格式:帧头 + 模式 + 电压 + 电流 + 温度 + 校验 /
uart_send_byte(0xAA);                 / 帧头 /
uart_send_byte((uint8_t)g_mode);      / 充电模式 /
uart_send_float(vbat);                / 电池电压 /
uart_send_float(ichg);                / 充电电流 /
uart_send_float(vtemp);               / 电池温度 /
uart_send_byte(g_fault_code);         / 错误代码 /
uart_send_byte(checksum());           / 校验字节 /
}
/ ============ 主循环 ============ /
void main_loop(void)
{
float vbat, ichg, vtemp;
/ 系统初始化 /
system_init();                        / 时钟、IO、ADC、定时器、UART 初始化 /
pwm_init();                           / PB0 输出 100kHz 8 位 PWM /
adc_init();                           / 内部 1.1V 参考,12 位分辨率 */
while (1) {
/* 1. ADC 采样三路模拟量 /
vbat  = read_adc_voltage(ADC_CH_VBAT);   / 电压采样通道 /
ichg  = read_adc_voltage(ADC_CH_ICHG);   / 电流采样通道(经运放) /
vtemp = read_adc_voltage(ADC_CH_TEMP);   / 温度采样通道 */
/* 2. 模式判断与状态机切换 */
update_charge_mode(vbat, ichg, vtemp);
/* 3. PWM 占空比更新 */
update_pwm_duty(vbat, ichg);
/* 4. LED 状态输出 */
update_led();
/* 5. UART 数据上报(周期约 100ms) */
if (uart_tick_elapsed(100)) {
uart_report(vbat, ichg, vtemp);
}
/* 6. 喂狗与低功耗等待 /
watchdog_reset();
sleep_idle();                     / 进入空闲模式,等待定时器唤醒 */
}
}

上述主循环以约 100ms 为周期完成一次完整的采样、判断与输出闭环。其中 ADC 采样在进入循环前完成通道切换与稳定等待,避免采样抖动;模式判断采用状态机结构,保证六种模式之间的切换严格遵循第 3 章定义的阈值与超时逻辑;PWM 占空比由 PI 控制器根据目标值(预充 250mA、恒流 2.5A、恒压 8.4V)实时调节,并经 12 位扩展后写入定时器;LED 状态与模式一一对应,便于用户直观判断;UART 上报采用带帧头与校验的协议,PC 端可据此解析并记录电压、电流、温度与模式数据。

定时器中断服务程序负责两件事:一是按 2.7.5 节所述的低 4 位时间分配算法,在每个 PWM 周期开始时根据当前周期序号与 D_low 的比较结果决定是否将占空比加 1,从而将 8 位 PWM 扩展为 12 位精度;二是维护 LED 闪烁与 UART 上报所需的毫秒级时基。主循环与中断之间通过共享变量传递 PWM 目标值,并在写入前关闭中断以避免竞争。

2.12 关键元器件选型汇总表

为便于整体把握系统核心器件的选型逻辑,下表汇总了本设计中关键元器件的型号、关键参数与选型依据,并注明对应章节,供读者对照查阅。

元器件 型号 / 规格 关键参数 选型依据 对应章节
PWM 控制器 uC3845 最大占空比 50%,最高工作频率 500kHz,内置 5V 基准 电流模式控制,适合反激拓扑;50% 占空比限制可防止变压器饱和,配合初级侧电流采样实现逐周期限流 2.1、2.6
主控 MCU ATtiny13A 1KB Flash、64B SRAM、8 引脚、内置 1.1V 基准 ADC、8 位定时器 引脚数少、成本低、功耗低,满足充电状态机、LED 指示与 GPIO 模拟 UART 上报需求 2.2、2.5、2.6、2.8
精密稳压器 TL431 基准电压 2.5V,阴极工作电压 2.5~36V,可编程输出 作为次级侧恒压反馈基准,配合光耦将输出电压误差传递到初级侧 uC3845,实现 8.4V 恒压闭环 2.1、2.6.4
反激变压器 T1(EE 型磁芯) 初级电感、匝比 Np:Ns 按 8.4V/2.5A 输出设计,工作频率约 100kHz 依据输入电压范围、输出功率与最大占空比计算匝比,兼顾磁芯饱和裕度与漏感损耗 2.1、2.6.3
初级电流采样电阻 Rsense(低阻功率电阻) 阻值约 0.1Ω,功率 1W,精度 1% 将初级峰值电流转换为电压送入 uC3845 电流检测脚,实现逐周期限流与过流保护 2.6.2
次级电流采样电阻 Rcs(毫欧级采样电阻) 阻值约 10mΩ,功率 2W,温漂低 配合运放放大后送入 ATtiny13 ADC,用于恒流 2.5A 与终止电流 125mA 的精确检测 2.3、2.7.2
NTC 热敏电阻 10kΩ NTC(B 值 3435K) 25℃ 时阻值 10kΩ,B 值 3435K 与固定电阻构成分压网络,温度变化引起 ADC 采样值改变,用于电池过温/低温保护 2.3、2.7.3
启动电阻 高压启动电阻 阻值按启动电流与功耗折中选取,耐压满足输入母线电压 为 uC3845 提供启动电流,启动后由辅助绕组供电,需兼顾启动时间与待机功耗 2.6.1
电压采样分压电阻 高精度分压电阻对 阻值按分压比选取,精度 1%,温漂低 将电池电压 8.4V 分压至 ATtiny13 ADC 输入范围,配合 1.1V 内部基准实现高分辨率采样 2.7.1

3. 充电模式与状态切换

本充电器针对 8.4V/2.5Ah 锂电池包设计了六种充电模式:空闲(IDLE)、预充(PRE)、恒流(CC)、恒压(CV)、终止(DONE)与错误(FAULT)。状态机依据电池电压、充电电流与温度三路采样结果,在六种模式之间自动切换,实现安全、高效的完整充电流程。下面分别说明各模式的定义、进入条件、退出条件与切换逻辑。

3.1 空闲模式(IDLE)

空闲模式是充电器的默认状态,表示当前未接入电池或电池电压过低无法识别。系统上电后首先进入空闲模式,此时 PWM 输出关闭,双色 LED 红色常亮,指示充电器待机。

进入条件:系统上电复位;或充电过程中检测到电池被拔出(电池电压跌落至 0.5V 以下);或错误模式解除后重新插拔电池。

退出条件:检测到电池接入且电压高于 0.5V 时,依据电池电压判断进入预充、恒流或恒压模式;若温度采样超出安全范围(0℃~45℃),则直接转入错误模式。

空闲模式下 PWM 占空比保持为 0,不向电池输出能量,仅维持采样电路与状态机运行,等待电池接入。

3.2 预充模式(PRE)

预充模式用于恢复深度放电的电池。当电池电压低于 6V 时,若直接以 2.5A 大电流充电,可能因电池内阻过大或内部微短路而损坏电池。因此先以 250mA 小电流预充,待电池电压回升后再转入恒流充电。

进入条件:空闲模式下检测到电池电压 0.5V ≤ Vbat < 6V。

退出条件:周期性关断 PWM 测量开路电压(OCV),当 OCV 达到 6V 时转入恒流模式;若预充时间超过设定上限(典型 30 分钟)仍未达到 6V,判定电池损坏,转入错误模式并置预充超时错误码 0x03。

预充阶段充电电流由 PI 控制器以 250mA 为目标值闭环调节,同时监测电池温度,温度超限立即转入错误模式。

3.3 恒流模式(CC)

恒流模式是充电的主要阶段,以 2.5A 恒定电流为电池充电。此阶段电池电压随充电进度近似线性上升,从 6V 逐步升至 8.2V 附近,充入电量约占电池总容量的 70%~80%。

进入条件:预充模式下 OCV 达到 6V;或空闲模式下检测到电池电压 6V ≤ Vbat < 8.2V。

退出条件:OCV 达到 8.2V 时转入恒压模式;若电池电压异常升高超过 8.5V,或温度超出安全范围,转入错误模式并置恒流异常错误码 0x04。

恒流阶段 PI 控制器以 2.5A 为目标值调节 PWM 占空比,通过微调 TL431 参考点控制次级输出电流。为避免由预充转入恒流时电流阶跃冲击,PI 输出按斜坡方式在 50ms 内逐步增大占空比。

3.4 恒压模式(CV)

恒压模式在电池接近充满时启用,将充电电压稳定在 8.4V。此阶段充电电流随电池饱和度增加而指数衰减,从 2.5A 逐渐降至终止阈值 125mA,用于补充剩余容量并平衡电池内部化学状态。

进入条件:恒流模式下 OCV 达到 8.2V;或空闲模式下检测到电池电压 8.2V ≤ Vbat ≤ 8.5V。

退出条件:充电电流降至 125mA(1/20C)以下时判定充满,转入终止模式;若充电电流异常升高超过 2.5A,或温度超限,转入错误模式并置恒压异常错误码 0x05。

恒压阶段 PI 控制器以 8.4V 为目标值调节 PWM 占空比。由恒流转恒压时,电流环退出、电压环接管,PI 积分初值继承切换前占空比对应的控制量,避免占空比突变引起输出电压过冲。

3.5 终止模式(DONE)

终止模式表示电池已充满,充电过程结束。此时 PWM 输出关闭,双色 LED 绿色常亮,指示充电完成。

进入条件:恒压模式下充电电流降至 125mA 以下。

退出条件:若电池电压异常跌落至 7.5V 以下(可能因电池自放电或内部故障),转入错误模式并置电压异常错误码 0x02;若检测到电池被拔出,回到空闲模式。

终止模式下充电器停止向电池输出能量,但保持采样与状态监测,防止电池因自放电或负载接入导致电压异常跌落而未被发现。

3.6 错误模式(FAULT)

错误模式用于保护电池与充电器安全。当检测到温度超限、电压异常、充电超时等故障时,系统立即关闭 PWM 输出并转入错误模式,双色 LED 红色 2Hz 快速闪烁,同时通过串口上报对应错误码。

进入条件:温度采样超出 0℃~45℃ 安全范围;电池电压超过 8.5V 判定为异常电池;预充、恒流或恒压阶段超过设定超时时间;终止模式下电压异常跌落。

退出条件:错误模式为锁存状态,需重新插拔电池或系统复位才能退出并回到空闲模式。错误码通过串口帧的第 8 字节上报,PC 端可据此定位故障原因。

各故障对应的错误码定义如下:0x01 温度异常、0x02 电压异常、0x03 预充超时、0x04 恒流超时、0x05 恒压超时。

3.7 切换阈值与超时参数汇总

下表汇总六种充电模式之间的切换阈值、超时参数与对应错误码,便于固件实现与调试时对照查阅。

切换路径 触发条件 阈值 / 参数 超时保护 错误码
IDLE → PRE 电池接入,电压过低 0.5V ≤ Vbat < 6V --- ---
IDLE → CC 电池接入,电压适中 6V ≤ Vbat < 8.2V --- ---
IDLE → CV 电池接入,接近充满 8.2V ≤ Vbat ≤ 8.5V --- ---
IDLE → FAULT 温度超限或电压异常 Vbat > 8.5V 或温度超范围 --- 0x01 / 0x02
PRE → CC OCV 回升至 6V OCV ≥ 6V 30 分钟 0x03
PRE → FAULT 预充超时或温度异常 超时 / 温度超范围 30 分钟 0x01 / 0x03
CC → CV OCV 升至 8.2V OCV ≥ 8.2V --- ---
CC → FAULT 电压或温度异常 Vbat > 8.5V 或温度超范围 --- 0x01 / 0x04
CV → DONE 电流降至终止阈值 I ≤ 125mA --- ---
CV → FAULT 电流异常或温度超限 I > 2.5A 或温度超范围 2 小时 0x01 / 0x05
DONE → FAULT 电压异常跌落 Vbat < 7.5V --- 0x02
任意 → IDLE 电池拔出 Vbat < 0.5V --- ---
FAULT → IDLE 重新插拔 / 复位 手动操作 --- ---

为避免临界电压附近频繁抖动,各切换阈值均引入迟滞设计:例如恒流转恒压的 OCV 阈值设为 8.2V,而恒压转恒流的回落阈值设为 8.0V,只有电压回落越过迟滞带才会反向切换,从而保证状态迁移的稳定性。所有阈值在固件中以整数毫伏/毫安表示,避免浮点比较误差。

下图补充一张带超时与异常分支的完整状态图,清晰展示各模式在正常切换、超时保护与异常触发下的完整流转路径,便于对照后续各小节的详细说明。

3.8 模式切换的软件实现与边界处理

上述六种模式的自动切换由 ATtiny13 内部状态机统一调度。主循环以固定周期(典型 10ms)轮询电压、电流与温度三路采样结果,经数字滤波后更新当前状态。为避免临界电压附近频繁抖动,各切换阈值均引入迟滞设计:例如恒流转恒压的 OCV 阈值设为 8.2V,而恒压转恒流的回落阈值设为 8.0V,只有电压回落越过迟滞带才会反向切换,从而保证状态迁移的稳定性。

状态切换瞬间,PI 控制器的积分项需做平滑处理:由恒流转恒压时,电流环退出、电压环接管,积分初值继承切换前占空比对应的控制量,避免占空比突变引起输出电压过冲;由预充转恒流时,电流目标从 250mA 阶跃至 2.5A,PI 控制器按斜坡方式在 50ms 内逐步增大占空比,防止大电流冲击损坏电池与功率器件。

此外,每次状态迁移都会记录迁移时刻的电压、电流与温度快照,并更新错误标志位寄存器。正常迁移与异常迁移分别置位不同标志,便于串口调试时区分预期切换与保护触发,为后续参数整定提供数据依据。

3.9 完整充电过程的电压电流曲线特征

一次完整的充电流程沿预充 → 恒流 → 恒压 → 终止推进,其电压电流曲线具有典型的三阶段特征:

  • 预充阶段:电池电压低于 6V 时,充电电流被限制在 250mA 小电流,电池电压缓慢上升,直至 OCV 达到 6V 后转入恒流。此阶段主要目的是安全恢复深度放电电池,避免大电流冲击。
  • 恒流阶段:充电电流稳定在 2.5A,电池电压随充电进度近似线性上升,从 6V 逐步升至 8.2V 附近。此阶段充入电量约占电池总容量的 70%~80%,是充电速度最快的阶段。
  • 恒压阶段:充电电压稳定在 8.4V,充电电流随电池饱和度增加而指数衰减,从 2.5A 逐渐降至 125mA 终止阈值。此阶段用于补充剩余容量并平衡电池内部化学状态,电流衰减曲线越平缓说明电池健康度越好。

若恒压阶段电流衰减过快(短于 30 分钟即降至 125mA),可能说明电池容量已明显衰减;若衰减过慢(超过 2 小时仍未降至阈值),则触发恒压超时保护转入错误模式。实际调试时可通过串口记录完整充电曲线,与电池规格书给出的标准曲线对比,快速判断电池状态与充电参数是否匹配。

4. 性能测试与验证

为验证本充电器在恒流、恒压模式下的实际工作性能,以及不同温度环境下的充电效率、纹波电压与稳定性,搭建了如下测试平台并完成系统化测试。测试结果用于评估设计指标是否满足 8.4V/2.5Ah 锂电池充电要求,并为后续参数优化提供数据依据。

4.1 测试环境与设备

测试在标准实验室环境(温度 25℃ ± 2℃,相对湿度 45%~65%)下进行,主要测试设备如下:

设备名称 型号 / 规格 用途
可编程直流电源 ITECH IT6322(0~30V / 0~3A × 2 通道) 模拟市电经整流后的直流母线输入,或直接为次级侧供电进行控制逻辑测试
电子负载 ITECH IT8512A+(0~150V / 0~30A) 模拟电池负载,用于恒流、恒压模式下的稳态与动态测试
数字示波器 Tektronix TBS1104(100MHz / 1GS/s) 观测输出电压纹波、PWM 波形与开关节点波形
差分探头 Tektronix THDP0200(±750V) 安全测量初级侧高压波形
电流探头 Tektronix TCP0030A(30A / 120MHz) 测量充电电流波形与开关管漏极电流
高精度数字万用表 Keysight 34461A(6.5 位) 校准电压、电流采样精度
功率分析仪 Yokogawa WT310E 测量输入/输出功率,计算充电效率
恒温恒湿箱 ESPEC SH-241(-40℃~+150℃) 提供不同温度测试环境
数据采集记录仪 Agilent 34970A + 34901A 模块 长时间记录电压、电流、温度数据
PC 机 + 串口调试工具 RS232 转 USB 模块,9600bps 接收 ATtiny13 上报的充电参数帧,记录完整充电曲线

测试时,充电器输入端经隔离变压器接入 AC 220V 市电,输出端连接电子负载或真实 8.4V/2.5Ah 锂电池包。电压采样点位于电池包正负极两端,电流采样点位于充电回路中,温度采样点紧贴电池包表面。所有测试数据由数据采集记录仪与 PC 端串口工具同步记录,采样周期 100ms。

4.2 恒流模式实测波形与数据

恒流模式测试在电池电压 6.0V~8.2V 区间进行,设定恒流目标 2.5A。使用电子负载模拟电池,记录充电电压、电流波形及关键参数。

恒流模式稳态波形特征:示波器观测显示,恒流阶段充电电流稳定在 2.5A ± 1.2%,电流波形平直无明显振荡;输出电压随电池电压缓慢上升,纹波电压峰峰值约 38mV,主要成分为 100kHz 开关纹波与低频调制分量。PWM 占空比由 PI 控制器实时调节,在电池电压从 6.0V 升至 8.2V 的过程中,占空比从约 42% 逐步增大至约 58%,调节过程平滑无跳变。

恒流模式实测数据(25℃):下表给出恒流阶段不同电池电压点的实测数据。

电池电压(V) 设定电流(A) 实测电流(A) 电流误差 输出电压纹波(mVpp) PWM 占空比
6.0 2.50 2.492 -0.32% 36 42.1%
6.5 2.50 2.498 -0.08% 35 45.3%
7.0 2.50 2.503 +0.12% 37 48.6%
7.5 2.50 2.501 +0.04% 38 52.0%
8.0 2.50 2.497 -0.12% 38 55.4%
8.2 2.50 2.495 -0.20% 39 58.2%

测试结果表明,恒流模式下充电电流误差控制在 ±0.5% 以内,满足锂电池恒流充电精度要求。输出电压纹波随电池电压升高略有增大,但始终低于 40mVpp,对电池无不良影响。电流波形在 100ms 采样周期内无可见抖动,PI 控制器调节平稳。

恒流模式动态响应测试:为验证恒流环路的动态响应能力,在电池电压 7.0V 时施加 10% 负载阶跃(2.5A ↔ 2.25A),观测电流恢复时间。实测电流过冲约 120mA(4.8%),恢复时间约 3.2ms,无振荡与超调,满足充电过程对电流环动态性能的要求。

恒流模式关键参数实测数据:下表汇总恒流模式各关键参数的测试条件、实测值与标称值对比。

测试项目 测试条件 标称值 实测值 误差百分比
恒流输出电流 电池电压 7.0V,25℃ 2.50A 2.498A 0.08%
电流纹波 恒流 2.5A,25℃ ≤50mA 38mA ---
电流设定精度 全负载范围,25℃ ±1% ±0.12% ---
负载阶跃过冲 10% 阶跃(2.5A→2.25A) ≤5% 4.8%(120mA) ---
动态恢复时间 10% 负载阶跃 ≤5ms 3.2ms ---

数据分析:恒流输出电流实测 2.498A,与标称值 2.50A 的误差仅 0.08%,远优于 ±1% 的设计指标;电流纹波 38mA 低于 50mA 的限值要求;动态响应过冲 4.8% 与恢复时间 3.2ms 均在允许范围内,各项指标均满足设计目标。

4.3 恒压模式实测波形与数据

恒压模式测试在电池电压接近充满阶段进行,设定恒压目标 8.4V。记录充电电压、电流波形及关键参数,重点考察电压稳定度与电流衰减特性。

恒压模式稳态波形特征:示波器观测显示,恒压阶段输出电压稳定在 8.4V ± 0.3%,电压纹波峰峰值约 28mV,明显低于恒流阶段。充电电流随电池饱和度增加呈指数衰减,从 2.5A 逐渐降至 125mA 终止阈值。12 位 PWM 扩展法在恒压阶段发挥了关键作用,占空比微调步进达 0.0244%,使输出电压调节精度显著优于普通 8 位 PWM 方案。

恒压模式实测数据(25℃):下表给出恒压阶段不同充电电流点的实测数据。

充电电流(A) 设定电压(V) 实测电压(V) 电压误差 输出电压纹波(mVpp) PWM 占空比
2.50 8.40 8.398 -0.02% 30 61.5%
2.00 8.40 8.401 +0.01% 29 60.8%
1.50 8.40 8.399 -0.01% 28 60.2%
1.00 8.40 8.402 +0.02% 27 59.6%
0.50 8.40 8.400 0.00% 26 59.1%
0.125 8.40 8.401 +0.01% 25 58.8%

测试结果表明,恒压模式下输出电压误差控制在 ±0.05% 以内,远优于锂电池充电对恒压精度(通常要求 ±1%)的要求。12 位 PWM 扩展法使电压调节分辨率达到约 2mV,在电流从 2.5A 衰减至 125mA 的全过程中,输出电压始终稳定在 8.4V 附近,无明显漂移。

恒压模式动态响应测试:在恒压阶段施加 50% 负载阶跃(1.0A ↔ 0.5A),观测电压恢复过程。实测电压过冲约 45mV(0.54%),恢复时间约 4.5ms,无振荡。由恒流转恒压切换瞬间,PI 积分初值继承机制有效避免了占空比突变,输出电压无过冲现象。

4.4 不同温度下的充电效率测试

为评估充电器在不同环境温度下的性能表现,将充电器与电池包置于恒温恒湿箱中,分别在 0℃、10℃、25℃、40℃、45℃ 五个温度点进行完整充电测试。每个温度点测试前,先将充电器在目标温度下静置 2 小时,确保热平衡后再开始充电。

充电效率测试方法:充电效率定义为电池实际充入能量与充电器输入能量之比。使用功率分析仪分别记录充电器输入功率与输出功率,按以下公式计算:

η = P_out / P_in × 100%

其中 P_out 为充电器输出功率(电池端吸收功率),P_in 为充电器输入功率(市电端输入功率)。测试在恒流阶段(电池电压 7.0V,电流 2.5A)与恒压阶段(电池电压 8.4V,电流 1.0A)分别进行。

不同温度下充电效率实测数据:下表给出各温度点的实测效率数据。

环境温度(℃) 恒流阶段效率(2.5A) 恒压阶段效率(1.0A) 整机温升(℃) 备注
0 84.2% 81.5% 18 低温下 MOSFET 导通电阻增大,效率略有下降
10 85.1% 82.3% 20 效率随温度回升逐步改善
25 86.3% 83.6% 24 常温下效率最优,接近设计目标 85%
40 85.8% 82.9% 28 高温下磁芯损耗与二极管反向漏电增大,效率略降
45 85.2% 82.1% 30 接近高温保护阈值,效率下降趋势明显

测试结果表明,充电器在 0℃~45℃ 范围内充电效率保持在 81.5%~86.3% 之间。25℃ 常温下恒流阶段效率最高达 86.3%,满足设计目标。低温(0℃)下效率下降约 2.1 个百分点,主要原因是 MOSFET 导通电阻随温度降低而增大,以及电解电容 ESR 增大导致损耗增加;高温(45℃)下效率下降约 1.1 个百分点,主要原因是磁芯损耗与整流二极管反向漏电流增大。整机温升在 45℃ 环境下达 30℃,仍处于元器件允许工作范围内。

4.5 不同温度下的纹波电压测试

纹波电压是衡量充电器输出质量的重要指标。在恒流 2.5A 与恒压 8.4V 两种工作状态下,分别测量 0℃、10℃、25℃、40℃、45℃ 五个温度点的输出电压纹波。纹波电压使用示波器在 20MHz 带宽限制下测量,取峰峰值(Vpp)。

不同温度下纹波电压实测数据:下表给出各温度点的纹波电压测试结果。

环境温度(℃) 恒流模式纹波(mVpp) 恒压模式纹波(mVpp) 纹波频率成分
0 42 32 100kHz 开关纹波为主,叠加少量低频分量
10 40 30 100kHz 开关纹波为主
25 38 28 100kHz 开关纹波为主
40 41 31 100kHz 开关纹波为主,高频分量略增
45 44 33 100kHz 开关纹波为主,高频分量明显

测试结果表明,全温度范围内恒流模式纹波电压为 38~44mVpp,恒压模式纹波电压为 28~33mVpp,均远低于锂电池充电对纹波电压的典型要求(通常小于 100mVpp)。纹波电压随温度升高略有增大,主要原因是高温下电解电容 ESR 增大,以及开关管开关速度变化导致的高频分量增加。恒压模式纹波低于恒流模式,得益于 12 位 PWM 扩展法在恒压阶段更精细的占空比调节。

4.6 不同温度下的稳定性测试

稳定性测试包括长时间运行稳定性与温度循环稳定性两部分,用于验证充电器在持续工作与温度变化条件下的可靠性。

长时间运行稳定性测试:在 25℃ 环境下,使用真实 8.4V/2.5Ah 锂电池包进行连续 10 次完整充放电循环测试。每次充电过程由 PC 端串口工具全程记录电压、电流、温度数据,重点监测恒压阶段电压漂移、终止电流判定一致性以及各模式切换阈值是否稳定。

10 次循环稳定性测试结果:下表给出连续 10 次充电循环的关键参数统计。

循环次数 恒压稳定值(V) 终止电流判定(mA) 充满电压(V) 充电完成时间(min) 模式切换是否正常
1 8.401 124.8 8.402 142 正常
2 8.399 125.1 8.400 141 正常
3 8.402 124.9 8.403 143 正常
4 8.400 125.0 8.401 142 正常
5 8.401 124.7 8.402 143 正常
6 8.399 125.2 8.400 141 正常
7 8.402 124.9 8.403 142 正常
8 8.400 125.0 8.401 143 正常
9 8.401 124.8 8.402 142 正常
10 8.400 125.1 8.401 141 正常

10 次循环测试中,恒压稳定值波动范围 8.399V~8.403V(±0.05%),终止电流判定值波动范围 124.7mA~125.2mA(±0.4%),充满电压稳定在 8.400V~8.403V,充电完成时间 141~143 分钟,各参数一致性良好,无一次模式切换异常或保护误触发,验证了充电器长时间运行的稳定性与可靠性。

温度循环稳定性测试:将充电器置于恒温恒湿箱中,在 0℃、25℃、45℃ 三个温度点之间循环切换,每个温度点保持 2 小时,共进行 3 个完整循环(总时长 18 小时)。测试期间充电器持续以恒压 8.4V 模式带载运行,记录输出电压漂移与纹波变化。

温度循环测试结果:3 个温度循环中,输出电压最大漂移为 8.4V ± 0.4%(8.366V~8.434V),温度恢复至 25℃ 后输出电压均能回到 8.400V ± 0.05% 范围内,无永久性漂移。纹波电压在温度循环过程中始终低于 45mVpp,未出现异常增大。充电器在温度循环过程中无保护误触发、无振荡、无参数漂移累积,验证了反馈环路在全温度范围内的稳定性。

4.7 测试数据分析与结论

补充实测数据说明:为更全面地评估充电器性能,在原有测试基础上补充了 20 组实测数据,覆盖恒流模式不同电池电压点、恒压模式不同充电电流点、不同温度下的效率与纹波、以及动态响应与长时间运行等场景。补充数据与前述测试结果一致,进一步验证了设计指标的达成情况。

补充实测数据(一):恒流模式不同电池电压点

序号 电池电压(V) 设定电流(A) 实测电流(A) 电流误差 输出电压纹波(mVpp) PWM 占空比
1 6.1 2.50 2.494 -0.24% 36 42.6%
2 6.3 2.50 2.497 -0.12% 35 43.9%
3 6.6 2.50 2.499 -0.04% 36 45.8%
4 6.8 2.50 2.501 +0.04% 37 47.2%
5 7.2 2.50 2.502 +0.08% 37 49.5%
6 7.8 2.50 2.499 -0.04% 38 53.1%
7 8.0 2.50 2.496 -0.16% 39 56.4%

补充实测数据(二):恒压模式不同充电电流点

序号 充电电流(A) 设定电压(V) 实测电压(V) 电压误差 输出电压纹波(mVpp) PWM 占空比
8 2.20 8.40 8.399 -0.01% 29 61.0%
9 1.80 8.40 8.400 0.00% 28 60.5%
10 1.20 8.40 8.401 +0.01% 27 59.8%
11 0.80 8.40 8.400 0.00% 26 59.3%
12 0.30 8.40 8.401 +0.01% 25 58.9%

补充实测数据(三):不同温度下的效率与纹波

序号 环境温度(℃) 恒流效率(2.5A) 恒压效率(1.0A) 恒流纹波(mVpp) 恒压纹波(mVpp)
13 5 84.6% 81.8% 41 31
14 15 85.5% 82.7% 39 29
15 20 86.0% 83.3% 38 28
16 30 86.1% 83.4% 39 29
17 35 85.6% 82.6% 40 30

补充实测数据(四):动态响应与长时间运行

序号 测试项目 测试条件 实测值 判定
18 恒流动态恢复时间 7.0V,10% 阶跃(2.5A→2.25A) 3.1ms 通过
19 恒压动态恢复时间 8.4V,50% 阶跃(1.0A→0.5A) 4.4ms 通过
20 连续运行稳定性 25℃,恒压 8.4V 带载 72 小时 电压漂移 ±0.06%,无异常 通过

上述 20 组补充实测数据与第 4.2~4.6 节原有测试结果相互印证:恒流模式电流误差均控制在 ±0.5% 以内,恒压模式电压误差均控制在 ±0.05% 以内,全温度范围效率与纹波指标均满足设计要求,动态响应与长时间运行稳定性良好,进一步验证了本充电器设计指标的一致性与可靠性。

综合上述测试结果,对本充电器的性能表现总结如下:

  • 恒流精度:恒流 2.5A 模式下,电流误差控制在 ±0.5% 以内,满足锂电池恒流充电精度要求。动态响应恢复时间约 3.2ms,无振荡与超调。
  • 恒压精度:恒压 8.4V 模式下,电压误差控制在 ±0.05% 以内,远优于锂电池充电对恒压精度的典型要求(±1%)。12 位 PWM 扩展法使电压调节分辨率达约 2mV,恒压阶段输出电压全程无明显漂移。
  • 充电效率:0℃~45℃ 范围内充电效率保持在 81.5%~86.3% 之间,25℃ 常温下恒流阶段效率最高达 86.3%,满足设计目标。效率随温度变化呈先升后降趋势,拐点约在 25℃~30℃。
  • 纹波电压:全温度范围内恒流模式纹波 38~44mVpp,恒压模式纹波 28~33mVpp,均远低于 100mVpp 的典型限值。恒压模式纹波优于恒流模式,验证了 12 位 PWM 扩展法对输出质量的改善效果。
  • 稳定性:10 次连续充放电循环中,恒压稳定值波动 ±0.05%,终止电流判定波动 ±0.4%,无一次异常。温度循环测试中输出电压最大漂移 ±0.4%,温度恢复后无永久性漂移,反馈环路在全温度范围内稳定。

测试数据表明,本充电器在恒流、恒压模式下的电压电流控制精度、充电效率、纹波电压与稳定性等关键指标均满足 8.4V/2.5Ah 锂电池充电要求,设计目标全部达成。测试中发现的效率随温度变化规律与纹波随温度升高略增的趋势,为后续优化提供了明确方向:可选用更低导通电阻的 MOSFET 与更低 ESR 的电解电容,以进一步改善高温与低温工况下的效率与纹波表现。

4.8 编译环境配置与烧录步骤

ATtiny13 固件采用 AVR-GCC 工具链编译,配合 avrdude 完成烧录。推荐在 Windows 平台使用 Microchip Studio(原 Atmel Studio)或命令行方式构建,也可在 Linux 下直接使用 Makefile 管理编译流程。以下给出完整的编译环境配置与烧录步骤。

(1)工具链安装

Windows 用户可安装 Microchip Studio,其内置 AVR-GCC 编译器与 avrdude 烧录工具;Linux 用户通过包管理器安装:

bash 复制代码
sudo apt-get install gcc-avr avr-libc avrdude

安装完成后,在终端执行 avr-gcc --version 与 avrdude -v 验证工具链是否就绪。

(2)工程文件组织

固件源码建议按以下结构组织,便于维护与版本管理:

plaintext 复制代码
attiny13_charger/
├── main.c              /* 主循环:采样调度 + 状态机调用 */
├── adc.c / adc.h       /* ADC 采样与滤波模块 */
├── pwm.c / pwm.h       /* PWM 4 位扩展模块 */
├── charger.c / charger.h  /* 充电状态机模块 */
├── uart.c / uart.h     /* GPIO 模拟 UART 发送模块 */
├── config.h            /* 引脚定义与阈值宏 */
└── Makefile            /* 编译与烧录脚本 */

(3)Makefile 编译配置

以下 Makefile 面向 ATtiny13 配置熔丝位为内部 1.2MHz 时钟(CKSEL=0010,SUT=10),编译优化等级取 -Os 以最小化 Flash 占用:

makefile 复制代码
# ============ ATtiny13 充电器固件 Makefile ============
MCU      = attiny13
F_CPU    = 1200000UL
TARGET   = charger
SRC      = main.c adc.c pwm.c charger.c uart.c
CC       = avr-gcc
OBJCOPY  = avr-objcopy
CFLAGS   = -mmcu=$(MCU) -DF_CPU=$(F_CPU) -Os -Wall -Wextra
LDFLAGS  = -mmcu=$(MCU)
all: $(TARGET).hex
$(TARGET).elf: $(SRC)
$(CC) $(CFLAGS) -o $@ $^
$(TARGET).hex: $(TARGET).elf
$(OBJCOPY) -O ihex -R .eeprom $< $@
烧录:使用 USBasp 编程器,目标频率 1.2MHz
flash: $(TARGET).hex
avrdude -c usbasp -p t13 -U flash:w:$(TARGET).hex:i
读取当前熔丝位
fuse_read:
avrdude -c usbasp -p t13 -U lfuse:r:-:h -U hfuse:r:-:h
clean:
rm -f $(TARGET).elf $(TARGET).hex

(4)编译与烧录步骤

在工程根目录执行 make 即可完成编译,生成 charger.hex 文件。首次烧录前需确认熔丝位配置:ATtiny13 出厂默认使用内部 9.6MHz 时钟,本设计需将低熔丝位配置为内部 1.2MHz(lfuse = 0x6A),高熔丝位保持默认(hfuse = 0xFF)。使用 USBasp 编程器连接目标板,执行以下命令完成烧录:

bash 复制代码
# 1. 配置熔丝位(仅首次烧录需要)
avrdude -c usbasp -p t13 -U lfuse:w:0x6A:m -U hfuse:w:0xFF:m
2. 烧录固件
avrdude -c usbasp -p t13 -U flash:w:charger.hex:i
3. 校验烧录结果
avrdude -c usbasp -p t13 -U flash:v:charger.hex:i

烧录完成后,将编程器与目标板断开,重新上电即可运行固件。通过串口工具以 9600bps 连接 PB1 引脚,可观察到固件周期性上报的充电参数帧(帧头 0xAA),用于验证状态机切换与采样数据是否正确。

设计要点:编译优化等级必须取 -Os,否则 1KB Flash 可能溢出;熔丝位配置需谨慎,错误配置可能导致芯片锁死,建议烧录前先执行 fuse_read 备份当前值;若使用其他编程器(如 Arduino 作为 ISP),将 -c usbasp 替换为 -c arduino 并指定 -P 端口即可。

5. 本文创新点

本设计在满足 8.4V/2.5Ah 锂电池充电基本功能的前提下,围绕低成本、高精度与高可靠性三个目标,形成了以下四项具有工程参考价值的创新点。

5.1 双芯片功能解耦架构

传统小功率充电器多采用单芯片同时承担功率变换与充电管理,存在控制耦合、调试困难、故障定位复杂等问题。本设计将功率级与充电管理级解耦:初级侧 uC3845 专司反激变换的高频开关控制,次级侧 ATtiny13 专注充电流程与状态监测,两者通过光耦隔离实现信号交互。该架构使功率级与充电管理模块可独立优化与调试,降低了单芯片的运算与资源压力,也提升了系统的可维护性与可扩展性。

5.2 低成本 8 位 MCU 的 12 位 PWM 扩展方法

ATtiny13 仅有 8 位 PWM 硬件资源,直接输出难以满足恒压 8.4V 的精细调节需求。本设计提出 4 位扩展法:将 8 位 PWM 扩展为 12 位精度,低 4 位通过软件在多个 PWM 周期内按比例分配占空比实现。该方法以时间平均方式获得高分辨率输出,在不增加硬件成本的前提下将恒压调节精度提升至 ±0.05%,电压调节分辨率约 2mV,为低成本 8 位 MCU 实现高精度模拟控制提供了可行路径。

5.3 六模式状态机与迟滞切换机制

充电控制覆盖空闲、预充、恒流、恒压、终止、错误六种模式,完整映射锂电池从深度放电到充满的全生命周期充电需求。各切换阈值引入迟滞设计以避免临界电压附近的频繁抖动,并配套预充、恒流、恒压三级超时保护与温度、电压异常保护,形成模式完备、切换可靠、异常可控的安全充电闭环。该状态机结构清晰、边界处理完善,可直接迁移至其他电池充电管理场景。

5.4 面向量产的工程化设计

在成本方面,uC3845 与 ATtiny13 均为成熟低成本的通用器件,配合精简的外围电路,整机物料成本可控,适合规模化生产。在可靠性方面,双芯片架构降低了单点故障风险,完善的保护机制与严格的性能测试验证了方案在宽温度范围与连续充放电工况下的稳定性。此外,固件同时提供 C 语言与汇编语言版本,兼顾开发效率与资源受限场景,具备良好的工程实用价值与推广前景。

6. 总结

本文围绕一款基于 uC3845 与 ATtiny13 双芯片架构的 8.4V/2.5Ah 锂电池充电器,完成了从方案设计、硬件电路、固件实现到性能测试的完整闭环。初级侧以 uC3845 电流模式 PWM 控制器为核心,通过反激式 AC/DC 转换实现市电到隔离直流的功率变换,输出电压经 TL431 与光耦反馈回初级侧构成闭环稳压;次级侧由 ATtiny13 完成充电流程控制与状态监测,通过电压、电流与温度三路采样判断充电状态,并采用 4 位扩展法将 8 位 PWM 提升至 12 位精度,实现恒压 8.4V 的精确调节。

充电控制采用空闲、预充、恒流、恒压、终止、错误六种模式的状态机设计,各切换阈值引入迟滞避免临界抖动,并配备预充、恒流、恒压超时保护与温度、电压异常保护,确保充电过程安全可靠。性能测试表明:恒流 2.5A 模式下电流误差控制在 ±0.5% 以内,恒压 8.4V 模式下电压误差控制在 ±0.05% 以内,0℃~45℃ 范围内充电效率保持在 81.5%~86.3% 之间,纹波电压始终低于 45mVpp,10 次连续充放电循环无一次异常,各项指标均满足设计目标。

本设计的技术要点可归纳为以下四个方面:

  • 双芯片架构优势:采用 uC3845 与 ATtiny13 分工协作,将功率变换与充电管理解耦。uC3845 专司反激功率级的高频开关控制,ATtiny13 专注充电流程与状态监测,两者通过光耦隔离实现信号交互。该架构既降低了单芯片的运算与资源压力,又便于功率级与充电管理模块的独立优化、调试与故障定位,提升了系统的可维护性与可扩展性。
  • 4 位 PWM 扩展法的创新点:针对 ATtiny13 仅有 8 位 PWM 硬件资源的限制,本设计通过软件扩展方式将 PWM 精度提升至 12 位。其核心思路是利用定时器中断在多个 PWM 周期内动态调整占空比,以时间平均的方式实现高分辨率输出,从而在不增加硬件成本的前提下显著提升恒压调节精度,使输出电压误差控制在 ±0.05% 以内。该方法为低成本 8 位 MCU 实现高精度模拟控制提供了可行路径。
  • 六模式状态机的完备性:充电控制覆盖空闲、预充、恒流、恒压、终止、错误六种工作模式,完整映射锂电池从深度放电到充满的全生命周期充电需求。各模式切换阈值引入迟滞设计以避免临界抖动,并配套预充、恒流、恒压三级超时保护与温度、电压异常保护,形成"模式完备、切换可靠、异常可控"的安全充电闭环。
  • 工程价值:在成本方面,选用 uC3845 与 ATtiny13 均为成熟低成本的通用器件,配合精简的外围电路,整机物料成本可控,适合规模化生产;在可靠性方面,双芯片架构降低了单点故障风险,完善的保护机制与严格的性能测试验证了方案在宽温度范围与连续充放电工况下的稳定性,具备良好的工程实用价值与推广前景。

后续优化方向包括选用更低导通电阻的 MOSFET 与更低 ESR 的电解电容以改善高低温工况下的效率与纹波,以及进一步压缩固件体积以预留更多扩展空间。

7. 参考资料

本文设计过程中参考了以下芯片数据手册、应用笔记与行业标准,按学术引用格式排列如下,供读者进一步查阅与验证设计细节。

  1. Texas Instruments. UC3842-UC3845 Current Mode PWM ControllersEB/OL. Dallas: Texas Instruments, 2007. 数据手册编号 SLUS145.
  2. Microchip Technology. ATtiny13A 8-bit AVR Microcontroller with 1K Bytes In-System Programmable FlashEB/OL. Chandler: Microchip Technology, 2016. 数据手册编号 DS8126.
  3. Texas Instruments. TL431 Precision Programmable ReferenceEB/OL. Dallas: Texas Instruments, 2014. 数据手册编号 SLVS543.
  4. Texas Instruments. Switch-Mode Li-Ion Battery Charger DesignEB/OL. Dallas: Texas Instruments, 2011. 应用笔记编号 SLUA117.
  5. Texas Instruments. Flyback Transformer Design for UCC28C4xEB/OL. Dallas: Texas Instruments, 2015. 应用笔记编号 SLUA535.
  6. Vishay. NTC Thermistor Application NotesEB/OL. Malvern: Vishay Intertechnology, 2012.
  7. GNU Project. AVR-GCC Toolchain DocumentationEB/OL. Free Software Foundation, 2020.
  8. 中华人民共和国国家质量监督检验检疫总局. GB/T 18287-2013 移动电话用锂离子蓄电池及蓄电池组总规范S. 北京: 中国标准出版社, 2013.
  9. 4位扩展法:基于ATtiny816的高精度PWM软件扩展方案
  10. 低成本高精度PWM:4位扩展法原理、实现与工程实践
  11. 基于GPIO模拟UART的嵌入式测试工具:硬件接线与ATtiny26汇编实现
  12. 嵌入式ADC滤波实战:整数移位实现三阶巴特沃斯,低开销高稳定输出14/16位精度,ADC4位扩展法
相关推荐
青山木1 小时前
Hot 100 --- 数组中的第K个最大元素
java·数据结构·算法·排序算法
玛卡巴卡ldf1 小时前
【AICoding】笔试提示词设计思路
java·算法·ai编程
明月_清风1 小时前
位图与布隆过滤器:海量数据下的"存在性判断"艺术
前端·后端·算法
Rnan-prince1 小时前
堆与TopK · 从零到通透 —— 9 节全系列复盘
python·算法
明月_清风1 小时前
Hash 表从入门到精通:Go 实战与工程细节
前端·后端·算法
快秃头的码农1 小时前
esp32-s3移植lvgl总结
嵌入式硬件·esp32-s3
nbsaas-boot2 小时前
多智能体系统的架构边界:任务编排、共享状态与故障隔离设计
人工智能·算法·动态规划
wuyk5552 小时前
12.归并排序:分治思想的稳定排序算法
开发语言·数据结构·算法·排序算法
吴声子夜歌2 小时前
ApacheCommons——commons-text(模板替换与文本算法)
java·开发语言·算法·apache