摘要:CAN 总线波形正常,ACK 也有,但 MCU 就是进不了接收中断?不是波特率问题,而是 CAN 过滤器(Filter)把报文“静默丢弃”了。本文拆解 CAN Filter 的掩码(Mask)与列表(List)模式。
一、问题描述(现象)
**示波器看 CANH/CANL 波形完美,ACK 位也有;
用 CAN 分析仪能收到所有报文;
唯独自己的 MCU 节点,一个数据都收不到。**
很多工程师的排查方向是:
ID 是不是设错了?
中断没开?
换个 CAN 口试试?
二、原理分析
1. 物理模型
CAN 控制器内部有一个硬件过滤器。
CAN Bus -> [Bit Timing] -> [Filter Bank] -> [FIFO] -> [CPU]关键点:
如果 Filter 没配好,报文根本到不了 FIFO,你永远进不了中断。
2. 核心参数
Filter Bank:过滤器组(STM32 通常有 14 个)。
Filter Scale:32 位或 16 位。
Filter Mode:
Mask(掩码):关心哪几位,哪几位必须匹配。
List(列表):精确匹配 ID。
3. 反直觉真相
CubeMX 生成的 Filter 默认配置,通常是“只收特定 ID”。
如果你没改:
默认 ID = 0x321。
默认 Mask = 0x7FF。
结果:只有 0x321 能进来,其他全部被丢弃。
三、工程级解决方案
方案 1:只想调试,先全放开(最简单)
开发阶段,直接关闭过滤,收所有报文。
// STM32 HAL 示例:设置 Filter 为 Mask 模式,接收所有标准帧 CAN_FilterTypeDef canFilter; canFilter.FilterBank = 0; canFilter.FilterMode = CAN_FILTERMODE_IDMASK; canFilter.FilterScale = CAN_FILTERSCALE_32BIT; canFilter.FilterIdHigh = 0x0000; canFilter.FilterIdLow = 0x0000; canFilter.FilterMaskIdHigh = 0x0000; // 掩码全 0 = 不关心 canFilter.FilterMaskIdLow = 0x0000; canFilter.FilterFIFOAssignment = CAN_FILTER_FIFO0; canFilter.FilterActivation = ENABLE; HAL_CAN_ConfigFilter(&hcan, &canFilter);方案 2:掩码模式(量产推荐)
只收某一类 ID(如 0x100~0x1FF)。
// ID: 0x100 // Mask: 0x700 (二进制 111 0000 0000) // 含义:ID 的高 3 位必须是 001 FilterId = 0x100 << 5; // 标准帧 ID 在高 11 位 FilterMask = 0x700 << 5;方案 3:列表模式(最安全)
只允许指定的几个 ID 进来。
配置多个 Filter Bank。
每个 Bank 对应一个精确的 ID。
适合高安全性要求的 ECU。
四、选型避坑建议
标准帧 vs 扩展帧:
标准帧:11 位 ID。
扩展帧:29 位 ID。
Filter 必须匹配帧类型,否则收不到。
IDE 位:过滤器中要指定 IDE 位是否匹配。
FIFO 分配:Filter 可以指定进 FIFO0 或 FIFO1,别配错。
五、总结 Checklist
[ ] 是否用示波器确认了 ACK 位存在?
[ ] 是否确认 Filter 模式(Mask/List)符合预期?
[ ] 是否确认接收的是标准帧还是扩展帧?
[ ] 是否尝试过“全放开”模式测试?
六、写在最后(关注我,少走弯路)
我是gqqsherry,一个拒绝调包、专注底层逻辑的嵌入式工程师。
CAN 过滤器是“守门员”,配错了,后面再完美的代码也白搭。
关注我的专栏《嵌入式底层避坑指南》,我会持续更新 CAN、UART、SPI 等外设的真实调试案例和量产级解决方案。
👉系列完结预告:《CAN 核心参数与调试速查表》
References
STM32 Reference Manual – CAN filter registers
ISO 11898-1 – Frame format and filtering
如果你曾被 CAN Filter 的配置绕晕过,欢迎在评论区晒出你的配置代码,我来帮你找茬。
原创文章,转载请注明出处。