CAN总线简介

CAN 是 Controller Area Network 的缩写(以下称为 CAN),是 ISO*1 国际标准化的串行通信协议。在当前的汽车产业中,出于对安全性、舒适性、方便性、低公害、低成本的要求,各种各样的电子控制系统被开发了出来。由于这些系统之间通信所用的数据类型及对可靠性的要求不尽相同,由多条总线构成的情况很多,线束的数量也随之增加。为适应“减少线束的数量”、“通过多个 LAN,进行大量数据的高速通信”的需要,1986 年德国电气商博世公司开发出面向汽车的 CAN 通信协议。此后,CAN 通过 ISO11898 及 ISO11519 进行了标准化,现在在欧洲已是汽车网络的标准协议。现在,CAN 的高性能和可靠性已被认同,并被广泛地应用于工业自动化、船舶、医疗设备、工业设备等方面。

图1是车载网络的构想示意图。CAN 等通信协议的开发,使多种 LAN 通过网关进行数据交换得以实现。

图2是CAN的应用示例

在这里插入图片描述
在这里插入图片描述

通信协议复习

CAN总线是基于此环境下诞生,那么它的特点是什么,我们不妨根据我们学习过过的通信方式对比查看一下。

  • USART

    USART通常是在板级距离的通信主要用作调试功能。支持全双工通信,使用方便,只用两个引脚即可。因为他是逐位传输的所以即使收到干扰也是只有单个字节受到影响,所以抗干扰能里比较强,通信时速率一般设为115200,也就是115.2kbps,速度不算快。USART在多机通信上会出现短板,但是也可以通过设置9bit模式来实现。

  • I2C

    I2C则是适用于多机通信的场景,采用的是一主多从的通信模式,由主机控制时钟线,通过逻辑线与的机制来实现通信和通信仲裁。I2C只需要两个引脚,所以在多机通信的场景下是性价比之选。通信速率标准模式是100kbps,快速模式为400kbps,如果想要达到Mbps级别的传输速率,则需要硬件支持,比如stm32F4系列。但是I2C的通信是半双工的,并且一般是多机场景,这就导致一次通讯中会有大量的无效数据。是典型的牺牲效率换取资源

  • SPI

    SPI可以用一句话概括,牺牲了所有的换取了效率,很轻易的就来到了Mbps级别的通讯速率。支持多机通信,但是每多一个设备就需要多接一根CSS线,并且在通信中没有任何数据帧格式,总线上发送的都是有效数据。

我们知道I2C和SPI都是有时钟线控制通信节奏的,所以很明显这是同步通信,那么USART只有收发两条线,所以是异步通信。

以上就是简单的回顾了之前学习过的通信协议,下面让我们简单了解一下CAN总线的同步。

可以先简单概括一下,CAN是一个很稳定,数据传输能力有限,并且支持多机的异步通信协议。

差分信号

首先先介绍一下差分信号。了解差分信号之前就要先了解什么是单端信号。

那么什么是单端信号呢,我们已经接触过了,在我们学习上面三个通信协议画的时序图就是单端信号。
单端信号是一根信号线和一根地线,以地线为基准根据信号线的电平大小输出高低电平,所以这种情况下有外部干扰的话,地线是不会变的,而信号线就很容以收到影响,那么就会改变原来的电平状态。
而差分信号线是一对信号线,同时输出电压,根据两根信号线的电势差来判断是高电平还是低电平。所以当出现干扰的时候,两根信号线的收的干扰程度是一样的,所以电势差是不变的,则输出的电平状态不变,所以抗干扰能力强。
就好比你去爬山,一直以地面为参考,那么就会越来越高,但是如果你已自己的鞋为参考,你的高度始终如一。
在这里插入图片描述

  • 高速CAN规定:
    电压差为0V时表示逻辑1(隐性电平)
    电压差为2V时表示逻辑0(显性电平)
  • 低速CAN规定:
    电压差为-1.5V时表示逻辑1(隐性电平)
    电压差为3V时表示逻辑0(显性电平)

CAN的帧格式

关于CAN为什么数据传输十分有限我们可以先看一下它的数据帧,CAN有很多数据帧格式都会讲到,我们先看一下数据帧。

