CAN网络学习总结

什么是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。

bitrateMax Length
1mbps40m
500kbps130m
250kbps270m
125kbps530m
100kbps620m
50kbps1.3km
20kbps3.3km
10kbps6.7km
5kbps10km

同一网络中,所有节点的速率必须相同,并且固定不变。

  • 总线仲裁技术
    当多个节点同时向总线发送信息时,优先级低的会主动退出发送,而优先级高的节点可不受影响的继续
    传送数据,从而大大节省了总线冲突仲裁时间,尤其在网络负载很重的情况下也不会出现网络瘫痪情况。
    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 */

对于数据帧,则由应用程序自行解析数据内容;对于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仲裁控制数据CRCACKEOF
标准011+12+4=dlc..
扩展029+12+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

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值