STM32F103 CAN 实战:双机通信与 TJA1050 全流程拆解
为什么汽车和工业现场都用 CAN而不是 UART、SPI、I2C本文以 STM32F103 TJA1050 双机通信为例从硬件接线、位时序计算、过滤器配置到三邮箱发送、FIFO 中断接收逐段拆解附 6 条避坑清单。为什么是 CAN一场总线混战做嵌入式这些年你一定用过 UART、SPI、I2C。它们各有绝活但到了汽车和工业现场大家默契地换成了 CAN。原因很直接CAN 是多主机总线。UART 只能点对点SPI 必须有主机I2C 虽支持多设备但仲裁机制复杂。CAN 总线上任意节点都能主动发数据靠 ID 优先级自动仲裁谁重要谁先走。报文本身是广播式的一帧发出去所有节点都能收到收不收由各节点自己的过滤器决定。UART 得一对一拉线SPI 得有个主机指挥CAN 这种「一喊全听见」的模型天然适合节点多的场景。再看物理层。CAN 用差分信号传输CANH 和 CANL 两根线互为参考抗干扰能力远超单端信号。500kbps 下能传 40 米降到 250kbps 能到 100 米这距离 UART 想都不敢想。汽车里几十个 ECU 就是靠 CAN 串成一张网。这套机制最早由博世在 80 年代提出后来成了汽车界的默认总线工业设备也大量沿用。今天我们不聊理论直接上手两块 STM32F103 各接一个 TJA1050 收发器500kbps 双机通信。硬件接线别把芯片直接怼总线上STM32 的 CAN 控制器输出 3.3V 逻辑电平驱动不了总线必须加收发器。TJA1050 是经典之选5V 供电TXD/RXD 直接兼容 3.3V 逻辑不用电平转换外围只要 0.1μF 10μF 去耦电容。接线核心是终端电阻。CAN 总线两端各需一个 120Ω 电阻用来吸收信号反射。怎么验证断电后量 CANH-CANL 之间应该约 60Ω两个 120Ω 并联。缺了一端高速率下波形会振铃、丢帧。双绞线也别省。CANH 和 CANL 是成对出现的差分线走线要绞合在一起绞得越密外界干扰在两根线上留下的痕迹越接近接收端做差后能抵消大半。挂示波器看差分波形CH1 减 CH2隐性时 CANH、CANL 都约 2.5V压差约 0显性时 CANH 拉到约 3.5V、CANL 降到约 1.5V压差超过 2V。只盯单根线容易误判。引脚方面F103 默认 CAN1 复用 PA11(RX)/PA12(TX)也可重映射到 PB8(RX)/PB9(TX)用GPIO_Remap1_CAN1开启。PB9 配复用推挽 50MHzPB8 配浮空或上拉输入。TJA1050 一共 8 个脚逻辑侧 TXD/RXD 接 MCU总线侧 CANH/CANL 接双绞线VCC 接 5VGND 和 MCU 共地。收发器和 MCU 必须共地差分电平才有共同的参考基准不然波形会漂。⚠️F103 的 USB 和 CAN 不能同时用。两者共享 512B SRAM这是硬件限制重映射也救不了。设计时二选一。初始化位时序才是灵魂CAN 挂在APB1 总线 36MHz不是 APB2 的 72MHz。很多人在这里翻车。先开时钟、配引脚。默认引脚 PA11(RX)/PA12(TX)TX 配复用推挽输出RX 配上拉输入RCC_APB1PeriphClockCmd(RCC_APB1Periph_CAN1,ENABLE);RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);GPIO_InitStructure.GPIO_PinGPIO_Pin_12;// TXGPIO_InitStructure.GPIO_ModeGPIO_Mode_AF_PP;// 复用推挽GPIO_InitStructure.GPIO_SpeedGPIO_Speed_50MHz;GPIO_Init(GPIOA,GPIO_InitStructure);GPIO_InitStructure.GPIO_PinGPIO_Pin_11;// RXGPIO_InitStructure.GPIO_ModeGPIO_Mode_IPU;// 上拉输入GPIO_Init(GPIOA,GPIO_InitStructure);用重映射 PB8/PB9 时还要额外开 AFIO 时钟再调GPIO_PinRemapConfig(GPIO_Remap1_CAN1, ENABLE)。波特率公式APB1 / Prescaler / (1 BS1 BS2)500kbps 36MHzPrescaler9、BS16tq、BS21tq即 36/9/8 500k采样点 87.5%。常见误区Prescaler9、BS113tq、BS22tq 算出来是 250kbps不是 500k。精确 500k 需要 Prescaler×(1BS1BS2)72。采样点放在 87.5% 也有讲究采样点越靠位末端离波特率跳变沿越远越不容易采到边沿噪声。CAN 波特率是全员必须一致的硬约定SJW 允许每个节点在同步段微调相位弥补晶振偏差。CAN_InitStructure.CAN_SJWCAN_SJW_1tq;CAN_InitStructure.CAN_BS1CAN_BS1_6tq;CAN_InitStructure.CAN_BS2CAN_BS2_1tq;CAN_InitStructure.CAN_Prescaler9;CAN_InitStructure.CAN_ModeCAN_Mode_Normal;// 双机用 NormalCAN_InitStructure.CAN_NARTENABLE;// 禁自动重发CAN_Init(CAN1,CAN_InitStructure);CAN_Init内部会自动处理 INRQ 进入/退出不用手动操作。接下来是过滤器。14 组0-13掩码模式里Mask1 必须匹配0 任意。收 0x123 标准帧ID 要左移 5 位掩码 11 位全匹配FilterActivation必须 ENABLE否则白配。过滤器分两种模式掩码模式IdMask适合范围过滤Mask 全 1 就是精确匹配列表模式IdList只能精确点名一个滤波器能装两个 ID第二个填在FilterMaskId*里。多个滤波器同时命中时编号小的优先级高。日常双机通信一个掩码滤波器就够。CAN_FilterInitStructure.CAN_FilterNumber0;CAN_FilterInitStructure.CAN_FilterModeCAN_FilterMode_IdMask;CAN_FilterInitStructure.CAN_FilterScaleCAN_FilterScale_32bit;CAN_FilterInitStructure.CAN_FilterIdHigh0x1235;CAN_FilterInitStructure.CAN_FilterIdLow0x0000;CAN_FilterInitStructure.CAN_FilterMaskIdHigh0x7FF5;// 11 位全匹配CAN_FilterInitStructure.CAN_FilterMaskIdLow0x0000;CAN_FilterInitStructure.CAN_FilterFIFOAssignmentCAN_FIFO0;CAN_FilterInitStructure.CAN_FilterActivationENABLE;CAN_FilterInit(CAN_FilterInitStructure);掩码全 0 就是收所有帧调试时很实用。发送三个邮箱的江湖F103 有3 个发送邮箱。CAN_Transmit返回邮箱号 0-2如果都占满了返回CAN_TxStatus_NoMailBox0x04。这里有个经典坑邮箱全满时如果 NART 没开硬件会一直自动重发等不到 ACK 就卡死邮箱。双机通信建议直接NARTENABLE禁掉自动重发。也别把NoMailBox当邮箱号传给CAN_TransmitStatus会查无此箱。uint8_tCAN_SendFrame(uint32_tid,uint8_t*buf,uint8_tlen){CanTxMsg TxMsg;TxMsg.StdIdid;TxMsg.IDECAN_Id_Standard;TxMsg.RTRCAN_RTR_Data;TxMsg.DLClen;for(uint8_ti0;ilen;i)TxMsg.Data[i]buf[i];if(CAN_Transmit(CAN1,TxMsg)CAN_TxStatus_NoMailBox)return0;return1;}三个邮箱各有状态位TME 位为 1 表示邮箱空闲可投递。连续发多帧时下一帧会排队进下一个空邮箱全满才返回 NoMailBox。发送完成后可用CAN_TransmitStatus确认返回CAN_TxStatus_Ok才是真正发出去了CAN_TxStatus_Failed说明没等来 ACK多半是总线没接好。顺带说下帧格式。标准帧 ID 是 11 位扩展帧 29 位靠 IDE 标志区分数据场最长 8 字节DLC 表示长度。还有一种 RTR 远程帧不带数据用来向对端要数据发一个 RTR 帧对端收到后把数据帧填回来。日常双机通信用标准帧数据帧就够代码里CAN_Id_StandardCAN_RTR_Data就是标准配置。帧尾还有 ACK 槽接收节点要在 ACK 槽回显一个显性位发送节点才确认对端在场。单机 Normal 模式自测发不出去原因就在这总线上没有第二块板子应答。接收FIFO 与中断接收有 FIFO0 和 FIFO1 两个队列各能存 3 帧。过滤器把匹配的帧送进指定 FIFO双机通信把帧全送 FIFO0 就够。推荐用中断使能CAN_IT_FMP0帧到达时触发挂起中断在 ISR 里用CAN_Receive取走。别忘了 NVICNVIC_EnableIRQ(USB_LP_CAN1_RX0_IRQn)并设好优先级不然帧到了中断也进不来。voidUSB_LP_CAN1_RX0_IRQHandler(void){CanRxMsg RxMsg;if(CAN_GetITStatus(CAN1,CAN_IT_FMP0)!RESET){CAN_Receive(CAN1,CAN_FIFO0,RxMsg);// 处理 RxMsg.StdId / RxMsg.DataCAN_ClearITPendingBit(CAN1,CAN_IT_FMP0);}}注意如果 FMP 中断触发后没及时取走新帧可能覆盖旧帧。想锁定旧帧可配置 RFLM 选项。CAN_Receive取走帧后 FIFO 计数自动减一所以 ISR 里先读计数再取帧也行。帧不多、丢一两帧无所谓的场景也可以改成轮询主循环里查 FIFO 计数再取帧代码更简单。双机通信建议中断响应快。调试时先开 LoopBack 模式自测回环帧只在控制器内部绕一圈不上总线不需要任何外部电路就能验证过滤器和收发逻辑。A 发 B 收两边先各自回环自测软件没问题了再切 Normal 上真机。避坑清单6 个血泪教训波特率算错记住 APB1 是 36MHzPrescaler9、BS113tq、BS22tq 是 250k不是 500k。终端电阻缺一端断电量 CANH-CANL约 60Ω 才对缺一端高速率必丢帧。USBCAN 不能同时用共享 512B SRAM硬件限制重映射也不行。过滤器忘 ENABLEFilterActivation必须 ENABLEMask1 是必须匹配标准帧 ID 记得5。发送 NoMailBox 卡死开 NART、别死等、必要时用 TME 中断。回环 vs 正常模式混淆LoopBack 只走内部不上总线双机必须 Normal。工具上带 CAN 解码的逻辑分析仪能直接标出 ID、DLC 和数据比盯着波形数位快得多示波器则用来抓差分波形验证波特率、采样点和 ACK 槽是否正常。先量电阻、再抓波形、最后查代码这个顺序能避开大部分玄学。写在最后CAN 的入门门槛不高但细节极多。位时序、终端电阻、过滤器、邮箱状态每一环都是坑叠出来的。上手时先跑 LoopBack 自测回环通了再上双机能省下不少排查时间。另外提醒一句CAN 调试最坑的往往不是代码是硬件接线松了、电阻缺了、共地没共好代码再对也白搭。先把硬件验证扎实再怀疑软件。你调 CAN 时踩过最深的坑是哪个欢迎在评论区聊聊一起避坑。推荐阅读[STM32F103 SPI 实战W25Q64 Flash 读写全流程拆解]8MB 大容量存储方案[STM32F103 I2C 实战AT24C02 EEPROM 读写全流程拆解]256 字节小存储的取舍

