博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
CAN网络学习总结
阅读量:4222 次
发布时间:2019-05-26

本文共 6868 字,大约阅读时间需要 22 分钟。

什么是CAN

控制器局域网(CAN-Controller Area Network)是 BOSCH公司为现代汽车应用领先推出的一种多主机局部网,由于其卓越性能现已广泛应用于工业自动化、多种控制设备、交通工具、医疗仪器以及建筑、环境控制等众多部门。 
CAN bus - Wikipedia https://en.wikipedia.org/wiki/CAN_bus

组网方式

总线型组网。类似一根葫芦藤上长了7个小葫芦一样。当然通过网关、转换器等方式,可以组成树形网络。 
CAN的直接通信距离最远可达10km(速率5kbps以下),速率最高可达1mbps (此时通信距离最长为40m)。 
问题:数据流通有方向吗? 
http://embed.21ic.com/hardware/can/201611/42974_2.html

特点

多主节点 
网络上任一节点均可在任意时刻主动地向网络上其他节点发送信息,而不分主从,通信方式灵活。 
可以随时动态添加新节点到网络中。 
同一时刻,只能有一个节点处于发送状态。发送的报文要么同时被其他节点收到,要么同时不能收到。

节点无地址 

不像以太网,CAN网络中每个节点并没有地址,发送信息的节点 无法控制信息发送给谁。信息是以广播的形式发送,所有节点都同时收到信息。但收不收是接收者的事情。

节点有ID标识符 

节点虽然没有地址,但是有ID标识符。在发送信息的时候,节点ID标识符成为信息内容的一部分被发送出去。

网络报文格式 

CAN网络中传输的报文只有几种类型:数据帧,远程请求帧,错误帧,过载帧。具体详细见下文通信协议。

网络中流通的报文由接收者定义是否要接收 

报文内容中包括了发送节点的ID标识符,而网络中其他每个节点都能收到报文内容。所以接收者可以定义是否要接收报文。 
接收者可以规定,只接受某ID标识符发送来的报文内容。其他节点不予以接收。 
因此,CAN网络很容易制定出实现点对点、一点对多点及一点对全局广播等几种方式传送接收数据。

接收者通过向CAN芯片设置Filter来定义是否接收报文 

当接收节点收到报文的时候,可以根据Filter来决定是否接收这一帧报文。 
Filter包括MASK和欲接收节点的ID标识符。 
所谓MASK,是指接收节点在进行接收到的报文HEADER进行对比的时候,只需要关注Header中哪些位。如果MASK中某位设置为1,表示需要关注报文Header中的该位的值,如果MASK某位为0,则表示不用管接收到的报文中ID标识符对应的位是什么,都需要接收进主机。 
首先将接收到的报文header中的ID标识符与MASK做与操作之后,得到一个值。这个值是收到的报文MASK值。 
然后将设置的欲接收节点的ID标识符与MASK也做与操作之后,得到一个值。这个是预先设定的愿意接收的节点MASK值。 
如果上述两值相同,则说明该报文需要接受,否则不需要接收。 
参考: 
Canbus ID filter and mask - carprog - 博客园 http://www.cnblogs.com/shangdawei/p/4716860.html 
可以同时设置多个接收Filter。

RTR-发送器通过发送远程请求帧来主动获得数据报文 

当报文中Header的ID标识符字段中的RTR位置1,表示当前帧是远程请求帧。请求远程节点ID为本帧中指定ID的节点发送远程数据。 
接收器接收到的报文中,通过RTR位也可以看出该报文是否是其他节点发送的Remote Request报文。 
该场景比较普遍,比如我现在急需要远端节点ID=123的节点汇报设备当前的温度。 
我使用别人的数据,有两种方式:别人定时或者不定时的主动发出来,也不管有人要不要这些数据;别人是个木瓜呆子,需要人推一下动一下,不推不动就闷声睡觉,自然就没有数据发出来。 
所以当我需要节点的数据时,而那该死的节点迟迟不主动发送,那么只好本节点亲自请求它发送了。

