CAN
目录
CAN总线协议
总述
CAN总线(Controller Area Network Bus)控制器局域网总线
CAN总线是由BOSCH公司开发的一种简洁易用、传输速度快、易扩展、可靠性高的串行通信总线,广泛应用于汽车、嵌入式、工业控制等领域
特征
-
两根通信线(CAN_H、CAN_L),线路少
-
差分信号通信,抗干扰能力强
-
高速CAN(ISO11898):125k~1Mbps, <40m
-
低速CAN(ISO11519):10k~125kbps, <1km
-
异步,无需时钟线,通信速率由设备各自约定
-
半双工,可挂载多设备,多设备同时发送数据时通过仲裁判断先后顺序
-
11位/29位报文ID,用于区分消息功能,同时决定优先级
-
可配置1~8字节的有效载荷
-
可实现广播式和请求式两种传输方式
-
应答、CRC校验、位填充、位同步、错误处理等特性
硬件电路
-
每个设备通过CAN收发器挂载在CAN总线网络上
-
CAN控制器引出的TX和RX与CAN收发器相连,CAN收发器引出的CAN_H和CAN_L分别与总线的CAN_H和CAN_L相连
-
高速CAN使用闭环网络,CAN_H和CAN_L两端添加120Ω的终端电阻

- 低速CAN使用开环网络,CAN_H和CAN_L其中一端添加2.2kΩ的终端电阻

电平标准
CAN总线采用差分信号,即两线电压差(VCAN_H-VCAN_L)传输数据位
-
高速CAN规定:
-
电压差为0V时表示逻辑1(隐性电平)
-
电压差为2V时表示逻辑0(显性电平)

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

CAN收发器 - TJA1050(高速CAN)

CAN总线帧格式
| 帧类型 | 用途 |
|---|---|
| 数据帧 | 发送设备主动发送数据(广播式) |
| 遥控帧 | 接收设备主动请求数据(请求式) |
| 错误帧 | 某个设备检测出错误时向其他设备通知错误 |
| 过载帧 | 接收设备通知其尚未做好接收准备 |
| 帧间隔 | 用于将数据帧及遥控帧与前面的帧分离开 |
数据帧
图示

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

错误帧
总线上所有设备都会监督总线的数据,一旦发现“位错误”或“填充错误”或“CRC错误”或“格式错误”或“应答错误” ,这些设备便会发出错误帧来破坏数据,同时终止当前的发送设备

过载帧
当接收方收到大量数据而无法处理时,其可以发出过载帧,延缓发送方的数据发送,以平衡总线负载,避免数据丢失

帧间隔
将数据帧和遥控帧与前面的帧分离开

图中下面部分是被动错误状态的帧间隔。
位填充规则
发送方每发送5个相同电平后,自动追加一个相反电平的填充位,接收方检测到填充位时,会自动移除填充位,恢复原始数据
- 例如:
即将发送: 100000110 10000011110 0111111111110
实际发送: 1000001110 1000001111100 011111011111010
实际接收: 1000001110 1000001111100 011111011111010
移除填充后: 100000110 10000011110 0111111111110
-
位填充作用:
-
增加波形的定时信息,利于接收方执行“再同步”,防止波形长时间无变化,导致接收方不能精确掌握数据采样时机
-
将正常数据流与“错误帧”和“过载帧”区分开,标志“错误帧”和“过载帧”的特异性
-
保持CAN总线在发送正常数据流时的活跃状态,防止被误认为总线空闲
位时序与同步
CAN总线没有时钟线,总线上的所有设备通过约定波特率的方式确定每一个数据位的时长
发送方以约定的位时长每隔固定时间输出一个数据位
接收方以约定的位时长每隔固定时间采样总线的电平,输入一个数据位
理想状态下,接收方能依次采样到发送方发出的每个数据位,且采样点位于数据位中心附近
问题可能
- 接收方以约定的位时长进行采样,但是采样点没有对齐数据位中心附近

- 接收方刚开始采样正确,但是时钟有误差,随着误差积累,采样点逐渐偏离

位时序
为了灵活调整每个采样点的位置,使采样点对齐数据位中心附近,CAN总线对每一个数据位的时长进行了更细的划分,分为同步段(SS)、传播时间段(PTS)、相位缓冲段1(PBS1)和相位缓冲段2(PBS2),每个段又由若干个最小时间单位(Tq)构成

