3、BMS软件架构:AUTOSAR与非AUTOSAR方案、应用层与底层软件划分、状态机设计(上电/下电/故障)
聊到BMS软件架构,很多刚入行的朋友会问我:「到底要不要上AUTOSAR?」。说实话,这个问题没有标准答案。我做了这么多年BMS集成,两种方案都深度用过,今天就把我的真实体会摊开来聊聊。
3.1 AUTOSAR方案 vs 非AUTOSAR方案
先说说AUTOSAR。这玩意儿说白了就是一套汽车软件的标准架构。它的核心思想是「分层」和「解耦」。应用层写逻辑,底层管硬件,中间用RTE(运行时环境)隔开。好处很明显——换芯片就像换衣服,应用层代码基本不用动。
我记得2018年做的一个项目,客户中途要求把MCU从英飞凌TC275换成TC397。用AUTOSAR架构的团队,两周就搞定了底层移植。而另一个用非AUTOSAR方案的兄弟团队,光重写驱动就折腾了两个月。嗯,这就是差距。
但AUTOSAR也有它的痛点:
- 学习曲线陡峭——光配置工具就能让你怀疑人生
- 代码体积大——ROM和RAM占用比非AUTOSAR多30%~50%
- 调试困难——出了问题,你很难分清是应用层bug还是RTE配置问题
非AUTOSAR方案呢?说白了就是「裸奔」。所有代码揉在一起,应用层直接操作寄存器。优点是轻量、高效、调试直观。我早期做的一个48V轻混BMS,用的就是非AUTOSAR方案,整个软件只有80KB,跑得飞快。
但代价是什么?换芯片等于重写。而且代码复用性极差,每个项目都是「从零开始」。
我的建议:
- 如果你们公司平台化程度高,多个项目共用同一套硬件平台 → 上AUTOSAR
- 如果项目周期紧、资源有限、芯片固定 → 非AUTOSAR更务实
- 如果你们是初创公司,我建议先非AUTOSAR跑通,后期再迁移
3.2 应用层与底层软件划分
不管用哪种方案,应用层和底层的划分原则是相通的。我习惯这样切:
| 层次 | 包含内容 | 典型模块 |
|---|---|---|
| 应用层(ASW) | 业务逻辑、控制策略 | SOC估算、SOP控制、均衡策略、故障诊断 |
| 中间层(RTE/BSW) | 通信、调度、抽象 | CAN通信、NVM管理、OS调度、诊断栈 |
| 底层(MCAL/驱动) | 硬件直接操作 | ADC采样、GPIO控制、SPI通信、PWM输出 |
这里有个坑,我踩过好几次——不要把硬件相关的逻辑写在应用层。比如,有些人图方便,直接在SOC算法里写了个「如果ADC值大于3000就...」。你想想看,下次换ADC芯片,你连SOC算法都得改,这不是给自己挖坑吗?
我的经验法则:
应用层只认「物理量」——电压、电流、温度、SOC百分比。底层只认「寄存器值」——ADC码值、GPIO电平、PWM占空比。中间层负责转换。这样切,后期维护成本至少降低一半。
3.3 状态机设计:上电/下电/故障
状态机是BMS软件的「骨架」。我见过太多项目因为状态机设计不合理,导致上电时序错乱、下电丢失数据、故障恢复逻辑死循环。嗯,这里要重点讲。
3.3.1 上电状态机
BMS上电不是简单的「通电就干活」。我一般把它拆成这几个阶段:
// 伪代码示例:上电状态机
typedef enum {
POWER_OFF, // 完全断电
WAKEUP_DETECT, // 检测唤醒源
INIT_HARDWARE, // 初始化硬件
SELF_CHECK, // 自检
PRECHARGE, // 预充电
MAIN_CONTACTOR_ON, // 主继电器闭合
NORMAL_OPERATION // 正常运行
} BMS_PowerState;
为什么要分这么细?我举个例子。预充电阶段,如果直接闭合主继电器,大电流冲击能把继电器触点烧熔。我曾经在一个项目中遇到过,预充电电阻选小了,每次上电都「啪」一声响,吓得测试工程师都不敢靠近。
避坑指南:
我曾经在预充电阶段忘记检查母线电压上升率,结果预充电完成后母线电压还没稳定,主继电器一闭合就产生电弧。后来我强制要求:预充电完成后,必须等待母线电压与电池电压差值小于5V,且稳定保持100ms以上,才能闭合主继电器。
3.3.2 下电状态机
下电比上电更讲究。很多人觉得「断电嘛,直接关就行了」。错了!
// 伪代码示例:下电状态机
typedef enum {
NORMAL_OPERATION, // 正常运行
SHUTDOWN_REQUEST, // 收到下电请求
SAVE_DATA, // 保存关键数据到NVM
DISCHARGE_CAP, // 放电电容
MAIN_CONTACTOR_OFF, // 断开主继电器
SLEEP_MODE // 进入休眠
} BMS_ShutdownState;
关键点在于「保存数据」这一步。SOC、SOH、故障码这些数据,必须在断电前写入NVM。我见过一个项目,下电时直接断电,结果SOC数据丢失,下次上电SOC从50%跳到了80%,整车直接报错。
还有一点——下电时序要保证「先保存、后断电」。我曾经在项目中加了一个「下电完成标志位」,只有所有数据都保存成功了,才允许MCU进入休眠。这个习惯救了我好几次。
3.3.3 故障状态机
故障处理是BMS最考验功力的地方。我把它分成三级:
| 故障等级 | 处理方式 | 示例 |
|---|---|---|
| 一级(警告) | 上报故障码,不限制功率 | 单体电压偏差过大、温度传感器异常 |
| 二级(降功率) | 限制充放电功率,继续运行 | 电池过温(非临界)、SOC过低 |
| 三级(紧急下电) | 立即断开继电器,停止所有操作 | 绝缘故障、电池过压、硬件看门狗超时 |
这里有个设计原则——故障恢复要「慢进快出」。什么意思?故障触发要快,比如过压检测,一旦超过阈值立即动作。但故障恢复要慢,比如过压解除后,要等待一段时间(比如5秒)确认电压稳定了,才允许恢复正常状态。
我的血泪教训:
我曾经设计过一个故障恢复逻辑,过温解除后立即恢复功率。结果电池温度在阈值附近来回震荡,导致功率频繁波动,整车驾驶体验极差。后来我加了「恢复迟滞」——过温解除后,必须等待30秒且温度低于阈值5°C以上,才允许恢复。从此再没出过问题。
最后说一句,状态机设计一定要考虑「异常路径」。比如上电过程中突然收到下电请求怎么办?预充电超时怎么办?这些边界情况,才是真正考验工程师功底的地方。我每次评审状态机设计,都会拿着笔一条一条画异常路径,画不完不签字。
好了,这一章就聊到这里。下一章我们聊聊BMS的通信协议——CAN和CANFD,以及DBC文件怎么设计才不容易踩坑。