在这里插入图片描述
可以看到它的数据帧格式是比较严格的所以如果多帧拼接还是比较麻烦的,而且这里显示数据段是0-64bit也就是8字节。这也是很符合它诞生的场景,在开篇已经了解是为了汽车工业领域进行控制,所以只是传输指令或传感器内容,自然不需要过多的数据位,所以我们在使用CAN时,也应该考虑到这一点,不能用CAN像串口一样进行大量数据的收发。

既然CAN发送的数据量比较有限,又支持多机通信,并且也没有使用多个引脚,也是和USART一样只有两个引脚Tx和Rx,所以很明显也是一种异步通信协议,那么他是怎么维护通信的呢?一个是帧格式一个是过滤器。
CAN是一个多主机通信的通信协议,正如上文所说他不能通过上述这些东西进行控制,所以它设置了很多帧类型用来在特定的场合进行发送。但其实就练习而言只需要一个数据帧也是够的。下面我们逐个讲解这些帧

数据帧

如上图所示,数据帧由7个段构成

  • 帧起始:
    SOF(Start of Frame):帧起始,表示后面一段波形为传输的数据位
  • 仲裁段:
    ID(Identify):标识符,区分功能,同时决定优先级
    RTR(Remote Transmission Request ):远程请求位,区分数据帧和遥控帧
  • 控制段:
    IDE(Identifier Extension):扩展标志位,区分标准格式和扩展格式
    r0/r1(Reserve):保留位,为后续协议升级留下空间
    DLC(Data Length Code):数据长度,指示数据段有几个字节
  • 数据段
    Data:数据段的1~8个字节有效数据
  • CRC段
    CRC(Cyclic Redundancy Check):循环冗余校验,校验数据是否正确
  • ACK段
    ACK(Acknowledgement):应答位,判断数据有没有被接收方接收
    CRC/ACK界定符:为应答位前后发送方和接收方释放总线留下时间
  • 帧结束
    EOF(End of Frame ):帧结束,表示数据位已经传输完毕

数据帧的发展历史
可以看到上图有两种数据帧,第一个是1.0版本,第二个是2.0版本,主要是因为ID不够用,所以更新了一个扩展帧的格式,所以为了区分这是标准格式还是扩展帧格式那么之前预留位r1就显示出了他的作用,用来区分当前帧是标准格式还是扩展格式。但是总体不会影响我们的使用。

遥控帧

在这里插入图片描述
我在另一个参考文档中也看到叫远程帧,他的作用就是发送给目的主机,让他发送一个数据帧,根据功能来讲的话,我们也可以叫它请求帧。
那么遥控帧的结构相较于数据帧也只是少了一个数据段,所以不再单列其他都是一样的。

错误帧

用于在接收和发送消息时检测出错误通知错误的帧。错误帧由错误标志和错误界定符构成。
在这里插入图片描述
错误帧没有一个固定的格式,任何帧都可以是一个错误帧,当发现发送的消息出现了问题的时候,会自行作废该帧,怎么知道该帧是废帧呢?就是连着六个相同的位,这部分涉及到CAN的资源分配规则我们可以在后面细讲,在这里知道有一个错误帧就可以了
另外可以了解一下,错误帧有两种,一个是主动错误,就是6个显性位也就是6个1;另外一个就是被动错误,那么也就是6个隐性位,就是6个0

过载帧

过载帧是用于接收单元通知其尚未完成接收准备的帧。过载帧由过载标志和过载界定符构成。
在这里插入图片描述
过载帧的格式也是六个显性位,那么这里就出现了一个问题了,这与错误帧的主动错误是一样的该怎恶魔区分呢?
过载真当接收方收到大量数据而无法处理时,其可以发出过载帧,延缓发送方的数据发送,以平衡总线负载,避免数据丢失。所以这里我们就应该会有一个简单的想法,过载帧应该是在帧结束之后的,而错误帧是在正在发送的帧种出现的

帧间隔

帧间隔是用于分隔数据帧和遥控帧的帧。数据帧和遥控帧可通过插入帧间隔将本帧与前面的任何帧(数据帧、遥控帧、错误帧、过载帧)分开。
过载帧和错误帧前不能插入帧间隔。
在这里插入图片描述

  1. 间隔
    3 个位的隐性位。
  2. 总线空闲
    隐性电平,无长度限制(0 亦可)。
    本状态下,可视为总线空闲,要发送的单元可开始访问总线。
  3. 延迟传送(发送暂时停止)
    8 个位的隐性位。
    只在处于被动错误状态的单元刚发送一个消息后的帧间隔中包含的段。