相关新闻

后端服务迁向云原生的分阶段路线

后端服务迁向云原生的分阶段路线

后端服务迁向云原生的分阶段路线迁移后端服务前,应先梳理会话状态、文件依赖和入口流量,而不是急着把进程封装进容器。 保持旧格式可读 整理环境变量、配置和定时任务,确认哪些状态需要外置。新服务先兼容旧格式,调用方改造完成后…

2026/11/12 23:23:57 阅读更多 →
服务网格与微服务的权限供应链防线

服务网格与微服务的权限供应链防线

服务网格与微服务的权限供应链防线网格增加了证书和代理层,权限检查必须能区分应用身份、网格身份与构建制品。 限制服务间访问 按服务账号授权,不用宽泛网段放行。轮换工作负载证书时,明确新旧证书的接受范围。 服务网格能够为服务间流量提供…

2026/10/24 20:50:43 阅读更多 →
云原生存储网络选型的测试分层

云原生存储网络选型的测试分层

云原生存储网络选型的测试分层存储网络选型需要看数据路径和恢复过程,一次读写成功并不代表工作负载迁移后仍可靠。 分层检查存储语义 本地测试验证挂载参数,集成测试连接真实存储类和网络策略,场景测试覆盖迁移后的重新挂载。 选型前先写清工…

