STM32系列文章(2):CAN总线过滤器详解
前言
STM32 CAN总线的过滤器的作用主要是通过数据的帧ID,过滤掉一部分数据不做处理节约CPU硬件资源,我们可以设置不同的过滤条件来滤除不需要的数据,本文主要讲ID掩码过滤模式
一、与滤波设置相关的结构体
在HAL库中,跟滤波设置相关的结构体是CAN_FilterTypeDef
,下面逐步讲解过滤过程。
二、逐步讲解
1.定义一个滤波器设置结构体
CAN_FilterTypeDef CAN_FilterInitStructure;
2.设置过滤模式
CAN_FilterInitStructure.FilterMode = CAN_FILTERMODE_IDMASK;
3.设置 过滤比例
这里可能不明白什么意思,我用的STM32信号是F407 CAN总线有14个过滤器,每个过滤器有2个32位寄存器可以配置,可以配置成32位也可以配置成两个16位。
CAN_FilterInitStructure.FilterScale = CAN_FILTERSCALE_32BIT;
4.设置过滤ID和掩码ID
这是本文重点,两者共同确定了,到底哪些ID接收哪些ID过滤,下面我先把我的代码贴出来作为例子讲解.
CAN_FilterInitStructure.FilterIdHigh = 0x0020;
CAN_FilterInitStructure.FilterIdLow = 0x0000;
CAN_FilterInitStructure.FilterMaskIdHigh = 0xFF80;
CAN_FilterInitStructure.FilterMaskIdLow = 0x0000;
首先这个ID是真正的帧ID左移21位得到的,也就是说我这里0x00200000,是由0x01左移21位得到的(这里指标准帧,扩展帧是3位)。
ID高16位 | ID低16位 |
0x0020 | 0x0000 |
0000 0000 0010 0000 | 0000 0000 0000 0000 |
掩码高16位 | 掩码低16位 |
0xFF80 | 0x0000 |
1111 1111 1000 0000 | 0000 0000 0000 0000 |
我们把这两个数据的二进制形式放在一起,先看高16位如下:
ID | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
掩码 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
掩码是1的位,意味着通过的数据帧的ID必须与上面一行我们指定的ID的对应位相等,如果掩码位是0,则没有要求,这样看来我们上面的高16位,能够通过的数据帧ID 必须是
ID | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0/1 | 0/1 | 0 | 0 | 0 | 0 | 0 |
然后再右21位得到帧ID,由此看来,我这种过滤方法,只能让0x00,0x01,0x02,0x03通过,别的ID统统过滤掉,经过我的验证,确实是这样,所以暂且认为我理解的是对的.
2.完整代码供大家参考
void CAN_FilterInit(CAN_HandleTypeDef *hcan)
{
CAN_FilterTypeDef CAN_FilterInitStructure;
CAN_FilterInitStructure.FilterMode = CAN_FILTERMODE_IDMASK;
CAN_FilterInitStructure.FilterScale = CAN_FILTERSCALE_32BIT;
CAN_FilterInitStructure.FilterIdHigh = 0x0020;
CAN_FilterInitStructure.FilterIdLow = 0x0000;
CAN_FilterInitStructure.FilterMaskIdHigh = 0xFF80;
CAN_FilterInitStructure.FilterMaskIdLow = 0x0000;
CAN_FilterInitStructure.FilterBank = 0;
CAN_FilterInitStructure.FilterFIFOAssignment = CAN_RX_FIFO0;
CAN_FilterInitStructure.FilterActivation = ENABLE;
CAN_FilterInitStructure.SlaveStartFilterBank = 14;
if(HAL_CAN_ConfigFilter(hcan,&CAN_FilterInitStructure) != HAL_OK)
{
Error_Handler();
}
if(HAL_CAN_ActivateNotification(hcan,CAN_IT_RX_FIFO0_MSG_PENDING) != HAL_OK)
{
Error_Handler();
}
if(HAL_CAN_Start(hcan) != HAL_OK)
{
Error_Handler();
}
}
三.扩展说明
我们还可以通过或CAN_ID_EXT和CAN_RTR_DATA等define值来实现只接受扩展数据帧或者扩展遥控帧等等,具体如下例子(其中slave_id为要保留的id号):
1、对扩展数据帧进行过滤:(只接收扩展数据帧)
CAN_FilterInitStructure.CAN_FilterIdHigh = (((u32)slave_id<<3)&0xFFFF0000)>>16;
CAN_FilterInitStructure.CAN_FilterIdLow = (((u32)slave_id<<3)|CAN_ID_EXT|CAN_RTR_DATA)&0xFFFF;
CAN_FilterInitStructure.CAN_FilterMaskIdHigh = 0xFFFF;
CAN_FilterInitStructure.CAN_FilterMaskIdLow = 0xFFFF;
2、对扩展远程帧过滤:(只接收扩展远程帧)
CAN_FilterInitStructure.CAN_FilterIdHigh = (((u32)slave_id<<3)&0xFFFF0000)>>16;
CAN_FilterInitStructure.CAN_FilterIdLow = (((u32)slave_id<<3)|CAN_ID_EXT|CAN_RTR_REMOTE)&0xFFFF;
CAN_FilterInitStructure.CAN_FilterMaskIdHigh = 0xFFFF;
CAN_FilterInitStructure.CAN_FilterMaskIdLow = 0xFFFF;
3、对标准远程帧过滤:(只接收标准远程帧)
CAN_FilterInitStructure.CAN_FilterIdHigh = (((u32)slave_id<<21)&0xffff0000)>>16;
CAN_FilterInitStructure.CAN_FilterIdLow = (((u32)slave_id<<21)|CAN_ID_STD|CAN_RTR_REMOTE)&0xffff;
CAN_FilterInitStructure.CAN_FilterMaskIdHigh = 0xFFFF;
CAN_FilterInitStructure.CAN_FilterMaskIdLow = 0xFFFF;
4、对标准数据帧过滤:(只接收标准数据帧)
CAN_FilterInitStructure.CAN_FilterIdHigh = (((u32)slave_id<<21)&0xffff0000)>>16;
CAN_FilterInitStructure.CAN_FilterIdLow = (((u32)slave_id<<21)|CAN_ID_STD|CAN_RTR_DATA)&0xffff;
CAN_FilterInitStructure.CAN_FilterMaskIdHigh = 0xFFFF;
CAN_FilterInitStructure.CAN_FilterMaskIdLow = 0xFFFF;
5、对扩展帧进行过滤:(扩展帧不会被过滤掉)
CAN_FilterInitStructure.CAN_FilterIdHigh = (((u32)slave_id<<3)&0xFFFF0000)>>16;
CAN_FilterInitStructure.CAN_FilterIdLow = (((u32)slave_id<<3)|CAN_ID_EXT)&0xFFFF;
CAN_FilterInitStructure.CAN_FilterMaskIdHigh = 0xFFFF;
CAN_FilterInitStructure.CAN_FilterMaskIdLow = 0xFFFC;
6、对标准帧进行过滤:(标准帧不会被过滤掉)
CAN_FilterInitStructure.CAN_FilterIdHigh = (((u32)slave_id<<21)&0xffff0000)>>16;
CAN_FilterInitStructure.CAN_FilterIdLow = (((u32)slave_id<<21)|CAN_ID_STD)&0xffff;
CAN_FilterInitStructure.CAN_FilterMaskIdHigh = 0xFFFF;
CAN_FilterInitStructure.CAN_FilterMaskIdLow = 0xFFFC;
四.总结
通过对以上两种的综合运用,相信可以实现对任意帧种类任意帧ID进行过滤了。累了,拜拜