硬同步
每个设备都有一个位时序计时周期,当某个设备(发送方)率先发送报文,其他所有设备(接收方)收到SOF的下降沿时,接收方会将自己的位时序计时周期拨到SS段的位置,与发送方的位时序计时周期保持同步
硬同步只在帧的第一个下降沿(SOF下降沿)有效
经过硬同步后,若发送方和接收方的时钟没有误差,则后续所有数据位的采样点必然都会对齐数据位中心附近
再同步
若发送方或接收方的时钟有误差,随着误差积累,数据位边沿逐渐偏离SS段,则此时接收方根据再同步补偿宽度值(SJW)通过加长PBS1段,或缩短PBS2段,以调整同步
再同步可以发生在第一个下降沿之后的每个数据位跳变边沿

-
调整量限制:≤ SJW(1-4个时间单位)
-
调整方向:只能调整相位缓冲段(不能动同步段)
- 调整效果:持续到下次边沿检测
- 逐位调整:每个位都可能触发调整
波特率
$$ 波特率 = \frac{1}{一个数据位的时长 }= \frac{1}{T_{SS} + T_{PTS} + T_{PBS1} + T_{PBS2}} $$
- 例如:
SS = 1Tq,PTS = 3Tq,PBS1 = 3Tq,PBS2 = 3Tq
Tq = 0.5us
波特率 = 1 / (0.5us + 1.5us + 1.5us + 1.5us) = 200kbps
多设备仲裁
CAN总线只有一对差分信号线,同一时间只能有一个设备操作总线发送数据,若多个设备同时有发送需求,该如何分配总线资源?
解决问题的思路:制定资源分配规则,依次满足多个设备的发送需求,确保同一时间只有一个设备操作总线
先到先得原则
-
若当前已经有设备正在操作总线发送数据帧/遥控帧,则其他任何设备不能再同时发送数据帧/遥控帧(可以发送错误帧/过载帧破坏当前数据)
-
任何设备检测到连续11个隐性电平,即认为总线空闲,只有在总线空闲时,设备才能发送数据帧/遥控帧
-
一旦有设备正在发送数据帧/遥控帧,总线就会变为活跃状态,必然不会出现连续11个隐性电平,其他设备自然也不会破坏当前发送
-
若总线活跃状态其他设备有发送需求,则需要等待总线变为空闲,才能执行发送需求
非破坏性仲裁
若多个设备的发送需求同时到来或因等待而同时到来,则CAN总线协议会根据ID号(仲裁段)进行非破坏性仲裁,ID号小的(优先级高)取到总线控制权,ID号大的(优先级低)仲裁失利后将转入接收状态,等待下一次总线空闲时再尝试发送
实现非破坏性仲裁需要两个要求:
-
线与特性:总线上任何一个设备发送显性电平0时,总线就会呈现显性电平0状态,只有当所有设备都发送隐性电平1时,总线才呈现隐性电平1状态,即:0 & X & X = 0,1 & 1 & 1 = 1
-
回读机制:每个设备发出一个数据位后,都会读回总线当前的电平状态,以确认自己发出的电平是否被真实地发送出去了,根据线与特性,发出0读回必然是0,发出1读回不一定是1
这样,我们就可以理解CAN总线是怎么实现非破坏性仲裁的,以两个设备为例:
-
两个设备不知道对方的存在。
-
两个设备同时开始(SS),回读总线为SS,发送无误。
- 两个设备依次发送ID号,前面几位均是0,或者同样是1,设备回读时均无误。
- 当首次两设备的发送ID位号不一样,发送1的设备回读失败,则会退出发送,即表明ID号大的仲裁失败。
同时,若数据帧和遥控帧ID号一样时,数据帧的优先级高于遥控帧。(因为遥控帧的RTR位为1,同样在仲裁段内)
标准格式11位ID号和扩展格式29位ID号的高11位一样时,标准格式的优先级高于扩展格式(SRR必须始终为1,以保证此要求)
错误
错误类型

错误状态
-
主动错误状态的设备正常参与通信并在检测到错误时发出主动错误帧
-
被动错误状态的设备正常参与通信但检测到错误时只能发出被动错误帧
-
总线关闭状态的设备不能参与通信
-
每个设备内部管理一个TEC和REC,根据TEC和REC的值确定自己的状态。TEC和REC是用来衡量设备的可信度的。

错误值变动

