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

发布时间:2026/9/1 20:54: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库开发从配置到调试本文

相关新闻

3-ansible user使用加密密码创建用户

3-ansible user使用加密密码创建用户

2026/9/1 20:44:45

1.利用python程序生成sha512加密密码 Command: python -c import crypt,getpass;pw="test";print(crypt.crypt(pw)) [root@cent79-2 ~]# python -c import crypt,getpass;pw="test";print(crypt.crypt(pw)) $6$SU7Mzt1FAW63QD08$LYBib22jotPJMA7IsYEmE…

基于Qt与C++的前视声纳数据显示与预处理软件实现

基于Qt与C++的前视声纳数据显示与预处理软件实现

2026/9/1 20:44:45

简介:本资源是一套面向高校本科生课程设计与期末大作业的前视声纳数据可视化与预处理软件系统,基于Qt框架与C开发,聚焦水下探测信号的实时显示、滤波去噪、距离校正等典型预处理任务,适用于智能感知、海洋工程或嵌入式图像处理类实…

Android工程师笔试题全解析:从Handler到内存优化的核心考点

Android工程师笔试题全解析:从Handler到内存优化的核心考点

2026/9/1 20:44:45

翻到这份“货拉拉2018秋招Android工程师笔试题卷三(A)”的时候,我愣了挺久。2018年Android面试和现在最大的区别是,那时候大家还会老老实实刷四大组件和Handler,现在动不动就问协程和Compose。但说真的,越往…

360春招笔试复盘:算法题型与解题思路全解析(含避坑指南)

360春招笔试复盘:算法题型与解题思路全解析(含避坑指南)

2026/9/1 22:14:53

又到一年春招季,不少同学应该已经在牛客、力扣上刷了一圈题,准备投360的春招。我是去年参加的第二批笔试,当时做完之后整理了不少复盘笔记,一直没来得及发出来。今天就把当时的原题考点、我的解题思路、还有踩过的坑一次性说清楚&…

软件工程的核心:管理复杂性,让系统可控演化

软件工程的核心:管理复杂性,让系统可控演化

2026/9/1 22:14:53

不知道你有没有过这种体验:一个项目刚起步时只有几千行代码,你一个人维护,改起来很顺手。过了半年,代码量突破五万行,团队从1个人变成8个人,这时你发现,真正让你痛苦的不再是某个算法不会写、某…

PJSK跑团Replay视频制作全指南:从骰点记录到语音合成

PJSK跑团Replay视频制作全指南:从骰点记录到语音合成

2026/9/1 22:14:53

在 PJSK(Project Sekai)同人社区里,跑团 Replay 已经是一种非常成熟的二次创作形态。你很可能刷到过类似《才不是喜欢你呢》这样的标题——它看起来像一场跑团直播的录像,又带着完整的剧情剪辑和角色演出,弹幕和评论区…

从零跑通MPX小程序项目:核心机制、跨端实践与排错指南

从零跑通MPX小程序项目:核心机制、跨端实践与排错指南

2026/9/1 22:14:53

如果只给开发者看一场 MPX 宣传片,最容易被记住的通常是跨端、组件化、高性能这些词。但宣传片不会告诉你的是,在真实项目里,脚手架装到一半就报错、写好的页面在微信开发者工具里打不开、一个setData的差异让跨端表现不一致,这些…

Python+Django招聘数据分析可视化系统:从爬虫到ECharts实战

Python+Django招聘数据分析可视化系统:从爬虫到ECharts实战

2026/9/1 22:14:53

简介:这是一套面向计算机专业本科生毕业设计与课程实践的招聘数据分析可视化系统完整实现,基于Python Django框架开发,兼顾数据爬取、清洗、分析与前端可视化全流程,特别适合毕设选题为Web应用或数据分析方向的学生快速搭建可演示…

16卡算力平台从零搭建:硬件选型到DDP实战全攻略

16卡算力平台从零搭建:硬件选型到DDP实战全攻略

2026/9/1 22:04:52

最近后台收到不少开发者的私信,内容出奇一致:5080 显卡价格一路走高,原本预算范围内能组起来的机器,现在要多花不少钱。与此同时,市面上的 16 卡算力平台需求却越来越旺盛,朋友圈里搞 AI 训练、微调、推理服…

备战数据库管理工程师校招:索引、事务、备份恢复核心考点解析

备战数据库管理工程师校招:索引、事务、备份恢复核心考点解析

2026/9/1 1:53:39

每年校招季我都会接触不少准备数据库方向笔试的同学,看到最多的状态就是:简历上写着“熟悉 MySQL”“了解索引优化”,一碰到数据库管理工程师的笔试卷,却在索引、事务、锁、备份恢复这些题目上翻车。网易这套 2018 校园招聘数据库…

数字电路时序基石:深入理解建立时间与保持时间

数字电路时序基石:深入理解建立时间与保持时间

2026/9/1 9:55:14

1. 这不是“背公式”的事:时间参数到底在约束什么你翻过数字电路教材,一定见过这两个词:建立时间(Setup Time)和保持时间(Hold Time)。它们常被并列写在触发器(Flip-Flop&#xff09…

蓝桥杯国赛超声波测距机:从单片机原理到嵌入式系统实战

蓝桥杯国赛超声波测距机:从单片机原理到嵌入式系统实战

2026/8/31 17:18:46

1. 项目缘起:从赛题到超声波测距机的诞生第八届蓝桥杯单片机设计与开发国赛的题目,我至今记忆犹新。它没有直接给出一个花哨的名字,而是用“超声波测距机”这个朴实无华的功能描述,精准地勾勒出了考核的核心。对于当时备赛的我而言…

远程协作的工作台整理

远程协作的工作台整理

2026/9/1 0:03:36

远程协作的工作台整理远程协作的核心不是再加一个工具,而是让交接信息足够完整。异步任务要写明目标、输入位置、完成标准和需要决策的人。 工作台的最小配置 将日程、待办、代码和沟通入口收拢到少数固定位置;通知按紧急程度分层。工作台不需要模仿办公…

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能

2026/9/1 0:03:36

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能分类:[AI/大模型]细分主题:AI 增强型 CI/CD 流水线自动化与 GitOps 实践:Agent 工作流、工具调用与任务拆解:从原型到生产的验收清单很多团队在尝试用大…

容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场

容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场

2026/9/1 0:03:36

容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场分类:[工程技术]细分主题:Kubernetes 生产环境运维与排障实战:可复制的项目复盘模板与决策记录大部分团队的事故复盘报告,最后都变成了躺在 Confluence 或钉…

远程协作的工作台整理

远程协作的工作台整理

2026/9/1 0:03:36

远程协作的工作台整理远程协作的核心不是再加一个工具,而是让交接信息足够完整。异步任务要写明目标、输入位置、完成标准和需要决策的人。 工作台的最小配置 将日程、待办、代码和沟通入口收拢到少数固定位置;通知按紧急程度分层。工作台不需要模仿办公…

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能

2026/9/1 0:03:36

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能分类:[AI/大模型]细分主题:AI 增强型 CI/CD 流水线自动化与 GitOps 实践:Agent 工作流、工具调用与任务拆解:从原型到生产的验收清单很多团队在尝试用大…

容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场

容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场

2026/9/1 0:03:36

容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场分类:[工程技术]细分主题:Kubernetes 生产环境运维与排障实战:可复制的项目复盘模板与决策记录大部分团队的事故复盘报告,最后都变成了躺在 Confluence 或钉…