车联网安全:网络协议
网络协议
CAN/CAN FD
CAN通信原理
CAN(Controller Area Network)是一种车辆ECU之间的通信方式,CAN协议规定ECU产生的数据(0 1,数字信号)会被转换成电信号通过CAN总线进行传输,而这里的电信号具体指的是电压差,所以CAN总线总是双绞线,一根传输高电平称之为CAN高(CAN_H),一根传输低电平称之为CAN低(CAN_L)。CAN的示意图如下所示。


对于ECU而言,内部包含CAN收发器和CAN控制器。收发器,顾名思义就是用来传输CAN信号的,故会有两个引脚用来接入CAN高和CAN低。而现在的CAN控制器往往集成在了MCU/SOC芯片的内部,也就是说现在ECU中的MCU/SOC往往具备CAN控制功能。以下图为例,MCU计算的数据转换成电流通过电路板上的导线传递给CAN收发器,CAN收发器接收到之后分别向CANH和CANL输入对应的电平(如向CANH输入3.5v,向CANL输入1.5v)。


计算机的世界里面只有0和1,一般而言MCU/SOC和CAN收发器之间约定低电平表示0,高电平表示1。假如此时MCU想要表示数据0,那么它会产生一个低电平传递给can收发器,由于CAN协议规定canh和canl之间存在电压差时表示数据显性状态,即数据0;不存在电压差时表示隐形状态,即数据1,所以此时can收发器收到之后会向canh输入一个高电平,假设是3.5v,向canl输入一个低电平,假设是1.5v。此时在can总线上存在2v的电压差,整个can处于显性状态0,总线上的其他ECU也能感知到电压差,也就知道了它收到了一个二进制数0。同理,如果先要表示逻辑1,canh和canl会输出相同的电压(can总线上不传输数据时,由于内部的上拉电阻和其他原因,canh和canl始终处于相同的电压,不会存在电压差,可以理解为can总线一直处于隐性1的状态)。
通过有没有电压差就能表示逻辑0和1了,后续就可以规定什么样的0 1组合表示什么信息,并在can总线上传输了。
CAN报文结构
CAN帧就是一堆电压差/0和1,这些0或1会按照一定的数量和固定的格式进行排列,共同组成一个具备语义的CAN帧。一个CAN帧划分为七大域:帧起始、仲裁域、控制域、数据域、CRC域、ACK域和帧结束。

- 帧起始(1bit):由于默认状态下can处于隐性1,所以ECU想要发送数据时,必须让can总线上产生波动,因此这个bit位始终是0
- 仲裁域(12bit,标准帧的情况下)
- CAN ID(11bit,标准帧的情况下):CAN总线上存在很多的ECU,主机厂给这些ECU制定了唯一的ID,一个CAN ID表示唯一的一个ECU,因此CAN ID类似于身份证号或者门牌号。总线拓扑的特点就是类似于开会,一个ECU发信息所有的ECU都能收到,但是同一时间只能有一个ECU发送信息,所以CAN协议规定根据CAN ID判决这一时刻到底该由谁发送信息:CAN ID越小,优先级越高,话语权越高。所以这个域叫做仲裁域。
- RTR(1bit):如果是1表示远程请求帧(一般不会存在),如果是0表示数据帧(一般是这个)。
- 控制域(6bit)
- IDE(1bit):如果是1表示扩展帧(此时CAN ID的长度为29位),如果是0表示标准帧。
- 保留位(1bit):一般是0
- DLC(4bit):表示后续数据域的长度,经典CAN中数据的长度范围是0
8字节,064bit。所以,对于经典CAN而言,1000(8)~1111(15)都表示数据域是8个字节。
- 数据域(0~64bit,经典CAN的标准数据帧):实际的业务数据
- CRC域(16bit)
- CRC序列(15bit):通过一定的算法计算[帧起始, 数据域]的全部内容,避免数据(电压)因为环境的影响在传输过程中发生改变。
- CRC界定符(1bit):固定为1
- ACK域(2bit)
- ACK槽(1bit):发送方发完CRC界定符后立即发送一个隐性1,并在规定的时间窗口内(比如2μs)检查总线上的信号是0还是1,因为CAN规定如果接收方确认收到了CRC即以前的所有数据,那么必须立即发送一个显性信号0,让发送方知道它成功接收了。
- ACK界定符(1bit):固定为1
- 帧结束(7bit):7个1
CAN仲裁机制
总线拓扑的特点就是,一个ECU发送报文,总线上的所有ECU都能够收到,如果同一时刻有多个ECU想要发送数据,哪么到底改由谁发送呢。CAN总线的仲裁机制就是为了解决这个问题的。

ECU中的CAN收发器具备同时发送和监听报文的能力,即发送电路在向总线输出电信号的同时,接收电路也在同时监听CANH和CANL的电压。

我们知道CANH和CANL之间有电压差时表示逻辑0,没有电压差时表示逻辑1,而总统一根总线(两根导线)上,有电压差的状态是能够抑制没有电压差的状态,这是物理特性,所以为什么逻辑0也叫做显性状态,逻辑1也叫做隐形状态。因此,同一时刻当所有的ECU在向总线上输入电压表示物理地址时(CAN ID),bit 1会被bit 0所覆盖,导致CAN收发器中的监听电路得到的总线信号和CAN收发器中的发送电路发送的总线信号不一致,此时ECU就不会再进行后续的报文发送了。这就是CAN总线仲裁机制的简单理解,形成的现象可以简记为CAN ID越小,优先级越高。
正是由于这种开始直接发送,仲裁时自动退出的特点,不会干扰最终的仲裁胜出的ECU继续发送报文(不需要再重新发送帧起始和CAN ID了,接着发送后续的bit),所以仲裁机制具备非破坏性。