在这里上面的问题就可以得到回答了,简单概括就是:6个显性位出现在"帧中间"就是主动错误帧,出现在"帧与帧之间的间隔期"就是过载帧。

以上就是CAN的5种帧格式

位填充

位填充是为防止突发错误而设定的功能。当同样的电平持续 5 位时则添加一个位的反型数据。
在这里插入图片描述

  1. 发送单元的工作
    在发送数据帧和遥控帧时,SOF~CRC 段间的数据,相同电平如果持续 5 位,在下一个位(第 6 个位)则
    要插入 1 位与前 5 位反型的电平。
  2. 接收单元的工作
    在接收数据帧和遥控帧时,SOF~CRC 段间的数据,相同电平如果持续 5 位,需要删除下一个位(第 6 个
    位)再接收。如果这个第 6 个位的电平与前 5 位相同,将被视为错误并发送错误帧。

所以在这里就可以解释前面错误帧的问题了,CAN规定了这种位填充的机制,所以连续六个相同的bit位就是非法的,所以将这种非法帧当作错误帧,作为一种错误机制。

错误的种类和错误处理

错误的种类

在CAN种规定了5种错误,多种错误可能同时发生。分别是:

  • 位错误
  • 填充错误
  • CRC错误
  • 格式错误
  • ACK错误
    具体相关内容我们可以看一下手册种的这张表
    在这里插入图片描述
    从这张表中我们看最右侧的一栏——检测单元。我们发现一个问题,检测错误可以是自己也可以是其他节点。因为CAN是广播的,所以就是所有节点都是接收单元,这种感觉就是教室里一个同学起来回答问题,所有同学都在看着他一样。即一个节点发送节点,CAN总线上所有检点都去监督数据的正确性。

那么如果检测出非法帧或错误发送节点和其他节点是怎么处理的呢?

CAN的错误处理机制

首先先是要检测到错误,然后要知道检测到错误的是哪一个节点(主要确定是否是发送节点),最后检测出错误的处理办法是什么?

错误的类型我们已经在上图种列出来了

错误类型 触发条件 谁检测到
位错误(Bit Error) 发送的位与回读的总线电平不一致 发送方
填充错误(Stuff Error) 检测到连续6个相同电平(违反位填充规则) 所有节点
CRC错误 接收端计算的CRC值 ≠ 帧中的CRC值 接收方
格式错误(Form Error) 固定格式字段出现非法位 接收方
应答错误(ACK Error) 发送方在ACK槽未检测到显性位(无人应答) 发送方

那么我们可能会盲猜一下,之前我们学了错误帧是有两种,一个是主动错误,一个是被动错误,所以是不是由发送放自己检测出来的错误就是主动错误,由其它节点检测出来的就是被动错误。
这是一种错误的想法,对于主动被动的区分不是用来区分检测对象是谁,个人感觉这样做的意义也确实不是很大,错了重发就好了,不需要附带一个额外信息。

CAN的信任度管理系统

主动错误和被动错误是CAN协议中节点的两种工作状态,核心区别在于对总线的控制能力不同。
在CAN总线上的每个节点内部都维护着两个计数器

  • TEC(Transmit Error Counter):发送错误计数器
  • REC(Receive Error Counter):接收错误计数器
状态 条件
主动错误 TEC < 128 且 REC < 128
被动错误 TEC ≥ 128 或 REC ≥ 128
总线关闭 TEC ≥ 256

这两者的差异是什么呢?是如何实现对总线控制的呢

对比项 主动错误 被动错误
错误标志 6个显性位 6个隐性位
能否打断总线 ✅ 能 ❌ 不能
能否正常收发 ✅ 完全正常 ✅ 可以收发,但错误标志无效
对总线的威胁 正常参与者 被限制干扰能力

也就是说如果是被动错误状态是不能够打断状态的,那么就可以简单理解为,该节点不再具备监督权,就好像所有同学都在听在回答问题的同学说话,但是这个节点被老师再门外罚站了自然是没有监督里面同学的权力,但是该同学如果要求回到教室内部,就需要在全班面前开口接受所有同学监督。当然如果有同学频繁犯错,那就不只是门外罚站而是联系家长回家反省了,这种情况也是对应CAN总线对此的管理模式

  • 主动错误 = “可信节点”:你犯错少,协议信任你,允许你用显性位打断总线来报告错误
  • 被动错误 = “可疑节点”:你犯错太多了,协议限制你的权限,你的错误标志变成隐性位,无法打断别人
  • Bus Off = “隔离节点”:你犯错太多且持续不改,直接把你踢出总线

