3. CAN标准数据帧接收过滤配置
任务目标
在CAN通信中,扩展帧使用29位标识符,当总线上存在多种报文时,控制器需要只接收特定ID的报文,过滤掉其余无关流量。本案例实现基于STM32 bxCAN外设的扩展帧ID过滤器配置,使硬件仅接收指定的扩展帧ID(例如0x18FF50E5),其余扩展帧报文全部被硬件过滤丢弃。
环境依赖
- 硬件:STM32F103系列(bxCAN外设)
- 软件:STM32CubeIDE 或 Keil MDK,HAL库
- 时钟:CAN外设时钟已使能,波特率配置为500kbps(复用现有初始化)
核心实现
bxCAN提供14个过滤器组(F0~F13),每个过滤器组可配置为32位或16位模式。对于29位扩展帧ID过滤,使用32位过滤器组,将CAN_FxR1寄存器的高29位(STID[10:0]+EXID[17:0])与CAN_FxR2寄存器的高29位进行屏蔽比较。本案例配置过滤器组0,工作在屏蔽位模式,仅接收ID为0x18FF50E5的扩展帧。
/* 扩展帧ID过滤器配置 - 仅接收ID=0x18FF50E5 */
void CAN_Filter_ExtID_Config(CAN_HandleTypeDef *hcan)
{
CAN_FilterTypeDef sFilterConfig;
/* 过滤器组0,32位屏蔽位模式 */
sFilterConfig.FilterBank = 0;
sFilterConfig.FilterMode = CAN_FILTERMODE_IDMASK;
sFilterConfig.FilterScale = CAN_FILTERSCALE_32BIT;
/* 期望接收的扩展帧ID: 0x18FF50E5
* 29位ID在寄存器中的布局:
* bit[31:21] = STID[10:0] (标准ID部分,扩展帧中为ID的高11位)
* bit[20:3] = EXID[17:0] (扩展ID部分)
* bit[2:0] = 不使用,置0
*/
uint32_t ext_id = 0x18FF50E5;
uint32_t filter_id = (ext_id & 0x1FFFFFFF) << 3; /* 左移3位对齐到寄存器位 */
/* 屏蔽寄存器:全部匹配,不允许忽略任何位 */
uint32_t mask_id = 0x1FFFFFFF << 3; /* 高29位全1,低3位为0 */
sFilterConfig.FilterIdHigh = (uint16_t)(filter_id >> 16);
sFilterConfig.FilterIdLow = (uint16_t)(filter_id & 0xFFFF);
sFilterConfig.FilterMaskIdHigh = (uint16_t)(mask_id >> 16);
sFilterConfig.FilterMaskIdLow = (uint16_t)(mask_id & 0xFFFF);
sFilterConfig.FilterFIFOAssignment = CAN_RX_FIFO0;
sFilterConfig.FilterActivation = ENABLE;
if (HAL_CAN_ConfigFilter(hcan, &sFilterConfig) != HAL_OK)
{
Error_Handler();
}
}
/* 使用示例:在CAN初始化后调用 */
int main(void)
{
/* ... 系统时钟、GPIO、CAN初始化代码 ... */
CAN_Filter_ExtID_Config(&hcan);
/* 启动CAN并开启FIFO0中断(或轮询接收) */
HAL_CAN_Start(&hcan);
HAL_CAN_ActivateNotification(&hcan, CAN_IT_RX_FIFO0_MSG_PENDING);
while (1)
{
/* 主循环 */
}
}
验证方法
- 使用CAN分析仪或另一块开发板发送扩展帧ID=0x18FF50E5的报文,观察接收端能正常进入接收中断或查询到FIFO中有数据。
- 发送其他扩展帧ID(如0x18FF50E6、0x00FF1122)和任意标准帧,确认接收端不产生任何接收事件。
- 通过调试器查看寄存器CAN_FSR(过滤器状态寄存器)确认过滤器组0已激活,或观察HAL_CAN_GetRxFifoFillLevel返回值:仅当发送匹配ID时该值递增。
通过条件:发送匹配ID报文时接收成功;发送非匹配ID报文时,FIFO接收计数保持为0,证明硬件过滤生效。