BMS系统专栏: BMS_ProtectTask 电池保护任务

🎬 渡水无言 :个人主页渡水无言

❄专栏传送门 : 《linux专栏》《嵌入式linux驱动开发》《linux系统移植专栏》

❄专栏传送门 : 《freertos专栏》 《STM32 HAL库专栏》《linux裸机开发专栏》

❄专栏传送门 :《产品测评专栏》 《Ai智能体专栏) 《ROS开发专栏》

❄专栏传送门 :《BMS专栏》

⭐️流水不争先,争的是滔滔不绝

📚博主简介:第二十届中国研究生电子设计竞赛全国二等奖 |国家奖学金 | 省级三好学生

| 省级优秀毕业生获得者 | csdn新星杯TOP1 | 半导纵横专栏博主 | 211在读研究生

在这里主要分享自己学习的linux嵌入式领域知识;有分享错误或者不足的地方欢迎大佬指导,也欢迎各位大佬互相三连

​

目录

前言

一、整体架构与函数调用总览

二、任务基础配置与全局变量

[2.1 任务、定时器宏定义](#2.1 任务、定时器宏定义)

2.2、全局参数与状态变量

三、任务初始化与主状态机

[3.1、初始化函数 BMS_ProtectInit](#3.1、初始化函数 BMS_ProtectInit)

3.2、三大状态机定义

四、任务主循环

4.1、软件保护判断

4.1.1、工况分流入口

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 电池保护任务 。套保护任务基于状态机思想设计,区分充电、放电、待机、睡眠四大工况,实现过压、欠流、过流、短路、高低温等全场景保护逻辑。

相关推荐
La Pulga1 小时前
【FreeRTOS源码学习笔记】任务延时列表
笔记·mcu·学习·嵌入式·freertos·实时操作系统
2035去旅行1 小时前
bootcmd 详细讲解
linux·嵌入式·arm·soc
蓝天居士2 小时前
EtherCAT从入门到精通(7)
机器人·嵌入式·ethercat
shijuejianceliu4 小时前
传统规则视觉与嵌入式AI智能相机的技术差异
人工智能·嵌入式硬件·视觉检测·相机
蓝天居士4 小时前
EtherCAT从入门到精通(10)
机器人·嵌入式·ethercat
不脱发的程序猿7 小时前
GD32串口数据收进内存之后DMA如何处理?
单片机·嵌入式硬件·dma·嵌入式·串口通信·gd32
FPGA小迷弟11 小时前
FPGA 与千兆以太网校验和:从原理到 Verilog 实现
嵌入式硬件·fpga开发·无人机·ai编程·fpga
lishen221 小时前
06 · 我把开发流程拆成了 AI 能执行的技能
嵌入式
国科安芯1 天前
83 倍:ASC0108S 在推挽和开漏之间,差的不是速度,是回程
单片机·嵌入式硬件·架构·电平转换·抗辐射
国科安芯1 天前
从遥控到自治:ASP4644S2B支撑星载电源健康管理与容错配电
网络·单片机·嵌入式硬件·安全·dcdc·低轨卫星·商业航天