状态转换过程如下:

正常节点(TEC=0, REC=0)
    │
    │  偶尔出错,TEC逐渐增长
    ▼
主动错误状态(TEC<128, REC<128)
    │
    │  频繁出错,TEC≥128 或 REC≥128
    ▼
被动错误状态
    │
    │  持续出错,TEC≥256
    ▼
总线关闭(Bus Off)

关于计数器的增减规则了解一下就好了,这其实与我们写代码的关系不大。

事件 TEC变化
发送时检测到位错误 +8
发送时检测到其他错误(填充、CRC、格式) +8
发送ACK错误 +1
成功发送一帧 -1(最低到0)
事件 REC变化
接收时检测到位错误 +1
接收时检测到填充/CRC/格式错误 +1
发送错误标志(主动错误状态) +8
发送错误标志(被动错误状态) +8
成功接收一帧 -1(最低到0)

ok, 我们再回到错误检测的问题上,现在搞清了这里边存在一个信任管理机制,受信任的节点可以有更多的总线管理权限,也就是说,依据对应的错误类型,所有受信任的节点都可以打断。那么是如何打断的呢?

逻辑线与

我们在学习I2C的时候学习过他的仲裁模式,就是非破坏性仲裁,通过逻辑线与实现,也就是谁先发0谁获取总线控制权。那么在CAN种也是通过逻辑线与实现的。
当出现类似位错误的时候,发送节点自己会自己废弃该帧连续发送6个相同电平,视为错误帧。
如果是其它节点检测出来的错误,那么他们也是依靠这样的机制,由于逻辑线与的机制,我们也就能看出来为什么被动错误是隐性电平,主动错误是显性电平,也是同I2C一样的逻辑,显性电平可以改变整体的总线信号。
(CAN总线也是通过开漏+上拉实现的逻辑线与)

但是在这里你可能会有这样一个问题,就是CAN总线中有多个设备,那么肯定不会只有一个节点检测出错误,其它节点检测不出来,所以会不会出现不止6个连续相同的bit位。
是的是会出现这样的结果,出现错误帧的时候不见得是严格的6位,甚至更多,但是这个并不影响我们的结果。

而且因为逻辑线与的存在也解决了一个问题,就是发送节点不知到自己出错还是会继续发送数据,但是这时候电平已经被其它节点变为显性状态了,不会导致总线上的电平混乱。

那么在这里也可以提一嘴,CAN的仲裁方式也是非破坏性仲裁,当某个发送节点出现位错误时也就自行放弃了。

数据采样

因为CAN是异步多主机通信,没有统一的时钟管理。我们在学习USART的时候学到过,随着时间的推移其可靠性就会越来越差。就是采样点的偏移。而我们CAN的诞生是为了处理汽车上的指令这需要有高可靠性,所以关于数据采样,它也有自己比较完善的机制用来解决采样时机偏移的情况

由发送单元在非同步的情况下发送的每秒钟的位数称为位速率。一个位可分为 4 段。

  • 同步段(SS)
  • 传播时间(PTS)
  • 相位缓冲段1(PBS1)
  • 相位缓冲段2(PBS2)

这些段又由可称为 Time Quantum(以下称为 Tq)的最小时间单位构成。
1 位分为 4 个段,每个段又由若干个 Tq 构成,这称为位时序
1 位由多少个 Tq 构成、每个段又由多少个 Tq 构成等,可以任意设定位时序。通过设定位时序,多个单元可同时采样,也可任意设定采样点。
在这里插入图片描述
所谓采样点是读取总线电平,并将读到的电平作为位值的点。位置在 PBS1 结束处。

波特率计算

由此我们可以知道传输一个bit位是多长时间了,所以就可以计算他的波特率,因为这些时间段在我们编程中是我们自己设置的,所以波特率也是由我们自己控制,一般工作时间设置为250kbps,500kbps。
波特率 = 1 / 一个数据位的时长 = 1 / ( T S S + T P T S + T P B S 1 + T P B S 2 ) 波特率 = 1 / 一个数据位的时长 = 1 / (TSS + TPTS + TPBS1 + TPBS2) 波特率=1/一个数据位的时长=1/(TSS+TPTS+TPBS1+TPBS2)

