基于STM32开发板CAN总线通信协议浅析

基于STM32开发板CAN总线通信协议浅析

一、前言

控制器局域网(Controller Area Network,CAN),是由德国BOSCH(博世)公司开发,是目前国际上应用最为广泛的现场总线之一。其特点是可拓展性好,可承受大量数据的高速通信,高度稳定可靠,因此常应用于汽车电子领域、工业自动化、医疗设备等高要求环境。

二、物理层

2.1 Can电气特性

单端信号:是相对于差分信号而言的,单端输入指信号有一个参考端和一个信号端构成,参考端一般为地端。
差分信号:差分传输是一种信号传输的技术,区别于传统的一根信号线一根地线的做法(单端信号),差分传输在这两根线上都传输信号,这两个信号的振幅相等,相位相反。在这两根线上传输的信号就是差分信号。其特点如下:
(1)抗干扰能力强。干扰噪声一般会等值、同时的被加载到两根信号线上,而其差值为0,即,噪声对信号的逻辑意义不产生影响。
(2)能有效抑制电磁干扰(EMI)。由于两根线靠得很近且信号幅值相等,这两根线与地线之间的耦合电磁场的幅值也相等,同时他们的信号极性相反,其电磁场将相互抵消。因此对外界的电磁干扰也小。
(3)时序定位准确。差分信号的接受端是两根线上的信号幅值之差发生正负跳变的点,作为判断逻辑0/1跳变。而普通单端信号以阈值电压作为信号逻辑0/1的跳变点,受阈值电压与信号幅值电压之比的影响较大,不适合低幅度的信号。
CAN总线有两个ISO国际标准:ISO11519 和ISO11898。
ISO11519定义了通信速率为10~125Kbps的低速CAN通信标准,属于开环总线,传输速率为40Kbps时,总线长度可达1000米;
ISO11898定义了通信速率为125Kbps~1 Mbps的高速CAN通信标准,属于闭环总线,传输速率可达1Mbps,总线长度≤40米;
高速CAN主要应用在发动机、变速箱等对实时性、传输速度要求高的场景。低速CAN主要应用在车身控制系统等可靠性要求高的场景,低速CAN在断掉其任一导线后,仍可以继续接收数据,因此在汽车发生交通事故时,使用低速CAN能更大提高设备正常接收数据工作的可能性,提高安全性。
如下图:低速
基于STM32开发板CAN总线通信协议浅析_第1张图片

总线由CAN_H和CAN_L两根线组成,总线上可以挂多个节点设备。每个节点设备由CAN控制器和CAN收发器组成,CAN控制器通常作为外设集成在MPU/MCU上,而CAN收发器则需要外围添加芯片电路。
高速如下图:
基于STM32开发板CAN总线通信协议浅析_第2张图片

类似RS485,CAN也使用差分信号传输数据(两个信号线的振幅相等,相位相反)。CAN总线使用CAN_H和CAN_L的电位差来表示数据电平。电位差分为显性电平和隐性电平,分别表示逻辑0和1。低俗和高速两者物理层电气特性不一样(如下图),因此不能将它们连接在一起。可以看到当CAN_H和CAN_L电压相近,则表示隐性电平,对应逻辑1,当两个电压相差较大,表示显性电平,对应逻辑0。添加链接描述
基于STM32开发板CAN总线通信协议浅析_第3张图片

基于STM32开发板CAN总线通信协议浅析_第4张图片

在CAN总线中,必须使它处于隐性电平(逻辑1)或显性电平(逻辑0)中的其中一个状态。假如有两个CAN通讯节点,在同一时间,一个输出隐性电平,另一个输出显性电平,类似I2C总线的”线与”特性将使它处于显性电平状态,显性电平的名字就是这样来的,即可以认为显性具有优先的意味。
由于CAN总线协议的物理层只有1对差分线,在一个时刻只能表示一个信号,所以对通讯节点来说,CAN通讯是半双工的,收发数据需要分时进行。在CAN的通讯网络中,因为共用总线,在整个网络中同一时刻只能有一个通讯节点发送信号,其余的节点在该时刻都只能接收。

2.2 协议

2.2.1 数据帧
2.2.1.1 种类及结构

