尧图网络 高端网站定制 · 原创设计
免费咨询热线
400-888-6620
免费获取方案
STM32F1 CAN 标准帧与扩展帧实战:6种过滤器配置与收发测试代码
STM32F1 CAN标准帧与扩展帧实战6种过滤器配置与双机通信全解析在工业控制、汽车电子和物联网设备中CAN总线因其高可靠性和实时性成为首选通信协议。STM32F1系列微控制器内置CAN控制器但实际开发中工程师常面临标准帧与扩展帧混用场景下的过滤器配置难题。本文将深入解析6种过滤器模式并提供可直接移植的代码实现。1. CAN帧类型与STM32过滤器核心机制CAN协议定义了两种帧格式标准帧11位ID和扩展帧29位ID。STM32F1的CAN控制器通过硬件过滤器实现高效帧过滤其核心机制包含三个关键点双FIFO结构STM32F1提供FIFO0和FIFO1两个接收缓冲区每个可存储3个完整报文14个共享过滤器所有过滤器编号0-13可灵活分配给FIFO0或FIFO1两种过滤模式标识符屏蔽模式CAN_FilterMode_IdMask标识符列表模式CAN_FilterMode_IdList标准帧与扩展帧的ID结构差异如下表所示帧类型ID长度结构组成典型应用场景标准帧11位11位基础ID简单控制指令、传感器数据扩展帧29位11位基础ID 18位扩展ID复杂系统、大容量数据传输关键提示扩展帧的IDE位恒为1隐性电平标准帧IDE位恒为0显性电平。这一特性是硬件过滤器区分帧类型的基础。2. 6种过滤器配置模式详解2.1 标准数据帧过滤模式1// 只接收指定ID的标准数据帧 void CAN_Filter_StdDataFrame(uint8_t fifo, uint8_t filter_num, uint32_t id) { CAN_FilterInitTypeDef filter; filter.FilterNumber filter_num; filter.FilterMode CAN_FilterMode_IdMask; filter.FilterScale CAN_FilterScale_32bit; // 高16位标准ID左移5位对齐到bit15-bit5 filter.FilterIdHigh (id 5) 0xFFFF; // 低16位IDE0标准帧RTR0数据帧 filter.FilterIdLow (id 5) | CAN_ID_STD | CAN_RTR_DATA; filter.FilterMaskIdHigh 0xFFFF; // 必须完全匹配ID filter.FilterMaskIdLow 0xFFFF; // 必须匹配IDE和RTR位 filter.FilterFIFOAssignment fifo ? CAN_FIFO1 : CAN_FIFO0; filter.FilterActivation ENABLE; CAN_FilterInit(filter); }配置要点标准帧ID左移5位对齐到bit15-bit5IDE位显性0表示标准帧RTR位显性0表示数据帧2.2 标准遥控帧过滤模式2// 只接收指定ID的标准遥控帧 void CAN_Filter_StdRemoteFrame(uint8_t fifo, uint8_t filter_num, uint32_t id) { CAN_FilterInitTypeDef filter; filter.FilterNumber filter_num; filter.FilterMode CAN_FilterMode_IdMask; filter.FilterScale CAN_FilterScale_32bit; filter.FilterIdHigh (id 5) 0xFFFF; filter.FilterIdLow (id 5) | CAN_ID_STD | CAN_RTR_REMOTE; filter.FilterMaskIdHigh 0xFFFF; filter.FilterMaskIdLow 0xFFFF; filter.FilterFIFOAssignment fifo ? CAN_FIFO1 : CAN_FIFO0; filter.FilterActivation ENABLE; CAN_FilterInit(filter); }特殊处理遥控帧的RTR位置1隐性电平接收方需在中断处理中回复数据帧2.3 标准帧通用过滤模式3// 接收指定ID的所有标准帧数据帧遥控帧 void CAN_Filter_StdAll(uint8_t fifo, uint8_t filter_num, uint32_t id) { CAN_FilterInitTypeDef filter; filter.FilterNumber filter_num; filter.FilterMode CAN_FilterMode_IdMask; filter.FilterScale CAN_FilterScale_32bit; filter.FilterIdHigh (id 5) 0xFFFF; filter.FilterIdLow (id 5) | CAN_ID_STD; filter.FilterMaskIdHigh 0xFFFF; filter.FilterMaskIdLow 0xFFFC; // 不检查RTR和保留位 filter.FilterFIFOAssignment fifo ? CAN_FIFO1 : CAN_FIFO0; filter.FilterActivation ENABLE; CAN_FilterInit(filter); }应用场景需要同时处理数据帧和遥控帧屏蔽位设置为0xFFFC忽略RTR位差异2.4 扩展数据帧过滤模式4// 只接收指定ID的扩展数据帧 void CAN_Filter_ExtDataFrame(uint8_t fifo, uint8_t filter_num, uint32_t id) { CAN_FilterInitTypeDef filter; filter.FilterNumber filter_num; filter.FilterMode CAN_FilterMode_IdMask; filter.FilterScale CAN_FilterScale_32bit; // 高16位扩展ID高16位ID28-ID13 filter.FilterIdHigh (id 3) 16; // 低16位扩展ID低13位ID12-ID0 IDE1 RTR0 filter.FilterIdLow ((id 3) | CAN_ID_EXT | CAN_RTR_DATA) 0xFFFF; filter.FilterMaskIdHigh 0xFFFF; filter.FilterMaskIdLow 0xFFFF; filter.FilterFIFOAssignment fifo ? CAN_FIFO1 : CAN_FIFO0; filter.FilterActivation ENABLE; CAN_FilterInit(filter); }关键点29位ID左移3位后拆分到高低16位寄存器IDE位置1隐性电平表示扩展帧2.5 扩展遥控帧过滤模式5// 只接收指定ID的扩展遥控帧 void CAN_Filter_ExtRemoteFrame(uint8_t fifo, uint8_t filter_num, uint32_t id) { CAN_FilterInitTypeDef filter; filter.FilterNumber filter_num; filter.FilterMode CAN_FilterMode_IdMask; filter.FilterScale CAN_FilterScale_32bit; filter.FilterIdHigh (id 3) 16; filter.FilterIdLow ((id 3) | CAN_ID_EXT | CAN_RTR_REMOTE) 0xFFFF; filter.FilterMaskIdHigh 0xFFFF; filter.FilterMaskIdLow 0xFFFF; filter.FilterFIFOAssignment fifo ? CAN_FIFO1 : CAN_FIFO0; filter.FilterActivation ENABLE; CAN_FilterInit(filter); }注意事项接收到遥控帧后需在1ms内回复数据帧总线负载较高时需考虑响应实时性2.6 扩展帧通用过滤模式6// 接收指定ID的所有扩展帧数据帧遥控帧 void CAN_Filter_ExtAll(uint8_t fifo, uint8_t filter_num, uint32_t id) { CAN_FilterInitTypeDef filter; filter.FilterNumber filter_num; filter.FilterMode CAN_FilterMode_IdMask; filter.FilterScale CAN_FilterScale_32bit; filter.FilterIdHigh (id 3) 16; filter.FilterIdLow ((id 3) | CAN_ID_EXT) 0xFFFF; filter.FilterMaskIdHigh 0xFFFF; filter.FilterMaskIdLow 0xFFFC; // 不检查RTR和保留位 filter.FilterFIFOAssignment fifo ? CAN_FIFO1 : CAN_FIFO0; filter.FilterActivation ENABLE; CAN_FilterInit(filter); }典型应用需要处理同一ID的数据帧和遥控帧工业设备双向通信场景3. 双机通信实战环回模式与正常模式3.1 硬件连接方案双机通信硬件连接需注意CAN_H和CAN_L需使用双绞线总线两端各接120Ω终端电阻推荐使用TI的SN65HVD23x系列CAN收发器# STM32F103C8T6最小系统连接示例 ----------------- ----------------- | STM32 | | STM32 | | | | | | PA11 ------------------| PA12 (CAN_RX) | | PA12 ------------------| PA11 (CAN_TX) | | | | | ---------------- ---------------- | | \|/ \|/ -------------- -------------- | CAN_H | | CAN_H | | CAN_L | | CAN_L | -------------- -------------- | | \|/ \|/ ----------------- ----------------- | 120Ω 终端电阻 | | 120Ω 终端电阻 | ----------------- -----------------3.2 环回模式测试代码环回模式用于单节点自测试无需实际硬件连接void CAN_Mode_Config(uint8_t mode, uint32_t baudrate) { CAN_InitTypeDef CAN_InitStruct; CAN_StructInit(CAN_InitStruct); // 模式选择 if(mode 0) { CAN_InitStruct.CAN_Mode CAN_Mode_LoopBack; // 环回模式 } else { CAN_InitStruct.CAN_Mode CAN_Mode_Normal; // 正常模式 } // 波特率配置以1MHz为例 CAN_InitStruct.CAN_SJW CAN_SJW_1tq; CAN_InitStruct.CAN_BS1 CAN_BS1_3tq; CAN_InitStruct.CAN_BS2 CAN_BS2_2tq; CAN_InitStruct.CAN_Prescaler 6; // 36MHz/(132)/6 1MHz CAN_Init(CAN1, CAN_InitStruct); // 配置过滤器示例FIFO0接收标准数据帧ID0x123 CAN_Filter_StdDataFrame(0, 0, 0x123); }3.3 中断处理与数据收发完整的通信流程需要配合中断处理// 发送标准数据帧 int CAN_SendStdData(uint32_t id, uint8_t* data, uint8_t len) { CanTxMsg msg; msg.StdId id; msg.IDE CAN_ID_STD; msg.RTR CAN_RTR_DATA; msg.DLC len 8 ? 8 : len; memcpy(msg.Data, data, msg.DLC); uint8_t mailbox CAN_Transmit(CAN1, msg); return (mailbox ! CAN_NO_MB) ? 0 : -1; } // 接收中断处理 void USB_LP_CAN1_RX0_IRQHandler(void) { if(CAN_GetITStatus(CAN1, CAN_IT_FMP0)) { CanRxMsg rx_msg; CAN_Receive(CAN1, CAN_FIFO0, rx_msg); if(rx_msg.IDE CAN_ID_STD) { printf(StdID:0x%03X Data:, rx_msg.StdId); } else { printf(ExtID:0x%08lX Data:, rx_msg.ExtId); } for(int i0; irx_msg.DLC; i) { printf(%02X , rx_msg.Data[i]); } printf(\n); } CAN_ClearITPendingBit(CAN1, CAN_IT_FMP0); }4. 常见问题与调试技巧4.1 过滤器配置失败排查检查过滤器编号确保不重复使用同一过滤器编号验证ID对齐方式标准帧ID左移5位扩展帧ID左移3位确认FIFO分配过滤器必须明确指定到FIFO0或FIFO14.2 通信异常处理当通信异常时可通过以下寄存器状态诊断寄存器关键位含义CAN_ESRLEC[2:0]最后错误代码0无错误CAN_MSRSLAKI睡眠模式确认中断CAN_TSRTME[2:0]发送邮箱空状态错误处理参考代码void CAN_ErrorHandler(void) { uint32_t esr CAN-ESR; if(esr CAN_ESR_BOFF) { printf(Bus-off状态需重新初始化CAN\n); } else { switch((esr CAN_ESR_LEC) CAN_ESR_LEC_Pos) { case 1: printf(填充错误\n); break; case 2: printf(格式错误\n); break; case 3: printf(ACK错误\n); break; case 4: printf(隐性位错误\n); break; case 5: printf(显性位错误\n); break; case 6: printf(CRC错误\n); break; } } // 清除错误状态 CAN-MSR | CAN_MSR_ERRI; }4.3 性能优化建议过滤器分组策略高优先级消息分配到FIFO0低优先级消息分配到FIFO1中断优先级设置NVIC_InitTypeDef NVIC_InitStruct; NVIC_InitStruct.NVIC_IRQChannel USB_LP_CAN1_RX0_IRQn; NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority 1; // 高于其他通信接口 NVIC_InitStruct.NVIC_IRQChannelSubPriority 0; NVIC_InitStruct.NVIC_IRQChannelCmd ENABLE; NVIC_Init(NVIC_InitStruct);总线负载监控float CAN_GetBusLoad(void) { uint32_t esr CAN-ESR; uint32_t rec (esr CAN_ESR_REC) CAN_ESR_REC_Pos; uint32_t tec (esr CAN_ESR_TEC) CAN_ESR_TEC_Pos; return (rec tec) / 255.0f * 100; // 返回百分比 }5. 进阶应用混合帧网络设计在实际项目中常需同时处理标准帧和扩展帧。推荐两种设计方案方案A双过滤器组策略// FIFO0处理标准帧FIFO1处理扩展帧 void CAN_MixedFilter_Init(void) { // FIFO0过滤器组标准帧ID 0x100-0x103 CAN_Filter_StdDataFrame(0, 0, 0x100); CAN_Filter_StdDataFrame(0, 1, 0x101); // FIFO1过滤器组扩展帧ID 0x1000000-0x1000003 CAN_Filter_ExtDataFrame(1, 2, 0x1000000); CAN_Filter_ExtDataFrame(1, 3, 0x1000001); }方案B优先级分流策略// 高优先级消息标准帧用FIFO0普通消息扩展帧用FIFO1 void CAN_PriorityFilter_Init(void) { // FIFO0关键控制指令标准帧 CAN_Filter_StdDataFrame(0, 0, 0x01); // 紧急停止 CAN_Filter_StdDataFrame(0, 1, 0x02); // 状态查询 // FIFO1普通数据扩展帧 CAN_Filter_ExtDataFrame(1, 2, 0x10000001); // 传感器数据1 CAN_Filter_ExtDataFrame(1, 3, 0x10000002); // 传感器数据2 }在汽车电子控制系统中通常会采用混合帧设计关键控制指令使用高优先级的标准帧诊断和配置信息使用扩展帧。这种设计既保证了实时性又满足了大数据量传输需求。
RELATED

