1.1 定义接收过滤器类型定义结构体(CAN_FilterTypeDef)变量,配置包括
使能过滤器
定义过滤器模式:编码模式/掩码模式
定义过滤ID
typedef struct
{
uint32_t FilterIdHigh; /*!过滤器验证码ID高16位,只能填0到0xFFFF 中间的数值 */
uint32_t FilterIdLow; /*!过滤器ID低16位,只能填0到0xFFFF 中间的数值*/
uint32_t FilterMaskIdHigh; /*!过滤器掩码ID高16位,只能填0到0xFFFF中间的数值 */
uint32_t FilterMaskIdLow; /*!过滤器掩码ID低16位,只能填0到0xFFFF中间的数值 */
uint32_t FilterFIF(x)Assignment; /*!将通过的报文放入哪个FIFOx中,填写FIFO(x) */
uint32_t FilterBank; /*!使用过滤器编号。使用一个CAN,则可选 0~13;使用两个CAN可选0~27 */
uint32_t FilterMode; /*!过滤器模式选择。掩码模式填写 CAN_FILTERMODE_IDMASK,列表模式填写 CAN_FILTERMODE_IDLIST */
uint32_t FilterScale; /*!过滤器位宽,32位是CAN_FILTERSCALE_32BIT,16位是CAN_FILTERSCALE_16BIT */
uint32_t FilterActivation; /*!是否使能过滤器,DISABLE 或 ENABLE */
uint32_t SlaveStartFilterBank;
} CAN_FilterTypeDef;
关于过滤器模式:由两个32位寄存器组成,通过配置两种位宽,两种模式,得到 四种过滤模式,总结如下
模式 | ||
16位列表 | 可包含四个列表成员 | |
32位列表 | 可包含两个列表成员 | |
16位掩码 | 可包含两组验证码+掩码 | |
32位掩码 | 可包含一组验证码+掩码 |
注意:FilterIdHigh、FilterIdLow、FilterMaskIdHigh、FilterMaskIdLow这四个成员不是它的名字那么简单, 他们的功能取决于使用的过滤器模式。若为列表模式,则不管是FilterId还是FilterMaskId都表示的是列表成员,列表1和列表2。 在32位过滤器中,一组High和Low检验同一个CAN ID(FilterIdHigh和FilterIdLow组成一组32位ID);16位过滤器,则可分别独立检验一个ID
1.1.1关于移位操作:
标准帧用16位过滤器表示:FilterIdHigh、FilterIdLow、FilterMaskIdLow、FilterMaskIdLow各可以表示一个列表成员。由于标准帧的ID是11位的,所以需要将其ID左移5位。标准帧用32位过滤器表示:FilterIdHigh、FilterIdLow共同表示一个ID,FilterMaskIdLow、FilterMaskIdLow共同表示一个ID。由于标准帧ID是11位的,故表示时其ID需左移5位存入High,且LOW = 0 | CAN_ID_STD (意思是将IDE位置为0)。扩展帧用32位过滤器表示:扩展帧的ID是29位的,所以将扩展帧ID先左移3位与32位按高位对齐,再右移16位并取低16位,存入High;将扩展帧ID左移3位与32位对齐,再取低16位存入Low。具体操作如下
CAN_FilterTypeDef sFilterConfig //定义过滤器设置结构体变量
uint32_t StdId =0x321; //一个标准CAN ID
uint32_t ExtId =0x1800f001; //一个扩展CAN ID
sFilterConfig.FilterIdHigh = StdId<<5; //标准ID放入FilterIdHigh
sFilterConfig.FilterIdLow = 0|CAN_ID_STD; //标准ID,故设置IDE位为0
sFilterConfig.FilterMaskIdHigh = ((ExtId<<3)>>16)&0xffff; //扩展帧ID高16位放入 FilterMaskIdHigh
sFilterConfig.FilterMaskIdLow = (ExtId<<3)&0xffff|CAN_ID_EXT; //扩展帧ID高16位放入 FilterMaskIdLow,并设置 IDE位为1
1.2 配置CAN接收过滤器HAL_CAN_ConfigFilter
HAL_StatusTypeDef HAL_CAN_ConfigFilter(CAN_HandleTypeDef *hcan, CAN_FilterTypeDef *sFilterConfig)
功能:配置CAN过滤器
参数:第一个,CAN句柄指针,&hcan1 或 &hcan2
第二个,CAN配置结构体的指针
返回值:HAL状态注意:即使不过滤任何报文,也要将过滤器使能(ENABLE),可以用在掩码模式下将所有位配置为0实现无过滤
实例:
CAN_FilterTypeDef can_filter_st; //创建用于配置过滤器的FilterTypeDef类结构体
can_filter_st.FilterActivation = ENABLE; //使能过滤器
can_filter_st.FilterMode = CAN_FILTERMODE_IDMASK; //过滤模式位掩码模式
can_filter_st.FilterScale = CAN_FILTERSCALE_32BIT; //过滤器位宽为32位
can_filter_st.FilterIdHigh = 0x0000; //设置ID
can_filter_st.FilterIdLow = 0x0000;
can_filter_st.FilterMaskIdHigh = 0x0000;
can_filter_st.FilterMaskIdLow = 0x0000;
can_filter_st.FilterBank = 0; //过滤器编号
can_filter_st.FilterFIFOAssignment = CAN_RX_FIFO0; //把接收到的报文放入到FIFO0邮箱中
can_filter_st.SlaveStartFilterBank = 14; //为从属can选择开始的过滤库,对于单个CAN实例,这个参数没有意义,不考虑
HAL_CAN_ConfigFilter(&hcan1, &can_filter_st);//将配置好的结构体作为参数通过函数配置到CAN1的邮箱FIFO0的过滤器
2.开启CAN,HAL_CAN_Start
HAL_StatusTypeDef HAL_CAN_Start(CAN_HandleTypeDef *hcan);
功能:开启CAN,一般在while函数前一开始就要打开
参数:CAN句柄指针,&hcan1 或 &hcan2
返回值:返回值:HAL状态
3.1定义发送报文定义结构体(CAN_TxHeaderTypeDef)
配置包括:报文ID,帧类型IDE+RTR,数据长度DLC
typedef struct
{
uint32_t StdId; /*!标准ID。参数值只能是 0 到 0x7FF(二进制的11位1) */
uint32_t ExtId; /*!扩展ID。参数值只能是 0 到 0x1FFFFFFF(二进制的29位1)*/
//ExtId 与 StdId 这两个成员根据下面的 IDE 位配置,只有一个是有效的。
uint32_t IDE; /*!IDE。HAL库编程时,标准帧填写CAN_ID_STD,扩展帧填写CAN_ID_EXT */
uint32_t RTR; /*!RTR。HAL库编程时,数据帧填写CAN_RTR_DATA,遥控帧填写CAN_RTR_REMOTE */
uint32_t DLC; /*!DLC。数据长度,参数值只能是 0 到 8 */
FunctionalState TransmitGlobalTime; /*!< Specifies whether the timestamp counter value captured on start
of frame transmission, is sent in DATA6 and DATA7 replacing pData[6] and pData[7].
@note: Time Triggered Communication Mode must be enabled.
@note: DLC must be programmed as 8 bytes, in order these 2 bytes are sent.
This parameter can be set to ENABLE or DISABLE. */
} CAN_TxHeaderTypeDef;
3.2 发送报文,HAL_CAN_AddTxMessage
HAL_StatusTypeDef HAL_CAN_AddTxMessage(CAN_HandleTypeDef *hcan,
CAN_TxHeaderTypeDef *pHeader, uint8_t aData[], uint32_t *pTxMailbox);
功能:增加一个消息到第一个空闲的 Tx 邮箱,并且激活对应的传输请求
参数:第一个,CAN句柄指针,&hcan1 或 &hcan2
第二个,发送报文定义结构体的指针
第三个,数据帧数组的内容,长度不能超过定义的长度
第四个,Tx邮箱,可填 (uint32_t*)CAN_TX_MAILBOX0 ,CAN_TX_MAILBOX1 , CAN_TX_MAILBOX3
返回值:HAL状态注意:参数pTxMailbox是需要自己定义一个uint32_t的变量去传入,而非使用系统提供的发送邮箱宏定义。不然会进入硬件中断
4.1 定义接收报文定义结构体(CAN_RxHeaderTypeDef)
配置内容同上
typedef struct
{
uint32_t StdId;
uint32_t ExtId;
uint32_t IDE;
uint32_t RTR;
uint32_t DLC;
uint32_t Timestamp; /*!< Specifies the timestamp counter value captured on start of frame reception. @note: Time Triggered Communication Mode must be enabled.This parameter must be a number between Min_Data = 0 and Max_Data = 0xFFFF. */
uint32_t FilterMatchIndex; /*!< Specifies the index of matching acceptance filter element. This parameter must be a number between Min_Data = 0 and Max_Data = 0xFF. */
} CAN_RxHeaderTypeDef;
在中断回调中声明一个该类型结构体,不同配置,作为参数传递给getmessage函数
4.2接收报文
需要先开启中断HAL_CAN_ActivateNotification,第二个参数设置为CAN_IT_RX_FIFO0 _MSG_PENDING
HAL_StatusTypeDef HAL_CAN_ActivateNotification(CAN_HandleTypeDef *hcan, uint32_t ActiveITs)
功能:使能中断
参数:第一个,CAN句柄指针,&hcan1 或 &hcan2
第二个,使能哪个中断,在stm32f4xx_HAL_Driver.h中,搜索Receive Interrupts可以查到各宏定义,作为接收端时开启相对应的FIFO邮箱的接受中断
返回值:HAL状态
HAL_StatusTypeDef HAL_CAN_GetRxMessage(CAN_HandleTypeDef *hcan,
uint32_t RxFifo, CAN_RxHeaderTypeDef *pHeader, uint8_t aData[])
功能:从Rx FIFO收取一个 CAN 帧
参数:第一个,CAN句柄指针,&hcan1 或 &hcan2
第二个,Rx FIFO,可填 CAN_RX_FIFO0, CAN_RX_FIFO1
第三个,接收报文定义结构体的指针
第四个,接受数据数组
返回值:HAL状态
5. 接收中断回调函数HAL_CAN_RxFifo0MsgPendingCallback
每当CAN完成一帧数据的接收时,即当CAN控制器接收到一个消息并存放在FIFO邮箱中时,就会触发一次CAN接收中断处理函数,接收中断函数完成一些寄存器的处理之后会调用CAN接收中断回调函数。
一般在函数里面定义接收报文定义结构体(CAN_RxHeaderTypeDef)结构体变量,并用接收函数HAL_CAN_GetRxMessage接收
void HAL_CAN_RxFifo0MsgPendingCallback(CAN_HandleTypeDef *hcan)(根据使用0可能替换成1)
功能:接收回调函数,CAN回调后进行的操作。一般在此接收数据
参数:第一个,CAN句柄指针,&hcan1 或 &hcan2
返回值:void
6.函数实例
可以分别集成为四个函数
启动函数:启动CAN+使能中断
过滤器配置函数:定义过滤器结构体+配置CAN接收过滤器
发送函数:定义发送报文定义结构体+发送报文至邮箱
回调接收函数:在回调函数中定义接收报文结构体+接收邮箱内报文
启动函数:
void CAN_Start(CAN_HandleTypeDef *hcan)
{
HAL_CAN_Start(&hcan);
HAL_CAN_ActivateNotification(&hcan ,CAN_IT_RX_FIFO0_MSG_PENDING);
}
过滤器配置函数:
/**
* @brief 16位列表模式过滤器配置
* @param hcan CAN的句柄
* @param StdId1~StdId4 4个标准ID
*/
CAN_FilterTypeDef can_filter; //创建用于配置过滤器的FilterTypeDef类结构体
can_filter_st.FilterActivation = CAN_FILTER_ENABLE; //使能过滤器
can_filter_st.FilterMode = CAN_FILTERMODE_IDMASK; //过滤模式为掩码模式
can_filter_st.FilterScale = CAN_FILTERSCALE_32BIT; //过滤器位宽为32位
can_filter_st.FilterIdHigh = 0x0000; //设置ID
can_filter_st.FilterIdLow = 0x0000;
can_filter_st.FilterMaskIdHigh = 0x0000; //掩码模式下1为考虑为忽略,全为0即可以接收所有报文
can_filter_st.FilterMaskIdLow = 0x0000;
can_filter_st.FilterBank = 0; //过滤器编码0~27
can_filter_st.FilterFIFOAssignment = CAN_RX_FIFO0; //设置为FIFO0邮箱的过滤器
can_filter_st.SlaveStartFilterBank = 14; //为从属can选择初始的过滤库,对于单个CAN实例,这个参数没有意义,不用考虑
HAL_CAN_ConfigFilter(&hcan, &can_filter_st);//将配置好的结构体作为参数通过函数配置到CAN1的邮箱FIFO0的过滤器
发送函数:
uint8_t TX_data[8]; //创建用于存放所发送数据的数组
uint32_t mailbox; //作为SendMessage的参数,返回数据存放的邮箱
static CAN_TxHeaderTypeDef Tx_Header; //创建发送报文结构体
Tx_Header.StdId=0x12345678; //标准帧ID
Tx_Header.ExtId=0; //扩展帧ID,由于IDE配置为标准帧,故EXTID无效
Tx_Header.IDE=CAN_ID_STD; //帧类型——标准帧
Tx_Header.RTR=CAN_RTR_DATA; //帧类型——数据帧
Tx_Header.DLC=8; //长度——8位
HAL_CAN_AddTxMessage(&hcan, &Tx_Header, TX_data, &mailbox) //选择1个空置的发送邮箱,请求发送,邮箱马上进入挂号状态,并等待成为最高优先级的邮箱,其状态变为预定发送状态。一旦CAN总线进入空闲状态,预定发送邮箱中的报文就马上被发送(进入发送状态)。一旦邮箱中的报文被成功发送后,它马上变为空置邮箱。
void HAL_CAN_RxFifo0MsgPendingCallback(CAN_HandleTypeDef *hcan)
{
CAN_RxHeaderTypeDef RxHeader; //接受句柄
HAL_CAN_GetRxMessage(hcan, CAN_RX_FIFO0, &RxHeader, Rx_data); //接收数据存放到指定邮箱
}
回调+接收函数:
/**
* @brief CAN FIFO0的中断回调函数,在里面完成数据的接收
* @param hcan CAN的句柄
*/
uint8_t date_CAN1[8];//设为全局变量,用于接收CAN1数据
uint8_t date_CAN2[8];//设为全局变量,用于接收CAN2数据
void HAL_CAN_RxFifo0MsgPendingCallback(CAN_HandleTypeDef *hcan)
{
if(hcan->Instance ==CAN1)
{
CAN_RxHeaderTypeDef RxHeader; //创建接收报文结构体,只声明不配置
HAL_CAN_GetRxMessage(&hcan1, CAN_RX_FIFO0, &RxHeader, date_CAN1); //接收,CAN邮箱为0
return ;
}
else if(hcan->Instance == CAN2)
{
CAN_RxHeaderTypeDef RxHeader; //创建接收报文结构体,只声明不配置
HAL_CAN_GetRxMessage(&hcan2, CAN_RX_FIFO0, &RxHeader, date_CAN2); //接收,CAN邮箱为0
}
}