本文介绍: > 16:最后将上一步结果右移16位。因此,整个操作的目的是从32位的slave_id中提取出低16位,并将扩展帧和数据帧标志位添加到其中,最后进行掩码操作,得到最终的ID低位部分,并放置到CAN_FilterInitStructure.CAN_FilterIdLo中,以用作CAN过滤器的ID低位部分。因此,整个操作的目的是从32位的slave_id中提取出高16位,并放置到CAN_FilterInitStructure.CAN_FilterIdHigh中,以用作CAN过滤器的ID高位部分

CAN


一、配置

slave_id=0x18010001为只接收id号):

1、对扩展数据帧进行过滤:(只接收扩展数据帧)

CAN_FilterInitStructure.CAN_FilterIdHigh=(((u32)slave_id<<3)&0xFFFF0000)>>16;
CAN_FilterInitStructure.CAN_FilterIdLow=(((u32)slave_id&lt;<3)|CAN_ID_EXT|CAN_RTR_DATA)&amp;0xFFFF;
CAN_FilterInitStructure.CAN_FilterMaskIdHigh  = 0xFFFF;
CAN_FilterInitStructure.CAN_FilterMaskIdLow   = 0xFFFF;

CAN_FilterIdHigh:

一步是为了从32位的slave_id中提取出高16位作为CAN过滤器的ID高位部分

(u32)slave_id << 3:首先将slave_id强制转换为32位的无符号整数(u32),然后将其左移3位。这是为了将slave_id向左移动3位,为后续的位运算准备

&amp; 0xFFFF0000:然后结果与0xFFFF0000进行按位操作。0xFFFF0000是一个32位的十六进制数,它的二进制表示是11111111111111110000000000000000。这个操作会将结果的低16位全部变为0,只保留高16位的内容。>> 16:最后将上一步的结果右移16位。这个操作是为了将之前保留的高16位部分移到最低的16位中,这样就得到了最终的ID高位部分。

因此,整个操作的目的是从32位的slave_id中提取出高16位,并放置到CAN_FilterInitStructure.CAN_FilterIdHigh中,以用作CAN过滤器的ID高位部分。

CAN_FilterIdLow:

一步是为了从32位的slave_id中提取出低16位,并添加扩展帧和数据帧标志位,最后将结果进行掩码操作。

(u32)slave_id << 3:首先将slave_id强制转换为32位的无符号整数(u32),然后将其左移3位。这是为了将slave_id向左移动3位,为后续的位运算准备

| CAN_ID_EXT | CAN_RTR_DATA:然后将上一步的结果与CAN_ID_EXT和CAN_RTR_DATA进行按位或操作。CAN_ID_EXT代表扩展帧标志位,CAN_RTR_DATA代表数据帧标志位。通过按位或操作,可以将这两个标志位添加到ID的低16位部分。

&amp; 0xFFFF:最后将上一步的结果与0xFFFF进行按位与操作。0xFFFF是一个16位的十六进制数,它的二进制表示是1111111111111111。这个操作会将结果的高16位全部变为0,只保留低16位的内容

因此,整个操作的目的是从32位的slave_id中提取出低16位,并将扩展帧和数据帧标志位添加到其中,最后进行掩码操作,得到最终的ID低位部分,并放置到CAN_FilterInitStructure.CAN_FilterIdLo中,以用作CAN过滤器的ID低位部分。

2、对扩展远程过滤:(只接收扩展远程帧)

CAN_FilterInitStructure.CAN_FilterIdHigh = (((u32)slave_id<<3)&amp;0xFFFF0000)>>16;
CAN_FilterInitStructure.CAN_FilterIdLow  = (((u32)slave_id<<3)|CAN_ID_EXT|CAN_RTR_REMOTE)&amp;0xFFFF;
CAN_FilterInitStructure.CAN_FilterMaskIdHigh  = 0xFFFF;
CAN_FilterInitStructure.CAN_FilterMaskIdLow   = 0xFFFF;

3、对标准远程过滤:(只接收标准远程帧)

CAN_FilterInitStructure.CAN_FilterIdHigh   =(((u32)slave_id<<21)&amp;0xffff0000)>>16;
CAN_FilterInitStructure.CAN_FilterIdLow  = (((u32)slave_id<<21)|CAN_ID_STD|CAN_RTR_REMOTE)&amp;0xffff;
CAN_FilterInitStructure.CAN_FilterMaskIdHigh  = 0xFFFF;
CAN_FilterInitStructure.CAN_FilterMaskIdLow   = 0xFFFF;