CAN是一种基于消息广播模式的串行通信总线,即在同一时刻网络上所有节点监测到的数据是一致的,各节点根据报文ID来甄别是否是发给自己的报文。
CAN总线以“帧”(Frame)的形式进行通信。CAN 总线协议规定了5种帧,分别是数据帧、远程帧、错误帧、超载帧以及帧间隔,其中数据帧最常用
(1)数据帧:发送节点向接收节点传输数据的帧;
(2)远程帧:接收节点向具有相同ID的发送节点请求数据的帧;
(3)错误帧:检测出错时,向其它节点通知错误的帧;
(4)超载帧:接收节点通知其尚未做好接收准备的帧;
(5)帧间隔:将数据帧及远程帧与前面的帧分离开来的帧;
以数据帧为例:
基于STM32开发板CAN总线通信协议浅析_第5张图片

数据帧以一个显性位(逻辑0)开始,以7个连续的隐性位(逻辑1)结束,在它们之间,分别有仲裁段、控制段、数据段、CRC段和ACK段。
帧起始:数据帧的开始的段;帧起始信号只有一个数据位,是一个显性电平,它用于通知各个节点将有数据传输,其它节点通过帧起始信号的电平跳变沿来进行硬同步。
仲裁段:帧优先级的段;和IIC仲裁一样
基于STM32开发板CAN总线通信协议浅析_第6张图片

控制段:数据的字节数及保留位的段;在控制段中的r1和r0为保留位,默认设置为显性位。它最主要的是DLC段(Data Length Code),译为数据长度码,它由4个数据位组成,用于表示本报文中的数据段含有多少个字节,DLC段表示的数字为0~8。
数据段:数据的内容,一帧可发送0~8个字节的数据;
CRC段:校验数据的段;CRC部分的计算一般由CAN控制器硬件完成,出错时的处理则由软件控制最大重发数。在CRC校验码之后,有一个CRC界定符,它为隐性位,主要作用是把CRC校验码与后面的ACK段间隔起来。
ACK段:确认正常接收的段;类似I2C总线,在ACK槽位中,发送节点发送的是隐性位,而接收节点则在这一位中发送显性位以示应答。在ACK槽和帧结束之间由ACK界定符间隔开。
帧结束:数据帧结束的段;帧结束段由发送节点发送的7个隐性位表示结束。
基于STM32开发板CAN总线通信协议浅析_第7张图片

2.2.1.2 通信过程

先规定空闲状态,所谓的空闲状态就是指没有节点正在传输数据的时候,在CAN协议中,当总线上的上出现连续的11位隐性电平,那么总线就处于空闲状态。也就是说对于任意一个节点而言,只要它监听到总线上连续出现了11位隐性电平,那么该节点就会认为总线当前处于空闲状态。
每次发送数据前,节点都会监听总线的状态,如果总线状态为空闲时,它就会立即向总线上发送自己的数据,这个数据里不仅有数据,还有本身的ID信息或者其他的控制指令,应称为数据包(数据帧),也叫做报文。当报文被传输到其它节点时,只要这些节点按格式去解读,就能还原出原始数据。
(报文: 在原始数据段的前面加上传输起始标签、片选(识别)标签、控制标签,在数据的尾段加上 CRC 校验标签、应答标签和传输结束标签。类似这样的数据包就被称为 CAN 的数据帧。为了更有效地控制通讯,CAN 一共规定了 5 种类型的帧,帧也称为报文。)
举个例子,比如总线上有3个节点,节点1设置ID为000100 00110,节点2设置ID为000100 00111,节点3验收滤波ID表中有节点1和节点2的ID号,节点1和节点2同时向节点3发送1字节的信息。
总线空闲,节点1和节点2同时发送帧起始信号,3个节点同时调整位时序(硬同步);
节点1和节点2开始仲裁,两者同时向总线发送第一位0,同时回读总线状态与本身状态相与,得0,两者第1位仲裁均通过;一直持续到第9位1,两者同时向总线发送1,同时回读总线状态,得1,两者第9位仲裁均通过;
直到第11位,当两个节点回读总线状态与本身状态相与时,总线得显性将隐性屏蔽,即总线状态为显性,则节点1得0(与本身状态相同),而节点2得0(与本身状态不同),此时节点1仲裁胜利,节点2放弃发送请求;
从第1位仲裁到第11位仲裁得同时,节点1向其他节点广播了本身的ID,当然节点1本身也接收到节点2的ID信息,因此节点2和节点3也都收到了节点1的ID信息,只不过节点2对节点1不敢兴趣,因而选择了忽略节点1后续的信息,节点3则开始接收节点1的数据;
从硬同步之后,每当节点1和节点2发出一个仲裁位,三个节点的CAN控制器都在检测本身的位时序与总线位时序是否一致,当有相位超前或者滞后时则自动进行位时序的重新同步。在后续的报文传送中亦是如此。

