CAN 滤波器设置的指南
CAN帧
帧的分类:
数据帧结构:
最常见使用的就是数据帧,下面就详细捋一捋数据帧。
参考【1】根据CAN2.0的标准知数据帧有标准格式和扩展格式,用来传输数据。
从图上看标准格式与扩展格式的区别只有ID的差距;
标准格式与扩展格式仲裁段
关于ID:
关于标识符:
32单片机CAN的过滤器设置
知道上面的ID设定,下面看看STM32的CAN控制器是怎么将ID过滤的。
过滤器组
32单片机有好多个滤波器组,每个滤波器组可以配置为掩码模式和列表模式,每个模式都可以配置为16位和32位过滤器。
只有一个CAN外设的MCU一般有编号为0~13共14个过滤器可用;
在有两个CAN外设的MCU中:CAN0使用的是过滤器编号为0-13;而CAN1使用的是14-27;共有28个过滤器;

一个过滤器组是由两个32位寄存器组成,CAN_FxR1与CAN_FxR2组成;可以将其配置为:
掩码模式
当我们设置为掩码模式时:一般我们称R1寄存器为ID寄存器(或者验证码寄存器),R2为掩码寄存器。
掩码模式的过滤器计算逻辑为:
ID码: 0110 0110 //0x66
掩码: 0101 0101 //0x55
计算结果:
x1x0 x1x0 //
0100 0100-0x44;
0100 0110-0x46;
0100 1100-0x4b;
0100 1110-0x4e;
0110 0100-0x64;
0110 0110-0x66;
0110 1100-0x6b;
0110 1110-0x6e;
1100 0100-0xb4;
1100 0110-0xb6;
1100 1100-0xbb;
1100 1110-0xbe;
1110 0100-0xe4;
1110 0110-0xe6;
1110 1100-0xeb;
1110 1110-0xee;
这些结果都是可以通过过滤器的。
16位掩码模式应用实例
项目要求:过滤出来0x62a-0x62c和0x64a-0x64c的ID
因为是标准ID所以选择16位模式,设置两个过滤器;
0x62a – 0000 0110 0010 1010
0x62b – 0000 0110 0010 1011
0x62c – 0000 0110 0010 1100
看到只有低三位不一样,所以:ID码为: 0000 0110 0010 1000 - 0x628 掩码为: 1111 1111 1111 1000 - 0xff8 这样就可以将0x628-0x62f全部过滤出来了(其中包括我们想要的0x62a-0x62c)
看上图寄存器每一个位的映射关系可以看出高11位存的是STID,所以要把掩码和ID移位到对应的位上;
can_filter.filter_list_high = (uint16_t)(0x628<<5);//设置接受地址为0x628-0x62f的数据
can_filter.filter_mask_high = (uint16_t)(0xfff8<<5);//
同样的,过滤0x64a-0x64c的设置为:
can_filter.filter_list_low = (uint16_t)(0x648<<5);//设置接受地址为0x648-0x64f的数据
can_filter.filter_mask_low = (uint16_t)(0xfff8<<5);//
由此可见,掩码模式可以过滤掉大部分不想要的ID,但是也会有一些不想要的ID会通过。所以掩码模式的优势和缺点显而易见。
32位掩码模式
明白16位掩码模式,32位掩码模式也就明白了。32位掩码模式可用于扩展帧的ID(标准帧也可以用),只需要根据下图将ID和掩码的每一位与CAN_FxR1和CAN_FxR2寄存器的每一位的映射对应起来就好了。
列表模式
列表模式相对来说比较简单,把想要的ID移位后赋给CAN_FxRx寄存器就可以了;
还是上面的项目场景设计为列表模式就需要至少两个滤波器组;
将滤波器设置为16位列表模式,一个过滤器组可以设置4个滤波器;总共要过滤6个ID,需要两个;
/* filter config */
can_filter.filter_number = 1;//过滤器编号
can_filter.filter_list_high = (uint16_t)0x62a<<5;//
can_filter.filter_mask_high = (uint16_t)(0x62b<<5);//
can_filter.filter_list_low = (uint16_t)0x62c<<5;//
can_filter.filter_mask_low = (uint16_t)(0x64a<<5);//
can_filter.filter_number = 2;//过滤器编号
can_filter.filter_list_high = (uint16_t)0x64b<<5;//
can_filter.filter_mask_high = (uint16_t)(0x64c<<5);//
can_filter.filter_list_low = (uint16_t)0x0000;//
can_filter.filter_mask_low = (uint16_t)0x0000;//
当然也可以将过滤器设置为32位列表模式,那就需要3个过滤器组了,没有太大的必要;
参考文章:
【1】CAN协议帧结构-part1
【2】CAN筛选器之ID配置
【3】CAN总线笔记(2)-CAN通信的数据帧与遥控帧
【4】CAN总线通信协议(总结篇)
【5】CAN总线基础知识(2)——CAN的数据帧