EFF-扩展帧Flag 

关于报文格式,有两种格式,标准帧和扩展帧。区别在于帧头中标识符的长度,一个是11位,一个是29位。 
11位的ID标识符,表示的节点个数肯定小于29位ID标识符,也就是说接入到网络中的节点数目不一样。

CAN总线bitrate vs 任意两节点间的最大距离

CAN网络的位速率取决于总线长度。控制器最快能达到1mbps,但对总线长度有限制。对于50m长的总线,最大bitrate是1mbps,而1500m的总线,bitrate约为0.05mbps。

bitrate    Max Length

1mbps    40m
500kbps    130m
250kbps    270m
125kbps    530m
100kbps    620m
50kbps    1.3km
20kbps    3.3km
10kbps    6.7km
5kbps    10km
同一网络中,所有节点的速率必须相同,并且固定不变。

总线仲裁技术 

当多个节点同时向总线发送信息时,优先级低的会主动退出发送,而优先级高的节点可不受影响的继续 
传送数据,从而大大节省了总线冲突仲裁时间,尤其在网络负载很重的情况下也不会出现网络瘫痪情况。 
ID标识符值越小,优先级越高。标准格式报文优先级高于扩展格式报文。数据报文高于远程请求报文。
基于Linux SocketCAN的RAW socket应用注意
ID如何分配 
首先确定是使用标准格式报文还是扩展格式报文。标准格式ID占用11位。扩展格式ID占用29位。 
需要根据整个网络情况,统筹合理分配ID。

BitRate如何设置 

应根据距离最远的两个节点间的距离反推出整个网络统一设置的bit rate。

can_frame 

是应用程序与内核驱动交互的结构体。内核驱动与CAN硬件交互之后,BUS上传输的通信协议由下文的通信协议指定。

/*

* 扩展格式识别符由 29 位组成。其格式包含两个部分:11 位基本 ID、18 位扩展 ID。
* Controller Area Network Identifier structure
*
* bit 0-28     : CAN识别符 (11/29 bit)
* bit 29     : 错误帧标志 (0 = data frame, 1 = error frame)
* bit 30     : 远程发送请求标志 (1 = rtr frame)
* bit 31     :帧格式标志 (0 = standard 11 bit, 1 = extended 29 bit)
*/
typedef __u32 canid_t;

struct can_frame { 

     canid_t can_id;  /* 32 bit CAN_ID + EFF/RTR/ERR flags */
      __u8    can_dlc; /* 数据长度: 0 .. 8 */
      __u8    data[8] __attribute__((aligned(8))); 
 };
可发送什么数据 
基于Linux Socket CAN的原始套接字,利用can_frame格式,一次最大发送8个字节数据。当然,也可以使用ISOTP格式,一次可以发送64字节。 
数据内容应用可以自行定义。

可收到什么数据 

根据CAN通信协议,可以收到3种类型数据:数据帧,远程请求帧,错误帧。数据帧,远程请求帧包括标准格式和扩展格式,错误帧没有区分。 
所有收到的数据,都是struct can_frame结构体表示。 
通过can_frame.can_id ,可以知道是什么格式数据。

/* special address description flags for the CAN_ID */

#define CAN_EFF_FLAG 0x80000000U /* EFF/SFF is set in the MSB */
#define CAN_RTR_FLAG 0x40000000U /* remote transmission request */
#define CAN_ERR_FLAG 0x20000000U /* error message frame */
1
2
3
4
对于数据帧,则由应用程序自行解析数据内容;对于RTR帧,数据帧没有内容;对于错误帧,格式如下: 
can_frame.can_id 中0~28位表示错误类:

/* error class (mask) in can_id */

