个人认为过滤器的本质就是对ID值(局部or全部)的比较。
协议层雅特力跟标准CAN略有不同,详见:【雅特力AT32】 MCU CAN入门指南(超详细)
协议层了解差不多,直接来应用编程实战就好了,CAN实操学习步骤大致如下(个人见解,欢迎讨论,小白有问题可私信):
- CANdb++Editor安装包及教程移步:
【安装手册】CANdb++ Editor - DBC文件如何看懂,怎么使用?做一个就知道了:
【使用手册】CANdb++Editor:自制一个DBC文件 - 雅特力AT32 CAN使用入门:
【雅特力AT32 CAN】 MCU CAN入门使用指南(超详细) - can数据收发实战:
【CAN 数据收发实战】上位机ZCANPRO发送+USART打印DBC文件发送的报文信息——以雅特力AT32为例
【以雅特力AT32为例】CAN过滤器及其原理与邮箱配置 - CAN报文解析:
【DBC报文矩阵分析】读懂.DBC文件报文矩阵,信号矩阵数据解析思路(源码见链接)
【数据存储】大/小端存储与字节顺序转换函数详解 - 解析代码实现移步:
【CAN报文数据解析】矩阵信号Intel与Motorola格式(C语言)代码 - SocketCan 应用编程与Socket网络编程及其相似:
【CAN 应用编程基础】SocketCan实战 - 学完QT,尝试试自己做一个CAN上位机软件,基本掌握CAN;
【自制 CAN上位机】MY_CAN Tool V1.0 (GitHub开源)
优秀文章参考与推荐见文末。
目录
1.AT32–过滤器
1.1 过滤器的位宽
1.2 过滤器模式2.AT32过滤器的使用(过滤器工作原理
2.1 过滤器配置结构体参数说明
2.2 过滤器工作原理
2.3 过滤器应用实例3.AT32收发邮箱(FIFO)
1. AT32–过滤器
在 CAN 协议里,报文的 ID 不代表节点的地址,而是跟报文的内容相关的。
首先,发送者以广播的形式把报文发送给所有的接收者。
其后,节点在接收报文时,根据 ID 的值决定软件是否需要该报文;如果需要,就存到接收 FIFO 里,用户可通过软件读取接收邮箱寄存器获取该报文;如不需要,报文就被丢弃且无需软件的干预。
为满足这一需求,AT32 CAN 控制器为应用程序提供了 28 个硬件过滤器组(AT32F435 系列有 28 个过滤器组,0~27;但 AT32F403A 等系列只有 14 个过滤器组,0~13。具体请参考相应型号的 RM),以便只接收那些软件需要的报文。用户配置好需要的 ID 后,整个过滤过程无需软件参与,不占用CPU 资源。
1.1 过滤器的位宽
每个过滤器组由 2 个 32bit 的寄存器,CAN_FiFB1 和 CAN_FiFB2 组成。
通过配置 CAN_FBWCFG寄存器的 FBWSELx 位,设置 2 个 16 位宽或 1 个 32 位宽的过滤器。
32 位宽的过滤器寄存器 CAN_FiFBx :一组 SID[10:0]、EID[17:0]、IDT 和 RTR 位。
16 位宽的过滤器寄存器 CAN_FiFBx :两组 SID[10:0]、IDT、RTR 和 EID[17:15]位。
1.2 过滤器模式
通过设置 CAN_FMCFG 寄存器的 FMSELx 位可以设置过滤器寄存器工作在标识符掩码模式或者标识符列表模式。
掩码模式:用来指定 ID 的哪些位需要与预设 ID 相同,哪些位无需比较;第一步:首先准备好一张表,把需要关注的所有CAN报文ID写上去;第二步:过滤对比次表,如果接收报文ID与表相符则通过,没有则不通过。列表模式:用来表示 ID的每个位都必须与预设 ID 一致。第一步:获取想进城的人的身份证号码;第二步:只看获取到身份证的第7~9位,其他位忽略;第三步:将忽略后的结果与1156进行比较;第四步:比较结果相同则通过,不同则不能通过。
两种模式与过滤器位宽配合使用,可以有以下四种过滤方式:
加强理解:验证码与屏蔽码
掩码模式的过滤器计算逻辑为:
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-0x6c;
0110 1110-0x6e;
1100 0100-0xc4;
1100 0110-0xc6;
1100 1100-0xcc;
1100 1110-0xce;
1110 0100-0xe4;
1110 0110-0xe6;
1110 1100-0xec;
1110 1110-0xee;
这些结果都是可以通过过滤器的。
2. AT32过滤器的使用(过滤器工作原理)
2.1 过滤器配置结构体参数说明
typedef struct
{confirm_state filter_activate_enable; /*!< 用于启用或禁用过滤器激活.*/can_filter_mode_type filter_mode; /*!< 用于配置过滤器模式,可以是掩码模式或列表模式.*/can_filter_fifo_type filter_fifo; /*!< 用于配置将匹配的帧存储在哪个 FIFO 中. */uint8_t filter_number; /*!< 用于配置过滤器编号,范围从 0 到 13. */can_filter_bit_width_type filter_bit; /*!< 用于配置过滤器的位宽,可以是 16 位或 32 位.*/uint16_t filter_id_high; /*!< 用于配置过滤器的标识符高位部分. */uint16_t filter_id_low; /*!< 用于配置过滤器的标识符低位部分. */uint16_t filter_mask_high; /*!< 用于配置过滤器的掩码或标识符的高位部分. */uint16_t filter_mask_low; /*!< 用于配置过滤器的掩码或标识符的低位部分. */
} can_filter_init_type;
2.2 过滤器工作原理
网上看了一堆没懂,感觉好多废话,**上面的引入(验证码与屏蔽码)**看懂就没啥问题,过滤器玩来玩去就原理这么两句(红色框):
重点在于掩码模式:对结构体后四个值filter_id_high\low、filter_mask_high\low的配置;
2.3 过滤器应用实例
典例1:16/32位掩码模式应用实例
以下位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
设置为掩码模式时:一般我们称R1寄存器为ID寄存器(或者验证码寄存器),R2为掩码寄存器。
看上图寄存器每一个位的映射关系可看出高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会通过。所以掩码模式的优势和缺点显而易见。
典例2:试试看!
典例3:AT32过滤器配置例程
/* extended identifier */
#define FILTER_EXT_ID1 ((uint32_t)0x18F5F100)
#define FILTER_EXT_ID2 ((uint32_t)0x18F5F200)
#define FILTER_EXT_ID3 ((uint32_t)0x18F5F300)/* standard identifier */
#define FILTER_STD_ID1 ((uint16_t)0x04F6)
#define FILTER_STD_ID2 ((uint16_t)0x04F7)
#define FILTER_STD_ID3 ((uint16_t)0x04F8)
/* can filter 0 config:对拓展帧的处理 */can_filter_init_struct.filter_activate_enable = TRUE; //激活/失能can_filter_init_struct.filter_mode = CAN_FILTER_MODE_ID_LIST; //列表/掩码ID模式can_filter_init_struct.filter_fifo = CAN_FILTER_FIFO0; //FIFOcan_filter_init_struct.filter_number = 0; //编号can_filter_init_struct.filter_bit = CAN_FILTER_32BIT; //位宽can_filter_init_struct.filter_id_high = (((FILTER_EXT_ID1 << 3) >> 16) & 0xFFFF); /* extended identifier is 29 bit */can_filter_init_struct.filter_id_low = ((FILTER_EXT_ID1 << 3) & 0xFFFF) | 0x04;can_filter_init_struct.filter_mask_high = ((FILTER_EXT_ID2 << 3) >> 16) & 0xFFFF; /* extended identifier is 29 bit */can_filter_init_struct.filter_mask_low = ((FILTER_EXT_ID2 << 3) & 0xFFFF) | 0x04;can_filter_init(CAN1, &can_filter_init_struct);/* can filter 1 config:对标准帧的处理 */can_filter_init_struct.filter_activate_enable = TRUE;can_filter_init_struct.filter_mode = CAN_FILTER_MODE_ID_LIST;can_filter_init_struct.filter_fifo = CAN_FILTER_FIFO0;can_filter_init_struct.filter_number = 1;can_filter_init_struct.filter_bit = CAN_FILTER_32BIT;can_filter_init_struct.filter_id_high = FILTER_STD_ID1 << 5; /* standard identifier is 11 bit */can_filter_init_struct.filter_id_low = 0;can_filter_init_struct.filter_mask_high = FILTER_STD_ID2 << 5;/* standard identifier is 11 bit */can_filter_init_struct.filter_mask_low = 0;can_filter_init(CAN1, &can_filter_init_struct);
3. AT32收发邮箱(FIFO)
AT32只有发送邮箱有优先级配置,接收邮箱主要起一个缓存存储的作用,后续以发送邮箱为主介绍。
详细见:【雅特力AT32 CAN】 MCU CAN入门使用指南(超详细)-CSDN博客
CAN 发送流程见下图 10 和以下的步骤:
下图 10 中标志位和操作位说明如下:
★★★其他优秀讲解推荐★★★:
真正让我搞清楚过滤器high/low规则:
☆CAN的过滤器设置☆、[关于CAN过滤器的一些设置方法 - WCH_CH32 - 博客园 (cnblogs.com)](https://www.cnblogs.com/wchmcu/p/17170782.html#:~:text=可过滤出一个标识。,此时CAN_FxR0和CAN_FxR1中的都是要匹配的标识符,收到的帧的标识符必须与其中的一个吻合才能通过过滤。 注意:CAN_FilterIdHigh是指高16位CAN_FilterIdLow是低16位应该将需要得到的帧的和过滤器的设置值左对齐。)
CAN收发及波特率配置、过滤器与邮箱的配置与使用:
工业协议 专栏: CAN总线(二) 、 CAN总线的过滤器与邮箱(四)
e=blogcolumn&sharetype=blogcolumn&sharerId=11201295&sharerefer=PC&sharesource=Thmos_vader&sharefrom=from_link) 专栏: CAN总线(二) 、 CAN总线的过滤器与邮箱(四)
CAN小知识 专栏: STM32 CAN过滤器详解 、 RMer:CAN通信配置过滤器和使用三个邮箱发送