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文件怎么设计才不容易踩坑。