参考:
https://blog.csdn.net/MQ0522/article/details/130067130

前言:
学习总结CAN的知识点:
1.can是什么,历史由来和背景
2.can的物理层,链路层
3.初始化的流程和关键点
4.波特率怎么设置
5.can id怎么过滤
6.can的发送和接收原理
7.can的发送和接收API

1. CAN过滤器----简介

在CAN协议里,报文的标识符不是和设备进行绑定的,也就是说报文的标识符如0x123可以由A节点发送也可以由B节点发送,接收对象可以是C节点或者是D节点。因此发送者以广播的形式把报文发送给所有的接收者。节点在接收报文时,根据标识符(CAN ID)的值决定软件是否需要该报文;如果需要,就拷贝到SRAM里;如果不需要,报文就被丢弃且无需软件的干预。
为满足这一需求,STM32F407为每个CAN控制器提供了14个位宽可变的、可配置的过滤器组(013或1427),以便只接收那些软件需要的报文。硬件过滤的做法节省了CPU开销,否则就必须由软件过滤从而占用一定的CPU开销。每个过滤器组x由2个32位寄存器,CAN_FxR0和CAN_FxR1组成。

1. CAN过滤器组
STM32F407有两路CAN,所以有28个过滤器组,具体如下表:
在这里插入图片描述

2. CAN过滤器模式
掩码模式: 标识符寄存器与掩码寄存器关联,用以指示标识符的哪些位必须匹配,哪些位无关。
列表模式: 传入标识符的所有位都必须与筛选器寄存器中指定的位匹配。

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

4. CAN过滤器匹配序号:
消息接收到 FIFO 中后,即可供应用程序使用。
通常情况下,报文中的数据被拷贝到SRAM中;为了把数据拷贝到合适的位置,应用程序需要根据报文的标识符来辨别不同的数据。bxCAN提供了过滤器匹配序号,以简化这一辨别过程。
根据过滤器优先级规则,过滤器匹配序号和报文一起,被存入邮箱中。因此每个收到的报文,都有与它相关联的过滤器匹配序号。
过滤器匹配序号的使用方法有两种:
把过滤器匹配序号跟一系列所期望的值进行比较
把过滤器匹配序号当作一个索引来访问目标地址
对于列表模式过滤器,软件不再需要比较标识符。
对于掩码模式过滤器,软件只须对需要的那些屏蔽位(必须匹配的位)进行比较即可。
筛选器编号与筛选器组的激活状态无关。此外,还将使用两个独立的编号方案,每个 FIFO 各一个。具体举例如下:
在这里插入图片描述

此图只是举例,具体配置不用按照此图。

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

6. CAN过滤器配置
过滤器组可以通过相应的CAN_FMR寄存器(CAN过滤器主控寄存器)配置。但是不是什么时候都可以直接配置,在配置一个过滤器组前,必须通过清除CAN_FAR寄存器(CAN过滤器激活寄存器)的FACT位,把它设置为禁用状态。然后才能设置或设置过滤器组的配置
通过设置CAN_FS1R(CAN过滤器位宽寄存器)的FSCx位,可以配置一个过滤器组的位宽。
通过设置CAN_FM1R(CAN过滤器模式寄存器)的FBMx位,可以配置对应的屏蔽/标识符寄存器的标识符列表模式或掩码模式。
过滤器配置具体如下图所示:
在这里插入图片描述

2. CAN过滤器----配置实验

以下是STM32F407----CAN过滤器----配置的具体实验内容和代码。
实验内容: CAN通信波特率为 500K bps,将接收到的CAN_ID发送出来,发送帧ID为0x18888888,前4个字节数据为接收到的CAN_ID。
过滤器配置-----代码模板
在STM32CubeMX生成【HAL库】程序中,没有关于过滤器相关的配置代码,如果不配置过滤器又无法接收数据,所以需要我们自己手写代码配置过滤器。
以下是 所有CAN帧ID都可以通过的过滤器 配置代码。
具体过滤器配置代码模板如下:

void CAN1_Filter_Bank(void)//过滤器
{
    CAN_FilterTypeDef FilterConfig;

    /*配置CAN过滤器*/
    FilterConfig.FilterBank = 0;                      //过滤器组号
    FilterConfig.FilterMode = CAN_FILTERMODE_IDMASK;  //过滤模式:屏蔽位模式--CAN_FILTERMODE_IDMASK,列表模式--CAN_FILTERMODE_IDLIST
    FilterConfig.FilterScale = CAN_FILTERSCALE_32BIT; //过滤器位宽:32位
    FilterConfig.FilterIdHigh = 0x0000;               //32位ID
    FilterConfig.FilterIdLow = 0x0000;
    FilterConfig.FilterMaskIdHigh = 0x0000;           //32位MASK
    FilterConfig.FilterMaskIdLow = 0x0000;
    FilterConfig.FilterFIFOAssignment = CAN_RX_FIFO0; //过滤器0关联到FIFO0
    FilterConfig.FilterActivation = ENABLE;           //激活滤波器0
    FilterConfig.SlaveStartFilterBank = 14;           //单CAN此参数无意义
    
    //过滤器配置激活
    if (HAL_CAN_ConfigFilter(&hcan1, &FilterConfig) != HAL_OK)
    {
        Error_Handler();
    }
}

说明: 过滤器掩码模式:0不验证,1验证。所以屏蔽位都为0,就都不需要验证,所有CAN帧ID都可以接收了。

2.1 列表模式

只有列表中存放的CAN_ID才可以被接收到。

2.1.1. 列表模式----16位

在16位列表模式下,只能接收处理 标准帧CAN_ID。
CAN_FxR1和CAN_FxR2寄存器一共有64位,可以存放4个16位CAN_ID。
具体如下图所示:
在这里插入图片描述

过滤器配置具体说明如下:
在这里插入图片描述

因为在16位列表模式下,只能接收处理 标准帧CAN_ID,所以IDE位都置0。
具体代码如下:

void xl_CAN1_Filter_Bank_list16(void)//过滤器
{
    //标准帧ID
    uint16_t CanFilterListSTID0 = 0x101;
    uint8_t  CanFilterListRTR0  = 0x00;   //帧类型:0x00数据帧,0x01远程帧
    
    uint16_t CanFilterListSTID1 = 0x102;
    uint8_t  CanFilterListRTR1  = 0x00;   //帧类型:0x00数据帧,0x01远程帧
    
    uint16_t CanFilterListSTID2 = 0x103;
    uint8_t  CanFilterListRTR2  = 0x00;   //帧类型:0x00数据帧,0x01远程帧
    
    uint16_t CanFilterListSTID3 = 0x104;
    uint8_t  CanFilterListRTR3  = 0x00;   //帧类型:0x00数据帧,0x01远程帧
    
    CAN_FilterTypeDef FilterConfig;

    /*配置CAN过滤器*/
    FilterConfig.FilterBank = 0;                      //过滤器组号
    FilterConfig.FilterMode = CAN_FILTERMODE_IDLIST;  //过滤模式:列表模式--CAN_FILTERMODE_IDLIST
    FilterConfig.FilterScale = CAN_FILTERSCALE_16BIT; //过滤器位宽:16位
    FilterConfig.FilterIdHigh     = (CanFilterListSTID0<<5) | (CanFilterListRTR0<<4);           //ID
    FilterConfig.FilterIdLow      = (CanFilterListSTID1<<5) | (CanFilterListRTR1<<4);
    FilterConfig.FilterMaskIdHigh = (CanFilterListSTID2<<5) | (CanFilterListRTR2<<4);           //MASK
    FilterConfig.FilterMaskIdLow  = (CanFilterListSTID3<<5) | (CanFilterListRTR3<<4);
    FilterConfig.FilterFIFOAssignment = CAN_RX_FIFO0; //过滤器0关联到FIFO0
    FilterConfig.FilterActivation = ENABLE;           //激活滤波器
    FilterConfig.SlaveStartFilterBank = 14;           //单CAN此参数无意义
    //过滤器配置
    if (HAL_CAN_ConfigFilter(&hcan1, &FilterConfig) != HAL_OK)
    {
        Error_Handler();
    }


    //标准帧ID
    uint16_t CanFilterListSTID0_A = 0x105;
    uint8_t  CanFilterListRTR0_A  = 0x00;   //帧类型:0x00数据帧,0x01远程帧
    
    uint16_t CanFilterListSTID1_A = 0x106;
    uint8_t  CanFilterListRTR1_A  = 0x00;   //帧类型:0x00数据帧,0x01远程帧
    
    uint16_t CanFilterListSTID2_A = 0x107;
    uint8_t  CanFilterListRTR2_A  = 0x00;   //帧类型:0x00数据帧,0x01远程帧
    
    uint16_t CanFilterListSTID3_A = 0x108;
    uint8_t  CanFilterListRTR3_A  = 0x00;   //帧类型:0x00数据帧,0x01远程帧

    /*配置CAN过滤器*/
    FilterConfig.FilterBank = 1;                      //过滤器组号
    FilterConfig.FilterMode = CAN_FILTERMODE_IDLIST;  //过滤模式:列表模式--CAN_FILTERMODE_IDLIST
    FilterConfig.FilterScale = CAN_FILTERSCALE_16BIT; //过滤器位宽:16位
    FilterConfig.FilterIdHigh     = (CanFilterListSTID0_A<<5) | (CanFilterListRTR0_A<<4);           //ID
    FilterConfig.FilterIdLow      = (CanFilterListSTID1_A<<5) | (CanFilterListRTR1_A<<4);
    FilterConfig.FilterMaskIdHigh = (CanFilterListSTID2_A<<5) | (CanFilterListRTR2_A<<4);           //MASK
    FilterConfig.FilterMaskIdLow  = (CanFilterListSTID3_A<<5) | (CanFilterListRTR3_A<<4);
    FilterConfig.FilterFIFOAssignment = CAN_RX_FIFO0; //过滤器0关联到FIFO0
    FilterConfig.FilterActivation = ENABLE;           //激活滤波器
    FilterConfig.SlaveStartFilterBank = 14;           //单CAN此参数无意义
    //过滤器配置
    if (HAL_CAN_ConfigFilter(&hcan1, &FilterConfig) != HAL_OK)
    {
        Error_Handler();
    }
}