相关推荐

.cbz 文件怎么打开?OpenFiles 实测预览、翻页与书签完整教程

.cbz 文件怎么打开?OpenFiles 实测预览、翻页与书签完整教程

结论先说:.cbz 是 ZIP 封装的漫画/扫描页归档,OpenFiles 官方格式页将它标为 Comic Book Archive File (ZIP),并显示由 Ebook Reader 查看器支持。本文适合 Windows、macOS、Linux 用户处理“.cbz 文件打不开、页序不对、翻页异常、无法判断是…

📅 2026/10/9 22:55:54
基于 robotgo 实现 Windows 桌面 RPA 自动化框架:技术全解

基于 robotgo 实现 Windows 桌面 RPA 自动化框架:技术全解

、为何选择 robotgo 桌面 RPA 的本质是对操作系统的输入系统(鼠标、键盘、剪贴板、屏幕)进行程序化控制。在 Windows 上,主流的自动化方案有几种: UI Automation (UIA):通过可访问性树操控控件,精确但受限…

📅 2026/9/26 7:35:09
Java线程模型演进:从Thread到VirtualThread的性能实测与选型

Java线程模型演进:从Thread到VirtualThread的性能实测与选型

Java线程模型演进:从Thread到VirtualThread的性能实测与选型 一、引言 去年Q4做了一次项目技术债清理,翻到一个2019年写的HTTP网关模块——满屏的 new Thread(runnable).start(),两百多个并发连接各自占着一个平台线程,压测一到…

