传统CAN总线通信,一般是一个主站多个从站的设计,只有主站可以具有发送和接收通道,而从站不具有,如果从站1想获取从站2的信息就必须通过主站作为中介,很多情况下,需要从站也具有收发通道,以便于从站之间通信。但是又不希望网路里面通信混乱,比如从站1发送信息,其他的所有从站都会接收到,也都会回复,那样就会产生通信里的饥饿效应,或者惊群效应,这是通信网络里面不希望看到的,除非广播通信,其余情况下不希望产生惊群效应。
现对CAN2.0的标准帧ID做一个简单的修改,我们使用11位标准帧ID,将其分解为
10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
功能代码 | 源节点ID | 目标节点ID |
报文类型分5种分别是NMT EMCY TSDO RSDO NET-ERR
NMT NET-ERR报文通道只有主占可以使用,
报文类型 | 功能代码 | 源节点 | 目标节点 | CB-ID范围 |
NMT | 0000 | 目标节点ID | 000h | |
EMCY | 0001 | 源节点ID | 080h-0ffh | |
TSDO | 101 | 0-16 | 0-16 | 500h-5ffh |
RSDO | 110 | 0-16 | 0-16 | 600h-6ffh |
NMT-ERR | 111 | 1-127 |
| 700h-77fh |
NMT报文属于网路管理报文,只有主站发送因此只带有目标节点ID号,不必带有自身的ID,NMT报文只能由CAN网络中的主站发送,SDO报文属于过程通信报文,任意节点都可以互相发送目前支持16个节点,因此需要具备源ID和目标ID,EMERGENCY报文属于警情报文,任意节点都可以发送,如果需要更多的节点推荐使用扩展帧,支持29位ID。
各节点ID分配
节点 | 仪表 | 控制器 | 电池 | 传感器1 | Best |
NodeId | 0x00 | 0x01 | 0x02 | 0x03 | 0x04 |
SDO报文ID举例:
主节点 | 从节点 | 发送通道CO-ID | 接收通道CO-ID |
控制器0x02 | 电池0x03 | 0x523H | 0x623H |
仪表0x01 | 电池0x03 | 0x513H | 0x613H |
仪表0x01 | 控制器0x02 | 0x512H | 0x612H |
控制器0x02 | 仪表0x01 | 0x521H | 0x621H |
重要:因此控制器CAN芯片滤波器设置为:5x2(H),62x(H);仪表的CAN芯片滤波器设置为:5x1(H),61x(H) 等,NMT 、EMCY通道不可过滤
这时候每个从节点指向接收和发送自己通道的ID,而过滤其他不需要的ID,下面我没一控制器为例节点ID是2,控制器的接收通道为0x602-0x6F2, 0-F分别对应了其他节点发送过来的信息,也就是说控制接收通道需要过滤0x6*2,另外控制器的发送通道为0x620-0x62F, 响应的应答返回是0x502-0x5F2, 宗上所诉,控制需要过滤的ID段位0x6*2 和0x5*2另外控制还要接受广播通道和告警通道,我们以STM32为列:
过滤器代码如下:
注意147行,我们过滤器使用0XF1FF 分解为二进制 1110 0001 1111 1111,
0x602对应的二进制 0110 0000 0010右移5位变成1100 00000100 0000,
可以看到对602中间的位是放过的就是说,612-6F2这些ID都是可以通过的,
也就是控制器是支持0-F节点地址的ID来访问,
灵位0-F节点访问3号节点,那么这些信息是被过滤掉的
第二为了支持广播通信和报警通信,我还增加了一个列表模式,这样更加精确的过滤ID
比如广播的ID通道是000,这个ID是不会被过滤的,见168行。
这样就实现了只接受自己相关的ID通道屏蔽不相关的ID通道,从而避免惊