尧图网络 高端网站定制 · 原创设计
免费咨询热线
400-888-6620
免费获取方案
【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

相关推荐

OpenClaw智能体开发实战:从Skill封装到沙盒安全执行

OpenClaw智能体开发实战:从Skill封装到沙盒安全执行

在企业级智能体开发领域,如何让 AI 不仅理解指令,还能安全、可控地执行代码、调用工具,是构建真正“智能”应用的关键。OpenClaw 作为一个新兴的智能体开发框架,其核心设计理念正是围绕 Skill(技能包) 和…

📅 2026/10/1 10:22:45
OpenClaw Deep Agent:从聊天到执行,企业级AI智能体实战指南

OpenClaw Deep Agent:从聊天到执行,企业级AI智能体实战指南

你有没有遇到过这种情况:想给团队做一个能自动处理工单、分析数据、甚至写点简单代码的智能助手,结果发现市面上的方案要么太“玩具”,只能聊聊天;要么太“重型”,得从零开始搭一套复杂的架构,光是环境配置…

📅 2026/9/7 22:46:35
宝塔API一键建站系统:从签名认证到自动化部署实战

宝塔API一键建站系统:从签名认证到自动化部署实战

简介:2025最新宝塔API一键建站系统源码是一套面向个人站长、中小企业及PHP开发者的企业级建站工具,解决传统建站流程繁琐、技术门槛高、定制成本大等核心痛点,尤其适用于需快速交付多站点、自主掌控支付与模板体系的轻量级SaaS或建站服务商场…

📅 2026/9/8 17:05:33
MORE NEWS

更多资讯

📰

温县电工证报名常识:实操考试心里没底怕挂科?全国通用证书怎么拿?

温县电工证报名常识:实操考试心里没底怕挂科?全国通用证书怎么拿? 实操考试心里没底怕挂科?你不是一个人在战斗。很多人在报名电工证时,最大的担忧就是考试能不能通过,尤其是实操部分,一不小心就可能挂科。别慌,这篇内容专为温县电工证报名准备,帮你…

📰

天津最新电工证在哪考含金量高吗

天津最新电工证在哪考含金量高吗 你还在为找不到电工证发愁?找工作被拒?特种作业证已成为很多行业入场的“硬门槛”,尤其是电工证, 含金量…

📰

青岛电工证好考么现在官方报名入口在哪里

青岛电工证好考么现在官方报名入口在哪里 你是不是也遇到过这种情况,刚找了个电工相关的工作,结果公司要求先有特种作业操作证才能上岗?别急,今天就来聊聊 青岛电工证好考么现在 ,还有 官方报名入口…

📰

天津电工证延期怎么报名?怕考不过白交培训费的都看这里

天津电工证延期怎么报名?怕考不过白交培训费的都看这里 怕考不过白交培训费?天津电工证延期怎么报名?这些问题,不少打算报考电工证的朋友们都遇到过。别急,这篇文章就从真实经验出发,帮你理清流程、避开坑,还能帮你判断值不值得考这个证。…

📰

南靖电工证培训良心建议:学历不高怕报不上名?看看这些干货

南靖电工证培训良心建议:学历不高怕报不上名?看看这些干货 学历不高怕报不上名?别急,南靖电工证培训其实没有你想象中那么难。我认识不少初中毕业的学员,最后都顺利考下了电工证,找到稳定的工作,甚至还升职加薪了。关键是你得知道怎么走流程,别被那些…

📰

电工证不发实体卡保姆级教程:实操考试心里没底怕挂科

电工证不发实体卡保姆级教程:实操考试心里没底怕挂科 实操考试心里没底怕挂科?很多学员都遇到过这种情况,尤其是电工证不发实体卡的新政策一出,很多人都不知道该怎么应对。别担心,这篇保姆级教程就是为你准备的,从备考到考试,再到证书获取,手把手带你…

TODAY

今日更新

THIS WEEK

本周精选

THIS MONTH

本月热门

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

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

📞 💬