打印
[研电赛技术支持]

详解CAN通信的标识符掩码和标识符列表两种过滤机制

[复制链接]
2548|8
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
tpgf|  楼主 | 2023-10-17 17:17 | 只看该作者 |只看大图 回帖奖励 |倒序浏览 |阅读模式
CAN 通信的应用非常广泛,本文不涉及CAN通信的基础配置,重点分析一下STM32和GD32的CAN通信两种ID过滤方式。

首先,不管是STM32还是GD32,实现CAN通信ID过滤的机制和原理一定是一样的,只是用到的寄存器有差别。

1. ID过滤原理:
在CAN协议里,报文的标识符不代表节点的地址,而是跟报文的内容相关的。因此,发送者以广播的形式把报文发送给所有的接收者。节点在接收报文时,根据标识符的值决定软件是否需要该报文。
为满足这一需求,在互联型产品中,bxCAN控制器为应用程序提供了28个位宽可变的、可配置的过滤器组(270);在其它产品中,bxCAN控制器为应用程序提供了14个位宽可变的、可配置的过滤器组(130),以便只接收那些软件需要的报文。硬件过滤的做法节省了CPU开销,否则就必须由软件过滤从而占用一定的CPU开销。

每个过滤器组x由2个32位寄存器,在STM32中是由CAN_FxR0和CAN_FxR1组成。在GD32中是由器CAN_FxDATA0和CAN_ FxDATA1组成。

2. ID过滤方式:
掩码模式、列表模式。
不管是掩码模式还是列表模式,目的肯定都是为了让数据接收方接收特定ID的数据,但是既然分了两种模式,肯定有他们的不同的目的。

3.ID过滤方式1——掩码模式:
在掩码模式下,标识符寄存器和屏蔽寄存器一起,指定报文标识符的任何一位,应该按照“必须匹配”或“不用关心”处理。
举个例子:
假如是标准帧模式,以16位宽度为例,预设的ID=0x0001,当期望接收所有ID尾号为1的数据,那么设置对应的掩码为MASK=0x0001即可。
为什么呢?将ID的0x0001和MASK的0x0001解析成2进制:
预设ID:0000 0000 0000 0001;
MASK:0000 0000 0000 0001;
MSAK值的1的位表示:接收的ID必须与预设ID的位一致;
MASK值为0的位表示:接收的ID可以不与预设ID的位一致;
因此示例的MASK仅限制了ID的最后1位与预设ID的最后1为一致即可,其余的位不做限制,只要满足这样形式的ID数据,都能通过示例的过滤机制,从而被接收方正确接收,此处可知,掩码的作用就是要以预设ID为模板,决定过滤掉哪些类型的ID;

也就是说:
为了过滤出一组标识符,应该设置过滤器组工作在掩码模式。

注意,示例选用了标准帧模式,以16位宽度进行过滤,因此原本一个过滤器组的2个32位寄存器就分成了4个16位的空间,分别去保存预设的ID和相应的掩码:
格式如下:
预设ID1:【占用寄存器1的低16位】;
ID1的掩码:【占用寄存器1的高16位】;
同理:
预设ID2:【占用寄存器2的低16位】;
ID2的掩码:【占用寄存器2的高16位】;

由此可知,此种方式下,最多可预设2种ID,可过滤出多个ID;
STM32与GD32的过滤器机制一模一样:
(1)STM32参考手册的16位掩码模式过滤器如下:

(2)GD32参考手册的16位掩码模式过滤器如下:


注意,此种模式下,在配置时需要将对应的ID和掩码数据分别写进寄存器的STID区域,如上图所示,在16位空间中,STID区域处于高11位,因此需要将预设ID和掩码数据左移5位后写进寄存器。代码如下:

/**
* @brief    can外设配置
* @param    None
* @retval   返回值
*/
void can_config(void)
{
        GPIO_InitTypeDef GPIO_InitStructure;
        CAN_InitTypeDef CAN_InitStructure;
        CAN_FilterInitTypeDef CAN_FilterInitStructure;

        RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
        RCC_APB1PeriphClockCmd(RCC_APB1Periph_CAN1, ENABLE);

        /*
    CAN1_RX -- PA11
    CAN1_TX -- PA12
    */
        GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12;
        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
        GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
        GPIO_Init(GPIOA, &GPIO_InitStructure);

        GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11;
        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
        GPIO_Init(GPIOA, &GPIO_InitStructure);

        CAN_DeInit(CAN1);
        CAN_StructInit(&CAN_InitStructure);
        CAN_InitStructure.CAN_TTCM = DISABLE; //不生成时间戳
        CAN_InitStructure.CAN_ABOM = ENABLE;  //自动总线关闭管理
        CAN_InitStructure.CAN_AWUM = DISABLE; //自动唤醒模式
        CAN_InitStructure.CAN_NART = DISABLE; //仲裁丢失或出错后的自动重传功能
        CAN_InitStructure.CAN_RFLM = DISABLE; //接收FIFO加锁模式
        CAN_InitStructure.CAN_TXFP = ENABLE;  //传输FIFO优先级
        CAN_InitStructure.CAN_Mode = CAN_Mode_Normal;

        CAN_InitStructure.CAN_SJW = CAN_SJW_1tq;
        CAN_InitStructure.CAN_BS1 = CAN_BS1_9tq;
        CAN_InitStructure.CAN_BS2 = CAN_BS1_8tq;
        CAN_InitStructure.CAN_Prescaler = 40; // 波特率36000000/18/40 = 50KHz
        CAN_Init(CAN1, &CAN_InitStructure);

        CAN_FilterInit(&CAN_FilterInitStructure);
        CAN_FilterInitStructure.CAN_FilterNumber = 0;
        CAN_FilterInitStructure.CAN_FilterMode = CAN_FilterMode_IdMask;
        CAN_FilterInitStructure.CAN_FilterScale = CAN_FilterScale_16bit;
        if (can.device_mode == DEVICE_MASTER) //识别所有0x0xx类型的从设备地址
        {
                CAN_FilterInitStructure.CAN_FilterIdHigh = CAN_ID_BASE_SLAVE << 5; //ID1
                CAN_FilterInitStructure.CAN_FilterMaskIdHigh = 0x700 << 5;                   //ID1_MASK
                CAN_FilterInitStructure.CAN_FilterIdLow = CAN_ID_DEFAULT << 5;           //ID2
                CAN_FilterInitStructure.CAN_FilterMaskIdLow = 0x7FF << 5;                   //ID2_MASK
        }
        else //仅识别与本设备地址匹配的地址,保证主设备对从设备实现一对一通讯,也识别0x0000广播
        {
                CAN_FilterInitStructure.CAN_FilterIdHigh = can.std_id << 5; //ID1
                CAN_FilterInitStructure.CAN_FilterMaskIdHigh = 0x7FF << 5;        //ID1_MASK
                CAN_FilterInitStructure.CAN_FilterIdLow = 0x0000 << 5;                //ID2
                CAN_FilterInitStructure.CAN_FilterMaskIdLow = 0x7FF << 5;        //ID2_MASK
        }

        CAN_FilterInitStructure.CAN_FilterFIFOAssignment = CAN_Filter_FIFO0;
        CAN_FilterInitStructure.CAN_FilterActivation = ENABLE;
        CAN_FilterInit(&CAN_FilterInitStructure);

        CAN_ITConfig(CAN1, CAN_IT_FMP0, ENABLE); //FIFO0消息挂号中断
        nvic_set(USB_LP_CAN1_RX0_IRQn, IRQ_PRIO_CAN1);
}




4. ID过滤方式2——列表模式:
在标识符列表模式下,屏蔽寄存器也被当作标识符寄存器用。因此,不是采用一个标识符加一个屏蔽位的方式,而是使用2个标识符寄存器。接收报文标识符的每一位都必须跟过滤器标识符相同。通俗一点讲就是:接收的ID必须与预设的ID一模一样才能通过过滤,最终被接收到。