实验结果如下:
在这里插入图片描述

2.1.2. 列表模式----32位

在32位列表模式下,可以接收处理 标准帧CAN_ID和 扩展帧CAN_ID。
CAN_FxR1和CAN_FxR2寄存器一共有64位,可以存放2个32位CAN_ID。

具体如下图所示:
在这里插入图片描述

过滤器配置具体说明如下:
在这里插入图片描述

void xl_CAN1_Filter_Bank_list32(void)//过滤器
{
    //扩展帧ID
    uint32_t CanFilterListEXID0 = 0x00000123;
    uint8_t CanFilterListIDE0 = 0x01;       //帧类型:0x00标准帧,0x01扩展帧
    uint8_t CanFilterListRTR0 = 0x00;       //帧类型:0x00数据帧,0x01远程帧

    //标准帧ID
    uint16_t CanFilterListSTID1 = 0x701;
    uint8_t CanFilterListIDE1 = 0x00;//帧类型:0x00标准帧,0x01扩展帧
    uint8_t CanFilterListRTR1 = 0x00;//帧类型:0x00数据帧,0x01远程帧

    CAN_FilterTypeDef FilterConfig;

    /*配置CAN过滤器*/
    FilterConfig.FilterBank = 0;                      //过滤器组号
    FilterConfig.FilterMode  = CAN_FILTERMODE_IDLIST;  //过滤模式:列表模式--CAN_FILTERMODE_IDLIST
    FilterConfig.FilterScale = CAN_FILTERSCALE_32BIT; //过滤器位宽:32位

    FilterConfig.FilterIdHigh = (CanFilterListEXID0<<3)>>16;         //ID
    FilterConfig.FilterIdLow  = (CanFilterListEXID0<<3) | (CanFilterListIDE0<<2) | (CanFilterListRTR0<<1);
    
    FilterConfig.FilterMaskIdHigh = CanFilterListSTID1<<5;           //MASK
    FilterConfig.FilterMaskIdLow  = (CanFilterListIDE1<<2) | (CanFilterListRTR1<<1);
    
    FilterConfig.FilterFIFOAssignment = CAN_RX_FIFO0; //过滤器0关联到FIFO0
    FilterConfig.FilterActivation = ENABLE;           //激活滤波器
    FilterConfig.SlaveStartFilterBank = 14;           //单CAN此参数无意义
    //过滤器配置
    if (HAL_CAN_ConfigFilter(&hcan1, &FilterConfig) != HAL_OK)
    {
        Error_Handler();
    }

    //扩展帧ID
    uint32_t CanFilterListEXID0_A = 0x00000222;
    uint8_t CanFilterListIDE0_A = 0x01;       //帧类型:0x00标准帧,0x01扩展帧
    uint8_t CanFilterListRTR0_A = 0x00;       //帧类型:0x00数据帧,0x01远程帧

    //标准帧ID
    uint16_t CanFilterListSTID1_A = 0x666;
    uint8_t CanFilterListIDE1_A = 0x00;//帧类型:0x00标准帧,0x01扩展帧
    uint8_t CanFilterListRTR1_A = 0x00;//帧类型:0x00数据帧,0x01远程帧

    /*配置CAN过滤器*/
    FilterConfig.FilterBank = 1;                      //过滤器组号
    FilterConfig.FilterMode  = CAN_FILTERMODE_IDLIST;  //过滤模式:列表模式--CAN_FILTERMODE_IDLIST
    FilterConfig.FilterScale = CAN_FILTERSCALE_32BIT; //过滤器位宽:32位

    FilterConfig.FilterIdHigh = (CanFilterListEXID0_A<<3)>>16;         //ID
    FilterConfig.FilterIdLow  = (CanFilterListEXID0_A<<3) | (CanFilterListIDE0_A<<2) | (CanFilterListRTR0_A<<1);
    
    FilterConfig.FilterMaskIdHigh = CanFilterListSTID1_A<<5;           //MASK
    FilterConfig.FilterMaskIdLow  = (CanFilterListIDE1_A<<2) | (CanFilterListRTR1_A<<1);
    
    FilterConfig.FilterFIFOAssignment = CAN_RX_FIFO0; //过滤器0关联到FIFO0
    FilterConfig.FilterActivation = ENABLE;           //激活滤波器
    FilterConfig.SlaveStartFilterBank = 14;           //单CAN此参数无意义
    //过滤器配置
    if (HAL_CAN_ConfigFilter(&hcan1, &FilterConfig) != HAL_OK)
    {
        Error_Handler();
    }
}

