在第二篇中仲裁机制部分我们提到CAN协议帧,总的来说CAN协议帧有5种类型,下面逐个展开。
由于数据帧与遥控帧的最大差别在于遥控帧没有数据段,所以将两者放在一起讲述:
1 数据帧和遥控帧
数据帧和遥控帧都有标准格式和扩展格式,这2种格式都具有相同的帧结构。
数据帧由7个段构成,遥控帧由6个段构成。先看数据帧:
这里结合实际采集的CAN总线电压信号来看下标准格式的数据帧。
再看遥控帧(也叫远程帧):
通过对比数据帧和遥控帧有:
-
数据帧与遥控帧的不同
- 遥控帧的RTR位为隐性位,没有数据段。
- 没有数据段的数据帧与遥控帧可通过RTR位区分。
-
遥控帧没有数据段,数据长度码如何表示?
- 遥控帧的数据长度以所请求数据帧的数据长度码表示。
-
没有数据段的数据帧有何用途?
- 例如,可以用于各单元的定期连接确认/应答、或仲裁段本身带有实质性信息的情况下。
通过对数据帧和遥控帧有了基本认识,下面我们再具体了解下每个段。
1.1 帧起始(SOF, Start of Frame)
表示帧开始的段,1个位的显性位。(总线空闲时为隐性位,故帧起始以显性位非常好识别),对于数据帧和遥控帧的标准/扩展格式均如此。
1.2 仲裁段(Arbitration field)
表示数据的优先级的段,其作用就是根据报文ID来确定其发送优先级。标准格式和扩展格式在此的构成有所不同。
这里对比数据帧与遥控帧各自的两个格式,其不同为:
针对上表的这种设计,后面会具体分析其在仲裁过程的作用。
1.3 控制段(Control field)
表述数据段的字节数,由6个位构成,标准格式和扩展格式的构成有所不同。
1.4 数据段(Data Field)
数据段可包含0-8个字节的数据,从MSB(最高位)开始输出。遥控帧没有此段。
1.5 CRC段(Cyclic Redundancy Check Field)
检查帧传输错误的帧,由15个位的CRC顺序和1个位的CRC界定符(用于分隔位)构成。CRC界定符恒为隐性。
这里CRC顺序是根据多项式生成的CRC值,CRC的计算范围包括帧起始,仲裁段,控制段和数据段。
附2:https://en.wikipedia.org/wiki/Cyclic_redundancy_check , 如何通俗的理解CRC校验并用C语言实现, https://zhuanlan.zhihu.com/p/77
1.6 ACK段(Acknowledge Field)
用来确认是否正常接收。由ACK槽(ACK Slot)和ACK界定符2个位构成。
1.7 帧结束(End of Frame)
表示该帧的结束的段。由7个位的隐性位构成。
2 错误帧
用于在接收和发送消息时检测出错误通知错误的帧,错误帧由错误标志和错误界定符构成。
上图的错误标志包括主动错误标志(6个位的显性位)和被动错误标志(6个位的隐性位)两种。主动错误标志处于主动错误状态下的单元检测出错误时输出的错误标志。被动错误标志处于被动错误状态的单元检测出错误时输出的错误标志。错误界定符由8个位的隐性位构成。
注意上图0~6位的错误标志重叠,这段怎么确定呢?需先介绍2个概念:位填充和错误类型。
2.1 位填充(Bit Stuffing)
位填充是为防止突发错误而设定的功能。当同样的电平持续5位则添加一个位的反型数据位:
2.2 错误类型
针对上述位错误再做说明: 所谓“发出的电平与从总线上回读的电平不一致”,指的就是节点向总线发出隐性位,却从总线上回读到显性位或者节点向总线发出显性位,却从总线上回读到隐性位这两种情况。有三种例外情况不属于位错误: 在仲裁区,节点向总线发送隐性位却回读到显性位,不认为是位错误,这种情况表示该节点仲裁失败; 在ACK槽,节点向总线发送隐性位却回读到显性位,不认为是位错误,这种情况表示,该节点当前发送的这一帧报文至少被一个其它节点正确接收; 一个节点发送被动错误标志,该节点向总线发送连续六个隐性位(被动错误标志)却回读到显性位,不认为是位错误。因为被动错误标志是六个连续的隐性位,所以在总线上按照线与机制,有可能这六个连续隐性位被其它节点发送的显性电平覆盖。
2.3 错误处理
错误状态的种类有:主动错误状态,被动错误状态和总线关闭态3种状态。单元始终处于3种状态之一。
(1)主动错误状态:可以正常参加总线通信的状态,处于主动错误状态的单元检测出错误时,输出主动错误标志。
(2)被动错误状态:是易引起错误的状态。处于被动错误状态的单元虽能参加总线通信,但为不妨碍其他单元通信,接收时不能积极地发送错误通知;处于被动错误状态的单元即使检测出错误,而其它处于主动错误状态的单元如果没发现错误,整个总线也被认为是没有错误的。处于被动错误状态的单元检测出错误时,输出被动错误标志。另外,处于被动错误状态的单元在不能马上再次开始发送。在开始下次发送前,在间隔帧期间内必须插入“延迟传送”(8个位的隐性位)。
(3)总线关闭态是不能参加总线上通信的状态。信息的接收和发送均被禁止。
以上这些状态依靠发送错误计算和接收错误计数来管理,根据计数值决定进入何种状态。错误状态和计数值的关系如下表:
发送错误计数值和接收错误计数值根据一定的条件发送变化。错误计数值的变动条件如下表,一次数据的接收和发送可能同时满足多个条件。错误计数器在错误标志的第一个位出现的时间点上开始计数。
2.4 错误帧发送
检查到错误后,什么时候发送错误帧呢?按照CAN协议的规定:
- 位错误、填充错误、格式错误、ACK错误。在错误产生的那一位的下一位开始发送错误帧。
- CRC错误。紧随ACK界定符后的位发送错误帧。
具体来看一个例子:
- 1)发送节点Node_A发送一个显性位,但是却从总线上听到一个隐形位,于是Node_A节点就会检测到一个位错误;
- 2)Node_A检测到位错误之后,立即在下一位开始发送主动错误帧:6个连续显性位的主动错误标志+8个连续隐性位的错误界定符;
- 3)对应Node_A发出的主动错误标志,总线上电平为6个连续显性位;
- 4)接收节点Node_B和Node_C从总线上听到连续6个显性位,那么就会检测到一个填充错误,于是这两个节点都会发送主动错误帧;
- 5)对应Node_B和Node_C发出的主动错误标志,总线电平又有6个连续显性电平,对应Node_B和Node_C发出的错误界定符,总线电平有8个连续的隐性电平。
- 6)在间歇场之后,Node_A节点重新发送刚刚出错的报文。
在了解了错误帧的发送后,回到之前提到**错误标志重叠部分是怎样形成的,**再看一个例子:
在这个例子,我们知道位错误的错误标志与填充错误的错误标志重叠2位,剩下部分还有4位
3 过载帧
过载帧是用于接收单元通知其尚未完成接收准备的帧。过载帧由过载标志(6个位的显性位)和过载界定符(8个位的隐性位)构成。过载界定符的构成与错误界定符的构成相同。过载帧的构成如下图所示。
对于过载帧的帧结构我们可以这样理解:接收节点达到接收极限时,就会发出过载帧到总线上,显然,过载标志的6个连续显性位会屏蔽掉总线上其它节点的发送,也就是说这个时候的接收节点通过发送过载帧的方式来破坏其它节点的发送,这样在接收节点发送过载帧期间,其它节点就不能成功发送报文,于是就相当于把其它节点的发送推迟了,也就是说接收节点在其发送过载帧的这段时间得以“休息”。
有3种情况会引起过载帧:
- 接收节点自身原因。接收节点由于某种原因需要延迟接收下一个数据帧或者遥控帧。
- 在帧间隔的间歇段的第一位和第二位检测到一个显性位(正常的间歇段都是隐性位)。帧间隔的间隔段本应是三个连续的隐性位,如果接收节点在间隔段检测到显性位,那么就意味着此时有报文发向接收节点,但这个时候是不应该有报文发来的,于是接收节点发送过载帧。
- CAN节点在错误界定符或过载界定符的第八位(最后一位)听到一个显性位0,节点会发送一个过载帧,且错误计数器不会增加。接收节点在错误界定符和过载界定符的最后一位听到显性位,也意味着有报文发向接收节点,但这个时候是不应该有报文发来的,于是接收节点发送过载帧。
4 帧间隔
帧间隔是用于分隔数据帧和遥控帧的帧。数据帧和遥控帧可通过插入帧间隔将本帧与前面的任何帧(数据帧、遥控帧、错误帧、过载帧)分开。过载帧和错误帧前不能插入帧间隔。
针对上图,间隔为3个位的隐性位;总线空闲为隐性电平,无长度限制(0亦可);延迟传送为8个位的隐性位,只在处于被动错误状态的单元刚发送一个消息后的帧间隔中包含的段。这里为什么需要延迟传送段呢?
首先,考虑主动错误状态的节点A,发送主动错误标志之后,随之就要重新发送刚刚发送失败的报文,但是为了间隔开与前面刚刚发送的错误帧,总线在错误帧之后就会插入3个隐形位的帧间隔,在这3个隐形位期间,其它的节点不足以判定总线空闲(需要连续11个隐性位才能判定),所以节点A仍然占据着总线的控制权,于是在帧间隔之后,节点A能够接着发送报文。现在节点A转入到被动错误状态了,说明它已经不是很可靠了,这个时候如果没有延迟传送段,在节点A发出被动错误标志之后,它仍然能够在3位的帧间隔之后立即重新发送报文,这是不符合我们对被动错误状态的处理要求的当然也是不符合CAN协议的,于是乎对于发送出被动错误标志的节点,总线在帧间隔中加入了8个连续隐性位的延迟传送段,这样的3+8=11个连续隐性位。就能让节点A在这个帧间隔期间失去对总线的控制权,从而优先保证其它正常(处于主动错误状态)节点能够使用总线,而不必等着一个已经不可靠的节点A占据总线。