举个例子:
假如是标准帧模式,以16位宽度为例,预设的ID=0x0001,当期望仅接收与预设ID一致的数据,那么只要发送的ID与预设ID一样就可以被接收到,其余类型的ID数据都被过滤掉,接收方将接收不到此类数据。

也就是说:
为了过滤出一个标识符,应该设置过滤器组工作在标识符列表模式。

注意,示例选用了标准帧模式,以16位宽度进行过滤,因此原本一个过滤器组的2个32位寄存器就分成了4个16位的空间,分别去保存预设的ID:
格式如下:
预设ID1:【占用寄存器1的低16位】;
预设ID2:【占用寄存器1的高16位】;
预设ID3:【占用寄存器2的低16位】;
预设ID4:【占用寄存器2的高16位】;

由此可知,此种方式下,最多可预设4种ID,可过滤出4个ID;
STM32与GD32的过滤器机制一模一样:
(1)STM32参考手册的16位列表模式过滤器如下:

(2)GD32参考手册的16位列表模式过滤器如下:


注意,此种模式下,在配置时需要将对应的4个ID分别写进寄存器的STID区域,如上图所示,在16位空间中,STID区域处于高11位,因此需要将预设ID数据左移5位后写进寄存器。示例代码如下:

CAN_FilterInitStructure.CAN_FilterMode = CAN_FilterMode_IdList;     //??????  
  CAN_FilterInitStructure.CAN_FilterScale = CAN_FilterScale_16bit;    //?????16?  
  CAN_FilterInitStructure.CAN_FilterIdHigh = std_id<<5;  //4???CAN ID?????4????  
  CAN_FilterInitStructure.CAN_FilterIdLow = std_id1<<5;  
  CAN_FilterInitStructure.CAN_FilterMaskIdHigh = std_id<<5;  
  CAN_FilterInitStructure.CAN_FilterMaskIdLow = std_id1<<5;  
  CAN_FilterInitStructure.CAN_FilterFIFOAssignment = CAN_Filter_FIFO0;           //?????????FIFO0?  
        CAN_FilterInitStructure.CAN_FilterActivation = ENABLE;//激活过滤器0       


5. 总结一下:
两种过滤方式各有千秋,需要过滤出一组ID,使用掩码模式;
需要过滤出特定的几个ID,使用列表模式。
实际使用中可巧妙地调整预设ID和掩码,甚至组合使用掩码模式和列表模式实现自己想要的过滤效果。
————————————————
版权声明:本文为CSDN博主「stand_young」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/weixin_44612435/article/details/133701872

使用特权

评论回复
沙发
daichaodai| | 2023-10-17 23:29 | 只看该作者
CAN ID的过滤方式主要就是标准帧和扩展帧的区别

使用特权

评论回复
板凳
xia00| | 2023-10-22 10:14 | 只看该作者
在互联型产品中,bxCAN控制器为应用程序提供了28个位宽可变的、可配置的过滤器组(270)

使用特权

评论回复
地板
tpgf|  楼主 | 2023-11-2 10:07 | 只看该作者
daichaodai 发表于 2023-10-17 23:29
CAN ID的过滤方式主要就是标准帧和扩展帧的区别

CAN ID的过滤器一般来说 有四种工作模式

使用特权

评论回复
5
aoyi| | 2023-11-2 10:39 | 只看该作者
在寄存器里边如何配置使用哪种过滤方式呢

使用特权

评论回复
6
tfqi| | 2023-11-2 11:09 | 只看该作者
使用哪种模式还得看使用的是哪种模式

使用特权

评论回复
7
gwsan| | 2023-11-2 20:49 | 只看该作者
哪种过滤方式更加节省资源呢

使用特权

评论回复
8
zljiu| | 2023-11-2 21:13 | 只看该作者
如何验证当前配置是否已经生效了呢

使用特权

评论回复
9
nawu| | 2023-11-2 21:48 | 只看该作者
为什么我设置完成之后就不生效呢

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

1931

主题

15650

帖子

12

粉丝