CAN总线简易教程,小白也能快速上手!
扫描二维码
随时随地手机看文章
目录
- 什么是CAN总线?
- 物理层
- 差分信号
- 连接方式
- CAN节点
- CAN协议
- 如何寻址?
- 帧类型
- 数据帧
- 远程帧
- 错误帧
- 过载帧
- 消息时序以及同步
- 位时序
- 波特率
- 消息过滤器
- 如何配置?
- 总结
- 参考
什么是CAN总线?
Controller Area Network,简称CAN或者CAN bus) 是一种功能丰富的串行总线标准,最早的CAN控制芯片在奔驰车上应用并量产,因为支持多主机,多从机的优点,所以一辆车所有控制器,传感器,电子设备直接的通信只需要两条线就够了,大大优化了整车的布线。[^wiki can bus]随着技术的不断发展,CAN发布了相应的标准,国际化标准组织,公布了CAN的不同标准;标准 | 涵盖内容 |
---|---|
ISO 11898-1 | 数据链路层 |
ISO 11898-2 | 高速CAN的物理层 |
ISO 11898-3 | 低速容错CAN的物理层 |
ISO 11898-1
,ISO 11898-2
是对应的设计标准,去搜索就可以知道这个技术点是如何进行设计的。
物理层
差分信号
这里我们介绍一下物理层,什么是物理层呢?就是CAN的电信号的传输过程。CAN是串行异步通讯,只有CAN_HIGH
和CAN_LOW
两条差分信号线,数据通过差分信号的方式进行通讯,其优点就是可以增加信号的抗干扰能力,抑制共模信号的干扰;具体如下图所示;所以,信号在变成一个字节一个字节的数字信号之前,就是按照这种差分形式的模拟信号来传输的。我们可以简单地理解一下,当CAN_HIGH减去CAN_LOW大于某个阈值的时候,可以把它当做逻辑高,反之,当小于某一个阈值时,就变成逻辑低。下面我们再来看看CAN总线设备之间是如何连接的。连接方式
CAN总线支持多个节点挂载在总线上,比较类似I2C
总线,可以在SCL
和SDA
上挂载多个从机,具体如下图所示;不过CAN总线其实没有主从的概念,每个设备都是一个节点(Node
),节点直接可以相互通讯,相较于I2C
总线,CAN总线设置了终端电阻,常见的一种闭环连接模式,相对的还有开环的连接模式。不同的连接模式,他们的通讯速率也大不相同,这里也就是高速CAN和低速CAN的区别。两条电线组成一条双绞线,并且接有120Ω的特性阻抗。ISO 11898-2,也称为高速度CAN。它在总线的两端均接有120Ω电阻。使用了
120Ω
终端电阻(这是CAN的ISO标准里规定的),这种模式的最高通讯速率可以达到1Mbps,下面是传输距离和传输速度的关系;高速CAN的拓扑结构具体如下所示;还有一种是低速CAN,或者也叫做容错CAN,低速容错 CAN 总线将通讯的最大带宽从 1 Mbps
降低到 125 Kbps
,并且不再在总线的起点和终点使用两个终端电阻,而是将电阻分布在每个节点上。具体如下图所示;由于高速CAN和低速CAN的拓扑结构不同,另外终端电阻的分布也不同,所以CAN_HIGH
和CAN_LOW
上的电平是不相同的,这里有隐性电平和显性电平。硬件上的连接基本上都搞清楚了,下面就是如何去实现一个具体的CAN节点。我们来简单地介绍一下。
CAN节点
CAN节点通常分为三个部分;- MCU/CPU;
- CAN控制器,
- CAN收发器;
STM32
,所以我们常见的结构一般是这样子的。所以整体的流程是这样的,如下:- CAN总线上通过差分信号进行数据传输;
- CAN收发器将差分信号转换为TTL电平信号,或者将TTL电平信号转换为差分信号;
- CAN控制器将TTL电平信号接收,并传输给MCU;
CAN协议
CAN协议和网络协议比较类似,进行了分层的设计思想;按照我的理解;- 物理层就是前面提到过的硬件拓扑结构,包括高速CAN和低速CAN,而CAN收发器就属于物理层;
- 传输层则是CAN控制器所需要做的事情,包括CAN时序,同步,消息仲裁,确认,错误检验等,这个比较复杂,如果只是应用开发,我认为,简单了解一下即可;这一层需要做的工作包括:
- 故障约束;
- 错误监测;
- 消息验证;
- 信息确认;
- 仲裁;
- 信息帧;
- 传输速率和时间;
- 路由信息;
- 对象层,MCU应该是属于这一层,我们需要对CAN消息做信息的过滤设置,CAN消息的处理等等;
- 应用层就是基于对象层的进一步封装,不同的CAN标准,比如工业自动化领域的
CANopen
,汽车诊断ISO 14229 定义的UDS等等;
如何寻址?
CAN总线上的每个节点不需要设置节点的地址,而是通过消息的标识符(Identifier)来区别信息。因为CAN总线的消息是广播的(就是大家都可以收到消息),比如总线上有节点A,节点B,节点C,那么节点A发消息,节点B和节点C都会收到消息;节点B 和 节点C 会根据消息中的标识符,以及B和C中的消息过滤规则进行比较,如果不满足规则,就不接受这条信息。这里需要注意的是:- 发送消息的时候,总线必须处于空闲状态;
- 标识符越小,则消息获取总线的优先级越高;
帧类型
CAN有4种帧类型:- 数据帧:包含用于传输的节点数据的帧
- 远程帧:请求传输特定标识符的帧
- 错误帧:由任何检测到错误的节点发送的帧
- 过载帧:在数据帧或远程帧之间插入延迟的帧
数据帧
数据帧分为标准帧和扩展帧两种格式;- 基本帧格式:有11个标识符位
- 扩展帧格式:有29个标识符位
sof
:start of frame
,表示数据帧开始;(1 bit)Identifier
:标准格式11 bit,扩展格式29 bit包括Base Identifier(11 bit)和Extended Identifier(18 bit),该区段标识数据帧的优先级,数值越小,优先级越高;RTR
:远程传输请求位,0时表示为数据帧,1表示为远程帧,也就是说RTR=1时,消息帧的Data Field为空;(1 bit)IDE
:标识符扩展位,0时表示为标准格式,1表示为扩展格式;(1 bit)DLC
:数据长度代码,0~8表示数据长度为0~8 Byte;(4 bit)Data Field
:数据域;(0~8 Byte)CRC Sequence
:校验域,校验算法,DEL
:校验域和应答域的隐性界定符;(1 bit)ACK
:应答,确认数据是否正常接收,所谓正常接收是指不含填充错误、格式错误、 CRC 错误。发送节点将此位为1,接收节点正常接收数据后将此位置为0;(1 bit)SRR
:替代远程请求位,在扩展格式中占位用,必须为1;(1 bit)EOF
:连续7个隐性位(1)表示帧结束;(7 bit)ITM
:帧间空间,Intermission (ITM)
,又称Interframe Space
(IFS),连续3个隐性位,但它不属于数据帧。帧间空间是用于将数据帧和远程帧与前面的帧分离开来的帧。数据帧和远程帧可通过插入帧间空间将本帧与前面的任何帧(数据帧、遥控帧、错误帧、过载帧)分开。过载帧和错误帧前不能插入帧间空间。
远程帧
一般地,数据是由发送单元主动向总线上发送的,但也存在接收单元主动向发送单元请求数据的情况。远程帧的作用就在于此,它是接收单元向发送单元请求发送数据的帧。远程帧与数据帧的帧结构类似,如上图X所示。远程帧与数据帧的帧结构区别有两点:- 数据帧的 RTR 值为“0”,远程帧的 RTR 值为“1”
- 远程帧没有数据块
错误帧
用于在接收和发送消息时检测出错误时,通知错误的帧。错误帧由错误标志和错误界定符构成。错误帧的帧结构如图11示。- 错误标志:个显性/隐性重叠位
- 主动错误标志(6个显性位):处于主动错误状态的单元检测出错误时输出的错误标志
- 被动错误标志(6个隐性位):处于被动错误状态的单元检测出错误时输出的错误标志
- 错误界定符:8 个隐性位
过载帧
过载帧是用于接收单元通知发送单元它尚未完成接收准备的帧。在两种情况下,节点会发送过载帧:- 接收单元条件的制约,要求发送节点延缓下一个数据帧或远程帧的传输;
- 帧间空间(Intermission)的 3 bit 内检测到显性位
消息时序以及同步
位时序
在讲CAN消息时序和同步之前,我们可以对照一下UART串口的传输协议,他有起始位和停止位,然后大家都规定使用相同的通讯速率(波特率);其实CAN通讯也是类似的方式,它属于异步通讯,没有时钟信号线,所以所有节点之间要约定好使用相同的波特率来传输数据。在总线空闲一段时间后,在(起始位) 进行硬同步,同步方式是将每一位划分成多个称为量子的时间段(time quanta),并分配一定数量的量子到位中的四个阶段完成的。这四个阶段分别为:SYNC_SEG
:同步段,1 个时间量子长度。它用于同步各种总线节点;PROP_SEG
:传播段,1~8 时间量子长度。它用于补偿网络上的信号延迟。PHASE_SEG_1
:相位缓冲段1,1~8 时间量子长度。它用于补偿边缘相位误差,在重新同步期间可能会延长。PHASE_SEG_2
:相位缓冲段2,2~8 时间量子长度。它用于补偿边缘相位误差
波特率
如何计算波特率,需要知道每个量子时间的长度(time quanta),以及每一位需要多少个量子时间,假设这里time quanta = 1us
,并且1 bit = 8 tq
,那么上图中的波特率就应该是:消息过滤器
前面有提到消息在CAN总线上是广播式的,但并不是所有节点都会对总线上所有消息感兴趣。节点通过控制器中过滤码(Filter Code )和掩码(Mask Code),再检验总线上消息的标识符,来判断是否接收该消息(Message Filtering)。对于掩码,“1”表示该位与本节点相关,“0”表示该位与本节点不相关。举例如下:例1:仅接收消息标识符为00001567
(十六进制)的帧- 设置过滤码为
00001567
- 设置掩码为
1FFFFFFF
00001567
接收,否则舍弃。例2:接收消息标识符为00001567
到0000156F
的帧- 设置过滤码为
00001560
- 设置掩码为
1FFFFFF0
00001560
到 00001567
的帧- 设置过滤码为
00001560
- 设置掩码为
1FFFFFF8
- 设置过滤码为
0
- 设置掩码为
0
如何配置?
上面介绍了帧类型,那么如何基于MCU
进行配置呢?这里以STM32F407
为硬件平台,使用HAL库进行初始化,看一下都对哪些地方进行了配置。一般来说,我们需要配置CAN的波特率,消息过滤器等等,下面是简单的配置的代码;CAN_HandleTypeDef hCAN;
void MX_CAN_Init(void)
{
CAN_FilterTypeDef sFilterConfig;
/*CAN单元初始化*/
hCAN.Instance = CAN1; /* CAN外设 */
/* BTR-BRP 波特率分频器 定义了时间单元的时间长度42/(1 6 7)/6=500Kbps */
hCAN.Init.Prescaler = 6;
hCAN.Init.Mode = CAN_MODE_NORMAL; /* 正常工作模式 */
hCAN.Init.SyncJumpWidth = CAN_SJW_1TQ; /* BTR-SJW 重新同步跳跃宽度 1个时间单元 */
hCAN.Init.TimeSeg1 = CAN_BS1_6TQ; /* BTR-TS1 时间段1 占用了6个时间单元 */
hCAN.Init.TimeSeg2 = CAN_BS2_7TQ; /* BTR-TS1 时间段2 占用了7个时间单元 */
hCAN.Init.TimeTriggeredMode = DISABLE; /* MCR-TTCM 关闭时间触发通信模式使能 */
hCAN.Init.AutoBusOff = ENABLE; /* MCR-ABOM 自动离线管理 */
hCAN.Init.AutoWakeUp = ENABLE; /* MCR-AWUM 使用自动唤醒模式 */
hCAN.Init.AutoRetransmission = DISABLE; /* MCR-NART 禁止报文自动重传 DISABLE-自动重传 */
/* MCR-RFLM 接收FIFO 锁定模式 DISABLE-溢出时新报文会覆盖原有报文 */
hCAN.Init.ReceiveFifoLocked = DISABLE;
/* MCR-TXFP 发送FIFO优先级 DISABLE-优先级取决于报文标示符 */
hCAN.Init.TransmitFifoPriority = DISABLE;
if (HAL_CAN_Init(