搞过电动车直流快充联调的人,十有八九都被GB/T 27930-2015这套协议绕晕过。明明BMS和充电桩都能“说话”,可一上真实充电桩就各种握手失败、请求超时、电压电流异常,日志里全是CAN报文,看着一头雾水。我最早从BMS硬件转过来做充电协议联调时也是这样,对着几千帧报文根本分不清谁是主动、谁是被动,后来把国标几轮状态机走通了才真正搞明白。今天这篇文章,我就把国标GB/T 27930-2015的BMS充电全流程拆开揉碎,重点讲报文交互那条线:从握手、参数配置、正式充电到充满结束,每个阶段有哪些关键报文,报文的时序和字段到底怎么对应,以及联调中我踩过的坑。不管你是做BMS软件、充电桩嵌入式,还是整车测试,这套逻辑通了,后面调试效率能翻一倍。
1. 先搞清楚:GB/T 27930-2015到底管什么
1.1 直流快充和BMS之间那点事
很多刚入行的同学容易把标准名称看错,这里先泼盆冷水:GB/T 27930-2015不是“整车充电规范”,它的全称是《电动汽车非车载传导式充电机与电池管理系统之间的通信协议》。翻译成大白话,它就是直流快充桩和车上的BMS之间的“对话规则书”。交流慢充走的是另一套逻辑,CC/CP模拟信号占主导,报文协议相对简单,所以这套标准最核心、最复杂的场景就是直流快充,也就是我们常说的“插枪后桩上显示功率几百千瓦”的那种。
这个标准解决的问题很明确:充电桩不知道电池能不能充、需要多少电压多少电流、当前温度能不能顶住,而BMS不知道充电桩到底能给出多大能力、有没有故障、是不是已经就绪。两边要是不对齐信息,要么充不进去,要么把电池充坏,所以必须有统一协议,规定谁先说、说什么、多长时间说一次、收到什么才能进入下一步。理解了这句话,再看后面的报文就不会晕。
1.2 通信底层不是TCP/IP,是CAN
这套协议跑在CAN总线上,物理层用的是CAN 2.0B扩展帧,29位标识符,波特率常见250kbps。很多刚接触的同学习惯用以太网那套思路去理解CAN,总觉得怎么应答这么慢、周期这么死板。其实CAN总线在车载环境里皮实可靠,抗干扰强,实时性也够,虽然带宽和以太网没法比,但报文定义得很精简,一条报文8个字节,跑几千帧也没压力。
这里多说一句:实际抓包你会看到报文ID不是简单的0x0001这种,而是像0x18FF50F4之类的29位ID,里面通常包含源地址、目的地址、PDU格式等。很多主机厂在国标基础上会再自定义DBC文件,把每个Byte、每个Bit的信号名和缩放因子定义清楚。所以你们项目里的报文ID和标准不一定一字不差,这是正常现象。重点不是死背ID,而是搞清楚每个阶段“该有哪些报文在跑”,以及“报文的含义是什么”。
2. BMS在充电流程中的角色和内部准备
2.1 BMS和BMU到底是怎么分工的
先解决一个经常被搞混的概念:BMS是电池管理系统整体,BMU通常指电池采集单元,负责单体电压、温度采集和均衡控制,而真正的“大脑”是BCU或BMU上面的主控芯片,负责状态估算、故障判断和通信。很多开发工程师只做过BMU采集,一提到充电报文就觉得是别家的事,其实充电报文基本都是主控根据BMU采集到的数据算出来的。
打个比方,BMU是“眼睛和手”,负责盯着每一颗电芯、每路温度,必要时做电池均衡;而主控是“大脑”,拿到数据后判断当前电池健康状态,算出SOC和SOP,最后决定“我要向充电桩要多少电流”。如果BMU采集的某一颗单体电压偏高,或者温度探头读数漂移,主控再聪明也会发出错误需求。所以BMS充电协议调试时,先确认底层采集数据没问题,再去查报文解析,否则很容易白忙一场。
2.2 充电前BMS内部要先过一遍的“心算”
BMS发送第一条充电请求报文之前,自己其实要先完成好几项准备工作。首先是绝缘检测,整车高压回路对车身底盘的绝缘电阻是否合格,如果绝缘异常,BMS可能直接禁止充电或降低请求电流。然后是接触器状态检查,充电正负继电器是否已经断开、有没有粘连风险,这一步直接关系到插枪瞬间会不会拉弧。
其次是SOC和SOP估算。SOP的意思是当前电池能承受的最大充放电功率,它和SOC、温度、单体电压、健康状态SOH都有关系。很多工程师以为BCL里请求的电流随便填一个限值就行,实际上SOP算小了充电慢,算大了会过充甚至析锂,风险很大。最后BMS还要检查充电口的CC/CP信号,确认充电枪已经可靠插好,然后才允许充电桩低压辅助上电,整套流程像人过安检一样,一步都不能跳。
3. 充电全流程报文交互详解
3.1 第一阶段:物理连接和握手
整个交互从物理连接开始。充电枪插入车辆充电口,CC信号检测到枪头已经到位,CP信号完成连接确认,桩给车辆供上12V辅助电源,这时候BMS主控开始上电工作。BMS上电后干的第一个动作,就是按照国标要求发握手报文CHM。
CHM是BMS发给充电桩的第一条报文,里面带协议版本号和BMS通信地址。桩收到CHM后,如果识别出协议版本匹配,就回握手应答报文CRM,带上充电机地址和版本信息。这一来一回,相当于两个人见面互报家门:“我是BMS,协议版本2015,请多关照”“我是充电桩,协议版本一致”。如果CHM一直没人回,那大概率是BMS没发出、物理连接有问题、波特率不对,或者桩压根没进入充电流程。握手阶段最常见的问题就是日志里只有CHM没有CRM,后面排查部分细讲。
3.2 第二阶段:参数配置和“交底”
握手成功不代表就能充电,双方还要交换各自的底牌。这个阶段BMS会发BRM辨识报文,报出电池类型、电池生产厂商、电池组序号、充电次数等静态信息。充电桩拿到这些信息后,可以判断是否兼容,也有利于厂家后台记录。
紧接着BMS会发BCP报文,也就是电池充电参数报文,这是充电桩后续控制输出的核心依据。BCP里通常有最高允许单体电压、最高允许总电压、最高允许充电电流、电池额定容量、最高允许温度等参数。你可以把它理解成“充电桩你在控制我之前,必须先知道我的底线”。这些参数里,最高允许总电压和最高允许电流尤其关键,桩如果超出这个范围输出,属于直接违规,保护电路必须动作。
充电桩这边也不是光听着,它会发CTS时间同步报文和CML最大输出能力报文。CTS很直白,就是告诉BMS“现在几点几分”,后续充电计费和统计都用这个基准。CML告诉BMS“我最大能输出多大电压、多大电流”,相当于桩把自己的上限亮出来。如果BMS发现自己的充电需求不在桩的能力范围内,会调整策略或者直接报错,避免实际充电时无法收敛。
3.3 第三阶段:充电准备就绪和预充电
参数对齐之后,BMS开始发需求。BCL是电池充电需求报文,里面带的是BMS当前希望桩输出的目标电压和目标电流。这个报文到了充电阶段会周期性持续发送,因为电池状态一直在变,需求也在变,不能发一次就完事。
在正式输出大功率前,系统还要完成一次“烧脑确认”:BMS会发送准备就绪报文,告诉桩“我这边继电器可以闭合了”;充电桩检测到自己输出端电压已经建立、没有异常,才会回输出准备就绪报文。这里要注意一个细节,很多新手以为只要BMS发了需求,桩就该立刻拉满电流,其实不是。正常的启动过程是桩先建立一个较小的电压,BMS闭合充电继电器,然后电流才开始爬升,这个过程叫预充电或软启动,目的是防止大电流冲击把继电器触点烧蚀。
3.4 第四阶段:正常充电中的实时闭环
进入正常充电后,报文交互进入循环状态。BMS周期性发送BCL,告诉桩“我现在需要X伏、Y安培”,同时周期发送BSM状态信息报文,把当前电池组的最高单体电压、最低单体电压、最高温度、SOC、绝缘状态等实时报给桩。充电桩则周期发送CCS状态报文,把实际输出电压、实际输出电流、累计充电时间、累计充电能量反馈给BMS。
这个闭环逻辑和开车很像:BMS是驾驶员,根据路况(电池状态)决定踩多少油门(请求电流),充电桩是发动机,执行指令并回报实际转速(实际输出电流)。如果BMS发现单体电压涨得太快或温度异常,会立刻降低BCL里的需求电流;如果桩发现自己输出电压电流异常,也可以在CCS里带故障状态并启动保护。很多“充电中断”问题,根源就是这一层闭环里某个信号没对上,或者某个周期报文超时了。
3.5 第五阶段:结束和统计
充电结束分为正常结束和异常结束。正常充满时,BMS会发BST停止充电报文,里面带停止原因代码,比如“已充满”“达到电压上限”“人为停止”等,然后断开充电继电器。充电桩收到后,会停止输出并回复CST中止充电报文。如果哪一方在充电过程中检测到严重故障,也可以主动发起停止流程,逻辑是类似的,关键区别在于停止原因代码不同。
停止流程结束后,BMS还会发BSD电池统计数据报文,把本次充电了多少能量、充进了多少电量、充电时长等数据汇总给桩;桩也可能回CSP统计报文。这些数据主要用于计费、后台记录和后续运营分析。很多“结算金额不对”的问题,就得回头查这个阶段报文有没有丢、统计字段有没有解析错。
3.6 关键报文速查表
动手排查时,一张报文汇总表比翻标准原文方便得多。下面这个表是我习惯用的简化版,具体信号名和偏移量还是要以你们项目的DBC为准。
| 报文 | 方向 | 发送时机 | 关键信息 |
|---|---|---|---|
| CHM | BMS -> 桩 | 上电握手 | 协议版本号、BMS地址 |
| CRM | 桩 -> BMS | 收到CHM后 | 协议版本号、桩地址 |
| BRM | BMS -> 桩 | 握手成功后 | 电池类型、厂商、编号、充电次数 |
| BCP | BMS -> 桩 | 参数配置阶段 | 最高允许电压、电流、容量、温度 |
| CTS | 桩 -> BMS | 配置阶段周期发送 | 充电机时间 |
| CML | 桩 -> BMS | 配置阶段周期发送 | 最大输出电压、输出电流 |
| BCL | BMS -> 桩 | 就绪和充电阶段 | 需求电压、需求电流 |
| 准备就绪报文 | BMS -> 桩 | 需求后 | 是否允许输出 |
| 输出准备报文 | 桩 -> BMS | 预充电前 | 输出已就绪 |
| BSM | BMS -> 桩 | 充电阶段周期发送 | 最高/最低单体电压、温度、SOC |
| CCS | 桩 -> BMS | 充电阶段周期发送 | 实际输出电压、电流、累计数据 |
| BST | BMS -> 桩 | 需要停止时 | 停止原因代码 |
| CST | 桩 -> BMS | 收到BST后 | 中止原因代码 |
| BSD | BMS -> 桩 | 充电结束后 | 充电电量、时间 |
这张表里最容易被忽略的是周期要求。国标对不同报文有不同的超时容忍度,像BCL这种实时需求报文,如果桩一段时间没收到,就必须主动停机,因为BMS可能已经失联,继续充电太危险。实际开发中,务必查清楚每个报文的超时阈值,并在联调时做一次“断发测试”,验证桩会不会及时保护。
4. 一次真实充电过程的报文时序
4.1 抓包前先做好的三件事
很多人用CAN盒抓完报文,回来发现一团乱麻,原因多半是准备工作没做到位。第一,波特率必须设对,直流充电CAN通信常用250kbps,但也有个别厂商用500kbps,连上后先看是否出现大量错误帧,及时调整。第二,过滤条件不要一开始就做得太死,先抓全量报文,按时间轴看整体流程,否则很容易漏掉关键帧。第三,能导DBC就导DBC,ID和信号解析会轻松很多,但也要保留原始十六进制报文,方便排查解析问题。
4.2 从插枪到完成的报文时间线
下面这个时序是我在项目里经常看到的典型流程,报文名称和方向按国标逻辑排列,具体ID以你们工具里的DBC为准。
1. 插枪,CC/CP连接确认,桩提供12V低压 2. BMS -> CHM (请求握手) 3. 桩 -> CRM (应答握手) 4. BMS -> BRM (上报电池辨识信息) 5. BMS -> BCP (上报电池充电参数) 6. 桩 -> CTS (时间同步) 7. 桩 -> CML (上报最大输出能力) 8. BMS -> BCL (上报需求电压/电流) 9. BMS -> 准备就绪报文 (告诉桩可以输出) 10. 桩 -> 输出准备报文 (告诉BMS我要开始输出了) 11. BMS闭合充电继电器 12. BMS和桩进入周期性交互: BMS -> BCL BMS -> BSM 桩 -> CCS 13. BMS判定充满 -> BST 停止原因=充满 14. 桩 -> CST 中止原因=正常结束 15. BMS断开充电继电器 16. BMS -> BSD 统计数据对照这个时间线,再看抓包日志,你会发现自己一下子能“读”报文了。第4和第5步经常会同时出现,不要奇怪;第8到第10步之间,有些桩会先让电压爬升再闭合继电器,这个顺序看各家策略。
4.3 一个报文数值的计算例子
只看报文名称还不够,字段解析也要会算。BCL报文里的需求电压和需求电流通常有缩放因子,电压常见0.1V/位,电流常见0.1A/位。假设某条BCL里需求电压的原始值是0x0BB8,换算成十进制是3000,再乘以0.1V就是300.0V;需求电流原始值0x03E8是1000,乘以0.1A就是100.0A。很多“数据不对”的现场,其实就是有人在解析时没乘缩放因子,把300V看成了3000V,直接把桩吓停了。
BSM里的单体电压也同理,常见单位是mV,0x0E74等于3700,就是3.700V。温度字段很多用带偏移量的方式表示,比如原始值减去40才是实际摄氏度。这些细节在DBC里都有,但联调时经常有人拿着没换算的原始值去比对,怎么都对不上,最后发现是单位问题。我的经验是:关键报文里任何电压、电流、温度字段,先确认缩放因子,再确认偏移量,宁可多花一分钟核DBC,也不要凭感觉猜。
5. 常见故障与排查技巧实录
5.1 握手阶段车辆没反应
这个故障的特征是:桩屏幕上显示“车辆未连接”或“等待车辆握手”,而BMS日志里已经能看到CHM报文发出。先查物理层,CAN总线的终端电阻是不是120欧姆左右、A/B线是不是接反了;再查波特率,250kbps和500kbps混用会出现大量错误帧;最后查CHM的地址字段,有些项目BMS地址定义和桩端不匹配,桩直接忽略。
如果CHM根本没发出来,问题基本在BMS上电条件没满足。比如12V辅助电源没有正常建立,或CP信号状态不对,BMS不会启动通信。还有一次我遇到的情况是BMS程序跑起来了,但CAN控制器初始化失败,日志里只有发送失败计数在涨,查了半天是CAN收发器芯片虚焊。这类问题看起来是协议问题,实际是硬件问题,所以排查时不要只盯着报文,先确认硬件电平正常。
5.2 参数配置阶段卡死
握手成功了,但流程停在BRM/BCP之后,桩没有回复CTS或CML。这时候要重点检查BCP里的参数是否超出桩的能力范围。我见过最多的是:BMS上报最高允许充电电流300A,而桩的最大输出能力只有250A,按理说BMS应该调整需求,但有些程序的比较逻辑写反了,导致桩认为参数非法。另外也要检查协议版本号、报文周期,有些桩对BCP的周期要求很严格,周期太慢会判断超时。
还有一个容易踩的坑:BRM里包含电池识别信息和充电次数,有些后台系统会校验车辆VIN,如果BMS传的编号和桩后台注册的不一致,桩会直接拒绝进入充电流程。这种情况报文层面看不出毛病,需要查运营平台日志。所以参数配置阶段卡住,别老盯着CAN线上那几帧,后台数据绑定关系、套餐状态也要一起看。
5.3 充电过程中突然降流
最让人头疼的是“充电到一半,电流从200A掉到50A”,而且没报故障。这种多半不是故障,而是BMS在主动保护。打开BSM报文,看单体电压和温度是不是逼近限值了。比如充电桩给足了电流,但某一串单体电压比其他串高很多,BMS为了保护这颗电芯,会降低BCL里请求的电流,于是桩跟着降流。
如果BSM数据正常,再看CCS里桩的反馈,是不是桩端温度过高、或者桩输入侧电压偏低导致桩主动降流。很多项目里桩有自己的限功率策略,这个策略和BMS需求是两条线,都要监控。处理这类问题,我的做法是把BCL请求电流、CCS实际输出电流、BSM最高单体电压、最高温度四路信号画到同一张曲线图上,谁先掉头一目了然。
5.4 停止阶段不结束
充满后BMS发了BST,但桩没有及时停机,这属于严重风险。可能原因是桩没在限定时间内收到BST,或者CST逻辑没触发。排查重点:BST停止原因代码是否是桩能识别的枚举值,比如“正常充满”和“过压保护”在有些项目里代码很相似,解析错位后桩不认为需要停机。还有一个常见情况:BMS只发了BST但没有断开继电器,桩检测到负载还没断开,会保守地继续维持低电压输出,看起来就像“没结束”。
针对这类问题,我给出的排查优先级是:先看BMS继电器状态,再停看充电桩状态机指示,最后核对CST代码。现场实在找不到原因,把双方日志拉齐,按时间点逐帧比对,一般都能发现是谁先打破了时序。
| 现象 | 可能原因 | 优先检查项 |
|---|---|---|
| 握手无响应 | 物理层、上电条件、地址 | CAN终端电阻、波特率、CHM周期 |
| 参数配置卡死 | BCP超范围、版本不匹配 | 桩能力上限、BMS上报参数 |
| 充电中降流 | BMS保护或桩限功率 | BSM温度/单体电压、CCS反馈 |
| 停止不结束 | 停止代码不识别、继电器未断 | BST代码、继电器状态、CST逻辑 |
6. BMS充电联调的几句经验总结
6.1 用CANoe和HIL把桩“假”出来
BMS开发阶段不能每次测试都真插充电桩,所以团队一般会做一套仿真环境:用CANoe或周立功的CAN卡模拟充电桩,按国标时序发CRM、CTS、CML、CCS这些报文,BMS报文的收发完全走真实CAN链路。再进一步,就是上HIL测试,把BMS主控接入实时仿真模型,模拟电池单体电压、温度、绝缘电阻,注入各类故障,验证BMS在各种极端情况下会不会按国标发出正确的BST和故障码。
这套方法最大的价值是能稳定复现问题。真实充电桩上偶发的一次停止,在HIL里可能跑一千遍也复现不出来,但用报文级仿真,你可以在几分钟内模拟几百次握手,什么边角料时序都能测出来。我强烈建议做BMS充电协议的同学,至少学会用脚本自动发桩端报文,因为很多软件bug是重复跑到第几十次才暴露的。
6.2 几个值得长期坚持的习惯
最后说点个人习惯。第一,日志一定要存原始报文,不能只存解析后的工程值。解析代码万一写错了,原始数据还能帮你翻案;只存工程值的话,错一次就永远查不回来。第二,每个BMS软件版本发布前,至少跑一遍完整的握手-充电-停止回归用例,哪怕只改了一个温度滤波参数,也要跑,因为报文状态机非常容易被旁边模块的改动影响。第三,联调现场要对双方时间戳,桩和BMS的系统时钟很可能不同步,对时间线的时候要先把两边的基准对齐,不然“谁先谁后”永远扯不清。
我早年做BMS测试时,因为没保存原始报文,一个SOC字段解析错误折腾了两天,后来发现是DBC里SOC的起始位写反了。所以多存数据、多核DBC、多画曲线,这三件事比任何高级排查技巧都管用。搞明白GB/T 27930-2015不难,难的是遇到问题时愿意一层一层剥开看。希望这篇拆解能让你少走点弯路,下次再看到满屏CAN报文,心里能更有底气。