4、对标准数据过滤:(只接收标准数据帧)

CAN_FilterInitStructure.CAN_FilterIdHigh   =(((u32)slave_id<<21)&amp;0xffff0000)>>16;
CAN_FilterInitStructure.CAN_FilterIdLow  = (((u32)slave_id<<21)|CAN_ID_STD|CAN_RTR_DATA)&amp;0xffff;
CAN_FilterInitStructure.CAN_FilterMaskIdHigh  = 0xFFFF;
CAN_FilterInitStructure.CAN_FilterMaskIdLow   = 0xFFFF;

5、对扩展帧进行过滤:(只接收扩展帧)

 CAN_FilterInitStructure.CAN_FilterIdHigh   =(((u32)slave_id<<3)&amp;0xFFFF0000)>>16;
 CAN_FilterInitStructure.CAN_FilterIdLow  = (((u32)slave_id<<3)|CAN_ID_EXT)&amp;0xFFF
 CAN_FilterInitStructure.CAN_FilterMaskIdHigh  = 0xFFFF;
 CAN_FilterInitStructure.CAN_FilterMaskIdLow   = 0xFFFC;

6、对标准帧进行过滤:(只接收标准帧)

CAN_FilterInitStructure.CAN_FilterIdHigh   =(((u32)slave_id<<21)&amp;0xffff0000)>>16;
CAN_FilterInitStructure.CAN_FilterIdLow  = (((u32)slave_id<<21)|CAN_ID_STD)&amp;0xffff;
CAN_FilterInitStructure.CAN_FilterMaskIdHigh  = 0xFFFF;
CAN_FilterInitStructure.CAN_FilterMaskIdLow   = 0xFFFC;

二、CAN过滤器详解

2.1 过滤器

STM32总共提供14个过滤器组来处理CAN接收过滤问题每个过滤器包含两个32位寄存器CAN_FxR0和CAN_FxR1组成,在设置屏蔽模式下,其中一个作为标识符寄存器,另一个作为屏蔽寄存器过滤器组中的每个过滤器,编号(叫做过滤器号)从0开始,到某个最大数值(这时最大值并非13,而是取决于14个过滤器组的模式和位宽的设置,当全部配置为位宽为16,且为标识符列表模式时,最大编号为14*4-1=55)。

2.2 过滤器的过滤模式

    STM32提供两种过滤模式用户设置屏蔽模式标识符列表模式。

2.2.1 屏蔽位模式

为了过滤出一组标识符应该设置过滤器组工作屏蔽位模式。
屏蔽位模式下,标识符寄存器屏蔽寄存器一起,指定报文标识符的任何一位,应该按照“必须匹配”或“不用关心”处理

2.2.2 标识符列表模式

为了过滤出一个标识符应该设置过滤器组工作标识符列表模式。
标识列表模式下,屏蔽存器也被当作标识符寄存器用。因此,不是采用一个标识加一个屏蔽位的方式,而是使用2个标识符寄存器。接收报文标识符的每一位都必须跟过滤器标识符相同

2.3 过滤器的位宽

    每个过滤器组的位宽都可以独立配置,以满足应用程序不同需求。根据位宽的不同,每个过滤器组可提供:
    ●1个32位过滤器,包括:STDID[10:0]、EXTID[17:0]、IDE和RTR位
    ●2个16位过滤器,包括:STDID[10:0]、IDE、RTR和EXTID[17:15]位

2.3 过滤器组的过滤模式和位宽设置

    过滤器组可以通过相应的CAN_FMR寄存器(CAN过滤器主控存器)配置。但是不是什么时候可以直接配置,在配置一个过滤器组前,必须通过清除CAN_FAR寄存器(CAN过滤器激活寄存器)的FACT位,把它设置禁用状态然后才能设置或设置过滤器组的配置。

通过设置CAN_FS1R(CAN过滤器位宽寄存器)的相应FSCx位,可以配置一个过滤器组的位宽。
通过CAN_FM1R(CAN过滤器模式寄存器)的FBMx位,可以配置对应的屏蔽/标识符寄存器的标识符列表模式或屏蔽位模式。

