目录
[一、CAN 通讯概述](#一、CAN 通讯概述)
[二、 CAN 通讯原理](#二、 CAN 通讯原理)
[1.ISO11898 标准下的物理层特征](#1.ISO11898 标准下的物理层特征)
[2.CAN 协议的帧类型](#2.CAN 协议的帧类型)
[3. 总线仲裁介绍](#3. 总线仲裁介绍)
[5.STM32 CAN 控制器简介](#5.STM32 CAN 控制器简介)
[1.1初始化 CAN 控制器](#1.1初始化 CAN 控制器)
[1.3 将数据填充到发送缓冲区](#1.3 将数据填充到发送缓冲区)
[2.1初始化 CAN 控制器](#2.1初始化 CAN 控制器)
一、CAN 通讯概述
STM32 的 CAN 通讯是一种常用于嵌入式系统的串行通信协议,具有高可靠性和多主控制等特点,广泛应用于汽车电子、工业自动化等领域。
CAN 协议经过 ISO 标准化后有两个标准:ISO11898 标准和 ISO11519 - 2 标准。其中 ISO11898 是针对通信速率为 125Kbps - 1Mbps的高速通信标准,而 ISO11519 - 2 是针对通信速率为 125Kbps 以下的低速通信标准。STM32 的 CAN 控制器支持 CAN 2.0A 和 CAN 2.0B Active 版本协议。CAN 2.0A 只能处理标准数据帧,扩展帧的内容会识别为错误;CAN 2.0B Active 可以处理标准数据帧和扩展数据帧。
CAN 总线物理层主要有两种形式,一种是遵循 ISO11898 标准的高速、短距离 "闭环网络",总线最大长度为 40m ,通信速度最高为 1Mbps ,总线的两端各要求有一个 "120 欧" 的电阻。另一种是遵循 ISO11519 - 2 标准的低速、远距离 "开环网络",最大传输距离为 1km ,最高通讯速率为 125kbps,两根总线是独立的、不形成闭环,要求每根总线上各串联有一个 "2.2 千欧" 的电阻。
CAN 通讯节点由一个 CAN 控制器及 CAN 收发器组成,控制器与收发器之间通过 CAN_Tx 及 CAN_Rx 信号线相连,收发器与 CAN 总线之间使用 CAN_High 及 CAN_Low 信号线相连。差分信号传输方式具有抗干扰能力强、能有效抑制电磁干扰、时序定位精确等优点。
STM32 的 CAN 通讯具有多主控制、系统的柔软性、通信速度较快且通信距离远、具有错误检测和恢复功能、故障封闭功能以及连接节点多等特点。这些特点使得 CAN 特别适合工业过程监控设备的互连,越来越受到工业界的重视。
二、 CAN 通讯原理
1.ISO11898 标准下的物理层特征
CAN 控制器根据 CAN_L 和 CAN_H 上的电位差来判断总线电平。总线电平分为显性电平和隐性电平,二者必居其一。显性电平对应逻辑 "0",此时 CAN_High和 CAN_Low 之差为 2.5V 左右;隐性电平对应逻辑 "1",此时 CAN_High和 CAN_Low 电压都为 2.5V 左右,电位差为 0V。显性电平具有优先权,只要有一个单元输出显性电平,总线上即为显性电平。另外,在 CAN 总线的起止端都有一个 120Ω 的终端电阻,用于匹配总线阻抗,减少回波反射,提高数据通信的抗干扰能力以及可靠性。
2.CAN 协议的帧类型
CAN 协议有数据帧、遥控帧、错误帧、超载帧和间隔帧五种类型帧。
其中,数据帧最常用且复杂,一般由 7 个段构成,包括帧起始、仲裁段、控制段、数据段、CRC 段、应答段和帧结束。
帧起始由 1 个显性位构成,标志着报文的开始。
仲裁段表示该帧优先级,标准格式包含 11 位标识符和远程发送请求位 RTR,扩展格式包含 29 位标识符、SRR 位、IDE 位和 RTR 位。
控制段包含数据长度等信息。
数据段包含要发送的 0 - 8 个字节的数据。
CRC 段用于校验数据是否正确发送。
应答段用于确认是否正常接收。
帧结束由连续的 7 个隐性位组成。
3. 总线仲裁介绍
同时多个单元发送数据时,总线仲裁过程如下:多个单元同时开始向总线发送数据,开始部分数据格式一样,无法区分优先级。直到某个时刻,一个单元输出隐性电平,而另一个单元输出显性电平,此时输出隐性电平的单元仲裁失利,立刻转入接收状态工作,不再与其他单元竞争,而输出显性电平的单元则顺利获得总线使用权,继续发送自己的数据。规律为:总线空闲时,最先发送的单元获得发送优先权,一旦发送,其他单元无法抢占;如果有多个单元同时发送,则连续输出显性电平多的单元,具有较高优先级。
4.位时序
位速率是由发送单元在非同步的情况下发送的每秒钟的位数。一个位一般可以分为同步段(SS)、传播时间段(PTS)、相位缓冲段 1(PBS1)和相位缓冲段 2(PBS2)。
这些段又由可称为 Time Quantum(Tq)的最小时间单位构成,1 位分为 4 个段,每个段又由若干个 Tq 构成,这称为位时序。位时间 = 1 / 波特率,知道位时间,我们就可以知道波特率以及 1 位由多少个 Tq 构成、每个段又由多少个 Tq 构成等,可以任意设定位时序。通过设定位时序,多个单元可同时采样,也可任意设定采样点。
5.STM32 CAN 控制器简介
STM32F4 的 bxCAN 支持 CAN 协议 2.0A 和 2.0B 主动模式,波特率最高达 1Mbps,支持时间触发通信,具有 3 个发送邮箱,具有 3 级深度的 2 个接收 FIFO,可变的过滤器组(28 个,CAN1 和 CAN2 共享)。它的设计目标是以最小的 CPU 负荷来高效处理大量收到的报文,对于安全紧要的应用,提供所有支持时间触发通信模式所需的硬件功能。
6.标识符筛选器
CAN 的标识符不表示目的地址而是表示发送优先级。接收节点根据标识符的值,来决定是否接收对应消息。STM32 CAN 控制器提供了 28 个可配置的筛选器组,可降低 CPU 处理 CAN 通信的开销。STM32 CAN 控制器每个筛选器组由 2 个 32 位寄存器组成。根据位宽不同,每个筛选器组可提供
- 1 个 32 位筛选器,包括 STDID [10:0]、EXTID [17:0]、IDE 和 RTR 位;
- 或者2 个 16 位筛选器,包括 STDID [10:0]、IDE、RTR 和 EXTID [17:15] 位。
筛选器可配置为屏蔽位模式和标识符列表模式。在屏蔽位模式下,标识符寄存器和屏蔽寄存器一起,指定报文标识符的任何一位,应该按照 "必须匹配" 或 "不用关心" 处理。
三、软件设计
1.发送流程
1.1初始化 CAN 控制器
- 配置时钟:使能 CAN 控制器对应的时钟源。
- 设置工作模式:如正常模式、环回模式等。
- 配置波特率:通过设置位时序参数(同步段、传播段、相位缓冲段等)来确定合适的波特率。
- 初始化过滤器:设置过滤器的模式、位宽、标识符等,以确定哪些报文可以被接收。
1.2准备发送数据
定义一个CAN_TxHeaderTypeDef结构体变量,设置报文的标识符、数据长度、发送类型等信息。例如:
cpp
CAN_TxHeaderTypeDef txHeader;
txHeader.StdId = 0x123; // 标准标识符
txHeader.ExtId = 0; // 不使用扩展标识符
txHeader.DLC = 8; // 数据长度为 8 字节
txHeader.TransmitGlobalTime = DISABLE;
1.3 将数据填充到发送缓冲区
定义一个数组用于存储要发送的数据。例如:
cpp
uint8_t data[8] = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08};
1.4启动发送
使用HAL_CAN_AddTxMessage
函数将数据发送到 CAN 总线。例如:
cpp
HAL_StatusTypeDef status = HAL_CAN_AddTxMessage(&hcan, &txHeader, data, &txMailbox);
if (status!= HAL_OK) {
// 处理发送错误
}
该函数会返回发送状态,可根据返回值判断发送是否成功。如果发送失败,可以根据具体情况进行错误处理。
1.5等待发送完成
可以通过查询发送邮箱的状态标志或者使用中断方式来判断发送是否完成。例如,使用轮询方式:
cpp
while (HAL_CAN_IsTxMessagePending(&hcan, txMailbox)) {
// 等待发送完成
}
2.接收流程
2.1初始化 CAN 控制器
- 配置时钟:使能 CAN 控制器对应的时钟源。
- 设置工作模式:如正常模式、环回模式等。
- 配置波特率:通过设置位时序参数(同步段、传播段、相位缓冲段等)来确定合适的波特率。
- 初始化过滤器:设置过滤器的模式、位宽、标识符等,以确定哪些报文可以被接收。
2.2开启接收中断(可选)
如果希望使用中断方式接收数据,可以配置相应的中断并开启中断。例如:
cpp
void HAL_CAN_RxCpltCallback(CAN_HandleTypeDef *hcan) {
// 接收中断处理函数
}
2.3等待数据接收
可以通过查询接收邮箱的状态标志来判断是否有新的数据到达。例如:
cpp
if (HAL_CAN_GetRxFifoFillLevel(&hcan, CAN_RX_FIFO0) > 0) {
// 有数据到达
}
2.4读取数据
当检测到有数据接收后,使用HAL_CAN_GetRxMessage函数从接收邮箱中读取数据。例如:
cpp
CAN_RxHeaderTypeDef rxHeader;
uint8_t rxData[8];
HAL_CAN_GetRxMessage(&hcan, CAN_RX_FIFO0, &rxHeader, rxData);
该函数会将接收到的报文信息填充到传入的结构体和数据缓冲区中。
2.5处理接收的数据
根据实际应用需求对接收的数据进行处理。例如,可以根据标识符判断数据的来源和类型,然后进行相应的操作。