新闻详情

新闻详情

首页 / 资讯中心 / 详情

【CAN通信实战】STM32 HAL库开发:从配置到调试

发布时间:2026/9/1 20:55:46来源:尧图网络
【CAN通信实战】STM32 HAL库开发:从配置到调试
实战指南1. 写在前面2. 实验环境3. 硬件连接3.1. TJA1042 引脚连接板子上已经集成好4. STM32CubeMX 配置4.1. 使能CAN外设4.2. 配置CAN参数4.3. 中断配置5. 代码实现5.1. CAN初始化5.2. CAN发送函数5.3. CAN接收中断方式5.4. 错误中断5.5. 测试结果6. 常见问题排查6.1. 接收不到数据6.2. 采样点配置不当7. 总结8. 下篇预告9. 互动时间学习目标读完本文你将掌握STM32 CAN的完整配置方法能够编写发送和接收代码理解波特率计算并能够排查常见问题。适合做毕设和项目开发。⏱️预计学习时间30-40分钟前置知识建议先阅读前四篇文章了解CAN理论基础。需要基本的STM32 HAL库使用经验。1. 写在前面本文是《CAN通信从入门到实战》专栏的第 5 篇前面四篇主要讲了理论这一篇开始上手 STM32F407 的实战。本文将以STM32F407 TJA1042收发器为例手把手教你如何配置和使用CAN通信。这是一篇实践文章实现一个简单的can demo将bcan1和bcan2通过can总线连接相互发送can报文。2. 实验环境MCU野火霸天虎 STM32F407ZGT6 开发板板载 TJA1042CAN收发器TJA1042调试工具FireDAP开发工具STM32CubeMX VsCode CMake开发环境windows上安装的Ubuntu系统WSL安装的3. 硬件连接3.1. TJA1042 引脚连接板子上已经集成好无需连接使用的bcan2PB12和PB13为了方便测试我又另外购买了一款TJA1042的收发器通过杜邦线与板子连接TJA1042引脚连接说明VCC5V电源GND地TXD连接STM32的CAN_TX如PA12RXD连接STM32的CAN_RX如PA11CANHCAN总线高电平线与板子上的CAN_H连接CANLCAN总线低电平线与板子上的CAN_L连接S接地下拉normal模式悬空/高电平standbyNC悬空即可硬件连接⚠️ 提醒终端电阻CAN总线两端必须各接一个120Ω终端电阻共地所有节点必须共地线序CAN_H和CAN_L不能接反4. STM32CubeMX 配置4.1. 使能CAN外设在Connectivity中找到CAN1/CAN2选择Activated。4.2. 配置CAN参数基本配置ModenormalPrescaler (for Time Quantum)分频系数用于计算波特率Time Quanta in Bit Segment 1对应PBS1Time Quanta in Bit Segment 2对应PBS2Time for one Bit自动计算等于 1 PBS1 PBS2波特率计算示例500kbps80MHz系统时钟假设系统时钟42MHzCan挂载在APB1上APB1设置的是42MHz目标波特率500kbps采样点80%计算过程后续考虑使用脚本自动实现一个位时间 1 / 500k 2μs42MHz / Prescaler CAN时钟频率假设Prescaler 6则CAN时钟 7MHz一个Tq 1 / 7MHz 142.86ns一个位时间需要 2μs / 142.86ns 14 Tq采样点80%则 PBS1结束位置 14 × 0.8 11 Tq所以SS1, PBS110, PBS23CubeMX配置Prescaler: 6Time Quanta in Bit Segment 1: 10Time Quanta in Bit Segment 2: 3ReSynchronization Jump Width: 14.3. 中断配置在NVIC Settings中使能TXRXSCE中断。5. 代码实现5.1. CAN初始化/** * brief CAN初始化函数 * param None * retval HAL_StatusTypeDef */voidMX_CAN1_Init(void){/* 初始化hcan1结构体成员cubemx自动生成 *//* USER CODE BEGIN CAN1_Init 2 手动添加*//** * brief CAN1初始化完成后的处理 * 启动CAN外设并激活接收中断 * 1. 配置CAN过滤器 * 2. 启动CAN外设 * 3. 开启can相关中断 */CAN_Filter_Config(hcan1,0);HAL_CAN_Start(hcan1);HAL_CAN_ActivateNotification(hcan1,CAN_IT_TX_MAILBOX_EMPTY|// 发送队列为空时出触发TX中断CAN_IT_RX_FIFO0_MSG_PENDING|//FIFO 0接收到消息触发RX中断CAN_IT_ERROR|//只要发生错误就会触发中断CAN_IT_BUSOFF);//发生BUSOFF触发SCE中断/* CAN_IT_LAST_ERROR_CODE //最近一次错误代码捕获中断 CAN_IT_ERROR_WARNING //错误警告错误计数超过 96 CAN_IT_ERROR_PASSIVE //被动错误错误计数超过 127 等按需开启这些错误对应的都是SCE中断 *//* USER CODE END CAN1_Init 2 */}voidMX_CAN2_Init(void){//内容与can1类似不再赘述}需要手动实现CAN_Filter_Config的代码实现过滤器定义哪些id的can报文可以被收到。voidCAN_Filter_Config(CAN_HandleTypeDef*hcan,uint8_tfilterBank){CAN_FilterTypeDef sFilterConfig;// 配置过滤器参数哪些ID的can报文可以触发接受中断sFilterConfig.FilterBankfilterBank;// 使用过滤器组0sFilterConfig.FilterModeCAN_FILTERMODE_IDMASK;// 掩码模式根据掩码匹配sFilterConfig.FilterScaleCAN_FILTERSCALE_32BIT;// 32位过滤器比例sFilterConfig.FilterIdHigh0x0000;// 验证ID高16位0x0000表示不过滤高位sFilterConfig.FilterIdLow0x0000;// 验证ID低16位0x0000表示不过滤低位//并未配置过滤器所有报文均可收到sFilterConfig.FilterMaskIdHigh0x0000;// 掩码高16位0x0000表示不检查ID的高16位sFilterConfig.FilterMaskIdLow0x0000;// 掩码低16位0x0000表示不检查ID的低16位sFilterConfig.FilterFIFOAssignmentCAN_RX_FIFO0;// 过滤后的报文存入FIFO 0sFilterConfig.FilterActivationENABLE;// 启用过滤器sFilterConfig.SlaveStartFilterBank14;// 从过滤器组14开始作为从属CAN// 应用过滤器配置if(HAL_CAN_ConfigFilter(canHandle,sFilterConfig)!HAL_OK){Error_Handler();//后续考虑使用uart输出错误信息}}⚠️注意此处的FilterBank必须要大于SlaveStartFilterBankSlaveStartFilterBank的作用是将0-SlaveStartFilterBank分给can1SlaveStartFilterBank-28分给can25.2. CAN发送函数本demo中我开启了freertos在**StartDefaultTask**中周期调用发送函数如果你不用 FreeRTOS也可以在 while(1) 里用 HAL_Delay 周期调用 CANx_Send_Test逻辑是一样的。voidCAN1_Send_Test(void){CAN_TxHeaderTypeDef TxHeader;uint8_tTxData[8]{0x11,0x22,0x33,0x44,0x55,0x66,0x77,0x88};uint32_tTxMailbox;uint32_terr;TxHeader.StdId0x123;// 标准IDTxHeader.RTRCAN_RTR_DATA;// 数据帧TxHeader.IDECAN_ID_STD;// 标准格式TxHeader.DLC8;// 8字节TxHeader.TransmitGlobalTimeDISABLE;// 请求发送数据会直接回环到接收区if(HAL_OK!HAL_CAN_AddTxMessage(hcan1,TxHeader,TxData,TxMailbox)){Error_Handler();}}voidCAN2_Send_Test(void){CAN_TxHeaderTypeDef TxHeader;uint8_tTxData[8]{0x12,0x23,0x34,0x45,0x56,0x67,0x78,0x89};uint32_tTxMailbox;uint32_terr;TxHeader.StdId0x124;// 标准IDTxHeader.RTRCAN_RTR_DATA;// 数据帧TxHeader.IDECAN_ID_STD;// 标准格式TxHeader.DLC8;// 8字节TxHeader.TransmitGlobalTimeDISABLE;// 请求发送数据会直接回环到接收区if(HAL_OK!HAL_CAN_AddTxMessage(hcan2,TxHeader,TxData,TxMailbox)){Error_Handler();}}5.3. CAN接收中断方式接收到总线的报文后若符合过滤器条件则会触发RX中断// 在stm32f4xx_it.c中voidCAN1_RX0_IRQHandler(void){HAL_CAN_IRQHandler(hcan1);}voidCAN2_RX0_IRQHandler(void){HAL_CAN_IRQHandler(hcan2);}//最终都会走到此函数中在HAL库中被定义为weak类型用户需要根据需求自己实现voidHAL_CAN_RxFifo0MsgPendingCallback(CAN_HandleTypeDef*hcan){CAN_RxHeaderTypeDef RxHeader;uint8_tRxData[8];if(hcan-InstanceCAN1){// 从 FIFO 0 提取报文HAL_CAN_GetRxMessage(hcan,CAN_RX_FIFO0,RxHeader,RxData);// 验证数据如果是我们发的 ID 0x124就点个灯或串口打印输出if(RxHeader.StdId0x124){HAL_GPIO_TogglePin(LED1_GPIO_Port,LED1_Pin);}}if(hcan-InstanceCAN2){// 从 FIFO 0 提取报文HAL_CAN_GetRxMessage(hcan,CAN_RX_FIFO0,RxHeader,RxData);// 验证数据如果是我们发的 ID 0x123就点个灯或串口打印输出if(RxHeader.StdId0x123){HAL_GPIO_TogglePin(LED1_GPIO_Port,LED1_Pin);}}}5.4. 错误中断当总线发生错误时会触发SCE中断voidCAN1_SCE_IRQHandler(void){HAL_CAN_IRQHandler(hcan1);}voidCAN2_SCE_IRQHandler(void){HAL_CAN_IRQHandler(hcan2);}//用户自己手动实现weak函数voidHAL_CAN_ErrorCallback(CAN_HandleTypeDef*hcan){// 在这里调用 GetErroruint32_terrHAL_CAN_GetError(hcan);// 判断具体错误类型if(errHAL_CAN_ERROR_BOF){// 发生了离线错误 (Bus-Off)// 可以在这里执行恢复逻辑如 HAL_CAN_Start(hcan);}if(errHAL_CAN_ERROR_STF){// 填充错误 (Stuff Error)}// 清除错误信息}5.5. 测试结果在vscode通过FireDAP进行调试在报文接受函数中添加断点可以看到分别进入到can1和can2的接受函数且接收内容符合预期。我也额外购买了usb-can工具等工具到了之后会使用专业的工具查看总线数据进一步验证数据是否在总线上符合预期的发送。后续会更新新买的usbcan fd工具到达后连接板子的canh/canl到usbcanfd的can1上tja1042的canh/canl到usbcanfd的can2上打开设备设置好波特率即可看到can1/can2上有can数据并且在usbcan上发送数据在板子上也可以接收到。6. 常见问题排查6.1. 接收不到数据检查清单终端电阻是否正确连接120ΩCAN_H和CAN_L是否接反波特率是否匹配过滤器配置是否正确是否启动了CANHAL_CAN_Start6.2. 采样点配置不当现象波形正常但CRC错误解决调整BS1和BS2的比例使采样点位于位时间的75%-80%保证收发双方波特率相同7. 总结通过本文我们学习了✅STM32 CAN配置CubeMX配置、波特率计算✅发送代码完整的发送函数实现✅接收代码轮询和中断两种方式✅常见问题排查方法和解决方案✅调试技巧使用工具和添加日志8. 下篇预告代码写好了但调试时还是遇到各种问题下一篇《【CAN通信实战】调试技巧那些文档没写的坑》将分享示波器/逻辑分析仪的使用常见Bug的排查方法采样点配置的实战经验终端电阻问题的诊断后续我也会基于此代码为基础慢慢扩展其功能包括但不限于autosar风格分层、增加Json配置和解析脚本、自动解析DBC脚本等若大家有好的想法也欢迎留言讨论。敬请期待9. 互动时间你的CAN代码跑通了吗遇到了什么问题需要哪些功能的代码示例欢迎在评论区留言我会及时回复关注我获取完整代码资源。专栏目录✅ 【CAN通信入门】万字长文带你理解CAN从汽车减肥说起✅ 【CAN通信进阶】物理层两根线如何传输0和1✅ 【CAN通信进阶】数据链路层上帧结构全解析✅ 【CAN通信进阶】数据链路层下仲裁机制与错误处理✅ 【CAN通信实战】STM32 HAL库开发从配置到调试本文
网站建设高端定制企业官网
RELATED

相关资讯

更多精彩内容,欢迎继续阅读

较早相关资讯

最新相关资讯

AI视频清晰化避坑指南:漫剧二次剪辑怎么保画质? 2026/9/1 21:37:57

AI视频清晰化避坑指南:漫剧二次剪辑怎么保画质?

正在制作AI漫剧或AI动画视频的小伙伴,给大家推荐这里:AIGC梦工厂(www.aigcc.vip)。Ai漫剧一站式成片。输入一句话进去就能一键成片;画布模式可以精修每一帧画面;还有500多种Ai图片玩法。有兴趣的可以看看。…

阅读更多 →
Excel FILTER函数:告别VLOOKUP,掌握动态数组筛选新思维 2026/9/1 21:37:57

Excel FILTER函数:告别VLOOKUP,掌握动态数组筛选新思维

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

阅读更多 →
B站后端校招笔试卷B全解析:考点拆解与备战指南 2026/9/1 21:37:57

B站后端校招笔试卷B全解析:考点拆解与备战指南

每年金九银十的校招季,B站的后端笔试卷总能引起不少讨论。2023届这版B卷,我印象里算法题难度适中,但基础题覆盖面很广,选择题里藏着不少“陷阱”,系统设计题也很有B站业务特色。当时好几个学弟学妹做完出来吐槽“选择题…

阅读更多 →
动态视频与图文内容A/B测试:数据驱动的内容形式优化指南 2026/9/1 21:37:57

动态视频与图文内容A/B测试:数据驱动的内容形式优化指南

1. 先搞清楚“动态视频”到底在测什么数据看到“草东没有派对【但】闲得无聊发个动态视频看看数据会不会更好点”这个标题,第一反应可能有点懵。这不像一个标准的工具或技术项目,更像是一个社交媒体上的实验性表达。但恰恰是这种非典型的标题&#xff0c…

阅读更多 →
DCO-OFDM可见光通信MATLAB仿真全流程解析 2026/9/1 21:37:57

DCO-OFDM可见光通信MATLAB仿真全流程解析

简介:本资源是一个面向通信工程专业本科生与可见光通信初学者的MATLAB仿真项目,聚焦DCO-OFDM调制技术在可见光通信系统中的性能验证,重点解决直流偏置设计、正交频分复用信号生成、AWGN信道下误码率评估等核心问题,适用于课程设计…

阅读更多 →
Vue+SpringBoot图书管理系统源码解析与期末答辩指南 2026/9/1 21:34:56

Vue+SpringBoot图书管理系统源码解析与期末答辩指南

简介:本资源是一套完整的VueSpringBoot图书管理系统源码及配套数据库文件,专为计算机专业本科生期末大作业或Java全栈入门实践设计,解决传统图书管理效率低、前后端耦合度高、缺乏现代Web开发范式参考等问题。压缩包共92个文件,含…

阅读更多 →

今日资讯

本周资讯

本月资讯

看完文章仍有疑问?

联系尧图顾问,获取一对一建站咨询

立即免费咨询 📞 400-888-8888
📞