这些大家可以看一下。

2.4 过滤器匹配序号

            一旦收到的报文被存入FIFO,就可被应用程序访问。通常情况下,报文中的数据被拷贝到SRAM中;为了把数据拷贝到合适的位置应用程序需要根据报文的标识符来辨别不同的数据。bxCAN提供了过滤器匹配序号,以简化这一辨别过程。

         根据过滤器优先级规则,过滤器匹配序号和报文一起,被存入邮箱中。因此每个收到的报文,都有与它相关联的过滤器匹配序号。
         过滤器匹配序号可以通过下面两种方式来使用:
         ● 把过滤器匹配序号跟一系列期望的值进行比较
         ● 把过滤器匹配序号当作一个索引访问目标地址
        对于标识符列表模式下的过滤器(非屏蔽方式的过滤器),软件需要直接跟标识符进行比较。
        对于屏蔽位模式下的过滤器,软件只须对需要的那些屏蔽位(必须匹配的位)进行比较即可

在给过滤器编号时,并不考虑过滤器组是否激活状态。另外,每个FIFO各自对其关联的过滤器进行编号

在这里插入图片描述

2.5 过滤器优先级规则

根据过滤器的不同配置,有可能一个报文标识符能通过多个过滤器的过滤;在这种情况下,存放在接收邮箱中的过滤器匹配序号,根据下列优先级规则来确定:
● 位宽为32位的过滤器,优先级高于位宽为16位的过滤器
● 对于位宽相同的过滤器,标识符列表模式的优先级高于屏蔽位模式
● 位宽和模式都相同的过滤器,优先级由过滤器号决定,过滤器号小的优先级

三、CAN ID值的结构分析

给定一个CAN ID,如0x1800f001,当然这个是扩展ID,这里要问的是,这个CAN ID的值本身包含两部分,即基本ID与扩展ID,即么你知道这个扩展ID0x1800f001的哪些位是基本ID,哪些位又是扩展ID?(在基本CANID格式下不存在这个问题
我们先来看这两张图
在这里插入图片描述

在这里插入图片描述
图上说的很清楚 ID0-17是扩展ID,18-28为标准ID,这个时候我们就可以下手了
ID值0x1800f001用二进制表示为:0b 0001 1000 0000 0000 1111 0000 0000 0001,用括号分别区别为:0b 000[1 1000 0000 00][00 1111 0000 0000 0001],斜体部分为扩展ID,加粗分为基本ID。
每个寄存器都是32位的。最下边显示的是与CAN ID各位定位映射关系。上图最下边的映射关系恰好等于扩展CAN值左移3位再补上IDE(扩展帧标识),RTR(远程帧标志)。

3.1位宽为32位的屏蔽模式

在此种模式下中过滤多个CAN ID,此时,过滤器包含两个寄存器,屏蔽码寄存器和标识符寄存器。此模式下最多只存在一个屏蔽过滤器。
在这里插入图片描述
有些同学可能看不懂,我们可以从上帝视角看一下。上面的ID为标识符寄存器,中间部分的MASK为屏蔽码寄存器。可以看到他分成了4个块 比如你要发送ID为00 00 01 02 [7:0]=02 [15:8]=01依次类推。
对号入座的方法多种多样1:在各种过滤器模式下,CAN ID与寄存器相应位置一定要匹配;2:在屏蔽方式下,屏蔽码寄存器某位为1表示收到的CAN ID对应的位必须对验证码寄存器对应的位相同

3.2示例

下面给出一个代码例子假设我们要接收多个ID:0x7e9,0x1800f001,前面为标准ID,后面为扩展ID,要同时能接收这两个ID,那么该如何设置这个过滤器呢?

CAN_FilterInitTypeDef  CAN_FilterInitStructure;
U16 std_id =0x7e9;
U32 ext_id =0x1800f001;
U32 mask =0;
 
CAN_FilterInit(&amp;CAN_FilterInitStructure);     //初始化CAN_FilterInitStructrue结构变量
CAN_FilterInitStructure.CAN_FilterNumber=0;      //设置过滤器组0,范围为0~13
CAN_FilterInitStructure.CAN_FilterMode=CAN_FilterMode_IdMask;    //设置过滤器组0为屏蔽模式
CAN_FilterInitStructure.CAN_FilterScale=CAN_FilterScale_32bit;   //设置过滤器组0位宽为32位
 
//标识位寄存器的设置
//ext_id<<3对齐,见上图9,再>>16取高16位
CAN_FilterInitStructure.CAN_FilterIdHigh=(ext_id<<3) >>16) &amp;0xffff;  //设置标识符寄存器高字节。先左移三位将ID对齐(方便对号入座),然后右移16位把高位数据拿出来(下面还有补充)
CAN_FilterInitStructure.CAN_FilterIdLow=(U16)(ext_id<<3) | CAN_ID_EXT;   //设置标识符寄存器低字节(左移三位先对齐这个有补充可以看下面的
//这里也可以这样设置
//CAN_FilterInitStructure.CAN_FilterIdHigh=std_id<<5;  //设置标识符寄存器高字节.这里为什么是左移5位呢?从上图可以看出,CAN_FilterIdHigh包含的是STD[0~10]和EXID[13~17],标准CAN ID本身是不包含扩展ID数据,因此为了要将标准CAN ID放入此寄存器,标准CAN ID首先应左移5位后才能对齐.
//CAN_FilterInitStructure.CAN_FilterIdLow=0|CAN_ID_EXT;   //设置标识符寄存器低字节,这里也可以设置为CAN_ID_STD
 
