CAN及其应用
简介
CAN 总线由德国BOSCH公司开发,是一种多主控消息广播系统,其最大信号传输速率为1Mbps。与USB或以太网等传统网络不同,CAN 不会在中央总线主控的监督下从节点A向节点B点对点发送大量数据包。在CAN网络中,许多短消息(如温度或发动机转速)会广播到整个网络,从而确保系统每个节点的数据一致性。CAN 是国际标准化组织 (ISO) 定义的串行通信总线,最初是为汽车行业开发的,旨在用双线总线取代复杂的线束。该规范要求具有较高的抗电气干扰能力以及自我诊断和修复数据错误的能力。这些特性使得 CAN 在楼宇自动化、医疗和制造业等各种行业中广受欢迎。
CAN具有以下特点:
-
多主控制。在总线空闲时,所有单元都可以发送消息(多主控制),而两个以上的单元同时开始发送消息时,根据标识符(Identifier以下称为ID)决定优先级。ID并不是表示发送的目的地址,而是表示访问总线的消息的优先级。两个以上的单元同时开始发送消息时,对各消息ID的每个位进行逐个仲裁比较。仲裁获胜(被判定为优先级最高)的单元可继续发送消息,仲裁失利的单元则立刻停止发送而进行接收工作。
-
系统的柔软性。与总线相连的单元没有类似于“地址”的信息。因此在总线上增加单元时,连接在总线上的其它单元的软硬件及应用层都不需要改变。
-
通信速度较快,通信距离远。最高1Mbps(距离小于40M),最远可达10KM(速率低于5Kbps)。
-
具有错误检测、错误通知和错误恢复功能。所有单元都可以检测错误(错误检测功能),检测出错误的单元会立即同时通知其他所有单元(错误通知功能),正在发送消息的单元一旦检测出错误,会强制结束当前的发送。强制结束发送的单元会不断反复地重新发送此消息直到成功发送为止(错误恢复功能)。
-
故障封闭功能。CAN可以判断出错误的类型是总线上暂时的数据错误(如外部噪声等)还是持续的数据错误(如单元内部故障、驱动器故障、断线等)。由此功能,当总线上发生持续数据错误时,可将引起此故障的单元从总线上隔离出去。
-
连接节点多。CAN总线是可同时连接多个单元的总线。可连接的单元总数理论上是没有限制的。但实际上可连接的单元数受总线上的时间延迟及电气负载的限制。降低通信速度,可连接的单元数增加;提高通信速度,则可连接的单元数减少。
CAN 协议经过 ISO 标准化后有两个标准:ISO11898 标准(高速 CAN)和 ISO11519-2 标准(低速 CAN)。其中 ISO11898 是针对通信速率为 125Kbps~1Mbps 的高速通信标准,而ISO11519-2 是针对通信速率为 125Kbps 以下的低速通信标准。
下文默认介绍ISO11898-2标准下的CAN,也就是高速CAN。
物理层
高速CAN总线呈现闭环结构,总共由两根线(CAN_High和CAN_Low)组成,总线两端各串联120Ω电阻,用于阻抗匹配。每个挂载节点拥有独立的CAN控制器(通常集成于MCU内)和CAN收发器(通常为外部IC)。
与RS485类似,CAN通过差分信号传输数据,以降低共模噪声的干扰,通过CAN总线上两根线之间的电位差来判断总线电平。总线电平分为显性(Dominant)电平和隐性(Recessive)电平。当总线上任何设备传输显性 (0) 时,高速 CAN 信号会将 CANH 线驱动至 3.5 V,将 CANL 线驱动至 1.5 V;而如果没有设备传输显性,则终端电阻会将两条线被动地返回到隐性 (1) 状态,标称差分电压为 0 V。(接收器将任何小于 0.5 V 的差分电压视为隐性。)显性差分电压的标称值为 2 V。显性共模电压 (CANH+CANL)/2 必须在共模的 1.5 至 3.5 V 范围内,而隐性共模电压必须在共模的 ±12V 范围内。
也就是说,下文中:
- 显性电平:逻辑 0
- 隐性电平:逻辑 1
可见,显性电平的“显性”具有“优先”的意味,即总线上只要有一个单元输出显性电平,总线上即为显性电平。而隐性电平的“隐性”具有“包容”的意味,只有所有的单元都输出隐性电平,总线上才为隐性电平。
协议
CAN协议通过5种类型的帧进行:
- 数据帧:用于发送单元向接收单元传送数据
- 遥控帧:用于接收单元向具有相同ID的发送单元请求数据
- 错误帧:用于当检测出错误时向其它单元通知错误
- 过载帧:用于接收单元通知其尚未做好接收准备
- 间隔帧:用于将数据帧及遥控帧与前面的帧分离开来
数据帧和遥控帧还分为标准格式和扩展格式两种,标准格式的标识符(Identifier)为11位,扩展格式为29位。
标准格式下的数据帧
注意:下方D表示显性电平(逻辑0),R表示隐性电平(逻辑1),D/R表示逻辑电平视配置而定。
数据帧由7个段构成,分别为:
- 帧起始
- 仲裁段:表示该帧优先级
- 控制段:表示数据字节数和保留位
- 数据段:数据内容,一帧一般可发送0-8个字节
- CRC段:校验帧传输正确性
- ACK段:确认是否正常接收
- 帧结束
帧起始(1位)
- SOF:1位,显性电平,帧起始(Start of Frame),单个显性帧起始 (SOF) 位标记消息的开始,用于在空闲后同步总线上的节点。
仲裁段(11位)
- Identifier:11位(扩展下为29位),即标识符,又名仲裁段,标准CAN模式下为 11 位,用于确定消息的优先级。二进制值越低,优先级越高。
注意:无论是标准格式还是扩展格式,都禁止ID的高7位都为隐性,即禁止设定ID为1111111XXXX。
- RTR:1位,用于标识是否为远程帧(0:数据帧;1:远程帧)
控制段(6位)
- IDE:1位,标识符选择位(0:使用标准ID;1:使用扩展ID)
- r0:1位,显性电平,保留位(可能用于未来的标准修订)
- DLC:4位,标识当前正在传输的数据的字节数,高位在前
注意:对于DLC位,通常只允许传输0-8,但接收方对DLC=9~15的情况并不视作错误
数据字节数 | DLC3 | DLC2 | DLC1 | DLC0 |
---|---|---|---|---|
0 | D | D | D | D |
1 | D | D | D | R |
2 | D | D | R | D |
3 | D | D | R | R |
4 | D | R | D | D |
5 | D | R | D | R |
6 | D | R | R | D |
7 | D | R | R | R |
8 | R | D | D | D |
表中D和R实际上就是0和1.比如8个字节所对应的RDDD实际上就是二进制的1000.
数据段(0-64位)
数据段最多传输8字节数据,从最高位(MSB)开始输出。
CRC段(16位)
- CRC顺序:15位,循环冗余校验上一个传输的数据
- CRC界定符:1位,隐性电平,用于分割
CRC 顺序是根据多项式生成的 CRC 值,CRC 的计算范围包括帧起始、仲裁段、控制段、数据段。接收方以同样的算法计算 CRC 值并进行比较,不一致时会通报错误。
ACK段(2位)
- ACK槽(ACK Slot):1位
- ACK界定符:1位,隐性电平
注意:对于ACK Slot,其工作方式为:
- 对于发送单元:发送单元在ACK Slot发送1个隐性位
- 对于接收单元:接收到正确信息的单元在ACK Slot发送显性位,通知发送单元正常接收结束。该动作称作“发送 ACK”或者“返回 ACK”。
帧结束(7位)
表示帧结束,由7个隐性位构成。
错误帧
WIP
位时序
由发送单元在非同步的情况下发送的每秒钟的位数称为位速率。一个位可分为4段:
- 同步段(SS)
- 传播时间段(PTS)
- 相位缓冲段1(PBS1)
- 相位缓冲段2(PBS2)
这些段又由可称为 Time Quantum(以下称为 Tq)的最小时间单位构成。
1位分为4个段,每个段又由若干个Tq构成,这称为位时序。
1位由多少个Tq构成、每个段又由多少个Tq构成等,可以任意设定位时序。通过设定位时序,多个单元可同时采样,也可任意设定采样点。
图中的采样点是指读取总线电平并将其作为位值的点,位于PBS1结束处。
仲裁
CAN本质是半双工通信,因为总线上同一时刻只允许一个信号传输,ID优先级不够的信号会在仲裁时失去发送权。具体为:
- 若总线空闲:最先开始发送消息的单元取得发送权
- 若多个单元同时发送:各发送单元从仲裁段的第一位开始进行仲裁,连续输出显性电平(逻辑0)最多的单元可继续发送
STM32F4的CAN控制器
基本信息与标识符滤波器
STM32F4自带的是bxCAN,即基本扩展CAN,其支持CAN协议2.0A和2.0B。CAN2.0A只能处理标准数据帧,扩展帧的内容会识别错误;而CAN2.0B Active可以处理标准数据帧和扩展数据帧;CAN2.0B Passive只能处理标准数据帧,忽略扩展帧。
F429自带两个CAN控制器:CAN1和CAN2.两个CAN分别拥有自己的发送邮箱和接收FIFO,但二者共用28个滤波器,其分配方式通过CAN_FMR
寄存器设置。滤波器用于选择性接收符合特定条件的 CAN 消息,通过对 CAN 报文的标识符(ID)进行筛选,只接收满足条件的报文,将不相关的报文丢弃。这可以避免 MCU 对所有接收到的 CAN 报文进行处理,从而提升系统效率。
滤波器有两种工作模式:
-
标识符掩码模式(Identifier Mask Mode):
- 通过掩码定义哪些位需要匹配。
- 灵活性高,适合处理某些位通配的场景。
- 掩码中的每一位可以设置为:
- “0”: 忽略对应位。
- “1”: 匹配对应位。
- 例:目标只接收以
0x2A
(101010
)为前六位的标识符,则配置过滤器的标识符为0x2A0
(10101000000
),掩码为0xFC0
(11111100000
),接收到的ID与掩码进行按位比较,只匹配掩码为1的位。
-
标识符列表模式(Identifier List Mode):
- 直接指定一组标识符,只有匹配这些标识符的消息才会通过。
- 适合明确的标识符匹配。
- 例:指定
0x1A5
为期望标识符,则只有接收到的ID等于0x1A5
时该消息才会被允许通过。
发送
CAN 控制器有 3 个发送邮箱(Tx Mailbox),用于存储待发送的消息。发送时,将消息写入空闲邮箱,然后硬件根据仲裁机制将消息发送到总线上。仲裁失败的消息会被重新加入发送队列,直到成功发送。
正常发送流程为:
- 配置CAN发送帧,包括:
- 消息的标识符(11位或29位)
- 帧类型(数据帧或远程帧)
- 填充待发送数据
- 声明待发送数据长度 - 检查邮箱状态
- 确保至少有一个发送邮箱空闲(TME=1
) - 邮箱请求发送
- 设置CAN_TIxR的TXRQ位为1
- 邮箱挂号
-RQCP=0
,TXOK=0
,TME=0
- 等待成为最高优先级 - 预定发送
- 已成为最高优先级
- 等待CAN总线空闲 - 发送
- 发送成功
-RQCP=1
,TXOK=1
,TME=1
- 回到邮箱空闲状态 - 发送失败
-RQCP=1
,TXOK=0
,TME=1
- 回到邮箱空闲状态
接收
CAN接收到的有效报文,被存储在3级邮箱深度的FIFO中。FIFO完全由硬件来管理,从而节省了 CPU 的处理负荷,简化了软件并保证了数据的一致性。应用程序只能通过读取FIFO输出邮箱,来读取 FIFO 中最先收到的报文。
CAN的接收有2个FIFO,我们每个滤波器组都可以设置其关联的 FIFO,通过 CAN_FFA1R
的设置,可以将滤波器组关联到FIFOO/FIFO1.
有效报文:指那些正确被接收的(直到EOF都没有错误)且通过了标识符过滤的报文。
FIFO接收到的报文数可以通过查询CAN_RFxR
的FMP寄存器得到。
注意:必须在FIFO溢出之前读出至少1个报文,否则下个报文到来时FIFO将溢出,导致最早收到的报文丢失。每读出1个报文,相应的挂号就减1,直到FIFO为空。
位时间特性
不同于原本的CAN协议,STM32把传播时间段(PTS)和相位缓冲段(PBS1)合并,所以STM32的CAN一个位只有3段:
- 同步段(SYNC_SEG)
- 时间段1(BS1)
- 时间段2(BS2)
图中给出了CAN波特率的计算公式,只需要知道CAN_BTR中BRP、TS1和TS2的设置就可以计算。
寄存器
WIP