传统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通道,从而避免惊