实验结果如下:
在这里插入图片描述

2.2. 掩码模式

由屏蔽码决定是否与验证CAN_ID哪几位做比较,只有与验证CAN_ID一致,才可以接收到。屏蔽码:0不验证,1验证。
掩码模式举例说明:
在这里插入图片描述

屏蔽码是1的位,必须与验证码一致才可通过。
屏蔽码是0的位,0和1皆可通过。

2.2.1. 掩码模式----16位

在16位掩码模式下,只能接收处理 标准帧CAN_ID。
CAN_FxR1和CAN_FxR2寄存器一共有64位,可以存放2个16位验证码和2个16位屏蔽码。
具体如下图所示:
在这里插入图片描述

过滤器配置具体说明如下:
在这里插入图片描述

因为在16位列表模式下,只能接收处理 标准帧CAN_ID,所以IDE位都置0。

具体代码如下:

void xl_CAN1_Filter_Bank_Mask16(void)//过滤器
{
    uint16_t CanFilterMaskSTID0 = 0x7FC;    //屏蔽码:0不验证,1验证
    uint8_t  CanFilterMaskRTR0  = 0x00;     //帧类型:0x00数据帧,0x01远程帧
    uint16_t CanFilterSTID0 = 0x201;
    uint8_t  CanFilterRTR0  = 0x00;         //帧类型:0x00数据帧,0x01远程帧
    
    uint16_t CanFilterMaskSTID1 = 0x7CF;    //屏蔽码:0不验证,1验证
    uint8_t CanFilterMaskRTR1   = 0x00;     //帧类型:0x00数据帧,0x01远程帧
    uint16_t CanFilterSTID1 = 0x301;
    uint8_t CanFilterRTR1   = 0x00;         //帧类型:0x00数据帧,0x01远程帧

    CAN_FilterTypeDef FilterConfig;

    /*配置CAN过滤器*/
    FilterConfig.FilterBank = 0;                      //过滤器组号
    FilterConfig.FilterMode = CAN_FILTERMODE_IDMASK;  //过滤模式:掩码模式--CAN_FILTERMODE_IDMASK
    FilterConfig.FilterScale = CAN_FILTERSCALE_16BIT; //过滤器位宽:16位

    FilterConfig.FilterIdHigh = (CanFilterSTID0<<5) | (CanFilterRTR0<<4);               //ID
    FilterConfig.FilterIdLow  = (CanFilterSTID1<<5) | (CanFilterRTR1<<4);
    FilterConfig.FilterMaskIdHigh = (CanFilterMaskSTID0<<5) | (CanFilterMaskRTR0<<4);   //MASK
    FilterConfig.FilterMaskIdLow  = (CanFilterMaskSTID1<<5) | (CanFilterMaskRTR1<<4);

    FilterConfig.FilterFIFOAssignment = CAN_RX_FIFO0; //过滤器0关联到FIFO0
    FilterConfig.FilterActivation = ENABLE;           //激活滤波器
    FilterConfig.SlaveStartFilterBank = 14;           //单CAN此参数无意义
    //过滤器配置
    if (HAL_CAN_ConfigFilter(&hcan1, &FilterConfig) != HAL_OK)
    {
        Error_Handler();
    }
}