2026/10/24 14:54:46 阅读更多 →

最新新闻

Electron桌面应用开发实战:从环境搭建到打包发布全流程

Electron桌面应用开发实战:从环境搭建到打包发布全流程

做前端这些年,我大部分时间都在跟浏览器标签页打交道,直到第一次把桌面应用跑起来,才发现原来自己一直被限制在地址栏和刷新按钮围起来的框框里。Electron这个词,最开始是在某段时间频繁出现在同事的讨论里,一个用HTML…

2026/11/12 5:00:00 阅读更多 →
滑盖智能锁T109深度解析:结构原理、安装调试与故障排查

滑盖智能锁T109深度解析:结构原理、安装调试与故障排查

简介:亚太天能T109滑盖智能锁产品说明书是一份PDF格式的官方技术文档,主要面向智能锁安装人员、终端用户及售后维护者,帮助快速掌握产品安装、配置与常见故障处理。全包仅1个PDF文件,大小4.37MB,内容结构清晰&#xff…

2026/11/12 5:13:20 阅读更多 →
PMSM弱磁控制原理与Simulink建模:高速AGV驱动系统设计指南

PMSM弱磁控制原理与Simulink建模:高速AGV驱动系统设计指南

上个月我在调试一台高速AGV的驱动系统,整车要求空载跑到8m/s,电机转速已经拉到额定点,驱动器的输出电压也顶到了母线电压极限附近。再往上踩速度指令,转速纹丝不动,三相电流反而开始震荡。那会儿我的第一反应就是&…

