两轮BMS 防打火策略详解

BMS 防打火策略详解

本文基于量产 60V BMS(STM32F0 + SH367306 AFE),拆解"防打火"的原理与软件实现。


一、为什么会打火?

电动两轮车的电机控制器输入端有大容量电解电容(通常几千 µF)。BMS 输出端与控制器之间通过接插件连接。

复制代码
BMS 电池 ────[接插件]──── 电机控制器
                             │
                          ┌──┴──┐
                          │ 电容  │  ← 几千 µF,初始电压 0V
                          └─────┘

当接插件插入瞬间,电池电压(60V+)直接加到 0V 的电容上。电容充电电流 I = C × dV/dt,在 µs 级时间内电流可达几百安------接插件触点处产生电弧(打火),长期会烧蚀触点、熔毁接插件、甚至击穿 MOS。


二、怎么防?------预充电路

在放电主回路之外加一条预充支路:一个小功率 MOS 串一个 22Ω 限流电阻。

复制代码
电池+ ──┬── 放电 MOS ──────────┬── 负载+
        │                      │
        └── 预充 MOS ── 22Ω ──┘

流程:

复制代码
1. 预充 MOS 导通,放电 MOS 断开 → 电流经 22Ω 电阻给负载电容充电
   最大电流 = 60V / 22Ω ≈ 2.7A(安全)

2. 等待电容电压充到接近电池电压(数百 ms)

3. 放电 MOS 导通,预充 MOS 断开 → 正常放电,无打火

三、软件实现:Idle 状态机

PMM 模块在空闲模式下有一个四级状态机(PMM.c:35-39):

复制代码
kIdleInit ──→ kIdleFirePrevent ──→ kIdlePowerOn ──→ 放电模式

3.1 kIdleInit ------ 初始化防打火

  • 防打火使能:闭合充电 MOS + 预充 MOS,断开放电 MOS
  • 检测到放电电流 > 30mA(用户拧电门)→ 进入 kIdleFirePrevent
  • 防打火未使能:直接闭合放电 MOS,跳过预充

3.2 kIdleFirePrevent ------ 执行预充时序

PMM.c:156-175:

c 复制代码
// 阶段1:预充 MOS 断开 200ms
s_TimeDelay < 200ms → PreMos_Ctrl = 0

// 阶段2:预充 MOS 闭合 500ms(电流经 22Ω 给电容充电)
200ms ≤ s_TimeDelay < 900ms → PreMos_Ctrl = 1

// 阶段3:预充完成,标记防打火结束,跳转
s_TimeDelay ≥ 900ms → FirePreventEnd_flg = 1 → 进入 kIdlePowerOn

整个预充时序持续约 900ms:200ms 断开(等待) + 500ms 导通(充电容) + 200ms 余量。

3.3 kIdlePowerOn ------ 闭合主回路

预充完成后,放电 MOS 闭合,预充 MOS 断开,进入正常放电模式。

3.4 防打火重新开启

放电结束后电流归零超过 2 秒 ,s_FirePreventEnd_flg 自动清零,下次再有电流时重新走防打火流程。

3.5 什么时候触发防打火?

防打火只在 "负载电容可能已经放空了" 的时候触发,不是每次有电流都走。

触发(三种情况):

场景 触发原因
BMS 上电启动 默认 IdleStMachine = kIdleInit,直接走防打火
空闲时无电流 > 2s 电容可能通过漏电流放空,FirePreventEnd_flg 自动清零
充电 > 3 分钟后回空闲 IdleStMachine 重置为 kIdleInit

不触发:

从放电模式退出回空闲时,跳过防打火 ,直接跳到 kIdlePowerOn:

c 复制代码
// 从放电退出到idle模式,先到poweron模式
// (退到init中立刻拧电门有掉电的风险)
IdleStMachine_enum = kIdlePowerOn;

因为刚放完电,负载电容还满着------不需要预充。而且用户可能是等红灯松油门,马上又要拧------如果每次都走 700ms 防打火,体验会很差。


四、短路保护联动

短路发生后,即使 AFE 已经在 50µs 关断了放电 MOS,MCU 端的 PreChgIf 也会主动闭合预充 MOS(PreChgIf.c:122-125):