📅 2026/9/20 0:48:19
MORE NEWS

更多资讯

📰

2026年会员管理系统多少钱?先算清交易费率和第二年续费这笔账

年费从几百到几万,差别不在“贵不贵”据华为云社区2026年10月发布的一篇SaaS工具对比梳理,国内会员管理系统的年费跨度很大:码云数智基础版1998元/年,有赞基础版6800元/年起,微盟豪华版可达29800元/年。另一份来自乔拓…

📰

Agentic Coding:从生成代码到交付结果的AI编程范式

简介:一份由北大青鸟人工智能研究院等团队出品的《Agentic Coding:从Vibe Coding到超级个体的进化之路》内部研讨讲稿,面向无编程经验的产品经理、教师、技术创业者,也适合开发者、CTO及架构师建立AI编程的系统认知。内容系统梳理…

📰

AI代码评审两件套:superpowers-skills中如何请求评审,以及如何优雅地回怼反馈

【免费下载链接】superpowers-skills Community-editable skills for Claude Codes superpowers plugin 项目地址: https://gitcode.com/gh_mirrors/su/superpowers-skills 点击查看 免费下载 如果你在用 Claude Code 做开发,superpowers-skills 是 sup…

📰

Milvus 索引不重建也能查:为什么召回率悄悄掉到随机水平

