
🎬 渡水无言 :个人主页渡水无言
❄专栏传送门 : 《linux专栏》《嵌入式linux驱动开发》《linux系统移植专栏》
❄专栏传送门 : 《freertos专栏》 《STM32 HAL库专栏》《linux裸机开发专栏》
❄专栏传送门 :《产品测评专栏》 《Ai智能体专栏) 《ROS开发专栏》
❄专栏传送门 :《BMS专栏》
⭐️流水不争先,争的是滔滔不绝
📚博主简介:第二十届中国研究生电子设计竞赛全国二等奖 |国家奖学金 | 省级三好学生
| 省级优秀毕业生获得者 | csdn新星杯TOP1 | 半导纵横专栏博主 | 211在读研究生
在这里主要分享自己学习的linux嵌入式领域知识;有分享错误或者不足的地方欢迎大佬指导,也欢迎各位大佬互相三连
目录
[2.1 任务、定时器宏定义](#2.1 任务、定时器宏定义)
[3.1、初始化函数 BMS_ProtectInit](#3.1、初始化函数 BMS_ProtectInit)
4.1.2、充电工况保护(BMS_ChargeMonitor)
4.1.3、放电工况保护(BMS_DischargeMonitor)
4.2、硬件故障监控(BMS_ProtectHwMonitor)
前言
在上一期博客里我们详细讲解了BMS_MonitorTask电池状态监控任务,它负责电压、电流、温度等原始数据采集,是整个系统的数据来源。
而本期博客我们将聚焦BMS另一核心任务: BMS_ProtectTask 电池保护任务。
本套保护任务基于状态机思想设计,区分充电、放电、待机、睡眠四大工况,实现过压、欠流、过流、短路、高低温等全场景保护逻辑。
一、整体架构与函数调用总览
BMS_ProtectTask 是 BMS 系统安全核心任务 ,优先级高于普通监控任务 ,依托监控任务采集的电池数据,结合 BQ76920 硬件告警信号,实现软件保护 + 硬件保护双重兜底。
优先级:10 高于电池监控任务,确保故障发生时优先执行保护动作;
运行周期:200ms,兼顾故障响应速度与 CPU 负载;
配套单次定时器:用于故障延时恢复,防止故障反复触发。
核心职责:
依据系统当前工况(充电 / 放电 / 待机 / 睡眠)执行对应保护判断;
检测过压、欠压、充放电过流、负载短路、高温、低温故障;
故障触发时切断充放电回路,启动延时恢复机制;
故障条件解除后,自动恢复回路导通;
对接 BQ76920 硬件中断告警信号,响应硬件级故障。
完整函数调用栈
保护任务所有判断数据,均来自 BMS_MonitorTask 采集的全局结构体 BMS_MonitorData;
硬件故障信号来自 BQ76920 ALERT 告警引脚,通过 STM32 外部中断接入系统。
cpp
BMS_ProtectInit // 保护任务 & 延时定时器初始化
├── osThreadNew // 创建保护主线程
└── osTimerNew // 创建单次延时恢复定时器
└── BMS_ProtectTimerEntry // 定时器回调函数
BMS_ProtectTaskEntry // 保护任务主循环(状态机驱动)
├── PROTECT_STATE_MONITOR // 正常监控状态
│ ├── BMS_ProtectSwMonitor // 软件保护逻辑
│ │ ├── BMS_ChargeMonitor // 充电工况保护(过流/高温/低温)
│ │ │ ├── BMS_HalCtrlCharge // 关闭充电MOS
│ │ │ └── BMS_ProtectStartTimer // 启动恢复延时定时器
│ │ └── BMS_DischargeMonitor // 放电工况保护(高温/低温)
│ │ └── BMS_HalCtrlDischarge // 关闭放电MOS
│ └── BMS_ProtectHwMonitor // BQ76920硬件故障监控
│ └── BMS_ProtectStartTimer // 硬件故障启动延时
├── PROTECT_STATE_RELIEVE_WAIT // 故障解除等待状态
│ └── BMS_ProtectRelieveWait // 检测故障是否消失
└── PROTECT_STATE_RELIEVE // 故障恢复状态
└── BMS_ProtectRelieve // 恢复充放电回路
├── BMS_HalCtrlCharge // 恢复充电MOS
└── BMS_HalCtrlDischarge// 恢复放电MOS
└── BQ769X0_ControlDSGOrCHG // 操作BQ76920寄存器
└── BQ769X0_WriteRegisterByteWithCRC // I2C带CRC写寄存器
// 硬件中断触发入口(外部中断对接BQ76920 ALERT引脚)
BMS_ProtectHwOCD // 放电过流硬件触发
BMS_ProtectHwSCD // 负载短路硬件触发
BMS_ProtectHwOV // 充电过压硬件触发
BMS_ProtectHwUV // 放电欠压硬件触发
二、任务基础配置与全局变量
2.1 任务、定时器宏定义
cpp
#define BMS_DBG_TAG "Protect"
#include <stdio.h>
#include <stdbool.h>
#include <rtthread.h>
#include "bms_protect.h"
#include "bms_hal_monitor.h"
#include "bms_hal_control.h"
#include "bms_monitor.h"
#include "bms_global.h"
#include "bms_debug.h"
// 保护任务配置
#define PROTECT_TASK_STACK_SIZE 512 // 任务栈大小
#define PROTECT_TASK_PRIORITY 10 // 任务优先级(高于监控任务,保障故障优先响应)
#define PROTECT_TASK_TIMESLICE 25
#define PROTECT_TASK_PERIOD 200 // 任务基础运行周期 200ms
优先级:10 高于电池监控任务,确保故障发生时优先执行保护动作;
运行周期:200ms,兼顾故障响应速度与 CPU 负载;
配套单次定时器:用于故障延时恢复,防止故障反复触发。
2.2、全局参数与状态变量
cpp
// 故障告警标志位
BMS_ProtectAlertTypedef BMS_ProtectAlert = FlAG_ALERT_NO;
// 保护阈值参数结构体(所有保护门限统一配置)
BMS_ProtectParamTypedef BMS_ProtectParam =
{
.ShoutdownVoltage = INIT_SHUTDOWN_VOLTAGE, // 系统关机电压
.OVProtect = INIT_OV_PROTECT, // 单体过压阈值
.OVRelieve = INIT_OV_RELIEVE, // 过压恢复阈值
.UVProtect = INIT_UV_PROTECT, // 单体欠压阈值
.UVRelieve = INIT_UV_RELIEVE, // 欠压恢复阈值
.OCCProtect = INIT_OCC_MAX, // 充电过流阈值
.OCDProtect = INIT_OCD_MAX, // 放电过流阈值
.OVDelay = INIT_OV_DELAY, // 过压保护延时
.UVDelay = INIT_UV_DELAY, // 欠压保护延时
.OCDDelay = INIT_OCD_DELAY, // 放电过流延时
.SCDDelay = INIT_SCD_DELAY, // 短路保护延时
.OCDRelieve = INIT_OCD_RELIEVE, // 放电过流恢复延时
.SCDRelieve = INIT_SCD_RELIEVE, // 短路恢复延时
.OCCDelay = INIT_OCC_DELAY, // 充电过流延时
.OCCRelieve = INIT_OCC_RELIEVE, // 充电过流恢复延时
.OTCProtect = INIT_OTC_PROTECT, // 充电过温
.OTCRelieve = INIT_OTCRelieve, // 充电过温恢复
.OTDProtect = INIT_OTD_PROTECT, // 放电过温
.OTDRelieve = INIT_OTDRelieve,
.LTCProtect = INIT_LTC_PROTECT, // 充电低温
.LTCRelieve = INIT_LTCRelieve,
.LTDProtect = INIT_LTD_PROTECT, // 放电低温
.LTDRelieve = INIT_LTD_RELIEVE,
};
static osTimerId_t pTimerProtect; // 故障恢复定时器句柄
static BMS_ProtectStateTypedef ProtectState = PROTECT_STATE_MONITOR; // 保护状态机
所有保护阈值统一放入 BMS_ProtectParam 结构体,集中配置、便于量产改参数;
BMS_ProtectAlert:全局故障标志,区分过压 / 欠压 / 过流 / 短路 / 高低温;
ProtectState:状态机核心变量,实现三段式状态流转。
三、任务初始化与主状态机
3.1、初始化函数 BMS_ProtectInit
同时创建任务 + 定时器:
cpp
void BMS_ProtectInit(void)
{
osThreadId_t thread;
// 创建保护任务
thread = osThreadNew(BMS_ProtectTaskEntry, NULL, &protectTask_attributes);
if (thread == NULL)
{
BMS_ERROR("Create Task Fail");
}
// 创建单次定时器(用于故障延时恢复)
pTimerProtect = osTimerNew(BMS_ProtectTimerEntry, osTimerOnce, NULL, &protectTimer_attributes);
if (pTimerProtect == NULL)
{
BMS_ERROR("Create Timer Fail");
}
}
3.2、三大状态机定义
本保护任务采用经典三状态状态机,是嵌入式故障处理标准设计:
PROTECT_STATE_MONITOR:正常监控态,实时检测软硬件故障;
PROTECT_STATE_RELIEVE_WAIT:故障解除等待态,故障消失后先判断恢复条件;
PROTECT_STATE_RELIEVE:故障恢复态,重新打开充放电回路。
四、任务主循环
状态流转总逻辑
正常监控 → 检测到故障 → 进入等待恢复 → 故障条件满足 → 执行恢复 → 回到正常监控。
cpp
static void BMS_ProtectTaskEntry(void *paramter)
{
(void)paramter;
while(1)
{
switch(ProtectState)
{
case PROTECT_STATE_MONITOR:
{
BMS_ProtectSwMonitor(); // 软件保护判断
BMS_ProtectHwMonitor(); // 硬件故障判断
}break;
case PROTECT_STATE_RELIEVE_WAIT:
{
BMS_ProtectRelieveWait(); // 等待故障条件解除
}break;
case PROTECT_STATE_RELIEVE:
{
BMS_ProtectRelieve(); // 执行故障恢复
}break;
}
osDelay(PROTECT_TASK_PERIOD); // 200ms周期运行
}
}
4.1、软件保护判断
软件保护基于 BMS_MonitorTask 采集的电压、电流、温度数据,按工况分流判断 :区分充电、放电、待机、睡眠四种模式,不同工况执行不同保护规则。
cpp
├── BMS_ProtectSwMonitor // 软件保护逻辑
│ │ ├── BMS_ChargeMonitor // 充电工况保护(过流/高温/低温)
│ │ │ ├── BMS_HalCtrlCharge // 关闭充电MOS
│ │ │ └── BMS_ProtectStartTimer // 启动恢复延时定时器
│ │ └── BMS_DischargeMonitor // 放电工况保护(高温/低温)
│ │ └── BMS_HalCtrlDischarge // 关闭放电MOS
4.1.1、工况分流入口
代码如下所示:
cpp
static void BMS_ProtectSwMonitor(void)
{
switch(BMS_GlobalParam.SysMode)
{
case BMS_MODE_CHARGE:
{
BMS_ChargeMonitor(); // 充电保护逻辑
}break;
case BMS_MODE_DISCHARGE:
{
BMS_DischargeMonitor();// 放电保护逻辑
}break;
case BMS_MODE_STANDBY:
case BMS_MODE_SLEEP:
{
// 待机/睡眠无充放电,无需额外保护
}break;
default:;break;
}
}
4.1.2、充电工况保护(BMS_ChargeMonitor)
监控充电过流、充电高温、充电低温 三类故障,采用延时计数防误触发,代码如下所示:
cpp
static void BMS_ChargeMonitor(void)
{
static uint32_t ProtectCount = 0;
// 1. 充电过流判断
if (BMS_MonitorData.BatteryCurrent > BMS_ProtectParam.OCCProtect)
{
ProtectCount += PROTECT_TASK_PERIOD;
// 延时达到阈值,确认故障
if (ProtectCount / 60 >= BMS_ProtectParam.OCCDelay)
{
BMS_HalCtrlCharge(BMS_STATE_DISABLE); // 关闭充电MOS
BMS_ProtectStartTimer(BMS_ProtectParam.OCCRelieve); // 启动恢复定时器
BMS_ProtectAlert = FlAG_ALERT_OCC; // 标记充电过流故障
ProtectState = PROTECT_STATE_RELIEVE_WAIT; // 切换状态
BMS_WARNING("OCC Tigger");
}
}
// 温度数据无效,直接跳过
else if (BMS_MonitorData.CellTempEffectiveNumber == 0)
{
return;
}
// 2. 充电过温
else if (BMS_MonitorData.CellTemp[BMS_MonitorData.CellTempEffectiveNumber-1] > BMS_ProtectParam.OTCProtect)
{
BMS_HalCtrlCharge(BMS_STATE_DISABLE);
BMS_ProtectAlert = FlAG_ALERT_OTC;
ProtectState = PROTECT_STATE_RELIEVE_WAIT;
BMS_WARNING("OTC Tigger");
}
// 3. 充电低温
else if (BMS_MonitorData.CellTemp[0] < BMS_ProtectParam.LTCProtect)
{
BMS_HalCtrlCharge(BMS_STATE_DISABLE);
BMS_ProtectAlert = FlAG_ALERT_LTC;
ProtectState = PROTECT_STATE_RELIEVE_WAIT;
BMS_WARNING("LTC Tigger");
}
else
{
ProtectCount = 0; // 无故障,清空计数
}
}
OCCProtect为充电过流保护阈值。
充电过流增加软件延时滤波,瞬时电流冲击不触发保护;
温度无效时直接跳过判断,避免误保护;
故障触发后立即关闭充电回路,切换状态机。
4.1.3、放电工况保护(BMS_DischargeMonitor)
监控放电高温、放电低温,发现问题就立即关闭放电回路。
放电过流 / 短路交由硬件优先处理,
代码如下所示:
cpp
static void BMS_DischargeMonitor(void)
{
if (BMS_MonitorData.CellTempEffectiveNumber == 0)
{
return;
}
// 放电过温
else if (BMS_MonitorData.CellTemp[BMS_MonitorData.CellTempEffectiveNumber-1] > BMS_ProtectParam.OTDProtect)
{
BMS_HalCtrlDischarge(BMS_STATE_DISABLE);
BMS_ProtectAlert = FlAG_ALERT_OTD;
ProtectState = PROTECT_STATE_RELIEVE_WAIT;
BMS_WARNING("OTD Tigger");
}
// 放电低温
else if (BMS_MonitorData.CellTemp[0] < BMS_ProtectParam.LTDProtect)
{
BMS_HalCtrlDischarge(BMS_STATE_DISABLE);
BMS_ProtectAlert = FlAG_ALERT_LTD;
ProtectState = PROTECT_STATE_RELIEVE_WAIT;
BMS_WARNING("LTD Tigger");
}
}
4.2、硬件故障监控(BMS_ProtectHwMonitor)
对接 BQ76920 硬件告警,是整套系统最高优先级保护。
BQ76920 检测到过压、欠压、放电过流、短路后,通过 ALERT 引脚触发 STM32 外部中断,调用对应硬件故障函数标记告警位。
总流程:中断入口 → 故障标记 → 任务检测 → 保护执行
cpp
BMS_ProtectHwMonitor // BQ76920硬件故障监控
│ └── BMS_ProtectStartTimer // 硬件故障启动延时
BQ76920(硬件检测)
↓ 故障触发 → ALERT引脚电平翻转
STM32 外部中断服务函数
↓ 调用对应标记函数 → 置位全局故障标志 BMS_ProtectAlert
保护任务 BMS_ProtectTask(轮询)
↓ 检测到故障标志 → 执行保护动作 + 状态机跳转
所有故障检测依靠芯片内部硬件比较器实现:
具有独立性:MCU 死机、程序跑飞、I2C 通信异常时,硬件比较器依旧正常工作;
故障触发后,BQ76920 会自主拉低 CHG/DSG 引脚,直接切断充放电 MOS,形成第一道硬件防护。
当中断触发时,根据 BQ76920 寄存器状态,区分具体故障类型,并调用源码中对应的标记函数,代码如下:
cpp
// 放电过流硬件标记
void BMS_ProtectHwOCD(void)
{
if (BMS_ProtectAlert == FlAG_ALERT_NO)
{
BMS_ProtectAlert = FlAG_ALERT_OCD;
}
}
// 负载短路硬件标记
void BMS_ProtectHwSCD(void)
{
if (BMS_ProtectAlert == FlAG_ALERT_NO)
{
BMS_ProtectAlert = FlAG_ALERT_SCD;
}
}
// 充电过压硬件标记
void BMS_ProtectHwOV(void)
{
if (BMS_ProtectAlert == FlAG_ALERT_NO)
{
BMS_ProtectAlert = FlAG_ALERT_OV;
}
}
// 放电欠压硬件标记
void BMS_ProtectHwUV(void)
{
if (BMS_ProtectAlert == FlAG_ALERT_NO)
{
BMS_ProtectAlert = FlAG_ALERT_UV;
}
}
全局变量 BMS_ProtectAlert 作为故障状态寄存器,无故障时为 FlAG_ALERT_NO;
仅在当前无故障时才赋值,避免多个故障叠加导致标志错乱;
中断只做标记动作,不执行复杂保护逻辑,符合「中断快进快出」的嵌入式设计规范。
保护任务轮询检测(BMS_ProtectHwMonitor)
中断仅标记故障,实际保护逻辑交由周期性保护任务执行 ,对应函数为 BMS_ProtectHwMonitor,代码如下所示:
cpp
void BMS_ProtectHwMonitor(void)
{
switch(BMS_ProtectAlert)
{
case FlAG_ALERT_OCD: // 放电过流
case FlAG_ALERT_SCD: // 负载短路
{
BMS_ProtectStartTimer(BMS_ProtectParam.OCDRelieve);
ProtectState = PROTECT_STATE_RELIEVE_WAIT;
BMS_WARNING("OCD/SCD Tigger");
}break;
case FlAG_ALERT_OV: // 充电过压
case FlAG_ALERT_UV: // 放电欠压
{
ProtectState = PROTECT_STATE_RELIEVE_WAIT;
BMS_WARNING("OV/UV Tigger");
}break;
default:
{
}break;
}
放电过流 (OCD)、短路 (SCD):属于高危瞬时故障,启动延时恢复定时器,防止故障反复跳变导致回路频繁通断;
过压 (OV)、欠压 (UV):属于电压持续性故障,直接进入故障等待状态,不额外启动定时器。
检测到硬件故障后,统一将全局状态变量
ProtectState切换为PROTECT_STATE_RELIEVE_WAIT(故障等待态),整个保护流程进入统一的故障处理分支。进入
PROTECT_STATE_RELIEVE_WAIT状态后,执行 故障条件校验( 滞回保护措施**)**,当 电压回落至恢复阈值,才解除故障。
代码如下所示:
cpp
static void BMS_ProtectRelieveWait(void)
{
switch (BMS_ProtectAlert)
{
case FlAG_ALERT_OV:
{
// 电压回落至恢复阈值,才解除故障
if (BMS_MonitorData[CELL_MAX].CellVoltage < BMS_ProtectParam.OVRelieve)
{
ProtectState = PROTECT_STATE_RELIEVE;
BMS_INFO("OV Relieve");
}
}break;
case FlAG_ALERT_UV:
{
if (BMS_MonitorData[0].CellVoltage > BMS_ProtectParam.UVRelieve)
{
ProtectState = PROTECT_STATE_RELIEVE;
BMS_INFO("UV Relieve");
}
}
// 其余故障同理
}
}
cpp//故障条件满足后,进入 PROTECT_STATE_RELIEVE 状态,执行回路恢复、标志清零: static void BMS_ProtectRelieve(void) { switch(BMS_ProtectAlert) { case FlAG_ALERT_OCD: case FlAG_ALERT_SCD: case FlAG_ALERT_OV: case FlAG_ALERT_UV: // 恢复对应充放电MOS控制 BMS_HalCtrlXXX(xxx); break; } // 清空故障标志,回归正常监控态 BMS_ProtectAlert = FlAG_ALERT_NO; ProtectState = PROTECT_STATE_MONITOR; BMS_INFO("Protect Relieve"); }针对不同硬件故障的差异化防护策略:
过压 (OV)、欠压 (UV)、高低温:参数回落至恢复阈值,且清除芯片故障锁存后,立即恢复充放电,无额外延时;
放电过流 (OCD)、负载短路 (SCD):不仅要求电流恢复正常,还必须等待软件延时定时器超时,双重条件满足后才会恢复;
负载短路(SCD)
芯片级动作:BQ76920 硬件比较器微秒级切断放电回路,属于最高优先级防护;
中断上报:ALERT 引脚触发中断,MCU 标记短路故障;
任务处理:启动较长恢复延时,避免短路反复冲击硬件;
应用场景:防止线束、负载起火,是锂电最致命故障。
放电过流(OCD)
硬件先行切断放电 MOS;
软件层增加延时恢复,区分瞬时冲击电流与持续性过流;
适用场景:机器人电机堵转、负载超限。
充电过压(OV)
BQ76920 硬件关闭充电回路,防止电芯过充鼓包;
采用电压滞回恢复,电压回落至安全区间再恢复充电;
放电欠压(UV)
硬件切断放电,防止电芯深度过放造成永久性损坏;
电压回升至恢复阈值后,才允许继续放电。
总结
本期博客主要是实现 BMS_ProtectTask 电池保护任务 。套保护任务基于状态机思想设计,区分充电、放电、待机、睡眠四大工况,实现过压、欠流、过流、短路、高低温等全场景保护逻辑。