CAN外设
以STM32为例。
-
STM32内置bxCAN外设(CAN控制器),支持CAN2.0A和2.0B,可以自动发送CAN报文和按照过滤器自动接收指定CAN报文,程序只需处理报文数据而无需关注总线的电平细节
-
波特率最高可达1兆位/秒
-
3个可配置优先级的发送邮箱
-
2个3级深度的接收FIFO
-
14个过滤器组(互联型28个)
-
时间触发通信、自动离线恢复、自动唤醒、禁止自动重传、接收FIFO溢出处理方式可配置、发送优先级可配置、双CAN模式
-
STM32F103C8T6 CAN资源:CAN1
CAN网拓扑结构

电路参考

CAN框图

结构示意

发送流程
基本流程:选择一个空置邮箱→写入报文 →请求发送

- RQCP(Request Completed)
- 0 = 发送请求进行中
- 1 = 发送请求已完成(需软件清零)
- TXOK(Transmission OK)
- 0 = 发送请求进行中
- 1 = 发送请求已完成(需软件清零)
- TME(Transmit Mailbox Empty)
- TXRQ(Transmit Request)
- ABRQ(Abort Request):中止请求
- NART(No Automatic Retransmission)
接收流程
基本流程:接收到一个报文→匹配过滤器后进入FIFO 0或FIFO 1→CPU读取

- FMP(FIFO Message Pending)
- RFOM(Release FIFO Output Mailbox)
- FOVR(FIFO Overrun)
配置位说明
-
NART(Not Auto ReTransmit):置1,关闭自动重传,CAN报文只被发送1次,不管发送的结果如何(成功、出错或仲裁丢失);置0,自动重传,CAN硬件在发送报文失败时会一直自动重传直到发送成功
-
TXFP:置1,优先级由发送请求的顺序来决定,先请求的先发送;置0,优先级由报文标识符来决定,标识符值小的先发送(标识符值相等时,邮箱号小的报文先发送)
-
RFLM:置1,接收FIFO锁定,FIFO溢出时,新收到的报文会被丢弃;置0,禁用FIFO锁定,FIFO溢出时,FIFO中最后收到的报文被新报文覆盖
过滤器
由上面的框图知道,由一系列过滤器(STM32F103是14个),每个过滤器可以链接一个FIFO,过滤得到的信息会存入对应FIFO。
每个过滤器的核心由两个32位寄存器组成:R1[31:0]和R2[31:0],用于过滤指定ID(黑名单或者白名单)
- FSCx:位宽设置
-
置0,16位;置1,32位
-
FBMx:模式设置
-
置0,屏蔽模式;置1,列表模式
-
FFAx:关联设置
-
置0,FIFO 0;置1,FIFO 1
-
FACTx:激活设置
- 置0,禁用;置1,启用

说明
- STID为标准ID,EXID为拓展ID
- 若为屏蔽格式,则ID对应一个位宽的位置要设置为过滤掩码(Mask)
示例

位时间特性

波特率 = APB1时钟频率 / 分频系数 / 一位的Tq数量
= 36MHz / (BRP[9:0]+1) / (1 + (TS1[3:0]+1) + (TS2[2:0]+1))
中断
STM32F103 CAN外设占用4个专用的中断向量
-
发送中断:发送邮箱空时产生
-
FIFO 0中断:收到一个报文/FIFO 0满/FIFO 0溢出时产生
-
FIFO 1中断:收到一个报文/FIFO 1满/FIFO 1溢出时产生
-
状态改变错误中断:出错/唤醒/进入睡眠时产生

时间触发通信
-
TTCM:置1,开启时间触发通信功能;置0,关闭时间触发通信功能
-
CAN外设内置一个16位的计数器,用于记录时间戳
-
TTCM置1后,该计数器在每个CAN位的时间自增一次,溢出后归零
-
每个发送邮箱和接收FIFO都有一个TIME[15:0]寄存器,发送帧SOF时,硬件捕获计数器值到发送邮箱的TIME寄存器,接收帧SOF时,硬件捕获计数器值到接收FIFO的TIME寄存器
-
发送邮箱可配置TGT位,捕获计数器值的同时,也把此值写入到数据帧数据段的最后两个字节,为了使用此功能,DLC必须设置为8

错误处理和离线恢复
-
TEC和REC根据错误的情况增加或减少
-
ABOM:置1,开启离线自动恢复,进入离线状态后,就自动开启恢复过程;置0,关闭离线自动恢复,软件必须先请求进入然后再退出初始化模式,随后恢复过程才被开启
