转载自 http://blog.michiru.me/posts/can-bus-quick-introduction.html
最近来一家车企混实习证明,被叫去为他们写CAN测试程序。不幸这玩意儿以前只听说名字而已,让我们来看看它有什么有趣的。
CAN总线是什么
CAN是一种消息协议,1983年由德国公司Bosch开发。CAN是一种电子设备之间的通讯协议,包含了硬件和软件两方面的规定,类似于RS-232、USB、以太网等。他们都只是一种“线”。如果你不想要知道太多,那么只需要知道仪器用CAN线连在一起,他们之间就可以交换信息了。
CAN主要应用于汽车领域,开发的初衷之一正是统一车辆内各电子设备的通讯,精简复杂的线束。
稍详细的内容
CAN总线标准主要在ISO 11898
这个文档里,此外还有Bosch的CAN 2.0
。大致上可以分为“硬件结构是什么样”和“如何交换数据”两部分。
硬件结构是什么样
CAN是一种总线,也就是说所有的设备(以下称为节点,Node)都接在同一条线上。所有节点可以(尽管不应该)同时操作总线。
CAN是串行的,一般只需要3根线:CAN_H
、CAN_L
、GND
,没有时钟。CAN_H
与CAN_L
差分传送数据,物理上应该双绞,而GND做线壳。电压不定,一般来说5V电源时,要表示0
,CAN_H
和CAN_L
都是2.5V;表示1,CAN_H
是3.5V,CAN_L
是1.5V。
CAN线在物理上(不要在意如何)实现了“线与(wired-AND)”的连接方式——任何一个节点输出0
,总线即为0
。
如何交换数据
设备之间不分主从,任何设备(节点)都可以操作总线来发送消息,而此时另外的所有节点会收到这条消息。至于收到的消息有没有用,怎么用,由节点自行处理。
总线通讯不区分主从节点,就可能会出现冲突:尽管节点只应该在总线空闲时才发送消息,但仍可能会非常巧,有2个或以上的节点同时想要操作总线发送消息。这时需要“仲裁”,到底应该谁来发送。
仲裁利用了“线与”:在任何消息之前附加11位ID,ID决定了消息的优先度,小为优先度高。任何节点在发送消息ID(写总线)时也回读结果,如果发现和自己写的不一样,节点就知道还有别的节点在发送数据,并且自己发送的消息优先度更低,于是放弃操作总线。举个例子:
Node1: 00001000000
Node2: 000011*****
CANBUS: 00001000000
在第6位时,Node2向总线写0
,而Node2向总线写1
,总线结果为1&0=0
。这时Node2退出操作总线,Node1继续写总线。
除了ID之外,一条CAN消息的帧结构还有更多内容,有4位DLC来指示数据长度(意味着CAN消息是变长度的);有实际的数据位DATA,最长64位;有15位CRC来保证数据正确;消息后部分有一位ACK,这一位时,发送节点写1
,接收到的节点写0
,如果总线为0
,就表示有至少一个节点接收到了消息。还有其他一些结构,不过它们大多都不必在意。简单认为ID之后跟着DLC,之后跟着DATA,最后是ACK就好。
图片来自wikipedia
拥有了数据
得到了数据之后,这些数据都代表了什么,是应用层需要处理的事情,CAN标准没有规定。也就是每位设计,每个系统可以自由发挥。当然也是标准可以参考的,比如CANopen等。
更多内容
更多的内容可以先参考Wikipedia,你会知道:
- CAN线上的
0
被称为显性,而1
被称为隐性。 - 上面说的CAN电平其实是“高速CAN”的情况。
- CAN的ID也可以扩展到更多位数。
- CAN消息也分为几种,结构有些区别。
- CAN帧还要经过位填充之后才是实际发送到总线上(用示波器看到)的样子。这是为了进行没有时钟串行通信的各节点进行时钟同步。
- CAN信号的比特率大概是
<100MHz
,不过节点工作的频率应该更快(比如x8=800MHz
)才能较好处理通讯。 - 针对通讯错误(比如收到了非法结构的消息),标准规定了一套错误处理措施。措施的大意出错少的节点遇到错误时要主动打断正在传输的消息,而出错太多时要挂起自己以免干扰总线。
接下来可以阅读网上的一些更详细的教程,以及ISO 11898-1
、ISO 11898-2
。
(完)