2026/11/12 5:13:20 阅读更多 →
C++核心知识点:从内存管理到STL的实战指南

C++核心知识点:从内存管理到STL的实战指南

C 这门语言我前前后后折腾了十几年,用它写过嵌入式驱动、做过游戏服务端,也搭过基础组件库。每次看到新人一头扎进"C 核心知识点"这个搜索词,我其实挺感慨的——这门语言的难点从来不是语法多,而是知识点之间的耦合太深…

2026/11/12 18:22:26 阅读更多 →
T109滑盖智能锁怎么装?安装调试与故障排查全攻略

T109滑盖智能锁怎么装?安装调试与故障排查全攻略

简介:亚太天能T109滑盖智能锁产品说明书以PDF格式发布,适合智能锁用户、安装人员与售后维修人员阅读。内容围绕T109系列指纹密码刷卡锁展开,先介绍前面板、后面板、锁体、机械钥匙、电池盒盖等部件名称与功能,再给出完整安装步骤&…

2026/11/12 18:22:25 阅读更多 →
LLM知识降熵:从信息垄断到理解权下放

LLM知识降熵:从信息垄断到理解权下放

你有没有过这种经历:翻开源码注释、论文摘要或者一份专业报告,每个字都认识,连在一起却像天书。想找人聊聊,身边要么没人懂,要么懂的懒得跟你解释。后来我试着把同一段内容丢给一个大语言模型,几秒钟之后&a…

2026/11/12 5:13:20 阅读更多 →

日新闻

周新闻

月新闻