工业总线一瞥:RS485 / Modbus / CAN 为什么是 STM32 的主场
- 搞懂工业现场为什么不上 WiFi,而是 RS485 / Modbus / CAN——抗干扰、长距离、多节点、确定性
- 学会用 STM32 HAL 收发 RS485:UART + 一个方向控制脚(DE/RE),发完切回收
- 分清 Modbus 是建在 RS485 上的应用层协议,知道用现成栈而不是自己撸
- 了解 STM32 的 bxCAN / FDCAN 外设:报文 ID 仲裁、收发器、终端电阻该怎么接
你前面几关把 STM32 的点灯、外设、迁移对照都摸了一遍。现在换个场景:你被叫去对接一台车间里的设备——可能是个变频器、一台 PLC,或者一条产线上散布的十几个温度/液位传感器。你下意识想:那不简单,ESP32 连 WiFi,数据往云上一传不就完了?
到了现场你会发现行不通。设备之间隔着几十米线缆,旁边就是大功率电机在启停,电磁干扰一阵一阵;对方设备的接口上压根没有 WiFi,只有一个标着 A/B 两根线的端子,或者一对标 CAN_H / CAN_L 的口。这时候你才明白:工业现场有它自己的一套通信语言,而这套语言,恰恰是 STM32 的主场。这一篇就带你认全工业里最常打交道的三样——RS485、Modbus、CAN,搞清它们各管什么、STM32 用 HAL 怎么接。
这是 S 卷(STM32 迁移)里偏"认识全貌"的一篇,不是手把手做一个完整产品。RS485 收发、Modbus 栈、CAN 报文收发的具体函数名、句柄、寄存器位,强依赖你的芯片型号(F1/F4/G4/H7 的 CAN 外设差异很大)、HAL 版本、CubeMX 版本。本篇给的是主干流程参考 + 选型思路,所有代码片段请以你 CubeMX 实际生成的工程 + ST 官方应用笔记为准,别照搬当成确定无误。
先想清楚:工业现场为什么不上 WiFi
你在桌面上跑 ESP32 + WiFi 顺得很,到了工业现场却处处碰壁,原因就四个字摊开讲——抗干扰、长距离、多节点、确定性。WiFi 这四样恰好全是短板:
- 抗干扰。 车间里变频器、接触器、电机一启停,电磁噪声非常脏。WiFi 是无线,信道被干扰就丢包重传,时延飘忽。工业总线用差分信号走双绞线,干扰同时打在两根线上、做差就抵消了,这是物理层级别的抗扰,不是软件重传能比的。
- 长距离。 现场动辄几十米、上百米的布线。WiFi 隔几堵墙信号就崩;RS485 一对双绞线能拉到 1200 米(低速时),CAN 也能几百米。
- 多节点。 一条总线上要挂几个、十几个甚至几十个设备。WiFi 是星型、靠 AP 转发,节点一多 AP 就成瓶颈;RS485 / CAN 是总线型,所有节点挂在同一对线上,加节点就是并上去一对线的事。
- 确定性(实时)。 控制系统要求"这条指令多久内一定送到"。WiFi 时延不可预测,做不了硬实时;CAN 有基于报文 ID 的硬件仲裁,高优先级报文一定先发,这种确定性是工业控制的命根子。
一句话:WiFi 是为"人上网"设计的,工业总线是为"机器在恶劣环境下可靠、实时、多点通信"设计的。 场景不同,别硬套。而 STM32 这类 MCU 自带 UART、bxCAN/FDCAN 这些外设,加个收发器芯片就直接上总线——它本来就是为工业控制生的。
RS485:最常见的那对 A/B 线
你在现场见到最多的,十有八九是 RS485。它不是一个协议,而是一个物理层电气标准——规定了用差分信号、半双工、多机总线该怎么走线。
差分 + 半双工,是它的两个核心。 差分前面说了,抗干扰。半双工的意思是:同一对线,同一时刻只能有一个方向在传——要么你发、要么你收,不能同时。这跟 UART 那种 TX/RX 各一根线的全双工不一样。RS485 收发器(常见 MAX485、SP3485)芯片上有一个 方向控制脚(DE / RE):拉高是发送态,拉低是接收态。
这就引出了 STM32 上接 RS485 最容易翻车的一个点:你用 UART 发数据前,得先把方向脚拉到发送态;数据发完,必须立刻切回接收态,否则你这个节点会一直霸占总线,别人发的全收不到,整条总线瘫掉。
STM32 HAL 怎么接
硬件上:STM32 的某个 USART(比如 USART1,PA9/PA10)接到 MAX485 的 RO/DI,再用任意一个 GPIO(比如 PA8)接 MAX485 的 DE+RE(两脚短接一起控)。CubeMX 里把 USART 配成 Asynchronous、波特率对齐对方设备(工业上常见 9600 / 115200),把那个 GPIO 配成推挽输出。代码主干:
/* USER CODE BEGIN 0 */
#define RS485_DE_PORT GPIOA
#define RS485_DE_PIN GPIO_PIN_8
static void rs485_send(uint8_t *data, uint16_t len)
{
HAL_GPIO_WritePin(RS485_DE_PORT, RS485_DE_PIN, GPIO_PIN_SET); // 切发送态
HAL_UART_Transmit(&huart1, data, len, 100); // 阻塞发,100ms 超时
// 关键:等最后一个字节真的移出去(TC 标志置位)再切回收,早切会截断尾字节
while (__HAL_UART_GET_FLAG(&huart1, UART_FLAG_TC) == RESET) {}
HAL_GPIO_WritePin(RS485_DE_PORT, RS485_DE_PIN, GPIO_PIN_RESET); // 切回接收态
}
/* USER CODE END 0 */
方向脚切回收的时机,是 RS485 头号坑。 很多人 HAL_UART_Transmit 一返回就立刻拉低 DE,结果发现对方收到的数据末尾缺字节——因为 HAL_UART_Transmit 返回只代表数据进了发送寄存器,最后一个字节可能还没从移位寄存器移出去。一定要等 TC(Transmission Complete)标志置位再切方向。新一点的 STM32(带 USART 硬件 DE 功能的)能让外设自动管 DE,省掉这段忙等——CubeMX 里 USART 模式选 RS485 即可,能用就用,少一个坑。
Modbus:建在 RS485 上的"说话规矩"
RS485 只解决了"线怎么连、电平怎么定",它不管你发的字节是什么意思。两台设备都接上 RS485 了,可一个发 0x03 0x00 0x00 0x00 0x0A,另一个看不懂——因为没约定应用层协议。工业上用得最多的这个约定,就是 Modbus。
Modbus 是个主从协议:总线上一个主站(你的 STM32,或一台 PLC、上位机),多个从站(传感器、变频器、电表),从站各有一个站地址。通信永远是主站先问、从站才答,从站之间不直接说话。它有三种跑法:
- Modbus RTU:跑在 RS485(串口)上,二进制紧凑,工业现场最常见,也是你接 RS485 设备时八成会遇到的。
- Modbus ASCII:也跑串口,但用可读字符,效率低、现在少见。
- Modbus TCP:跑在以太网上,封装进 TCP 报文,用在带网口的设备。
它的核心就是几个功能码配上寄存器:0x03 读保持寄存器、0x06 写单个寄存器、0x10 写多个、0x01 读线圈……你要读一个温度传感器第 0 号寄存器,就是主站发"站地址 + 0x03 + 寄存器地址 + 数量 + CRC 校验",从站回数据。
别自己从零撸 Modbus 协议栈。 看着就几个功能码加一个 CRC,真自己写,CRC 字节序、超时重传、帧间隔(RTU 要求帧间至少 3.5 个字符的静默间隔)、异常码处理……坑能埋你一礼拜。用现成的:开源的 FreeMODBUS(移植到 STM32 很成熟)、或 ST 在部分方案里提供的 Modbus 中间件。 你只要在 CubeMX 配好 RS485 的 UART + DE 脚 + 一个定时器(给 RTU 算帧间隔),把收发底层对接到栈的回调上,业务层只管"读哪个寄存器、写什么值"。把精力花在你的业务逻辑上,别花在重新发明协议上。
CAN / CAN-FD:多节点广播总线
如果说 RS485 是"主从一问一答",CAN 就是另一套思路——广播 + 优先级仲裁。它从汽车里长出来,现在工业、机器人、电池管理(BMS)里也到处是。STM32 大多自带 CAN 外设:老些的系列叫 bxCAN,新些的(G4/H7 等)叫 FDCAN(支持更快的 CAN-FD)。
CAN 的几个特点跟 RS485 很不一样:
- 没有"地址",只有"报文 ID"。 每帧数据带一个 ID,标识"这是什么内容"(比如 0x100 是转速、0x200 是温度),而不是"发给谁"。所有节点都收到,各自决定要不要这帧——这就是广播。
- 靠 ID 做硬件仲裁,天生确定性。 两个节点同时想发,ID 数值小的(优先级高的)自动赢得总线,另一个退避等待,整个过程是硬件位仲裁完成的,不丢帧、不冲突。这就是前面说的"确定性"在 CAN 上的体现,也是它能做硬实时控制的根本。
- 数据短而频繁。 经典 CAN 一帧最多 8 字节(CAN-FD 放宽到 64),适合传"一个测量值、一条指令"这种小包高频数据,不适合传大块文件。
STM32 HAL 怎么接
硬件上 STM32 的 CAN_TX/CAN_RX 不能直接上总线,必须经过一颗 CAN 收发器把单端信号转成差分——常见 TJA1050(5V)、SN65HVD230(3.3V)。CubeMX 里使能 CAN/FDCAN、配好波特率(工业常用 250kbps / 500kbps,全总线必须一致),配置接收过滤器。bxCAN 主干长这样:
/* USER CODE BEGIN 2 */
CAN_TxHeaderTypeDef txHeader;
uint8_t txData[8] = {0x01, 0x02, 0, 0, 0, 0, 0, 0};
uint32_t txMailbox;
txHeader.StdId = 0x100; // 标准帧 ID(11 位)
txHeader.IDE = CAN_ID_STD;
txHeader.RTR = CAN_RTR_DATA; // 数据帧
txHeader.DLC = 2; // 这帧发 2 个字节
HAL_CAN_Start(&hcan); // 启动 CAN 外设
HAL_CAN_AddTxMessage(&hcan, &txHeader, txData, &txMailbox); // 把报文塞进发送邮箱
/* USER CODE END 2 */
收一般走中断:使能 HAL_CAN_ActivateNotification(&hcan, CAN_IT_RX_FIFO0_MSG_PENDING),在 HAL_CAN_RxFifo0MsgPendingCallback() 回调里用 HAL_CAN_GetRxMessage() 把报文取出来。新的 FDCAN 外设 API 换成 HAL_FDCAN_Start / HAL_FDCAN_AddMessageToTxFifoQ / HAL_FDCAN_GetRxMessage 这一套,结构类似但不通用——别把 bxCAN 的代码原样拿去 FDCAN 芯片上跑。
CAN 总线两端各一个 120Ω 终端电阻,少一个都不行——这是 CAN/RS485 共同的硬件铁律。 差分总线两端必须用 120Ω 电阻匹配阻抗,否则信号反射,表现是"短线能通、长线乱码"或"波特率一高就丢帧"。规矩是:整条总线的物理两端各接一个 120Ω,中间节点不接。 很多收发器模块板载一个跳线帽控制要不要接终端电阻——你得想清楚自己这个节点在不在总线末端。RS485 同理,两端也各一个 120Ω。这个坑极隐蔽:近距离调试时不接也能跑,一上现场拉长线就崩,很多人在这卡半天。
跟 ESP32 比一句
你可能想:ESP32 不是也有 CAN(叫 TWAI)、也有 UART 能接 RS485 吗?没错,ESP32-S3 确实带 TWAI 外设和多路 UART,纯技术上也能接这些总线,做点轻量工业联网很合适。
但工业现场选 STM32 而不是 ESP32,差别不在"能不能接",而在生态和认证的成熟度:STM32 在工业控制领域深耕多年,配套的 Modbus / CANopen 中间件、参考设计、行业认证案例(功能安全等)一大把,供货周期和工业级温度等级也更对得上工业客户的要求。ESP32 的强项在 WiFi/蓝牙这类无线联网——所以实际方案里常见的组合是:STM32 守在现场总线这头(RS485/CAN)干可靠实时的活,ESP32 当网关把数据转上云,各打各的强项。想细究为什么是这种分工,去看通信协议横向对比(如果你还没读过有线 vs 无线那块)。
小结 · 你现在掌握了什么
- 你搞清了工业现场为什么不上 WiFi:抗干扰、长距离、多节点、确定性这四样,RS485 / CAN 用差分信号 + 总线拓扑 + 硬件仲裁全占了,WiFi 全是短板。
- 你认识了 RS485:差分、半双工、靠一个 DE/RE 方向脚切收发,STM32 用 UART + GPIO 接,最大的坑是发完要等 TC 标志再切回收,两端各一个 120Ω 终端电阻。
- 你分清了 Modbus 是建在 RS485 上的应用层主从协议(RTU / ASCII / TCP),靠功能码 + 寄存器读写,别自己撸,用 FreeMODBUS 或 ST 中间件。
- 你了解了 CAN / CAN-FD:广播 + 报文 ID 仲裁带来的确定性,STM32 用 bxCAN / FDCAN 外设(
HAL_CAN_*/HAL_FDCAN_*),必须配 CAN 收发器(TJA1050 / SN65HVD230)+ 两端 120Ω。 - 你知道了跟 ESP32 的分工:STM32 守现场总线、ESP32 做无线网关,工业级生态 STM32 更成熟。
- 最重要的一条:本篇代码是主干流程参考,CAN/UART 的函数名、句柄、外设差异(bxCAN vs FDCAN、F1 vs G4/H7)强依赖你的芯片型号与 HAL 版本,以 CubeMX 实际生成的工程 + ST 官方应用笔记为准,别当成确定无误。
工业总线这一瞥认完,你对"什么场景该上 STM32"就有了实感。S 卷到这里,剩下的是把"从 ESP32 迁到 STM32"这件事系统收口——什么时候该迁、怎么把已有工程平移、两边能力怎么对照。接着看 STM32 迁移卷迁移对照与收口,把整条迁移路线串成一张图。想回看整卷路线,去 STM32 迁移卷总览。