在CAN总线的生态系统中,过滤器(Filter) 绝非一个次要功能,而是保障系统高效、稳定运行的核心机制。它充当着网络流量的“守门人”,在硬件层面进行消息预筛选,确保只有相关的数据才能进入CPU进行处理

一、 过滤器的核心价值:为何必不可少?

  1. 极大降低CPU负载:在一个繁忙的CAN网络(如汽车网络)中,每秒可能有数千条消息。如果没有过滤器,每个消息都会触发MCU的接收中断,CPU将疲于处理海量的中断,无法执行其主要控制任务。过滤器将绝大部分无关消息在硬件层面直接丢弃,CPU只处理它真正关心的消息。

  2. 简化软件逻辑:软件无需编写复杂的“if-else”语句来判断每个接收到的消息ID是否有用。软件从中断中读取的消息,默认就是需要处理的,这使得应用程序代码更加简洁和健壮。

  3. 保障实时性:高优先级的任务不能被低优先级消息的处理所阻塞。通过过滤掉无关消息,高优先级消息的中断能得到更及时的响应,满足了系统的实时性要求。

二、 过滤器的硬件基础:验收过滤器的架构

大多数现代MCU的CAN控制器(如STM32的bxCAN,NXP的FlexCAN)都集成了一定数量的过滤器组(Filter Bank)。这是一个有限的硬件资源,例如STM32F103有14个,STM32F407有28个。每个过滤器组都可以独立配置。

每个过滤器组本质上是一个比较器电路,它将线上传来的报文标识符与用户预先配置到寄存器中的期望值进行比对,并根据用户设置的匹配规则来决定是否接收该报文。

三、 过滤器的工作模式详解

过滤器主要工作在两种模式下,它们决定了比较的规则。

1. 标识符列表模式 (Identifier List Mode)
  • 工作原理:此模式将过滤器配置为一个精确的匹配列表。接收到的报文标识符必须与过滤器组中预设的某个标识符完全一致,才能被接收。

  • 类比:就像公司的前台有一份精确的访客名单(白名单)。只有名字完全出现在名单上的人才能被放行。

  • 使用:你只需要把你要接收数据的ID写入寄存器就可以,写入的,就是要接收的。

  • 特点

    • 非常严格,只接收明确指定的ID。

    • 适合已知且需要接收的报文ID数量较少,且非常固定的场景。

2. 标识符掩码模式 (Identifier Mask Mode)
  • 工作原理:此模式需要配置两个值:

    • 过滤器ID (Filter ID):期望的ID模式。

    • 过滤器掩码 (Filter Mask):决定标识符中哪些位必须与Filter ID严格匹配,哪些位可以被忽略。

      • 掩码位 = 1:表示对应的标识符位必须匹配

      • 掩码位 = 0:表示对应的标识符位“不关心”(可以是1也可以是0)。

  • 类比:就像前台根据规则放行。例如,规则是:“部门码必须是01(匹配),至于工号是多少我不管(不关心)”。那么所有部门码为01的员工,无论工号多少,都可以进入。

  • 使用:你需要先配置要筛选的某几位ID,再在掩码寄存器中写入相应的屏蔽位。

  • 特点

    • 极其灵活,可以用一个过滤器接收一组ID的报文。

    • 是实际项目中最常用、最强大的模式。

3.寄存器

四、实战详解

我们按照这张图配置

1、任意 ID

这个必须配置为掩码模式,就是设置位屏蔽模式,但是我们不屏蔽

把掩码寄存器全设置为0,就是所有都不屏蔽

//过滤器配置
void CAN_Filter() {

  CAN_FilterTypeDef CAN_FilterConfig;

  //设置过滤id  这里我们先配置为不过滤
  CAN_FilterConfig.FilterIdHigh = 0x000<<5;  //标准格式有11位,需要写入高位,左移5位
  CAN_FilterConfig.FilterIdLow = 0x000<<5;
  //过滤器掩码  这里我们先配置为不过滤
  CAN_FilterConfig.FilterMaskIdHigh = 0x000<<5;
  CAN_FilterConfig.FilterMaskIdLow = 0x000<<5;


  //关联FIFO0
  CAN_FilterConfig.FilterFIFOAssignment=CAN_RX_FIFO0;
  //编号
  CAN_FilterConfig.FilterBank=1;
  //过滤器工作模式  屏蔽--列表  这里是屏蔽
  CAN_FilterConfig.FilterMode = CAN_FILTERMODE_IDMASK;
  //位宽32--16
  CAN_FilterConfig.FilterScale=CAN_FILTERSCALE_32BIT;
  //使能
  CAN_FilterConfig.FilterActivation=ENABLE;
 
  HAL_CAN_ConfigFilter(&hcan, &CAN_FilterConfig);

}

2、单个或少量ID

由于我们只需要获取少量的ID,所有我们可以直接筛选,使用列表模式,把我们想要的ID直接列举出来。

列表模式就是我们,我们向寄存器写入那个ID,我们就接收那个ID。

我们需要0x234、0x345、0x567,我们直接写入寄存器就可以,记得移到高位