//屏蔽寄存器的设置
//这里思路是先将标准CAN ID和扩展CAN ID对应的ID值先异或取反为什么异或是为了找出两个CAN ID有哪些位是相同的,是相同的位则说明需要关心,需要关心的位对应的屏蔽码位应该设置为1,因此需要取反一下。最后再整体左移3位。
mask =(std_id<<18);//这里为什么左移18位?因为从ISO11898中可以看出,标准CAN ID占ID18~ID28,为了与CAN_FilterIdHigh对齐,应左移2位,接着为了与扩展CAN对应,还应该再左移16位,因此,总共应左移2+16=18位。也可以用另一个方式来理解:直接看Mapping内容发现STDID相对EXID[0]偏移了18位,因此左移18位.
mask ^=ext_id;//将对齐后的标准CAN与扩展CAN异或取反
mask =~mask;
mask <<=3;//再整体左移3位
mask |=0x02; //只接收数据帧,不接收远程
CAN_FilterInitStructure.CAN_FilterMaskIdHigh=(mask>>16)&amp;0xffff; //设置屏蔽寄存器高字节
CAN_FilterInitStructure.CAN_FilterMaskIdLow=mask&0xffff;   //设置屏蔽寄存器低字节
 
CAN_FilterInitStructure.CAN_FilterFIFOAssignment=CAN_FIFO0;  //此过滤器组关联到接收FIFO0
CAN_FilterInitStructure.CAN_FilterActivation=ENABLE; //激活此过滤器组
CAN_FilterInit(&CAN_FilterInitStructure); //设置过滤器

由于右移16位操作可能会导致结果超出16位无符号整数范围,因此需要使用& 0xFFFF进行按位运算,以确保结果不超过该范围

CAN_ID_EXT是用于设置标识符寄存器低字节的掩码。通过将ext_id左移3位后与CAN_ID_EXT进行按位运算,可以确保扩展ID的高位数正确设置,并将低位对齐到标识符寄存器的低字节

在CAN通信中,标识符寄存器的低字节包含了扩展ID的低位数据以及一些控制位,如远程帧标志位(RTR)等。所以需要使用按位运算来将扩展ID的低位数据与控制位进行合并,确保正确设置标识符寄存器的低字节。

总结可知,当过滤器为屏蔽模式时,标识符寄存器对应的ID内容可为任意需求接收的ID值,当同时要接收标准帧和扩展帧时,标识符寄存器对应IDE位也随意设置,屏蔽寄存器的IDE位设置为0,表示不关心标准帧还是扩展帧。而屏蔽寄存器对应的ID内容为各需求接收的ID值依次异或的结果再取反。

最后感谢
flydream0这位博主,我也只是在他的基础上加上自己的理解。

原文地址:https://blog.csdn.net/qq_51963216/article/details/134683930

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任

如若转载,请注明出处:http://www.7code.cn/show_33196.html

如若内容造成侵权/违法违规/事实不符,请联系代码007邮箱suwngjj01@126.com进行投诉反馈,一经查实,立即删除

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注