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

相关推荐
济6171 小时前
BMS系统专栏:电池状态监控任务
嵌入式硬件·嵌入式·bms电池系统管理
XTIOT6662 小时前
多形态护照 OCR 读取器传输机制、识别算法与行业落地技术对比
大数据·人工智能·嵌入式硬件·物联网·ocr
欢乐熊嵌入式编程2 小时前
选型避坑:ESP32 vs STM32+模组 vs NB-IoT,不同场景怎么选
stm32·单片机·嵌入式硬件·物联网·esp32·嵌入式iot
拎得清n4 小时前
寄存器点灯
单片机·嵌入式硬件
破晓单片机14 小时前
067、STM32项目分享:语音儿童学习书桌系统
stm32·单片机·嵌入式硬件
10WTW0114 小时前
微机原理 8259A 可编程中断控制器
单片机·嵌入式硬件
番茄灭世神16 小时前
RTC授时时间戳转换工具
c语言·单片机·嵌入式
破晓单片机16 小时前
068、STM32项目分享:智能小区门禁系统
stm32·单片机·嵌入式硬件
望眼欲穿的程序猿19 小时前
Hello World
嵌入式硬件·rust