实验结果如下:
在这里插入图片描述

可接收帧:0x200,0x201,0x202,0x203
可接收帧:0x301,0x311,0x321,0x331

2.2.2. 掩码模式----32位

在32位列表模式下,可以接收处理 标准帧CAN_ID和 扩展帧CAN_ID。
CAN_FxR1和CAN_FxR2寄存器一共有64位,可以存放1个32位验证码和1个32位屏蔽码。
具体如下图所示:
在这里插入图片描述

过滤器配置具体说明如下:
在这里插入图片描述

具体代码如下:

void xl_CAN1_Filter_Bank_Mask32(void)//过滤器
{
    uint32_t CanFilterMaskEXID = 0x1FFFFFFC;//屏蔽码:0不验证,1验证
    uint8_t CanFilterMaskIDE = 0x01;    //帧类型:0x00标准帧,0x01扩展帧
    uint8_t CanFilterMaskRTR = 0x00;    //帧类型:0x00数据帧,0x01远程帧

    uint32_t CanFilterEXID = 0x1B030F01;
    uint8_t CanFilterIDE= 0x01;     //帧类型:0x00标准帧,0x01扩展帧
    uint8_t CanFilterRTR= 0x00;     //帧类型:0x00数据帧,0x01远程帧

    CAN_FilterTypeDef FilterConfig;

    /*配置CAN过滤器*/
    FilterConfig.FilterBank = 0;                      //过滤器组号
    FilterConfig.FilterMode = CAN_FILTERMODE_IDMASK;  //过滤模式:掩码模式--CAN_FILTERMODE_IDMASK
    FilterConfig.FilterScale = CAN_FILTERSCALE_32BIT; //过滤器位宽:32位

    FilterConfig.FilterIdHigh = (CanFilterEXID<<3)>>16;               //ID
    FilterConfig.FilterIdLow =  (CanFilterEXID<<3)|(CanFilterIDE<<2)|(CanFilterRTR<<1);
    FilterConfig.FilterMaskIdHigh = (CanFilterMaskEXID<<3)>>16;           //MASK
    FilterConfig.FilterMaskIdLow = (CanFilterMaskEXID<<3)|(CanFilterMaskIDE<<2)|(CanFilterMaskRTR<<1);

    FilterConfig.FilterFIFOAssignment = CAN_RX_FIFO0; //过滤器0关联到FIFO0
    FilterConfig.FilterActivation = ENABLE;           //激活滤波器
    FilterConfig.SlaveStartFilterBank = 14;           //单CAN此参数无意义
    //过滤器配置
    if (HAL_CAN_ConfigFilter(&hcan1, &FilterConfig) != HAL_OK)
    {
        Error_Handler();
    }
}

实验结果如下:
在这里插入图片描述

可接收帧:0x1B030F00,0x1B030F01,0x1B030F02,0x1B030F03。

3. 源码

git clone git@gitee.com:xiaoliangliangcong/stm32.git
STM32F407ZGT6/16.CAN

Logo

智能硬件社区聚焦AI智能硬件技术生态,汇聚嵌入式AI、物联网硬件开发者,打造交流分享平台,同步全国赛事资讯、开展 OPC 核心人才招募,助力技术落地与开发者成长。

更多推荐