2.2.2 波特率及位同步
由于CAN属于异步通讯,没有时钟信号线,连接在同一个总线网络中的各个节点会像串口异步通讯那样,节点间使用约定好的波特率进行通讯,同时,CAN还会使用”位同步”的方式来抗干扰、吸收误差,实现对总线电平信号进行正确的采样,确保通讯正常。
2.2.2.1位时序分解

为了实现位同步,CAN协议把每一个数据位的时序分解成SS段、PTS段、PBS1段、PBS2段,这四段的长度加起来即为一个CAN数据位的长度。分解后最小的时间单位是Tq,而一个完整的位由8~25个Tq组成。
基于STM32开发板CAN总线通信协议浅析_第8张图片

CAN通讯信号每一个数据位的长度为19Tq,其中SS段占1Tq,PTS段占6Tq,PBS1段占5Tq,PBS2段占7Tq。信号的采样点位于PBS1段与PBS2段之间,通过控制各段的长度,可以对采样点的位置进行偏移,以便准确地采样。
各段作用:
(1)SS段(SYNC SEG):同步段,若通讯节点检测到总线上信号的跳变沿被包含在SS段的范围之内,则表示节点与总线的时序是同步的,当节点与总线同步时,采样点采集到的总线电平即可被确定为该位的电平。SS段的大小固定为1Tq。
(2)PTS段(PROP SEG):传播时间段,用于补偿网络的物理延时时间。是总线上输入比较器延时和输出驱动器延时总和的两倍。PTS段的大小可以为1~8Tq。
(3)PBS1段(PHASE SEG1):相位缓冲段,主要用来补偿边沿阶段的误差,它的时间长度在重新同步的时候可以加长。PBS1段的初始大小可以为1~8Tq。
(4)PBS2段(PHASE SEG2):另一个相位缓冲段,也是用来补偿边沿阶段误差的,它的时间长度在重新同步时可以缩短。PBS2段的初始大小可以为2~8Tq。

2.2.2.2波特率

总线上的各个通讯节点只要约定好1个Tq的时间长度以及每一个数据位占据多少个Tq,就可以确定CAN通讯的波特率。
例如,假设上图中的1Tq=1us,而每个数据位由19个Tq组成,则传输一位数据需要时间T1bit =19us,从而每秒可以传输的数据位个数为:
1x106/19 = 52631.6 (bps)这个每秒可传输的数据位的个数即为通讯中的波特率。
2.2.2.3同步过程分析
波特率只是约定了每个数据位的长度,数据同步还涉及到相位的细节,这个时候就需要用到数据位内的SS、PTS、PBS1及PBS2段了。
根据对段的应用方式差异,CAN的数据同步分为硬同步和重新同步。其中硬同步只是当存在”帧起始信号”时起作用,无法确保后续一连串的位时序都是同步的,而重新同步方式可解决该问题,这两种方式具体介绍如下:
(1)硬同步
若某个CAN节点通过总线发送数据时,它会发送一个表示通讯起始的信号,该信号是一个由高变低的下降沿。而挂载到CAN总线上的通讯节点在不发送数据时,会时刻检测总线上的信号。
基于STM32开发板CAN总线通信协议浅析_第9张图片

可以看到当总线出现帧起始信号时,某节点检测到总线的帧起始信号不在节点内部时序的SS段范围,所以判断它自己的内部时序与总线不同步,因而这个状态的采样点采集得的数据是不正确的。所以节点以硬同步的方式调整,把自己的位时序中的SS段平移至总线出现下降沿的部分,获得同步,同步后采样点就可以采集得正确数据了。
(2)重新同步
前面的硬同步只是当存在帧起始信号时才起作用,如果在一帧很长的数据内,节点信号与总线信号相位有偏移时,这种同步方式就无能为力了。因而需要引入重新同步方式,它利用普通数据位的高至低电平的跳变沿来同步(帧起始信号是特殊的跳变沿)。重新同步与硬同步方式相似的地方是它们都使用SS段来进行检测,同步的目的都是使节点内的SS段把跳变沿包含起来。
重新同步的方式分为超前和滞后两种情况,以总线跳变沿与SS段的相对位置进行区分。第一种相位超前的情况节点从总线的边沿跳变中,检测到它内部的时序比总线的时序相对超前2Tq,这时控制器在下一个位时序中的PBS1段增加 2Tq的时间长度,使得节点与总线时序重新同步。
基于STM32开发板CAN总线通信协议浅析_第10张图片