#define CAN_ERR_TX_TIMEOUT   0x00000001U /* TX timeout (by netdevice driver) */
#define CAN_ERR_LOSTARB      0x00000002U /* lost arbitration    / data[0]    */
#define CAN_ERR_CRTL         0x00000004U /* controller problems / data[1]    */
#define CAN_ERR_PROT         0x00000008U /* protocol violations / data[2..3] */
#define CAN_ERR_TRX          0x00000010U /* transceiver status  / data[4]    */
#define CAN_ERR_ACK          0x00000020U /* received no ACK on transmission */
#define CAN_ERR_BUSOFF       0x00000040U /* bus off */
#define CAN_ERR_BUSERROR     0x00000080U /* bus error (may flood!) */
#define CAN_ERR_RESTARTED    0x00000100U /* controller restarted */
具体错误信息由头文件指示:include/uapi/linux/can/error.h,由can_frame.data承载。 
http://androidxref.com/kernel_3.18/xref/include/uapi/linux/can/error.h#56

设置filter 

CAN_RAW_FILTER:设置接受数据帧和远程请求帧。 
CAN_RAW_ERR_FILTER:设置接受错误帧。 
具体可参考内核文档。 
翻译:http://blog.csdn.net/yuanlulu/article/details/7220060 
新设Filter覆盖旧Filter。 
内核没有检查可以设置的Filter个数,我曾经在2016年某个 内核patch看到最大512个Filter: 
LKML: Jiri Slaby: [PATCH 3.12 007/235] can: raw: raw_setsockopt: limit number of can_filter that can be set https://lkml.org/lkml/2017/1/27/412
通信协议
这里描述的通信协议,是底层硬件的通信协议,按位发送。应用程序通过struct can_frame结构体与驱动交互。驱动将struct can_frame 转换成硬件通信协议。 
硬件bus中的报文包括两种格式帧格式:标准格式,有11位的发送节点ID标识符;扩展格式,有29位的发送节点ID标识符,其他部分相同。

帧类型

数据帧:将发送器发送的数据传输到接收器。
远程请求帧:请求远程具有同样ID标识符的节点发送数据帧。 
“具有同样ID标识符”:这里进行对比的双方,一个是远程节点自己的ID,一个是远程请求帧中Header.ID。
错误帧:任何节点检测到错误,就发生错误帧。 
因为所有节点同时收到帧,会否同时多个节点检测到错误?从而会发生多个错误帧?
过载帧:两个相邻的数据帧或者远程请求帧之间,提供附加延时。 
数据帧和远程请求帧使用标准格式或者扩展格式。和前面的帧通过一个帧间间隔分开。
数据帧和远程帧格式
数据帧包括7个字段(Field):帧起始(Start Of Frame),仲裁字段(Arbitration Field),控制字段(Control Field),数据字段(Data Field),CRC字段(CRC Field),应答字段(ACK Field),帧结尾(End Of Frame)。

类型    SOF    仲裁    控制    数据    CRC    ACK    EOF

标准    0    11+1    2+4    =dlc    ..    …    …
扩展    0    29+1    2+4    =dlc    ..    …    …
SOF
只有在总线空闲状态才可以开始一帧的发送。

仲裁

标准格式仲裁字段
标准格式版本较早,当时还没有考虑到扩展格式。所以在标准格式中,仲裁字段由11位ID+1位RTR组成。

仲裁字段    控制字段

ID(11)+RTR(1)    R1(1)+R0(1)+DLC(4)
标准格式与扩展格式的区分方法
当发展到后期,发现11位ID标识符不够使用,需要扩充ID位数,幸好在控制字段中,有2位保留字段没有使用,都填充了0。于是扩展格式就通过控制字段中的R1位来表示当前是标准格式还是扩展格式。因此R1这一位在扩展格式中就成了IDE,就是扩展格式标识符。这一位被置1,表示是扩展格式报文。

扩展格式仲裁字段

仲裁字段    控制字段
ID(11)+SRR(1)+IDE(1)+ID2(18)+RTR(1)    R1(1)+R0(1)+DLC(4)
可以看到,扩展格式兼容标准格式。当老版本2.0A的CAN芯片解析扩展格式报文的时候,发现IDE位的值是1,与原始规定的R1应该是0不同,因此这个版本的CAN芯片无法理解该报文。 
而支持2.0B的CAN芯片发现IDE位为1,知道是扩展格式。 
可以发现扩展格式的控制字段,又有2位保留字段。是否还可以继续进行新的升级呢?说不定。