c 复制代码
// 发生短路,强制进行预充
if(g_Afe1SampleRawData.ShortCircuitPreChg_Cnt != 0)
{
    g_PreChg_cmd = 1U;  // 强制闭合预充 MOS
}

短路可能是负载电容充电的瞬时大电流导致的误判------强制预充相当于给电容一次"温柔充电"的机会,如果充满后不再触发短路,说明是容性负载而非真短路。


五、预充电路故障检测

预充支路通过 ADC 检测预充电阻上的电流(PreChgIf.c:137):

c 复制代码
// 22Ω 采样电阻,ADC 读数换算为电流
g_PreChgCurrent_mA = ADC值 × 33 × 10 × 1000 / (4095 × 22);

如果预充电流 > 2A 持续 1s ,判定预充电路故障(电阻短路或 MOS 击穿),上报 PreChgCircuitFlt,同时禁用防打火功能。


六、关键参数

参数 值 说明
预充电阻 22Ω 限流,60V 电池最大预充电流 ~2.7A
预充等待 200ms 断开等待
预充导通 500ms 电容充电时间
预充总时长 ~900ms
防打火重开 无电流 2s 自动重置
预充故障判定 >2A 持续 1s 电阻短路/MOS 击穿

七、200ms 断开阶段的作用

用户拧电门 → kIdleInit 检测到电流 → 进入 kIdleFirePrevent → 预充 MOS 先断开 200ms。

这 200ms 不是充电容,而是状态复位:

  • 进入 kIdleFirePrevent 之前,预充 MOS 在 kIdleInit 里已经是闭合的。先断开才有明确的预充起点
  • 给电路一个静默窗口,等残余电流或接触抖动消退
  • 如果 200ms 内电流归零,说明用户只是碰了一下油门而非真要骑车,不需要后续流程

八、为什么用时间预估而不是检测外侧电压?

更好的方案是:外侧加电压采集 → 读到 V_out ≈ V_bat 就切主 MOS。但这需要一路 ADC + 两个分压电阻(60V → 3.3V),板子上没做纯粹是省成本。

时间预估为什么够用?最差情况:

复制代码
预充电阻 22Ω,负载电容 5000µF:
  τ = 22 × 0.005 = 110ms
  5τ = 550ms → 充到 99%

实际给 500ms,电容再大也充到 95%,压差仅 ~3V,残余电流 < 140mA → 不打火

如果有外侧电压采集,逻辑可以简化成两个状态,还能额外获得:自适应电容、预充超时故障检测、MOS 粘连检测、接插件松动检测------但代价就是那两个电阻。


本文基于量产 BMS 代码分析。

相关推荐
lzhdim10 分钟前
C#不为人知的10个魔法特性:资深开发者也会震惊的底层奥秘
java·前端·javascript·算法·c#
weixin_3077791317 分钟前
C++代码实现MATLAB中的pade函数功能
开发语言·c++·算法·matlab
smj2302_7968265219 分钟前
解决leetcode第4064题至多一次取反能被k整除的最长子数组II
python·算法·leetcode
AIGC小尼23 分钟前
ACE-Step-1.5 本地 AI 音乐模型实战|text2music 歌词转人声,部署脚本、参数调优与排坑全记录
人工智能·算法·comfyui·ai漫剧
YOLO数据集集合30 分钟前
树木检测数据集 | 树木检测 树种分类 航拍林业 森林监测9131期
人工智能·算法·机器学习·分类·数据挖掘·林业·树种分类
青山木35 分钟前
Hot 100 --- 下一个排列
java·数据结构·算法·leetcode
垆边人似月.38 分钟前
字符串重排后最大字典序
算法·leetcode·职场和发展
码流子39 分钟前
AI稽核精灵-Agent落地
大数据·人工智能·物联网·算法·系统架构
微三云生态系统架构师-彭丹1 小时前
排队免单资金池专户存管与返本算法:队列模型与熔断保护
算法·熔断机制·排队免单·消费增值·资金池·队列系统·返本算法
wzdark1 小时前
矩阵快速幂算法在图路径计算中的应用4
线性代数·算法·矩阵