4、通信控制(0x28):报文发送使能/禁止、网络管理报文的控制策略
4.1 这个服务到底在管什么?
通信控制服务,服务ID是0x28。说白了,它就是一把“总闸”。
你想想看,BMS在工作的时候,CAN总线上跑着各种报文:有周期性的状态报文,有诊断请求/响应,还有网络管理报文。但有些特殊场景下,比如产线刷写、Bootloader跳转、或者某些故障保护模式,我们需要临时关掉一部分报文,或者只允许特定报文通过。
0x28服务就是干这个的。它允许诊断仪(Tester)去控制ECU的通信行为——让某些报文发,或者不让某些报文发。
我个人习惯把0x28服务理解成“通信权限管理器”。它不修改报文内容,只控制报文的“发送权”和“接收权”。
核心要点:0x28服务控制的是ECU的通信行为,不是控制总线上的其他节点。它只影响被诊断的ECU自己。
4.2 控制类型与子功能
0x28服务通过子功能参数来区分具体要控制什么。常见的子功能有这几个:
| 子功能(SubFunction) | 含义 | 典型场景 |
|---|---|---|
| 0x00 | 使能Rx/Tx(恢复通信) | 退出诊断会话后恢复所有报文 |
| 0x01 | 禁止Rx/Tx(完全静默) | Bootloader跳转前禁止所有通信 |
| 0x02 | 禁止Tx(只禁止发送) | 产线测试时不让ECU发报文干扰 |
| 0x03 | 禁止Rx(只禁止接收) | 特殊故障注入测试 |
| 0x04 | 使能Rx/Tx + 网络管理报文 | 恢复通信但保留网络管理报文 |
| 0x05 | 禁止Rx/Tx + 网络管理报文 | 静默模式但保持网络管理活跃 |
嗯,这里要注意:子功能0x04和0x05是专门针对网络管理报文的。很多工程师容易忽略这一点。
4.3 网络管理报文的特殊地位
为什么要把网络管理报文单独拎出来?
我在项目中遇到过这样一个坑:有一次做产线刷写,我们想通过0x28服务把BMS的所有报文都禁掉,只留诊断通信。结果刷到一半,整车网络管理器发现BMS的NM报文丢了,直接判定BMS“离线”,触发了整车下电。
你想想看,刷写过程中突然下电,后果是什么?ECU变砖的风险极高。
所以,0x28服务专门设计了针对网络管理报文的控制位。你可以选择:
- 完全禁止所有报文(包括NM报文)——适用于ECU即将进入休眠或Bootloader跳转
- 只禁止应用报文,保留NM报文——适用于需要保持网络活跃的诊断场景
- 只禁止NM报文,保留应用报文——这个用得少,但某些测试场景会用到
我的建议:在产线刷写或在线升级场景中,尽量使用子功能0x05(禁止Rx/Tx + 保留网络管理报文)。这样既能保证诊断通信不受干扰,又能让整车网络管理器认为BMS还在“活着”。
4.4 报文控制的具体策略
0x28服务控制的是“报文级别”,不是“信号级别”。什么意思呢?
比如BMS会周期发送0x100(电池状态)、0x200(故障码)、0x300(NM报文)。当你执行0x28禁止Tx时,这三个报文全部停止发送。但如果你只想停掉0x100,保留0x200和0x300,那0x28服务就做不到了——你得用其他手段,比如修改应用层的发送使能标志位。
在实际代码实现中,我一般会这样做:
/* 伪代码示例:0x28服务处理逻辑 */
void Diag_Handle_28(uint8_t subFunc, uint8_t *data, uint16_t len)
{
switch(subFunc)
{
case 0x00: /* 使能所有通信 */
g_ComCtrl_TxEnable = TRUE;
g_ComCtrl_RxEnable = TRUE;
g_ComCtrl_NM_Enable = TRUE;
break;
case 0x01: /* 禁止所有通信 */
g_ComCtrl_TxEnable = FALSE;
g_ComCtrl_RxEnable = FALSE;
g_ComCtrl_NM_Enable = FALSE;
break;
case 0x05: /* 禁止Rx/Tx,但保留NM */
g_ComCtrl_TxEnable = FALSE;
g_ComCtrl_RxEnable = FALSE;
g_ComCtrl_NM_Enable = TRUE; /* NM报文不受影响 */
break;
default:
/* 返回NRC 0x12(子功能不支持) */
break;
}
/* 注意:这里要立即生效,不能有延迟 */
CanIf_SetCommunicationMode(g_ComCtrl_TxEnable,
g_ComCtrl_RxEnable,
g_ComCtrl_NM_Enable);
}
警告:0x28服务执行后必须立即生效。不能等到下一个10ms周期任务再去处理。否则在临界状态下,ECU可能已经发出了不该发的报文。
4.5 避坑指南:我曾经踩过的雷
我曾经在一个项目中,把0x28服务的控制逻辑放在了应用层任务里。结果呢?诊断仪发了禁止Tx的请求,但应用层任务要等10ms后才执行。这10ms里,BMS又发出了一帧报文,恰好被整车控制器收到,触发了故障。
后来我改了设计:0x28服务直接在CAN接口层(CanIf)处理,不经过应用层。这样能做到“请求到达,立即生效”。
还有一个坑:0x28服务控制的是“发送使能”,不是“发送完成”。有些工程师误以为禁止Tx后,正在发送的报文会被中断。其实不会——正在发送的报文会正常发完,只是下一帧不再发送。
4.6 与诊断会话的关系
0x28服务跟诊断会话状态是联动的。我记得有一次测试,发现0x28服务在默认会话下也能执行成功,但退出诊断后,ECU自动恢复了所有通信。
这是因为UDS协议规定:
- 0x28服务可以在任何会话下执行(默认会话、扩展会话、编程会话)
- 但退出诊断会话时,ECU必须自动恢复通信(相当于执行了一次子功能0x00)
- 如果ECU进入休眠或复位,通信也会自动恢复
所以,0x28服务的效果是“临时的”。它不会永久改变ECU的通信行为。这一点在开发时要特别注意——不要指望通过0x28服务永久关掉某个报文。
4.7 实际应用场景总结
最后,我总结一下0x28服务在BMS开发中的典型用法:
- 产线刷写:使用子功能0x05,禁止应用报文,保留NM报文。刷写完成后用0x00恢复。
- Bootloader跳转:使用子功能0x01,完全静默。跳转前确保所有报文都停了。
- 故障注入测试:使用子功能0x02或0x03,单独控制发送或接收,模拟通信故障。
- 网络管理测试:使用子功能0x04或0x05,验证NM报文的独立控制逻辑。
嗯,0x28服务看起来简单,但用不好真的会出大问题。尤其是跟网络管理报文相关的控制策略,一定要跟整车网络团队对齐。别像我当年那样,刷写刷到一半被整车下电,那滋味可不好受。