例如:
S S = 1 T q , P T S = 3 T q , P B S 1 = 3 T q , P B S 2 = 3 T q , T q = 0.5 u s SS = 1Tq,PTS = 3Tq,PBS1 = 3Tq,PBS2 = 3Tq, Tq = 0.5us SS=1TqPTS=3TqPBS1=3TqPBS2=3Tq,Tq=0.5us

波特率 = 1 / ( 0.5 u s + 1.5 u s + 1.5 u s + 1.5 u s ) = 200 k b p s 波特率 = 1 / (0.5us + 1.5us + 1.5us + 1.5us) = 200kbps 波特率=1/(0.5us+1.5us+1.5us+1.5us)=200kbps

位时序

为了灵活调整每个采样点的位置,使采样点对齐数据位中心附近,CAN总线对每一个数据位的时长进行了更细的划分,分为同步段(SS)、传播时间段(PTS)、相位缓冲段1(PBS1)和相位缓冲段2(PBS2),每个段又由若干个最小时间单位(Tq)构成,下表就是手册中各段的作用
在这里插入图片描述

同步机制

这里的同步机制分为硬件同步和再同步,它们遵从如下规则。

  1. 1 个位中只进行一次同步调整。
  2. 只有当上次采样点的总线值和边沿后的总线值不同时,该边沿才能用于调整同步。
  3. 在总线空闲且存在隐性电平到显性电平的边沿时,则一定要进行硬件同步。
  4. 在总线非空闲时检测到的隐性电平到显性电平的边沿如果满足条件1和2,将进行再同步。但还要
    满足下面条件。
  5. 发送单元观测到自身输出的显性电平有延迟时不进行再同步。
  6. 发送单元在帧起始到仲裁段有多个单元同时发送的情况下,对延迟边沿不进行再同步。

硬同步

接收单元在总线空闲状态检测出帧起始时进行的同步调整。
在检测出边沿的地方不考虑 SJW 的值而认为是 SS 段。
硬件同步的过程如下图所示。
在这里插入图片描述

  • 硬同步只在帧的第一个下降沿(SOF下降沿)有效
  • 经过硬同步后,若发送方和接收方的时钟没有误差,则后续所有数据位的采样点必然都会对齐数据位中心附近
  • 每个设备都有一个位时序计时周期,当某个设备(发送方)率先发送报文,其他所有设备(接收方)收到SOF的下降沿时,接收方会将自己的位时序计时周期拨到SS段的位置,与发送方的位时序计时周期保持同步

再同步

在接收过程中检测出总线上的电平变化时进行的同步调整。
每当检测出边沿时,根据 SJW 值通过加长 PBS1 段,或缩短 PBS2 段,以调整同步。但如果发生了超出 SJW值的误差时,最大调整量不能超过 SJW 值。在这里插入图片描述

  • 若发送方或接收方的时钟有误差,随着误差积累,数据位边沿逐渐偏离SS段,则此时接收方根据再同步补偿宽度值(SJW)通过加长PBS1段,或缩短PBS2段,以调整同步
  • 再同步可以发生在第一个下降沿之后的每个数据位跳变边沿

发生冲突(多设备同时发送数据)

CAN中有多种处理机制。
首先是非破坏性仲裁,原理是和I2C一样的,不熟悉的同学可以复习一下I2C章节

第二就是先来先得,也就是说,如果有设备在发送数据,是不允许被打断的,只能等待数据发送完毕,才可以由其它节点发送,当然也不是绝对不可以打断,就是我们上面已经讲过的错误检测是可以打断的,也就只有这一种情况可以打断当前正在传输的数据帧

第三就是CAN中有对于不同帧有不同的优先级,比如数据帧是高于遥控帧的

第四就是根据ID号
其实三四的本质也还是基于逻辑线与的机制实现的。具体感兴趣大家可以研究一下这写数据帧是如何设置的如果发生仲裁的话,是如何仲裁最后判断的。

Logo

智能硬件社区聚焦AI智能硬件技术生态,汇聚嵌入式AI、物联网硬件开发者,打造交流分享平台,同步全国赛事资讯、开展 OPC 核心人才招募,助力技术落地与开发者成长。

更多推荐