CAN笔记(15) STM32-M4 CAN通讯
1. 期望效果
通过 KEY1 按键选择 CAN 的工作模式(正常模式/环回模式)
通过 KEY0 按键控制数据发送(8个8位随机数)
通过查询的办法,将接收到的数据显示在 LCD 模块上
环回模式下,用一个最小系统板即可测试
正常模式下,需要 2 个拥有 CAN接口的最小系统板,并且将其对接起来
用 2 根导线将两个 CAN 端子的 CAN_L
和 CAN_L
, CAN_H
和 CAN_H
连接起来
然后一个最小系统板发送数据,另外一个最小系统板将接收到的数据显示在 LCD 模块上
2. 硬件资源
除了F429最小系统板的基本硬件配置,还需要以下硬件资源:
- 指示灯 LED0
- 按键 KEY0 和 KEY1
- LCD 模块(如果没有屏幕显示模块,也可以采用串口通讯进行交互)
- CAN 收发芯片 JTA1050
3. 初始化配置
创建一个CANTest1
工程,包含了基础的 HAL库
CAN相关的函数在文件 stm32f4xx_hal_can.c
和 对应的头文件stm32f4xx_hal_can.h
中
3.1. 配置相关引脚
第一步就要使能 CAN 的时钟, CAN 的时钟通过 APB1ENR
的第 25 位来设置
其次要设置 CAN 的相关引脚为复用输出
这里需要设置 PA11(CAN1_RX
)和 PA12(CAN1_TX
)为复用功能( AF9)
并使能 PA 口的时钟
这里创建一个CAN底层驱动函数HAL_CAN_MspInit
,进行所述的配置
具体配置过程如下:
void HAL_CAN_MspInit(CAN_HandleTypeDef* hcan)
{
GPIO_InitTypeDef GPIO_Initure;
__HAL_RCC_CAN1_CLK_ENABLE(); //使能CAN1时钟
__HAL_RCC_GPIOA_CLK_ENABLE(); //开启GPIOA时钟
GPIO_Initure.Pin = GPIO_PIN_11 | GPIO_PIN_12; //PA11,12
GPIO_Initure.Mode = GPIO_MODE_AF_PP; //推挽复用
GPIO_Initure.Pull = GPIO_PULLUP; //上拉
GPIO_Initure.Speed = GPIO_SPEED_FAST; //快速
GPIO_Initure.Alternate = GPIO_AF9_CAN1; //复用为CAN1
HAL_GPIO_Init(GPIOA, &GPIO_Initure); //初始化
}
3.2. 设置 CAN 工作模式及波特率等
这一步通过先设置 CAN_MCR
寄存器的 INRQ
位,让 CAN 进入初始化模式
然后设置CAN_MCR
的其他相关控制位
再通过 CAN_BTR
设置波特率和工作模式(正常模式/环回模式)等信息
最后设置 INRQ
为 0,退出初始化模式
在库函数中,提供了函数 HAL_CAN_Init 用来初始化 CAN 的工作模式以及波特率
HAL_CAN_Init
函数体中,就会进行上述的配置
所以在调用这个函数的前后不需要再进行初始化模式设置
下面来看看 HAL_CAN_Init
函数的声明:
HAL_StatusTypeDef HAL_CAN_Init(CAN_HandleTypeDef* hcan);
该函数入口参数只有 hcan
一个,为 CAN_HandleTypeDef
结构体指针类型
结构体 CAN_HandleTypeDef
定义:
typedef struct
{
CAN_TypeDef *Instance; /*!< Register base address */
CAN_InitTypeDef Init; /*!< CAN required parameters */
CanTxMsgTypeDef* pTxMsg; /*!< Pointer to transmit structure */
CanRxMsgTypeDef* pRxMsg; /*!< Pointer to reception structure */
__IO HAL_CAN_StateTypeDef State; /*!< CAN communication state */
HAL_LockTypeDef Lock; /*!< CAN locking object */
__IO uint32_t ErrorCode; /*!< CAN Error code */
}CAN_HandleTypeDef;
该结构体除了 State
, Lock
,和 ErrorCode
三个 HAL 库处理状态过程变量之外
只有四个成员变量需要外部设置:
-
Instance
位寄存器基地址
这里使用 CAN1,设置为 CAN1 即可 -
Init
参数初始化配置
它是CAN_InitTypeDef
结构体类型,该结构体定义为:typedef struct { uint32_t Prescaler; //波特率分频器 uint32_t Mode; //模式 uint32_t SJW; //重新同步跳跃宽度 uint32_t BS1; //时间段 1 占用的时间单元数 uint32_t BS2; //时间段 2 占用的时间单元数 uint32_t TTCM; //时间触发通信模式 uint32_t ABOM; //自动的总线关闭管理 uint32_t AWUM; //自动唤醒模式 uint32_t NART; //禁止自动重发送 uint32_t RFLM; //接收 FIFO 锁定模式 uint32_t TXFP; //发送 FIFO 优先级 }CAN_InitTypeDef;
前面 5 个参数用来设置寄存器
CAN_BTR
,用来设置模式以及波特率相关的参数
后面 6 个参数用来设置寄存器CAN_MCR
,用来设置 CAN 通信相关的控制位 -
pTxMsg
发送消息结构体指针
在初始化 CAN 的时候要指定其指向
那么后面调用发送函数HAL_CAN_Transmit
之前,就可以通过pTxMsg
指定发送数据和参数 -
pRxMsg
接收消息结构体指针
在初始化 CAN 的时候要指定其指向
那么后面调用接收函数HAL_CAN_Receive
之后,就可以通过pRxMsg
获取接收数据和参数
这里创建一个CAN1初始化函数CAN1_Mode_Init
,进行所述的配置
具体配置过程如下:
CAN_HandleTypeDef CAN1_Handler; //CAN1句柄
CanTxMsgTypeDef TxMessage; //发送消息
CanRxMsgTypeDef RxMessage; //接收消息
u8 CAN1_Mode_Init(u32 tsjw, u32 tbs2, u32 tbs1, u16 brp, u32 mode)
{
CAN1_Handler.Instance = CAN1; //寄存器基地址
CAN1_Handler.pTxMsg = &TxMessage; //发送消息
CAN1_Handler.pRxMsg = &RxMessage; //接收消息
CAN1_Handler.Init.Prescaler = brp; //分频系数(Fdiv)为brp+1
CAN1_Handler.Init.Mode = mode; //模式设置
CAN1_Handler.Init.SJW = tsjw; //重新同步跳跃宽度(Tsjw)为tsjw+1个时间单位(CAN_SJW_1TQ~CAN_SJW_4TQ)
CAN1_Handler.Init.BS1 = tbs1; //tbs1范围(CAN_BS1_1TQ~CAN_BS1_16TQ)
CAN1_Handler.Init.BS2 = tbs2; //tbs2范围(CAN_BS2_1TQ~CAN_BS2_8TQ)
CAN1_Handler.Init.TTCM = DISABLE; //非时间触发通信模式
CAN1_Handler.Init.ABOM = DISABLE; //软件自动离线管理
CAN1_Handler.Init.AWUM = DISABLE; //睡眠模式通过软件唤醒(清除CAN->MCR的SLEEP位)
CAN1_Handler.Init.NART = ENABLE; //禁止报文自动传送
CAN1_Handler.Init.RFLM = DISABLE; //报文不锁定,新的覆盖旧的
CAN1_Handler.Init.TXFP = DISABLE; //优先级由报文标识符决定
if (HAL_CAN_Init(&CAN1_Handler) != HAL_OK) return 1; //初始化
}
其中HAL_CAN_Init
函数会调用HAL_CAN_MspInit
CAN底层驱动函数
3.3. 设置滤波器
将使用滤波器组 0,并工作在 32 位标识符屏蔽位模式下
先设置 CAN_FMR
的 FINIT
位,让过滤器组工作在初始化模式下
然后设置滤波器组 0 的工作模式以及标识符 ID和屏蔽位
最后激活滤波器,并退出滤波器初始化模式
在 HAL 库中,提供了函数 HAL_CAN_ConfigFilter
用来初始化 CAN 的滤波器相关参数
HAL_CAN_ConfigFilter
函数体中,就会进行上述的配置
HAL_CAN_ConfigFilter
函数的声明:
HAL_StatusTypeDef HAL_CAN_ConfigFilter(CAN_HandleTypeDef* hcan, CAN_FilterConfTypeDef* sFilterConfig)
该函数有 2 个入口参数:
第一个入口参数 hcan
,已经说明过了
第二个入口参数 sFilterConfig
, CAN_FilterConfTypeDef
结构体指针类型,用来设置滤波器相关参数
结构体 CAN_FilterConfTypeDef
定义为:
typedef struct
{
uint32_t FilterIdHigh; //过滤器的 32 位 ID<