CAN过滤器:基础知识概览

文章目录

  • 过滤器
  • 过滤器的过滤模式
  • 掩码(不常用掩码模式)
  • CAN的双接收中断
  • 使用CAN2过滤ID号(实验)
  • 参考资料
  • 过滤器

  • STM32的bxCAN接收时必须使用过滤器接收
  • 根据CAN外设数量的不同有以下情况:
  • 只有CAN1:CAN1有14个过滤器
  • 有CAN1和CAN2:CAN1和CAN2共享28个过滤器
  • 有CAN1~3:CAN1和CAN2共享28个过滤器,CAN3有独立的14个过滤器
  • 过滤器可以过滤CAN总线上帧的ID号
  • 可以不处理不想接收的ID号,只接收想要的ID号
  • 过滤器的过滤模式

  • 过滤器总长度64位,可以分为2个32位单元或4个16位单元
  • 两种过滤模式:掩码和列表
  • 掩码模式:由两个单元组成通过掩码匹配
  • 列表模式:由一个单元组成,ID号完全匹配即通过
  • ID号对齐最高位(MSB)
  • 仅32位单元可以过滤拓展ID
  • 在列表模式下,scale为32时,每个过滤器的列表只能写入两个报文ID,若scale为16时,每个过滤器的列表最多可写入4个CAN ID
  • 掩码(不常用掩码模式)

  • 两个单元分别组成匹配ID和掩码(MASK)

  • 被过滤的ID号和匹配ID号会和掩码进行按位与运算后再进行匹配

  • 也就是只有对应的掩码为1的位才会被匹配
  • 例如:

  • 匹配ID为0x200,掩码为0x000,则所有ID号都能通过
  • 匹配ID为0x200,掩码为0x700,则ID为0x200~0x2FF均可通过
  • 匹配ID为0x200,掩码为0x7FF,则只有0x200能通过
  • 可以指定一个ID号的范围,在这个范围内的ID号可以通过我们的过滤器

    过滤器一共有4种工作模式:

    32位宽的掩码模式,  配置过滤2个不同的ID号
    32位宽的列表模式,  配置过滤4个不同的ID号
    16位宽的列表模式,  配置过滤2个不同的ID号
    16位宽的掩码模式    配置过滤1个不同的ID号
    

    过滤器的位宽:

    16位过滤器
    32位过滤器
    
  • CAN的双接收中断

  • 每个CAN有两个接收中断,对应两组接收邮箱(FIFO)
  • 每个过滤器可以绑定一个CAN接收中断
  • 经过过滤器过滤的帧会进入该过滤器绑定的接收中断对应的邮箱
  • 匹配时,列表模式的优先级高于掩码模式,其次过滤器编号更小的优先级更高
  • 使用CAN2过滤ID号(实验)

  • CAN1给CAN2发送不同ID号的数据帧
  • CAN2使用过滤器进行过滤
  • RX0和RX1分别对应不同过滤器,接收到不同数组中
  • 在之前CAN实验的代码上修改

    这里我们只需要修改CAN2,把CAN_Configfilter()函数中的sFiterconfig拷贝下来

    覆盖掉之前的sFiterconfig.FilterBank

      sFiterconfig.FilterActivation = CAN_FILTER_ENABLE;//激活过滤器
      sFiterconfig.FilterBank=0;//过滤器编号,CAN1是0~13
      sFiterconfig.FilterFIFOAssignment=CAN_FILTER_FIFO0;
      sFiterconfig.FilterMode=CAN_FILTERMODE_IDMASK;//设置为掩码模式
      sFiterconfig.FilterScale=CAN_FILTERSCALE_32BIT;//设置为32位宽
      sFiterconfig.FilterIdHigh=0x0000;//设置验证码
      sFiterconfig.FilterIdLow=0x0000;
      sFiterconfig.FilterMaskIdHigh=0x0000;
      sFiterconfig.FilterMaskIdLow=0x0000;
      sFiterconfig.SlaveStartFilterBank=14;
    
    1. 列表模式

      绑定FIFO0
      把下面的FilterBank设置为14,FilterMode改为CAN_FILTERMODE_IDLIST,FilterScale改为CAN_FILTERSCALE_16BIT,下面的ID号改为我们需要的ID号,这里我们可以设为0x200左移5位(左移5是为了对齐msb)

      sFiterconfig.FilterActivation = CAN_FILTER_ENABLE;
      sFiterconfig.FilterBank=14;//过滤器编号,CAN2是14~27
      sFiterconfig.FilterFIFOAssignment=CAN_FILTER_FIFO0;//接收到的报文放入到FIFO0中
      sFiterconfig.FilterMode=CAN_FILTERMODE_IDLIST;//列表模式
      sFiterconfig.FilterScale=CAN_FILTERSCALE_32BIT;//设置32位宽
      sFiterconfig.FilterIdHigh=0x200<<5;//基本ID放入到STID中  
      sFiterconfig.FilterIdLow=0x201<<5;
      sFiterconfig.FilterMaskIdHigh=0x202<<5;//设置为0时,表示不过滤,可以接收任意的CANID数据,
      sFiterconfig.FilterMaskIdLow=0x203<<5;//不为0时,则表示过滤 对应MaskID为1的bit必须与FilterID中的bit位相同的CANID才能接收过来。
      sFiterconfig.SlaveStartFilterBank=14;
    
    1. 掩码模式

      绑定FIFO1
      在HAL库中FilterIdHigh,FilterIdLow,FilterMaskIdHigh,FilterMaskIdLow

      FilterBank是过滤器编号,为了避免重复,这里设置为15,FilterMode选择CAN_FILTERMODE_IDMASK,因为我们这里过滤标准帧,没必要使用32位,所以FilterScale选择16位,FilterIdHigh,FilterIdLow在16位模式下指代两个不同的掩码组,FilterIdHigh对应FilterMaskIdHigh,FilterIdLow对应FilterMaskIdLow,一共是两组;如果是32位,就要把他们整个拼成一段整体,因此这里我们需要把它们拼成两组

      sFiterconfig.FilterActivation = CAN_FILTER_ENABLE;
      sFiterconfig.FilterBank=15;//过滤器编号,CAN2是14~27
      sFiterconfig.FilterFIFOAssignment=CAN_FILTER_FIFO1;
      sFiterconfig.FilterMode=CAN_FILTERMODE_IDLIST;
      sFiterconfig.FilterScale=CAN_FILTERSCALE_16BIT;
      sFiterconfig.FilterIdHigh=0x200<<5;//ID和掩码都要移5位
      sFiterconfig.FilterMaskIdHigh=0x202<<5;
      sFiterconfig.FilterIdLow=0x201<<5;
      sFiterconfig.FilterMaskIdLow=0x203<<5;
      sFiterconfig.SlaveStartFilterBank=14;
    

    把FilterMaskIdHigh设置为0x700,这样就表示过滤0x200到0x2FF的ID号

    把FilterMaskIdHigh设置为0x7F0,这样就表示过滤0x200到0x20F的ID号

    这里我们设置为0x7F0,更方便我们观察现象

    然后把FilterFIFOAssignment改为CAN_FILTER_FIFO1,即绑定FIFO1,对应RX1的中断,这样就完成了掩码模式的配置

    最终CAN_Configfilter()代码如下:

    /* USER CODE BEGIN 4 */
    void CAN_Configfilter()
    {
      CAN_FilterTypeDef sFiterconfig;
      sFiterconfig.FilterActivation = CAN_FILTER_ENABLE;
      sFiterconfig.FilterBank=0;
      sFiterconfig.FilterFIFOAssignment=CAN_FILTER_FIFO0;
      sFiterconfig.FilterMode=CAN_FILTERMODE_IDMASK;
      sFiterconfig.FilterScale=CAN_FILTERSCALE_32BIT;
      sFiterconfig.FilterIdHigh=0x0000;
      sFiterconfig.FilterIdLow=0x0000;
      sFiterconfig.FilterMaskIdHigh=0x0000;
      sFiterconfig.FilterMaskIdLow=0x0000;
      sFiterconfig.SlaveStartFilterBank=14;
    
      if( HAL_CAN_ConfigFilter(&hcan1,&sFiterconfig)!=HAL_OK)
      {
        Error_Handler();
      }
    //列表模式
      sFiterconfig.FilterActivation = CAN_FILTER_ENABLE;
      sFiterconfig.FilterBank=14;
      sFiterconfig.FilterFIFOAssignment=CAN_FILTER_FIFO0;
      sFiterconfig.FilterMode=CAN_FILTERMODE_IDLIST;
      sFiterconfig.FilterScale=CAN_FILTERSCALE_16BIT;
      sFiterconfig.FilterIdHigh=0x200<<5;
      sFiterconfig.FilterIdLow=0x201<<5;
      sFiterconfig.FilterMaskIdHigh=0x202<<5;
      sFiterconfig.FilterMaskIdLow=0x203<<5;
      sFiterconfig.SlaveStartFilterBank=14;
    
      if( HAL_CAN_ConfigFilter(&hcan2,&sFiterconfig)!=HAL_OK)
      {
        Error_Handler();
      }
      //掩码模式
      sFiterconfig.FilterActivation = CAN_FILTER_ENABLE;
      sFiterconfig.FilterBank=15;
      sFiterconfig.FilterFIFOAssignment=CAN_FILTER_FIFO0;
      sFiterconfig.FilterMode=CAN_FILTERMODE_IDMASK;
      sFiterconfig.FilterScale=CAN_FILTERSCALE_16BIT;
      sFiterconfig.FilterIdHigh=0x200<<5;
      sFiterconfig.FilterIdLow=0x201<<5;
      sFiterconfig.FilterMaskIdHigh=0x202<<5;
      sFiterconfig.FilterMaskIdLow=0x203<<5;
      sFiterconfig.SlaveStartFilterBank=14;
      if(HAL_CAN_Start(&hcan1)!=HAL_OK)
      {
        Error_Handler();
      }
    
      if(HAL_CAN_Start(&hcan2)!=HAL_OK)
      {
        Error_Handler();
      }
    
      if(HAL_CAN_ActivateNotification(&hcan1,CAN_IT_RX_FIFO0_MSG_PENDING | CAN_IT_RX_FIFO1_MSG_PENDING)!=HAL_OK)
      {
        Error_Handler();
      }
    
        if(HAL_CAN_ActivateNotification(&hcan2,CAN_IT_RX_FIFO0_MSG_PENDING | CAN_IT_RX_FIFO1_MSG_PENDING)!=HAL_OK)
      {
        Error_Handler();
      }
    
    }
    void HAL_can_RxFifo0MsgPendingCallback(CAN_HandleTypeDef*hcan)//接收数据的回调函数
    {
      if(hcan==&hcan2)
      {
        HAL_CAN_GetRxMessage(&hcan2,CAN_RX_FIFO0,&rxHeader0,rxDateBuffer0);
      }
    }//RX0
    void HAL_can_RxFifo1MsgPendingCallback(CAN_HandleTypeDef*hcan)//接收数据的回调函数
    {
        if(hcan==&hcan2)
      {
        HAL_CAN_GetRxMessage(&hcan2,CAN_RX_FIFO1,&rxHeader1,rxDateBuffer1);
      }
    }//RX1
    /* USER CODE END 4 */
    

    然后就可以编译烧录。

    参考资料

    CH4.2 CAN 第2讲 过滤器【南工骁鹰嵌入式软件培训】
    STM32 CAN过滤器配置详解
    对于can通信过滤器的理解

    物联沃分享整理
    物联沃-IOTWORD物联网 » CAN过滤器:基础知识概览

    发表评论