基于STM8的快充快放程序设计方案
一、系统架构设计
1.1 硬件配置(STM8S003F3P6)
主控芯片:STM8S003F3P6(8KB Flash, 1KB RAM)
充电管理:CN3791(太阳能/锂电池充电芯片,支持MPPT)
快充协议:IP2712(支持QC/PD/FCP/SCP等协议)
放电控制:AO4407(P沟道MOS)+ AO3400(N沟道MOS)
监测电路:
- 电压采样:ADC1(电池电压)
- 电流采样:ACS712(霍尔电流传感器)
- 温度监测:NTC热敏电阻
保护电路:DW01+(锂电保护IC)
1.2 功能指标
| 参数 | 规格 |
|---|---|
| 电池类型 | 单节锂电芯(3.7V) |
| 快充输入 | 5-12V(支持QC2.0/3.0) |
| 最大充电电流 | 2A(可调) |
| 最大放电电流 | 3A(可调) |
| 转换效率 | ≥92% |
| 保护功能 | 过充/过放/过流/短路/过温 |
二、软件架构
2.1 程序流程图
上电初始化
↓
检测电池状态
↓
├─→ 电池正常 → 进入待机模式
↓
├─→ 检测到充电输入 → 启动快充协议协商
↓
├─→ 协议握手成功 → 进入CC-CV充电阶段
↓
├─→ 充电完成 → 进入浮充维护
↓
├─→ 检测到放电请求 → 启动PWM放电控制
↓
├─→ 实时监控(电压/电流/温度)→ 触发保护
2.2 核心状态机
typedef enum {
SYS_INIT = 0, // 系统初始化
SYS_STANDBY, // 待机模式
SYS_CHG_DETECT, // 检测充电输入
SYS_CHG_PROTOCOL, // 快充协议握手
SYS_CHG_CC, // 恒流充电
SYS_CHG_CV, // 恒压充电
SYS_CHG_DONE, // 充电完成
SYS_DISCHARGE, // 放电模式
SYS_PROTECT, // 保护状态
SYS_ERROR // 故障状态
} SystemState;
三、关键代码实现
3.1 主程序(main.c)
/**
* @file main.c
* @brief STM8快充快放主程序
*/
#include "stm8s.h"
#include "battery.h"
#include "charge.h"
#include "discharge.h"
#include "protocol.h"
#include "protect.h"
SystemState sys_state = SYS_INIT;
BatteryInfo bat_info;
ChargeInfo chg_info;
DischargeInfo dis_info;
void main(void)
{
/* 系统初始化 */
System_Init();
ADC_Init();
PWM_Init();
Timer_Init();
UART_Init(9600);
/* 读取电池信息 */
Battery_ReadInfo(&bat_info);
/* 主循环 */
while (1)
{
/* 状态机处理 */
switch (sys_state)
{
case SYS_INIT:
sys_state = SYS_STANDBY;
break;
case SYS_STANDBY:
/* 检测充电输入 */
if (Charge_DetectInput())
{
sys_state = SYS_CHG_PROTOCOL;
}
/* 检测放电请求 */
else if (Discharge_DetectRequest())
{
sys_state = SYS_DISCHARGE;
}
break;
case SYS_CHG_PROTOCOL:
/* 快充协议握手 */
if (Protocol_Handshake(&chg_info))
{
sys_state = SYS_CHG_CC;
}
else
{
sys_state = SYS_ERROR;
}
break;
case SYS_CHG_CC:
/* 恒流充电 */
Charge_CC_Control(&chg_info);
if (bat_info.voltage >= CV_THRESHOLD)
{
sys_state = SYS_CHG_CV;
}
break;
case SYS_CHG_CV:
/* 恒压充电 */
Charge_CV_Control(&chg_info);
if (chg_info.current < CV_CURRENT_MIN)
{
sys_state = SYS_CHG_DONE;
}
break;
case SYS_CHG_DONE:
/* 充电完成,进入浮充 */
Charge_FloatControl();
if (!Charge_DetectInput())
{
sys_state = SYS_STANDBY;
}
break;
case SYS_DISCHARGE:
/* 放电控制 */
Discharge_Control(&dis_info);
if (bat_info.voltage <= DISCHARGE_CUTOFF)
{
sys_state = SYS_STANDBY;
}
break;
case SYS_PROTECT:
/* 保护状态 */
Protect_Process();
break;
case SYS_ERROR:
/* 错误处理 */
Error_Handler();
break;
}
/* 实时监测 */
Battery_Monitor(&bat_info);
Protect_Check(&bat_info, &chg_info, &dis_info);
/* 延时10ms */
Delay_Ms(10);
}
}
3.2 充电控制(charge.c)
/**
* @file charge.c
* @brief 快充充电控制
*/
#include "charge.h"
#include "pwm.h"
/* 充电参数 */
#define CC_CURRENT 2000 // 恒流电流(mA)
#define CV_VOLTAGE 4200 // 恒压电压(mV)
#define CV_CURRENT_MIN 100 // 恒压截止电流(mA)
#define PRE_CHARGE_VOLT 3000 // 预充电压阈值(mV)
/* PWM配置 */
#define PWM_MAX_DUTY 95 // 最大占空比(%)
#define PWM_MIN_DUTY 5 // 最小占空比(%)
/* 充电控制结构体 */
ChargeInfo chg_info;
/* 初始化充电参数 */
void Charge_Init(void)
{
chg_info.state = CHG_IDLE;
chg_info.target_current = CC_CURRENT;
chg_info.target_voltage = CV_VOLTAGE;
chg_info.current_duty = 0;
chg_info.input_voltage = 0;
chg_info.protocol = PROTOCOL_NONE;
}
/* 检测充电输入 */
uint8_t Charge_DetectInput(void)
{
uint16_t vin = ADC_Read(ADC_VIN); // 输入电压采样
chg_info.input_voltage = (vin * 3300 * 11) / 4095; // 分压比11:1
return (chg_info.input_voltage > 4500); // >4.5V认为有输入
}
/* 恒流充电控制 */
void Charge_CC_Control(ChargeInfo *info)
{
uint16_t bat_voltage = Battery_GetVoltage();
uint16_t bat_current = Battery_GetCurrent();
/* PI调节PWM占空比 */
int16_t error = info->target_current - bat_current;
info->current_duty += (error * 3) / 100; // P=3
/* 限制占空比范围 */
if (info->current_duty > PWM_MAX_DUTY)
info->current_duty = PWM_MAX_DUTY;
if (info->current_duty < PWM_MIN_DUTY)
info->current_duty = PWM_MIN_DUTY;
/* 设置PWM输出 */
PWM_SetDuty(PWM_CHG, info->current_duty);
/* 更新充电状态 */
info->state = CHG_CC;
}
/* 恒压充电控制 */
void Charge_CV_Control(ChargeInfo *info)
{
uint16_t bat_voltage = Battery_GetVoltage();
/* PI调节PWM占空比 */
int16_t error = info->target_voltage - bat_voltage;
info->current_duty += (error * 5) / 100; // P=5
/* 限制占空比范围 */
if (info->current_duty > PWM_MAX_DUTY)
info->current_duty = PWM_MAX_DUTY;
if (info->current_duty < PWM_MIN_DUTY)
info->current_duty = PWM_MIN_DUTY;
/* 设置PWM输出 */
PWM_SetDuty(PWM_CHG, info->current_duty);
/* 更新充电状态 */
info->state = CHG_CV;
}
/* 预充电(低压保护) */
void Charge_PreCharge(void)
{
uint16_t bat_voltage = Battery_GetVoltage();
if (bat_voltage < PRE_CHARGE_VOLT)
{
/* 小电流预充 */
PWM_SetDuty(PWM_CHG, 10); // 10%占空比
}
}
3.3 快充协议(protocol.c)
/**
* @file protocol.c
* @brief 快充协议处理(QC2.0/3.0)
*/
#include "protocol.h"
#include "gpio.h"
/* QC协议引脚定义 */
#define QC_DP_PORT GPIOC
#define QC_DP_PIN GPIO_PIN_4
#define QC_DM_PORT GPIOC
#define QC_DM_PIN GPIO_PIN_5
/* 协议状态 */
ProtocolState proto_state = PROTOCOL_IDLE;
/* QC2.0电压设置 */
typedef enum {
QC2_5V = 0,
QC2_9V,
QC2_12V,
QC2_20V
} QC2_Voltage;
/* QC3.0步进电压 */
#define QC3_STEP_200MV 0x01
#define QC3_STEP_20MV 0x02
/* 初始化QC协议 */
void Protocol_Init(void)
{
/* 配置DP/DM为开漏输出 */
GPIO_Init(QC_DP_PORT, QC_DP_PIN, GPIO_MODE_OUT_OD_LOW_FAST);
GPIO_Init(QC_DM_PORT, QC_DM_PIN, GPIO_MODE_OUT_OD_LOW_FAST);
}
/* QC2.0握手 */
uint8_t QC2_Handshake(void)
{
/* 1. 拉高DP,拉低DM */
GPIO_WriteHigh(QC_DP_PORT, QC_DP_PIN);
GPIO_WriteLow(QC_DM_PORT, QC_DM_PIN);
Delay_Ms(1500);
/* 2. 拉高DP和DM */
GPIO_WriteHigh(QC_DP_PORT, QC_DP_PIN);
GPIO_WriteHigh(QC_DM_PORT, QC_DM_PIN);
Delay_Ms(50);
/* 3. 检测充电器响应 */
GPIO_Init(QC_DP_PORT, QC_DP_PIN, GPIO_MODE_IN_FL_NO_IT);
GPIO_Init(QC_DM_PORT, QC_DM_PIN, GPIO_MODE_IN_FL_NO_IT);
if (GPIO_ReadInputPin(QC_DP_PORT, QC_DP_PIN) == SET &&
GPIO_ReadInputPin(QC_DM_PORT, QC_DM_PIN) == SET)
{
return 1; // 握手成功
}
return 0; // 握手失败
}
/* 设置QC2.0输出电压 */
void QC2_SetVoltage(QC2_Voltage volt)
{
GPIO_Init(QC_DP_PORT, QC_DP_PIN, GPIO_MODE_OUT_OD_LOW_FAST);
GPIO_Init(QC_DM_PORT, QC_DM_PIN, GPIO_MODE_OUT_OD_LOW_FAST);
switch (volt)
{
case QC2_5V:
GPIO_WriteLow(QC_DP_PORT, QC_DP_PIN);
GPIO_WriteLow(QC_DM_PORT, QC_DM_PIN);
break;
case QC2_9V:
GPIO_WriteHigh(QC_DP_PORT, QC_DP_PIN);
GPIO_WriteLow(QC_DM_PORT, QC_DM_PIN);
break;
case QC2_12V:
GPIO_WriteLow(QC_DP_PORT, QC_DP_PIN);
GPIO_WriteHigh(QC_DM_PORT, QC_DM_PIN);
break;
case QC2_20V:
GPIO_WriteHigh(QC_DP_PORT, QC_DP_PIN);
GPIO_WriteHigh(QC_DM_PORT, QC_DM_PIN);
break;
}
Delay_Ms(100);
}
/* QC3.0连续调压 */
void QC3_ContinuousVoltage(uint8_t step)
{
GPIO_Init(QC_DP_PORT, QC_DP_PIN, GPIO_MODE_OUT_OD_LOW_FAST);
GPIO_Init(QC_DM_PORT, QC_DM_PIN, GPIO_MODE_OUT_OD_LOW_FAST);
if (step == QC3_STEP_200MV)
{
/* 200mV步进 */
GPIO_WriteHigh(QC_DP_PORT, QC_DP_PIN);
GPIO_WriteLow(QC_DM_PORT, QC_DM_PIN);
Delay_Ms(1);
GPIO_WriteLow(QC_DP_PORT, QC_DP_PIN);
GPIO_WriteLow(QC_DM_PORT, QC_DM_PIN);
}
else if (step == QC3_STEP_20MV)
{
/* 20mV步进 */
GPIO_WriteLow(QC_DP_PORT, QC_DP_PIN);
GPIO_WriteHigh(QC_DM_PORT, QC_DM_PIN);
Delay_Ms(1);
GPIO_WriteLow(QC_DP_PORT, QC_DP_PIN);
GPIO_WriteLow(QC_DM_PORT, QC_DM_PIN);
}
}
/* 协议握手主函数 */
uint8_t Protocol_Handshake(ChargeInfo *info)
{
/* 尝试QC2.0握手 */
if (QC2_Handshake())
{
/* 根据输入电压选择输出 */
if (info->input_voltage >= 9000)
{
QC2_SetVoltage(QC2_9V);
info->target_voltage = 9000;
}
else if (info->input_voltage >= 12000)
{
QC2_SetVoltage(QC2_12V);
info->target_voltage = 12000;
}
else
{
QC2_SetVoltage(QC2_5V);
info->target_voltage = 5000;
}
info->protocol = PROTOCOL_QC2;
return 1;
}
/* 尝试其他协议... */
return 0;
}
3.4 放电控制(discharge.c)
/**
* @file discharge.c
* @brief 快放控制(电池测试/应急供电)
*/
#include "discharge.h"
#include "pwm.h"
/* 放电参数 */
#define DISCHARGE_CURRENT 3000 // 放电电流(mA)
#define DISCHARGE_CUTOFF 3000 // 放电截止电压(mV)
#define PWM_FREQ 20000 // PWM频率(Hz)
/* 放电控制结构体 */
DischargeInfo dis_info;
/* 初始化放电 */
void Discharge_Init(void)
{
dis_info.state = DIS_IDLE;
dis_info.target_current = DISCHARGE_CURRENT;
dis_info.current_duty = 0;
dis_info.load_enable = 0;
}
/* 检测放电请求 */
uint8_t Discharge_DetectRequest(void)
{
/* 检测按键或通信命令 */
if (GPIO_ReadInputPin(DISCHARGE_KEY_PORT, DISCHARGE_KEY_PIN) == RESET)
{
return 1;
}
return 0;
}
/* 放电控制 */
void Discharge_Control(DischargeInfo *info)
{
uint16_t bat_current = Battery_GetCurrent();
uint16_t bat_voltage = Battery_GetVoltage();
/* 检查截止条件 */
if (bat_voltage <= DISCHARGE_CUTOFF)
{
Discharge_Stop();
return;
}
/* PI调节放电电流 */
int16_t error = info->target_current - bat_current;
info->current_duty += (error * 2) / 100; // P=2
/* 限制占空比 */
if (info->current_duty > 90) info->current_duty = 90;
if (info->current_duty < 10) info->current_duty = 10;
/* 设置放电PWM */
PWM_SetDuty(PWM_DIS, info->current_duty);
/* 使能负载 */
if (!info->load_enable)
{
GPIO_WriteHigh(LOAD_EN_PORT, LOAD_EN_PIN);
info->load_enable = 1;
}
info->state = DIS_RUNNING;
}
/* 停止放电 */
void Discharge_Stop(void)
{
PWM_SetDuty(PWM_DIS, 0);
GPIO_WriteLow(LOAD_EN_PORT, LOAD_EN_PIN);
dis_info.load_enable = 0;
dis_info.state = DIS_IDLE;
}
3.5 保护功能(protect.c)
/**
* @file protect.c
* @brief 电池保护功能
*/
#include "protect.h"
#include "battery.h"
/* 保护阈值 */
#define OVER_VOLTAGE 4300 // 过压阈值(mV)
#define UNDER_VOLTAGE 2800 // 欠压阈值(mV)
#define OVER_CURRENT 3500 // 过流阈值(mA)
#define OVER_TEMP 65 // 过温阈值(℃)
#define UNDER_TEMP -10 // 低温阈值(℃)
/* 保护状态 */
ProtectState protect_state = PROTECT_NORMAL;
/* 保护检测 */
void Protect_Check(BatteryInfo *bat, ChargeInfo *chg, DischargeInfo *dis)
{
uint8_t fault = 0;
/* 1. 电压保护 */
if (bat->voltage > OVER_VOLTAGE)
{
fault |= FAULT_OVER_VOLTAGE;
}
if (bat->voltage < UNDER_VOLTAGE)
{
fault |= FAULT_UNDER_VOLTAGE;
}
/* 2. 电流保护 */
if (bat->current > OVER_CURRENT)
{
fault |= FAULT_OVER_CURRENT;
}
/* 3. 温度保护 */
if (bat->temperature > OVER_TEMP)
{
fault |= FAULT_OVER_TEMP;
}
if (bat->temperature < UNDER_TEMP)
{
fault |= FAULT_UNDER_TEMP;
}
/* 4. 短路保护 */
if (bat->current > OVER_CURRENT * 2)
{
fault |= FAULT_SHORT_CIRCUIT;
}
/* 处理故障 */
if (fault)
{
Protect_Execute(fault);
}
}
/* 执行保护 */
void Protect_Execute(uint8_t fault)
{
/* 立即切断充放电 */
PWM_SetDuty(PWM_CHG, 0);
PWM_SetDuty(PWM_DIS, 0);
GPIO_WriteLow(LOAD_EN_PORT, LOAD_EN_PIN);
/* 记录故障码 */
protect_state.fault_code = fault;
protect_state.state = PROTECT_ACTIVE;
/* 报警指示 */
for (uint8_t i = 0; i < 5; i++)
{
GPIO_WriteReverse(LED_FAULT_PORT, LED_FAULT_PIN);
Delay_Ms(200);
}
}
四、STM8配置(stm8s_conf.h)
/* STM8S配置头文件 */
#ifndef __STM8S_CONF_H
#define __STM8S_CONF_H
#include "stm8s.h"
/* 时钟配置 */
#define HSI_VALUE 16000000UL // 内部16MHz RC
#define CPU_CLOCK 16000000UL // CPU时钟16MHz
/* 外设使能 */
#define USE_ADC
#define USE_TIM1
#define USE_TIM2
#define USE_UART1
#define USE_GPIO
/* 中断优先级 */
#define ITC_PRIORITY_0 0 // 最高优先级
#define ITC_PRIORITY_1 1
#define ITC_PRIORITY_2 2
#define ITC_PRIORITY_3 3 // 最低优先级
#endif /* __STM8S_CONF_H */
五、编译与烧录
5.1 IAR工程配置
Project Options:
- General Options → Target → Device: STM8S003F3
- C/C++ Compiler → Preprocessor → Include directories: ./
- Linker → Config → Linker configuration file: stm8s003f3.icf
- Debugger → Setup → Driver: ST-LINK
5.2 编译优化
/* 编译器优化选项 */
#pragma optimize=speed // 速度优化
#pragma vector=0xXX // 中断向量
参考代码 基于stm8的快充快放程序 www.youwenfan.com/contentcnu/56320.html
六、测试与调试
6.1 测试项目
| 测试项 | 方法 | 预期结果 |
|---|---|---|
| 充电握手 | 接入QC充电器 | 协议识别成功,电压切换正常 |
| 恒流充电 | 监测电流 | 稳定在设定值±5% |
| 恒压充电 | 监测电压 | 稳定在4.20V±0.05V |
| 过流保护 | 短路输出 | 立即切断,恢复需重启 |
| 过温保护 | 加热电池 | >65℃停止充放电 |
6.2 调试技巧
- 使用SWIM接口:ST-LINK/V2实时调试
- 串口打印:输出电压/电流/温度数据
- LED指示:不同闪烁模式表示状态
- 示波器监测:PWM波形、电压纹波
七、安全注意事项
重要安全提示:
- 电池选型:必须使用带保护板的锂电池
- 散热设计:MOS管和电感需足够散热
- 绝缘处理:高压部分做好绝缘隔离
- 认证要求:量产需通过GB31241/UL2054认证
- 失效保护:加入硬件看门狗(如IMP706)
八、扩展功能
8.1 增加蓝牙控制
/* 蓝牙通信协议 */
void BLE_ProcessCommand(uint8_t *cmd)
{
if (strcmp(cmd, "START_CHG") == 0)
{
sys_state = SYS_CHG_PROTOCOL;
}
else if (strcmp(cmd, "START_DIS") == 0)
{
sys_state = SYS_DISCHARGE;
}
else if (strncmp(cmd, "SET_CUR=", 8) == 0)
{
uint16_t cur = atoi(cmd+8);
chg_info.target_current = cur;
}
}
8.2 增加LCD显示
/* LCD显示充电状态 */
void LCD_DisplayStatus(void)
{
LCD_Clear();
LCD_ShowString(0, 0, "BAT:");
LCD_ShowNumber(30, 0, bat_info.voltage/1000, 1);
LCD_ShowString(50, 0, "V");
LCD_ShowString(0, 1, "CUR:");
LCD_ShowNumber(30, 1, bat_info.current, 4);
LCD_ShowString(70, 1, "mA");
LCD_ShowString(0, 2, "TEMP:");
LCD_ShowNumber(40, 2, bat_info.temperature, 2);
LCD_ShowString(70, 2, "C");
}