数据帧与远程发送请求帧区别

RTR位用来区分数据帧与远程发送请求帧的区别。 
RTR:Remote Transmission Request 
如果RTR位为1,表示是远程请求帧。否则是数据帧。 
远程请求帧中,数据字段位数为0.所以控制字段中的DLC没有意义。

SRR位

在扩展帧中,有SRR位,这是标准帧格式中的RTR位,SRR表示替代远程请求位(substitute Remote request)。在扩展帧中它的值永远是1. 
这种设计,就是CAN BUS硬件仲裁的机制利用。假设有一个基本帧,表示的ID为0xabcde。而一个扩展帧中,ID为0xa00abcde。 
那么abcde会出现在报文中的基本ID字段中。两个帧格式基本相同。而节点发送报文是按位发送。如何仲裁扩展帧退出?SRR位是1,隐性位,需要让位于显性位。 
如果标准格式的远程请求帧与扩展格式的数据帧呢?谁优先级高?

控制

包括2位保留字段,当前都为0。 
以及4位数据字段长度编码DLC。可以表示64位信息。刚好数据最大有8个字节,足够表示。

以下几个字段都是硬件工程师需要了解的。软件就不管了。

数据

CRC
ACK
EOF
错误帧
附录
显性=0/隐性=1
CAN2.0B规范定义了两种互补的逻辑数值:“显性”和“隐性”,同时传送“显性”和“隐性”位时,总线结果值为“显性”。“显性”(“Daminant”)数值表示逻辑“0”,而“隐性”(“Recessive”)表示逻辑“1”。

RS-232和CAN在电平和帧格式上都是很大的不同。具体表现如下: 

RS-232标准电平采用负逻辑,规定+3V~+15V之间的任意电平为逻辑“0”电平,-3V~-15V之间的任意电平为逻辑“1”电平。 
而CAN信号则使用差分电压传送,两条信号线称为“CAN_H”和“CAM_L”,静态时均为2.5V左右,此时的状态表示为逻辑“1”,也可以叫做“隐性”;用CAN_H比CAN_L高表示逻辑“0”,称为“显性”。显性时,通常电压值为:CAN_H=3.5V,CAN_L=1.5V;

一个可供参考的can bus java库

Overview (VI Module API) 
http://dz.prosyst.com/pdoc/mBS_TM_SDK_7.3.0/modules/vi/api/index.html?com/prosyst/mbs/services/vi/j2socketcan/CanSocket.html
--------------------- 
作者:w8u 
来源:CSDN 
原文:https://blog.csdn.net/w8u/article/details/61914994 
版权声明:本文为博主原创文章,转载请附上博文链接!

 

你可能感兴趣的文章
Android学习笔记之性能优化SparseArray
查看>>
linux多线程编程,用 pthread_cond_timedwait 代替sleep
查看>>
git 将本地代码关联到远程仓库管理
查看>>
第一次有人把5G讲的这么简单明了!
查看>>
RTSP/RTMP/HTTP/ QUIC/UDT/SRT
查看>>
Android Rxjava:这是一篇 清晰 & 易懂的Rxjava 入门教程
查看>>
Android自定义View的三种实现方式
查看>>
码流 / 码率 / 比特率 / 帧速率 / 分辨率 / 高清的区别
查看>>
IP分配及网段划分
查看>>
EventBus接收不到事件(debug版本可以接收,release接收不到)
查看>>
Android UI开发——Material Design界面设计风格
查看>>
简单工厂模式
查看>>
迭代器模式
查看>>
HashMap、ConcurrentHashMap和SynchronizedMap – 哈希表在Java中的多线程同步处理
查看>>
Lock和synchronized比较详解
查看>>
H264码流中SPS、PPS详解
查看>>
Android三种动画实现原理及使用
查看>>
Android Auto 架构了解
查看>>
Linux下使用putty进行UART串口调试
查看>>
WebSocket
查看>>