在重新同步的时候,ΔPBS1和ΔPBS2被定义为”重新同步补偿宽度。
第二种相位滞后的情况节点从总线的边沿跳变中,检测到它的时序比总线的时序相对滞后2Tq,这时控制器在前一个位时序中的PBS2段减少2Tq的时间长度,获得同步。
基于STM32开发板CAN总线通信协议浅析_第11张图片

2.2.3 工作模式

主要有3个工作模式:初始化、正常和睡眠模式。
这里我们主要讲解正常模式;
正常模式即,此时可以正常向节点发送和接收数据,分为静默模式和回环模式两种类型。

2.2.3.1 静默模式

节点的输出端的逻辑0数据会直接传输到自己的输入端,逻辑1可以被发送到总线,所以它不能向总线发送显性位(逻辑0), 只能发送隐性位(逻辑1),而不能正真发送报文。输入端可以从总线接收内容。
由于它只可发送的隐性位不会强制影响总线的状态,所以把它称为静默模式。这种模式一般用于监测,它可以用于分析总线上的流量,但又不会因为发送显性位而影响总线。
基于STM32开发板CAN总线通信协议浅析_第12张图片

2.2.3.2 回环模式

节点输出端的所有内容都直接传输到自己的输入端,输出端的内容同时也会被传输到总线上,即也可使用总线监测它的发送内容。输入端只接收自己发送端的内容,不接收来自总线上的内容。使用回环模式可以进行自检。
CAN 内核忽略确认错误(在数据/远程帧的确认位时刻,不检测是否有显性位)。在环回模式下,bxCAN 在内部把 Tx 输出回馈到 Rx 输入上,而完全忽略 CANRX 引脚的实际状态。发送的报文可以在 CANTX 引脚上检测到。
基于STM32开发板CAN总线通信协议浅析_第13张图片

回环静默模式是以上两种模式的结合,节点的输出端的所有内容都直接传输到自己的输入端,并且不会向总线发送显性位影响总线,不能通过总线监测它的发送内容。输入端只接收自己发送端的内容,不接收来自总线上的内容。这种方式可以在“热自检”时使用,即自我检查的时候,不会干扰总线。
回环静默模式是以上两种模式的结合,节点的输出端的所有内容都直接传输到自己的输入端,并且不会向总线发送显性位影响总线,不能通过总线监测它的发送内容。输入端只接收自己发送端的内容,不接收来自总线上的内容。这种方式可以在“热自检”时使用,即自我检查的时候,不会干扰总线。(回环模式下总线是可以接收到自检节点的报文的,而回环静默模式下,节点既不向总线发送数据也不接收数据)
基于STM32开发板CAN总线通信协议浅析_第14张图片

2.3.4 邮箱

邮箱即软件与硬件间传递报文的接口。邮箱中包含了所有和报文有光的信息:标识符、数据、控制、状态和时间戳。

2.3.4.1 发送邮箱

共有3个发送邮箱供软件来发送报文。发送调度器根据优先级决定哪个邮箱的报文先被发送。数据在发送前都会被送到优先级最高且空闲的发送邮箱,然后依次发送。 “发送邮箱有3个,且每个邮箱只能装一个报文”。
软件需要在一个空的发送邮箱中,把待发送报文的各种信息设置好(然后再发出发送的请求)。发送的状态可通过查询CAN_TSR寄存器获知

2.3.4.2 接收邮箱

共有2个接收FIFO,每个FIFO都可以存放3个完整的报文。它们完全由硬件来管理。
在接收数据端会有一个过滤器处于“接收邮箱”的前面,过滤器是用于删选“标识符”的,只有标识符符合的报文才会被放入到“接收邮箱”当中。“接收邮箱不同于发送邮箱,接收邮箱只有2(FIFO0、FIFO1)个,但是每一个有三层,每层都可以存放一个报文,即每一个接收邮箱可以接收三个报文。但读取时只能读到最先收到的报文,等这个读完之后,才能读下一个报文”。

基于STM32开发板CAN总线通信协议浅析_第15张图片

