2. CAN标准数据帧发送配置
任务目标
在CAN控制器中配置标准帧(11位ID)的验收滤波器,使节点仅接收指定ID的报文,其余ID全部屏蔽。本案例以STM32F103的bxCAN外设为例,实现只接收ID为0x321的标准帧数据报文。
环境与依赖
- 硬件:STM32F103系列开发板(含CAN收发器,如TJA1050)
- 软件:STM32CubeIDE 或 Keil MDK,使用STM32标准外设库(SPL)
- 已初始化:CAN外设时钟、GPIO(PA11=RX, PA12=TX)、CAN波特率(本案例使用500kbps)
核心原理
bxCAN提供28个滤波器组,每组可配置为掩码模式或列表模式。掩码模式下,通过ID掩码寄存器决定哪些位必须精确匹配、哪些位可忽略。本案例使用滤波器组0,掩码模式,仅匹配标准帧ID的bit[10:0]。
关键完整代码
#include "stm32f10x_can.h"
/* 滤波器配置:仅接收标准帧 ID = 0x321 */
void CAN_Filter_Config_StdID(void)
{
CAN_FilterInitTypeDef CAN_FilterInitStructure;
/* 使用滤波器组0 */
CAN_FilterInitStructure.CAN_FilterNumber = 0;
/* 掩码模式 */
CAN_FilterInitStructure.CAN_FilterMode = CAN_FilterMode_IdMask;
/* 32位宽度,适用于标准帧和扩展帧 */
CAN_FilterInitStructure.CAN_FilterScale = CAN_FilterScale_32bit;
/*
* 标准帧ID存储在寄存器高16位(STID[10:0]对应bit[28:18])
* 期望ID = 0x321,左移21位放入对应位置
* 掩码 = 0x7FF 表示11位全部必须匹配
*/
CAN_FilterInitStructure.CAN_FilterIdHigh = (uint16_t)(0x321 << 5); // 高16位:ID左移5位
CAN_FilterInitStructure.CAN_FilterIdLow = 0x0000;
CAN_FilterInitStructure.CAN_FilterMaskIdHigh = (uint16_t)(0x7FF << 5); // 掩码高16位
CAN_FilterInitStructure.CAN_FilterMaskIdLow = 0x0000;
/* 关联到FIFO0 */
CAN_FilterInitStructure.CAN_FilterFIFOAssignment = CAN_FIFO0;
CAN_FilterInitStructure.CAN_FilterActivation = ENABLE;
CAN_FilterInit(&CAN_FilterInitStructure);
}
/* 主程序调用示例(需先完成CAN外设初始化) */
void CAN_Receive_Only_0x321(void)
{
CanRxMsg RxMessage;
uint8_t data[8];
/* 假设CAN已初始化并进入正常模式 */
CAN_Filter_Config_StdID();
while (1)
{
/* 等待FIFO0收到报文 */
if (CAN_MessagePending(CAN1, CAN_FIFO0) > 0)
{
CAN_Receive(CAN1, CAN_FIFO0, &RxMessage);
/* 仅当ID匹配时处理(滤波器已保证,此处为双重校验) */
if ((RxMessage.IDE == CAN_Id_Standard) && (RxMessage.StdId == 0x321))
{
for (int i = 0; i < RxMessage.DLC; i++)
{
data[i] = RxMessage.Data[i];
}
/* 在此处处理接收到的数据 */
}
}
}
}
配置说明
- ID放置:标准帧11位ID在32位滤波器寄存器中位于bit[28:18],因此将
0x321左移21位后,高16位为0x321 << 5,低16位为0。 - 掩码设置:
0x7FF左移5位得到0xFFE0,表示bit[28:18]全部为必须匹配位,其余位(RTR、IDE等)不参与过滤。 - FIFO分配:匹配的报文进入FIFO0,通过
CAN_MessagePending查询接收状态。
运行与验证
- 将上述代码加入已初始化CAN的工程中,编译下载至开发板。
- 使用另一块CAN节点或USB-CAN分析仪发送以下报文:
发送1:标准帧 ID=0x321, DLC=8, Data=0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08
发送2:标准帧 ID=0x322, DLC=8, Data=0xAA 0xBB 0xCC 0xDD 0xEE 0xFF 0x11 0x22
- 在
CAN_Receive_Only_0x321的while循环中设置断点或通过串口打印接收到的数据。
通过条件:仅当发送ID=0x321的报文时,程序进入接收处理分支;发送ID=0x322的报文时,程序不进入接收分支(FIFO0无数据)。若需验证扩展帧也被屏蔽,可发送扩展帧ID=0x321,同样不应被接收。
常见问题
- 滤波器配置后收不到任何报文:检查CAN_FilterIdHigh/IdLow的移位是否正确,确认掩码位与ID位对齐。
- 所有ID都能收到:掩码寄存器被设为0,导致所有位不参与匹配。确认
CAN_FilterMaskIdHigh值不为0。 - 标准帧和扩展帧混淆:若需严格区分,可在掩码中增加IDE位(bit[2])的匹配,本案例未包含该设置,因此扩展帧ID=0x321也会通过滤波器(但代码中的双重校验会将其过滤)。