上一篇文章已经简述了CAN总线的一些基本特性和数据的时序位的构成,接下来分析CAN总线的协议构成! CAN的位同步数据同步 (1)CAN的位同步 在CAN中使用了位同步的方式来抵抗干扰、吸收误差,实现对总线电平信号的正常采样,确保通讯正常进行。同时,这个位同步也是用于调节通信过程中的采样点的。 (2)CAN的数据同步 CAN的数据同步使用到SS段、PTS段、PBS1段、PBS2段,并且数据的同步分为硬同步、重新同步。 1)硬同步 CAN节点希望通过总线发送数据时,会发送一个由高变低的下降沿作为通讯的起始信号;而节点不发送数据时会时刻检测总线上的信号。 一个硬同步的过程如下图示例: 从上图中可以看到当总线上出现了帧起始信号时,某一个节点检测到总线的帧起始信号不在该节点内部时序的SS段范围,所以就可以判断它自己的内部时序与总线不同步,因而这种状态下的采样点采集得的数据是不正确的。所以节点以硬同步的方式调整,把自己的位时序中的SS段平移至总线出现下降沿的部分,获得同步,同步后采样点就可以采集得正确数据了。 2)重新同步 硬同步是存在帧起始信号时才起作用,但是假如是一帧很长的数据,这一长串数据内不再出现帧起始信号,那么在节点信号与总线信号出现相位偏移时,用硬同步方式就行不通了。 所以就有了重新同步的方式,这种方式利用普通数据位的电平的高至低的跳变沿来同步同样都是在SS段中进行检测,从而实现同步的目的。 注意:同步的目的都是为了能在节点内的SS段把跳变沿包含起来。 重新同步可以细分为两种同步方式:相位超前重新同步和相位滞后重新同步。这两种方式以总线跳变沿与SS段的相对位置进行区分的。 3)相位超前重新同步 如下图所示: 上图中可以看到,节点的SS段相对于总线的边沿跳变往前了两个Tq的时间,即节点的时序比它检测的总线时序相对超前了2Tq。 解决这个问题可以在下一个位时序中的PBS1段增加2Tq的时间长度,使得节点与总线时序重新同步,如下图: 4)相位滞后重新同步 如下图所示: 上图中可以看到,节点的SS段相对于总线的边沿跳变延迟了两个Tq的时间,即节点的时序比它检测的总线时序相对落后了2Tq。 解决这个问题可以在下一个位时序中的PBS2段减少2Tq的时间长度,使得节点与总线时序重新同步,如下图: CAN的帧种类和用途 CAN的帧种类有如下几种: 特别地,数据帧和遥控帧有标准格式和扩展格式两种格式。标准格式有11个位的标识符ID 扩展格式有29个位的标识符ID CAN总线的数据帧 数据帧一般由7个段构成,即: 这几个段的作用如下: 1)帧起始。表示数据帧开始的段。 2)仲裁段。表示该帧优先级的段,即ID信息。 3)控制段。表示数据的字节数及保留位的段。 4)数据段。数据的内容,一帧可发送08个字节的数据。 5)CRC段。检查帧的传输错误的段。 6)ACK段。表示确认正常接收的段。 7)帧结束。表示数据帧结束的段。 CAN的数据帧有标准格式和扩展格式两种,这两者不同的地方如下图如下: 数据帧的标准格式和扩展格式两者的不同之处主要在于仲裁段中,控制段中有细微的不同。 1)标准格式的ID是11位。 从ID28到ID18一次发送,禁止高7位都为隐形(禁止ID1111111XXXX)。 2)扩展格式的ID有29个位。 基本ID从ID28到ID18,扩展ID由ID17到ID0表示。基本ID和标准格式的ID相同。 RTR位:帧选择位 0:数据帧1:远程帧 IDE位: 0:标准标识符1:扩展标识符 SRR位: 远程请求位,为隐形位,代替了标准帧中的RTR位。 r0、r1位: 保留位,发送时必须全部是显性电平,但是接收时可以是显性、隐形、任意组合的电平。 (1)起始帧 CAN的数据帧和远程帧开始发送时,是需要发送一个开始的标志的,称之为帧起始。它是一个显性位(逻辑0)。 一个CAN节点只有在总线处于空闲状态时才可以发送起始帧。 (2)仲裁段 起始帧发送完成之后,紧接着发送出的就是仲裁段的数据。 CAN2。0A的仲裁场一共有12位,如下图所示。 在这12位中,前11位表示的是11位标识符,第12位是远程发送请求RTR。在数据帧中RTR为显性,在远程帧中RTR为隐性。 如果相同标识符的数据帧与远程帧发生冲突,数据帧优先。 CAN2。0B的仲裁场一共有32位,它在CAN2。0A的基础上,将CANID扩展到了29位,并且向CAN2。0A兼容,如下图所示。 (3)控制段 仲裁之段后便是控制场。控制场的头两位为保留位(R1、R0),为隐性。 后面是数据长度代码DLC(DataLengthCode)。数据长度代码指示了数据场中有效的字节个数。DLC的长度为4位二进制数,虽然可以最大范围可以表示到015,但是由于CAN总线的数据域长度最大为8个字节,所以DLC的大小可以认为是最大为8。 控制场示意图如下: 详细示意图如下: (4)数据段 控制场传输完成之后,紧接着传输的就是数据场了,数据场里面传输的就是我们想要传输的数据,长度为8个字节,如下图所示。 详细示意图如下: (5)CRC段 CAN数据每次发送的时候,都会将CAN数据帧里面的有效数据进行CRC校验,并且将最终生成的CRC信息一起包含在数据帧中的CRC域内进行发送。 接收端接收到一帧CAN总线数据后,会将接收到的数据进行CRC计算,并且同发出端的CRC校验码进行比较,如果相同,则代表当前接收到的信息是正确的。 CRC段的示意如下: CRC校验域的格式如下图所示。 在经典CAN中,使用15位CRC。在硬件可使用移位和异或运算完成CRC的计算。CAN总线中使用的几种CRC生成多项式公式如下图所示。 (6)应答段 CAN总线的应答场长度为2个位,包含应答间隙(ACKSLOT)和应答界定符(ACKDELIMITER)。 在应答场里,发送站发送两个隐性位。当接收器正确地接收到有效的报文,接收器就会在应答间隙(ACKSLOT)期间(发送ACK信号)向发送器发送一显性的位以示应答。 应答间隙:所有接收到匹配CRC序列(CRCSEQUENCE)的站会在应答间隙(ACKSLOT)期间用以显性的位写入发送器的隐性位来作出回答。 ACK界定符:ACK界定符是ACK场的第二个位,并且是一个必须为隐性的位。因此,应答间隙(ACKSLOT)被两个隐性的位所包围,也就是CRC界定符(CRCDELIMITER)和ACK界定符(ACKDELIMITER)。 CAN总线的应答场如下图所示: (7)帧结束 应答段之后的7位数据是CAN总线的结束帧,是为7位连续的1(隐性电平),如下图所示。 CAN通信的数据段示例 下图可以看到一个CAN数据帧排列的所有数据域。下图展示了一个完整的数据段的通信过程,如下图: STM32的CAN的配置示例 这里以STM32F407的CAN外设的配置为例。代码如下: 配置CAN1,并配置使用CAN1中断接收CAN消息:GPIOInitTypeDefGPIOInitStructure;CANInitTypeDefCANInitStructure;CANFilterInitTypeDefCANFilterInitStructure;NVICInitTypeDefNVICInitStructure;RCCAHB1PeriphClockCmd(RCCAHB1PeriphGPIOA,ENABLE);使能PORTA时钟RCCAPB1PeriphClockCmd(RCCAPB1PeriphCAN1,ENABLE);使能CAN1时钟GPIOInitStructure。GPIOPinGPIOPin11GPIOPin12;GPIOInitStructure。GPIOModeGPIOModeAF;复用功能GPIOInitStructure。GPIOOTypeGPIOOTypePP;推挽输出GPIOInitStructure。GPIOSpeedGPIOSpeed100MHz;100MHzGPIOInitStructure。GPIOPuPdGPIOPuPdUP;上拉GPIOInit(GPIOA,GPIOInitStructure);初始化PA11,PA12GPIOPinAFConfig(GPIOA,GPIOPinSource11,GPIOAFCAN1);GPIOA11复用为CAN1GPIOPinAFConfig(GPIOA,GPIOPinSource12,GPIOAFCAN1);GPIOA12复用为CAN1CANInitStructure。CANTTCMDISABLE;非时间触发通信模式CANInitStructure。CANABOMDISABLE;软件自动离线管理CANInitStructure。CANAWUMDISABLE;睡眠模式通过软件唤醒(清除CANMCR的SLEEP位)CANInitStructure。CANNARTENABLE;启动禁止自动重传,即不自动重传CANInitStructure。CANRFLMDISABLE;报文不锁定,新的覆盖旧的CANInitStructure。CANTXFPDISABLE;优先级由报文标识符决定CANInitStructure。CANModeCANModeNormal;模式设置CANInitStructure。CANSJWCANSJW1tq;重新同步跳跃宽度(Tsjw)为tsjw1个时间单位CANSJW1tqCANSJW4tqCANInitStructure。CANBS1CANBS17tq;Tbs1范围CANBS11tqCANBS116tqCANInitStructure。CANBS2CANBS26tq;Tbs2范围CANBS21tqCANBS28tqCANInitStructure。CANPrescaler6;分频系数(Fp)为brp1波特率Fpclk1((BS11BS211)Prescaler),即42M((671)6)500KbpsCANInit(CAN1,CANInitStructure);初始化CAN1CANFilterInitStructure。CANFilterNumber0;过滤器0CANFilterInitStructure。CANFilterModeCANFilterModeIdMask;CANFilterInitStructure。CANFilterScaleCANFilterScale32bit;32位CANFilterInitStructure。CANFilterIdHigh0x0000;32位IDCANFilterInitStructure。CANFilterIdLow0x0000;CANFilterInitStructure。CANFilterMaskIdHigh0x0000;32位MASKCANFilterInitStructure。CANFilterMaskIdLow0x0000;CANFilterInitStructure。CANFilterFIFOAssignmentCANFilterFIFO0;过滤器0关联到FIFO0CANFilterInitStructure。CANFilterActivationENABLE;激活过滤器0CANFilterInit(CANFilterInitStructure);滤波器初始化CANITConfig(CAN1,CANITFMP0,ENABLE);FIFO0消息挂号中断允许。NVICInitStructure。NVICIRQChannelCAN1RX0IRQn;NVICInitStructure。NVICIRQChannelPreemptionPriority6;NVICInitStructure。NVICIRQChannelSubPriority0;NVICInitStructure。NVICIRQChannelCmdENABLE;NVICInit(NVICInitStructure); 作者简介: 本人95后技术男,从事嵌入式软件开发,专注于技术成长和技术分享。目标是每天进一步一点点,通过技术改变自己的生活,创造自己的美好未来!如果你也对嵌入式感兴趣,欢迎关注我呀! 声明: 本文作者:嵌入式之入坑笔记 文章版权归作者所有,转载请注明出处!