//过滤器配置
void CAN_Filter() {

  CAN_FilterTypeDef CAN_FilterConfig;

  //设置过滤id  这里我们先配置为不过滤
  CAN_FilterConfig.FilterIdHigh = 0x234<<5;  //标准格式有11位,需要写入高位,左移5位
  CAN_FilterConfig.FilterIdLow = 0x345<<5;
  //过滤器掩码  这里我们先配置为不过滤
  CAN_FilterConfig.FilterMaskIdHigh = 0x567<<5;
  CAN_FilterConfig.FilterMaskIdLow = 0x000<<5;


  //关联FIFO0
  CAN_FilterConfig.FilterFIFOAssignment=CAN_RX_FIFO0;
  //编号
  CAN_FilterConfig.FilterBank=1;
  //过滤器工作模式  屏蔽--列表  这里是列表
  CAN_FilterConfig.FilterMode = CAN_FILTERMODE_IDLIST;
  //位宽32--16
  CAN_FilterConfig.FilterScale=CAN_FILTERSCALE_16BIT;
  //使能
  CAN_FilterConfig.FilterActivation=ENABLE;
 
  HAL_CAN_ConfigFilter(&hcan, &CAN_FilterConfig);

}
3.某一类,有相同特征的ID

这种我们需要观察他们共同的特质,一般我们定义ID的时候,也会把ID分类,这样利于使用。

1. 对于ID范围 0x200 ~ 0x2FF(二进制 010 0000 0000 ~ 010 1111 1111
  • 分析:这个范围内的所有ID的高3位都是 010,而低8位变化(从 00000000 到 11111111)。因此,您只需要匹配高3位,低8位可以不关心。

  • 过滤器ID(Filter ID):设置为 0x200(二进制 010 0000 0000)。因为低8位不关心,所以通常将低8位设为0,但任何高3位为 010 的ID都可以作为基准(如 0x200 是合理的选择)。

  • 掩码(Mask):设置为 0x700(二进制 111 0000 0000)。这意味着掩码的高3位为 111(要求匹配),低8位为 000(不关心)。这样配置后,任何高3位为 010 的ID都会被接收,正好覆盖 0x200 ~ 0x2FF

2. 对于ID范围 0x320 ~ 0x32F(二进制 011 0010 0000 ~ 011 0010 1111
  • 分析:这个范围内的所有ID的高7位都是 0110010,而低4位变化(从 0000 到 1111)。因此,您只需要匹配高7位,低4位可以不关心。

  • 过滤器ID(Filter ID):设置为 0x320(二进制 011 0010 0000)。同样,低4位设为0,因为不关心。

  • 掩码(Mask):设置为 0x7F0(二进制 111 1111 0000)。这意味着掩码的高7位为 1111111(要求匹配),低4位为 0000(不关心)。这样配置后,任何高7位为 0110010 的ID都会被接收,正好覆盖 0x320 ~ 0x32F

//过滤器配置
void CAN_Filter() {

  CAN_FilterTypeDef CAN_FilterConfig;

  //设置过滤id  这里我们先配置为不过滤
  CAN_FilterConfig.FilterIdHigh = 0x200<<5;  //标准格式有11位,需要写入高位,左移5位
  CAN_FilterConfig.FilterIdLow = 0x700<<5;
  //过滤器掩码  这里我们先配置为不过滤
  CAN_FilterConfig.FilterMaskIdHigh = 0x320<<5;
  CAN_FilterConfig.FilterMaskIdLow = 0x7F0<<5;


  //关联FIFO0
  CAN_FilterConfig.FilterFIFOAssignment=CAN_RX_FIFO0;
  //编号
  CAN_FilterConfig.FilterBank=1;
  //过滤器工作模式  屏蔽--列表  这里是屏蔽
  CAN_FilterConfig.FilterMode = CAN_FILTERMODE_IDMASK;
  //位宽32--16
  CAN_FilterConfig.FilterScale=CAN_FILTERSCALE_16BIT;
  //使能
  CAN_FilterConfig.FilterActivation=ENABLE;
 
  HAL_CAN_ConfigFilter(&hcan, &CAN_FilterConfig);

}

五、 模式选择与设计策略总结

  1. 列表模式适用场景

    • 需要接收的ID数量少且固定

    • 需要接收的ID之间没有明显的位模式规律(数值离散)。

    • 需要为最高优先级的消息提供“专线”保障。

  2. 掩码模式适用场景

    • 需要接收一组ID

    • 这组ID有共同的前缀或特征位

    • 最常用的模式,可以极大地节省有限的过滤器硬件资源。

  3. 混合使用
    一个复杂的节点通常会同时使用两种模式。例如,用一个列表模式过滤器接收2个关键的高优先级消息,再用一个掩码模式过滤器接收几十个普通的控制消息,从而用最少的过滤器组完成最复杂的过滤任务。

总结
CAN总线过滤器是区分业余实现与专业设计的关键所在。深入理解并巧妙运用掩码模式和列表模式,能够最大化利用有限的硬件资源,构建出高效、可靠、实时的嵌入式网络系统。它是每一个嵌入式工程师必须掌握的核心技能。

具体的发送,接收代码请看上篇文章⬇⬇⬇https://blog.csdn.net/banxian_a/article/details/151072315?spm=1001.2014.3001.5502https://blog.csdn.net/banxian_a/article/details/151072315?spm=1001.2014.3001.5502

订阅专栏,期待更多内容发布把

Logo

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

更多推荐