本文摘要:换 Embedding 模型却不重建索引,查询不报错但召回率悄悄跌至随机。通过 IVF_PQ 双层失配机制复现相似度趋同,给出灰度切换方案。适用于新旧模型维度相同的场景,维度变更时查询直接报错。 一、问题与结论 先说结论&#…

📰

MySQL 8.0 联合索引走错:为什么加了索引查询反而从 200ms 变成 8s

本文摘要:线上订单加联合索引后从 200ms 变 8 秒,索引命中却更慢。根因是 MySQL 8.0 偏好免排序索引,低选择性前缀致回表暴涨。仅适用于非覆盖索引场景,统计信息过期需先刷新再判断。 一、问题与结论 环境:Docker 启动…

📰

【无套路自取】给 Inspector 换上 X 光镜:Odin V3.5 属性绘制器,让 Unity 数据编辑省心得多

【无套路自取】给 Inspector 换上 X 光镜:Odin V3.5 属性绘制器,让 Unity 数据编辑省心得多 【免费下载链接】Unity插件OdinV3.5下载 本仓库提供Unity插件——Odin V3.5的下载资源。Odin是一款强大的Unity插件,旨在提升Unity开发者的生产力&a…

TODAY

今日更新

THIS WEEK

本周精选

THIS MONTH

本月热门

读完文章,想聊聊您的网站?

告诉我们您的行业与需求,资深顾问一对一梳理方案与报价,全程免费。

📞 💬