CAN信号解析
CAN信号指的就是CAN帧数据域中的数据。

CAN协议本身没有规定哪些ECU要传输哪些数据、该如何表示数据、同一个帧中不同数据之间怎么排列,这些数据都是由主机厂自己制定的,所有的信号规定都会记录在一个信号矩阵表里面。同一个ECU一般不可能只产生一种数据,而是有多种,那么为了效率,会在同一帧的数据域中一起存放多种数据,所以信号矩阵表中需要规定每个数据在数据域中的起始位、长度、系数、单位等等。

信号矩阵中的bit起始位并不是按的从左往右的顺序编排的,而是按照下面二维表格的方式定义的bit编号。
最终还原成线性数组应该是这样的,但是不要去还原,计算的时候没有意义,只是为了强调不是线性顺序,计算的时候应始终以二维表格为工具。

现在假设起始位是40、长度为13、系数是0.05625、单位是km/h,想要表示时速为90km/h:先在二维表格中找到编号40的位置 ==> 将当前字节走完(如果是大端序,就往当前字节行中的大编号方向填写;如果是小端序,就往当前字节行中的小编好方向填写) ==> 如果位数不够,向其他字节借位(如果采用摩托罗拉序,就向上一个字节借位,再按照大端/小端填写;如果采用因特尔序,就向下一个字节借位,再按照大端/小端填写)。最终在实际的报文中因该呈现如下形式(假设数据域中暂时没有其他信号):
1 | |

我们从第五个字节和第六个字节中拿出表示车速的二进制数:00110 01000000(这是按照起始位是最低有效位计算的,如果起始位是最高有效位,那么得到的二进制数就应该是00000010 01100),换算成十进制就是1600(原始量),再乘以系数0.05625,最终的结果就是90(物理量),加上单位为90km/h。这里注意:物理量 = 原始量 * 系数 + 偏移量。
CAN FD


RRS:CAN FD中没有远程请求帧,但是为了兼容CAN,所以特定设置了这个位置,值固定为0
IDE:是否是扩展帧。如果是0表示是标准帧,如果是1表示是扩展帧
FDF:报文中的第15个bit。如果这个值是1表示当前是一个CAN FD的报文,ECU后续会按照CAN FD的结构解析后面的数据(比如说第16个bit表示保留位等等);如果这个值是0表示当前是一个经典CAN报文,ECU后续会按照经典CAN结构解析后面的数据(比如第16个bit就进入到了DLC的区域)
BRS:表示传输[BRS, CRC界定符]之间的区域时是否采用另外一种速率(一般来说是更高的)。在该位之前的所有数据全部采用CAN的通信速率传输(总线的默认传输速率),一般来说是500kbit/s。如果想要提高传输速率则将BRS设置为1,那么此时所有的ECU就会按照之前设定的另一种频率进行通信(注意,CAN FD的可变速率并不是实时的,而是指可以采用总线上默认的速率,也可以采用另外一种提前设定好的速率);如果BRS设置为0,那么表示还按照总线的默认速率传输
DLC:CAN FD中,数据域的长度为[0, 64]字节。但是注意,即便是CAN FD,DLC的区域也只有4个bit,而四个比特最多也就表示“1111”16个字节,所以CAN FD中的DLC有些特殊,二进制表示的字节数如下图所示

总线终端电阻
终端电阻的作用主要是减少环境干扰,使得信号更加稳定,减少错误帧的出现,终端电阻一般是120Ω

作用1:消除寄生电容,使显性信号更快地恢复成隐性信号,减少错误帧的出现(假设显性信号对应的电压差是2v且总线没有终端电阻,从显性信号恢复成隐性信号需要4μs,而ECU读取的频率是2μs,那么在2μs时总线上可能还存在0.8v的电压差,对于ECU而言,此时总线仍然表示出显性)

作用2:消除振铃,减少电流回波的干扰,使信号更加稳定

位填充机制
在CAN通信中,连续6个0或者1表示一种特殊的信息——错误帧,所以为了区分错误帧和连续6个bit相同的数据帧,CAN协议规定:只要在发送正常的数据时,如果已经连续发送了5个相同的信号,那么ECU将会自动补充发送一个相反的信号;对于接受而言,当ECU收到5个相同的信号时,会自动忽略第6个信号,不讲它作为数据。

CAN的五种错误
位错误

位填充错误

格式错误

应答错误

CRC错误

CAN节点三状态

常见的恢复策略

快恢复+慢恢复

CAN的错误帧

当节点A检测到格式错误时,将立即发送主动错误帧:“00000011111111”;节点B会同时检测到格式错误,也会立即发送主动错误帧:“00000011111111”;此时这段时间内,总线状态总体呈现“00000011111111”。

当节点A检测到位错误时,立即发送主动错误帧“00000011111111”;下面这个例子中,节点B会在节点A发出第二个0时检测出位填充错误,此时立即发送“00000011111111”。当节点A发送完“000000”想要发送”1“时,节点B仍然在发送显性0,显性信号会吞并隐性信号,总线上总体呈现显性0,此时对于节点A而言,他不会认为自己又发生了位错误,而是会意识到是其他的ECU在发送错误帧,会进入等待状态。等其他ECU发送完显性信号0时,再一起发送”11111111“。