基于STM32开发板CAN总线通信协议浅析_第16张图片

注:具体邮箱使用配置在代码实例中,由库函数寻找空的邮箱发送

三、程序示例(以回环模式为例)

3.1 过滤器

过滤器的配置很重要,不然是收不到想要的CAN消息的;但是也可以都设置成0x0000,不做任何过滤;每当收到一个报文,CAN就将这个报文先与FIFO_0关联的过滤器比较,如果被匹配,就将此报文放入FIFO_0中。如果不匹配,再将报文与FIFO_1关联的过滤器比较,如果被匹配,该报文就放入FIFO_1中。如果还是不匹配,此报文就被丢弃。
基于STM32开发板CAN总线通信协议浅析_第17张图片

过滤器模式:
根据标准标识符和扩展标识符分为两类:
(1)列表模式:“列表模式”中的过滤器会将设置好的所需的ID与报文中的标识符进行比较,只有每个位数据都相同时才视为匹配。因其这样的特性,所以只有唯一的标识符能成功进入接收邮箱。
(2)屏蔽模式:“屏蔽模式”的过滤器有两个值,“ID值” & “屏蔽值“。通过这两个值的配合与报文中的标识符进行比较从而删选出想要的报文。简单来说就是屏蔽码CAN_FxR1的某一位为1时,则CAN_FxR0中相应的位必须与收到的帧的标志符中的相应位吻合才能通过过滤器;反之为0时,相应位可不必与收到的帧进行匹配。
每个FIFO的所有过滤器都是并联的,只要通过了其中任何一个过滤器,该报文就有效。需要注意的是,每个FIFO必须至少激活一个过滤器,它才有可能收到报文。如果一个过滤器都没有激活,那么是所有报文都报废的。

3.2 发送

如果我们要发送数据帧,则还要定义数据的长度。不管是数据帧还是遥控帧,我们可以决定这一帧是使用标准ID还是扩展ID,以及相应ID的内容。
基于STM32开发板CAN总线通信协议浅析_第18张图片

发送函数:
HAL_StatusTypeDef HAL_CAN_AddTxMessage(CAN_HandleTypeDef *hcan, CAN_TxHeaderTypeDef *pHeader, uint8_t aData[], uint32_t *pTxMailbox);
参数:
*hcan :can的句柄,由CubeMX自动帮我们定义
*pHeader :发送结构体
aData[] :要发送的数据
*pTxMailbox :发送这条报文用的是哪个邮箱,这个作为输出参数。(因为STM32的CAN外设拥有三个发送邮箱,库函数会帮我们找到空的邮箱并把一帧报文装进去,这个参数便记录用到的邮箱号,具体怎么用目前还不清楚。因为CAN总线可能拥挤或是报文被抢占,因此数据并不是填到FIFO中就能马上发出去的,而是要等到合适的时机才能发出去)
基于STM32开发板CAN总线通信协议浅析_第19张图片

3.3 接收

CAN接收一般采用中断方式,图像化界面配置时如下:
基于STM32开发板CAN总线通信协议浅析_第20张图片

有两个中断,一个是FIFO0收到数据的RX0中断,另一个是FIFO1收到数据的RX1中断,这里只用到了FIFO0,所以只勾选这个。(这里也说一说自己的理解,由于一个FIFO只能保存3条报文,有了两个FIFO就能保存6条报文。我们可以通过筛选器把不同ID的报文装进不同的FIFO,比如我们可以让FIFO0来接收关键、重要的报文,用FIFO1来接收不那么重要的报文,并且这两个中断是独立的,我们甚至可以给它们配置不一样的中断优先级。)
中断开启,同时打开FIFO消息挂起中断(外设中断使能,相当于串口中断使能)
HAL_CAN_ActivateNotification(&hcan1, CAN_IT_RX_FIFO0_MSG_PENDING);

接收函数如下:
HAL_StatusTypeDef HAL_CAN_GetRxMessage(CAN_HandleTypeDef *hcan, uint32_t RxFifo, CAN_RxHeaderTypeDef *pHeader, uint8_t aData[]);
参数:
*hcan :can的句柄,由CubeMX自动帮我们定义
RxFifo :接收FIFO号。参数: CAN_RX_FIFO0 或 CAN_RX_FIFO1
pHeader :接收结构体,这里作为输出参数
aData[] :接收数组,这里作为输出参数

你可能感兴趣的:(STM32,stm32,单片机,嵌入式硬件)