资讯动态

RS485+STM32+LoRa+WiFi:工业数据透传网关实战解析

发布时间:2026/9/15 21:06:00 来源:尧图企业网站定制
简介这是一份嵌入式与工业通信实践项目资源以STM32F103C8为核心整合LoRa模组与RS485接口实现数据透明传输。适合正在学习STM32入门、无线通信组网或工业总线协议转换的开发者尤其适用于需要远距离低功耗传输的远程传感器、现场设备数据采集场景。资源共234个文件压缩包仅5.46MB主要包含Keil工程源码c、h、标准外设库文件stm32f10x_tim、stm32f10x_usart等、编译链接配置uvprojx、hex、axf、map以及CRC、I2C、定时器等模块文件完整覆盖从寄存器配置到应用层联调的开发链路。项目设计注重工程可读性目录结构清晰便于按模块拆解学习LoRa射频通信、RS485总线收发以及三者在STM32上的协作逻辑。已有344人浏览学习。通过分析源码可直观掌握将RS485现场数据无修改转发至LoRa链路的透传思路为后续搭建低功耗、远距离的一主多从工业监测系统提供可复用的代码框架与排错经验适合用于课程设计或物联网产品原型验证。1. 这套组合解决的其实是最后一公里问题现场几十台仪表挂在 RS485 总线上数据要进机房、进云端但车间到办公区隔着几百米穿墙布线又不现实。标题里这四个词拆开看都不稀奇拼在一起才构成完整链路RS485 负责把低速仪表汇到 MCUSTM32F103 当协议搬运工LoRa 把数据打到几公里外的接收端最后一跳由 LANDER_WiFi 送进局域网。真正反直觉的点在于数据透传不是把串口数据原样搬上网就完了RS485 的半双工时序、LoRa 的空中速率、WiFi 模块的上电缓冲任何一个环节不匹配透传都会变成丢包重传的灾难现场。这篇文章按实战顺序讲清这条链路的分工、代码落地和调试手段适合做网关、无线采集和环境监控的嵌入式工程师。2. LANDER_WiFi LoRa RS485 三层链路的分工与选型2.1 为什么底层一定是 RS485 而不是 TTL 或 RS232TTL 串口只适合板级通信超过半米就可能被噪声打穿RS232 虽然耐压高但负逻辑电平需要电平转换且只能点对点。RS485 用 A/B 差分线传输共模抑制能力强走双绞线在 9600bps 下能拉到 1200 米总线上挂 32 个节点是常见做法配合中继器还能再扩展。对传感器数据采集这种低速率、多节点、长距离场景RS485 几乎是唯一不需要额外拉电的可靠选择。RS485 是半双工总线同一时刻只能有一个节点往 A/B 线上驱动电平。STM32F103 的 USART 本身只提供 TX/RX 两线必须额外控制一个方向引脚去切 DE发送使能和 RE接收使能。常见的做法是把 DE/RE 短接在一起用一个 GPIO 控制拉高进入发送态拉低回到接收态。切换方向有毫秒级死区如果切换太快最后一个字节还在移位寄存器里就被切走帧尾就丢了。2.2 LoRa 承担空中接力LANDER_WiFi 负责进网段LoRa 模块SX1278/SX1262 或者带 AT 指令的成品模组工作在 sub-GHz 频段用扩频调制换链路余量。它不追求速率追求的是灵敏度SF7 带宽 125kHz 时灵敏度约 -123dBmSF12 时能到 -137dBm 左右视距环境下几公里是常态。这正好补上 RS485 有线的短板——现场有的点位实在拉不过去用 LoRa 跳过这段物理距离。但 LoRa 的数据进不了本地局域网云平台更不可能直接解析 LoRa 帧。这时 LANDER_WiFi 作为边缘桥接器登场它通常是一个 UART 转 WiFi 的透传模组STM32F103 把 LoRa 收到的数据从串口发给它它内部完成 TCP/UDP 协议栈把数据推给上位机或云平台。我一般把 LANDER_WiFi 理解成串口即服务的设备——控制面走 AT 指令配置 Wi-Fi 和 Socket数据面就是透明串口通道MCU 完全不用关心 DHCP、重连这些网络细节。表格里是这套系统典型的外设分配外设STM32F103 资源默认引脚速率/模式作用RS485USART1PA9/PA10 PB1 方向脚9600/115200 8N1与现场仪表总线通信LoRaSPI1PA5/PA6/PA7 PB0 复位PA8 中断SPI 1MHz 主模式空中收发数据LANDER_WiFiUSART3PB10/PB11115200 8N1与 TCP/云平台桥接调试口USART2PA2/PA3115200日志输出2.3 STM32F103 的资源边界要先盘清楚STM32F103 的中端型号如 RCT6有 48KB RAM、256KB Flash三个 USART、两个 SPI跑这套透传绰绰有余。真正的约束是时钟USART1 挂在 APB272MHzUSART2/3 挂在 APB136MHz。同样的 115200 波特率在 APB1 上分频可能产生更大的波特率误差这在后面调 WiFi 模块时是会吃大亏的细节。最小系统本身不复杂8MHz 晶振、复位电路、BOOT0/BOOT1 跳线、3.3V 电源去耦。但注意 PA11/PA12 在部分板子上和 USB 功能复用有些低成本的最小系统板会在这两个脚上引出奇怪的东西所以 RS485 方向脚和 LED 状态脚尽量避开这两个引脚。控制器配备双电源也是现场常见的做法RS485 侧用隔离 DC-DC 单独供电数字侧 3.3V 与总线侧隔离防地环路。3. STM32F103 上 RS485 与 LoRa 驱动的落地实现3.1 RS485 半双工收发串口 方向控制引脚先初始化 USART1 和方向 GPIO。用标准外设库直接操作寄存器的方式最直观也方便移植到 HAL 工程。// rs485_drv.c void RS485_Init(void) { GPIO_InitTypeDef gpio; USART_InitTypeDef usart; // USART1 在 APB2GPIOA 也在 APB2方向脚 PB1 在 APB1 RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1 | RCC_APB2Periph_GPIOA, ENABLE); RCC_APB1PeriphClockCmd(RCC_APB1Periph_GPIOB, ENABLE); // TXPA9 推挽复用输出RXPA10 浮空输入 gpio.GPIO_Pin GPIO_Pin_9; gpio.GPIO_Mode GPIO_Mode_AF_PP; gpio.GPIO_Speed GPIO_Speed_50MHz; GPIO_Init(GPIOA, gpio); gpio.GPIO_Pin GPIO_Pin_10; gpio.GPIO_Mode GPIO_Mode_IN_FLOATING; GPIO_Init(GPIOA, gpio); // 方向脚 PB1默认低 接收态 gpio.GPIO_Pin GPIO_Pin_1; gpio.GPIO_Mode GPIO_Mode_Out_PP; GPIO_Init(GPIOB, gpio); GPIO_ResetBits(GPIOB, GPIO_Pin_1); usart.USART_BaudRate 9600; usart.USART_WordLength USART_WordLength_8b; usart.USART_StopBits USART_StopBits_1; usart.USART_Parity USART_Parity_No; usart.USART_Mode USART_Mode_Rx | USART_Mode_Tx; USART_Init(USART1, usart); USART_Cmd(USART1, ENABLE); }发送函数的关键在于方向切换和最后一个字节发完的判断。如果 DE 拉低太早最后一位会被截断太晚则长时间占住总线其他从机无法应答。void RS485_Send(uint8_t *buf, uint16_t len) { GPIO_SetBits(GPIOB, GPIO_Pin_1); // DE 拉高进入发送态 for (uint16_t i 0; i len; i) { while (!(USART1-SR USART_FLAG_TXE)); // 等待发送数据寄存器空 USART1-DR buf[i]; } while (!(USART1-SR USART_FLAG_TC)); // 等待移位寄存器发送完成 GPIO_ResetBits(GPIOB, GPIO_Pin_1); // 回到接收态 }这里有个常规陷阱不能用 TXE 标志判断整包发完TXE 只表示数据进了移位寄存器最后一字节还在线上。必须等 TC传输完成否则 9600 波特率下最后一个字符可能被硬切接收端 CRC 校验失败。现场如果发现发出去的请求从机偶尔不应答先查这一处。3.1.1 自动收发电路要不要用RS485 自动收发电路把 TXD 经过三极管反相控制 DE/RE能省一个 GPIO但代价是发送低电平时 RGND 逻辑可能不稳定尤其在抗干扰要求高的环境。我的做法是只要 MCU 引脚够用一律用 GPIO 控向。GPIO 控向的切换时机完全可控调试时还能通过示波器测方向脚波形确认时序。TTL 转 RS485 成品模块很多内置了自动流控但那属于能用但不透明量产前务必实测误码率。RS485 总线侧还有三样标配120Ω 终端电阻只在总线两端各接一个中间节点不接A/B 线对地接 TVS如 SMBJ6.0CA总线侧建议并接上下拉偏置电阻A 上拉、B 下拉典型 10kΩ避免总线空闲时电平漂在阈值附近造成误帧。这些细节直接决定rs485 通讯干扰是不是现场最大痛点。3.2 LoRa 模块接入用 SPI 把寄存器读写握在自己手里LoRa 模块的接入分两种带 AT 指令的成品模组MCU 只需要串口发ATLORA_SEND...最简单但实时性差寄存器级 SX1278MCU 通过 SPI 直接操作 LoRa 核心。后者能精确控制发送时刻对 RS485 轮询和 LoRa 空中冲突管理有意义我按寄存器级讲。SPI1 配置为 1MHz 主模式SX1278 要求 SPI 时钟极性 CPOL0、相位 CPHA0也就是模式 0。初始化后先复位模块PB0 拉低 10ms 再拉高等待芯片稳定。之后读版本号寄存器0x42应为 0x12 之类的约定值用来确认 SPI 时序正常。void LoRa_TxPacket(uint8_t *payload, uint8_t len) { // 切到 Standby清掉上次的中断标志 LoRa_WriteReg(REG_OP_MODE, RF_OPMODE_STANDBY); LoRa_WriteReg(REG_IRQ_FLAGS, 0xFF); // 写 1 清中断 // FIFO 基址对齐 LoRa_WriteReg(REG_FIFO_TX_BASE_ADDR, 0x00); LoRa_WriteReg(REG_FIFO_ADDR_PTR, 0x00); // 逐字节写入 FIFO for (uint8_t i 0; i len; i) { LoRa_WriteReg(REG_FIFO, payload[i]); } LoRa_WriteReg(REG_PAYLOAD_LENGTH, len); // 载波侦听/包长都以它为准 // 写 Tx 模式即触发发射发送完成自动回 Standby LoRa_WriteReg(REG_OP_MODE, RF_OPMODE_TRANSMITTER); }发送完成后芯片会置起 TxDone 中断映射到 DIO0接到 PA8 外部中断。在中断里置一个标志位主循环轮询标志来清理状态不要在中断里做耗时操作。SX1278 单包最大 255 字节但 LoRa 空中速率低SF12/125kHz 时约 0.3kbps单包越大占用信道时间越长冲突概率越高。我一般限制应用层包长在 50 字节以内超过就拆包加序号。如果改用带 AT 指令的 LoRa 模块上述代码就被LoRa_SendAT(payload, len)串口命令替代代价是发送时刻不可控模块内部还要等它的协议循环吞吐和实时性都会打折。3.3 LANDER_WiFi 的串口桥接与主循环状态机LANDER_WiFi 走 USART3初始化与 USART1 类似注意波特率要设成模块固件匹配的值常见 115200。桥接逻辑不复杂三路数据进来各自进环形缓冲区主循环做搬运。// 透传主循环三路数据各进各的环形缓冲 while (1) { // RS485 收到一帧空闲中断判定见 4.1→ 原样交给 LoRa if (rs485_frame_ready lora_idle) { LoRa_TxPacket(rs485_rx_buf, rs485_rx_len); rs485_frame_ready 0; } // LoRa 收到一帧 → 交给 LANDER_WiFi 串口 if (lora_frame_ready) { UART3_Send(lora_rx_buf, lora_rx_len); lora_frame_ready 0; } // LANDER_WiFi 串口收到数据来自网络侧→ 交给 RS485 if (wifi_rx_len 0) { RS485_Send(wifi_rx_buf, wifi_rx_len); wifi_rx_len 0; } }注意最后一跳网络侧来的数据转成 RS485 发送时会被挂 STM32F103 和 RS485 总线两侧的速度差。WiFi 串口进来的数据如果按字节就转发每转发一字节就要切一次方向引脚效率极低且容易把总线上其他设备打乱。正确姿势是攒到一帧用空闲中断或 10ms 超时判定再一次发到 485 总线走上面的RS485_Send(buf, len)路径一次切换完成整包转发。4. 数据透传的帧格式、组网与参数标定4.1 透传不是裸传拿什么切分一帧数据很多人以为透传就是把串口收到的字节直接送出去结果对端永远收不齐一条完整报文。串口是流没有帧边界LoRa 单包又有长度上限。常见做法是按字节空闲时间切帧串口收到一个字节后启动定时器若连续两个字节间隔超过 T_idle通常取 3.5 个字符时间以上就认为一帧结束。波特率 9600 时一个字符约 1.04msT_idle 取 10ms 比较稳妥115200 时取 23ms 即可。实现上有两类一类开一个 1ms 硬件定时器收到字节就清零计数值计数值超阈值且缓冲区非空则置帧完成标志另一类用串口空闲中断IDLESTM32F103 的 USART 自带这一硬件中断收完一帧后总线空闲自动触发省 CPU 占用逻辑也简洁。我建议用 IDLE 中断 DMA 收 RS485把 CPU 留给协议处理和 LoRa 中断。帧切分之后再做最大包长约束LoRa 单包上限 255 字节但空口速率不高建议应用层把包长限制在 50 字节以内。对 Modbus RTU 这类报文RTU 本身最长 256 字节含地址、功能码、数据、CRC485 侧收到的一帧如果超过 LoRa 上限就按帧序号 总帧数 数据分片重打包接收端按序号重组。4.2 RS485 一主多从轮询与 LoRa 空中冲突的平衡RS485 侧典型的通信模型是一主多从网关发请求帧指定从机地址从机应答其他从机只监听。这意味着网关侧STM32F103 LoRa是从机请求的汇聚点多个 LoRa 远端节点要上报数据时如果各自随机时刻就往空口发必然碰撞。两个可行策略第一借鉴载波监听——发送前先读 SX1278 的 CAD信道活动检测发现信道忙就退避随机 50200ms 再试第二轮询制——上位机通过 LANDER_WiFi 侧发起查询每一个查询对应一个远端节点上报天然避免冲突。轮询的代价是实时性变差但换来的是确定性和近乎零碰撞。如果你的场景是报警优先、数据可等那轮询是最稳的。组网时给每个节点配唯一的逻辑地址地址放在应用层帧头里而不是依赖 LoRa 硬件地址过滤。这样无论是 485 侧还是 LoRa 空中都能用同一套帧格式解析调试时只需看十六进制内容即可定位是哪个节点、哪一跳出了问题。4.3 参数标定一张表解决为什么我传不动透传系统的参数不是拍脑袋定的每个参数都绑定一个瓶颈。下表是我的默认开局参数实际以现场距离和速率要求调整参数推荐值依据RS485 波特率9600距离优先1200m 内稳定仪表多为 9600LoRa 扩频因子 SF10先调试用 7SF7 快但灵敏度低SF12 慢但穿墙好LoRa 带宽 BW125kHz默认值兼容性好LoRa 编码率 CR4/5抗干扰与开销折中LoRa 空口速率视 SF/BW 组合SF10/125k 约 0.98kbps串口空闲超时 T_idle9600→10ms115200→2ms3.5 字符时间经验值LoRa 分片包长≤50 字节降低信道占用时间LANDER_WiFi 串口波特率115200匹配模块固件默认重传次数2485 请求无响应时避免重复请求打爆总线数据透传在这套系统里的真正含义是端到端的字节透明从 485 总线上发出去的任何字节序列远端网络侧调试助手收到的必须是相同的字节序列。因此只要中间任何一跳改了字节透传就是失败的。LoRa 空中速率决定吞吐上限例如 SF10/125kHz 大约 1kbps一帧 50 字节耗时约 0.4 秒你不可能用这套链路去推摄像头视频流它天生是给传感器状态、电表读数、液位报警这类小包数据用的。上电时序也是一个容易忽略的参数点LANDER_WiFi 模块固件启动需要时间实测常有 25 秒LoRa 模块冷启动也要几毫秒。MCU 复位后如果立即转发数据WiFi 模块还没连上 Socket第一包就丢在串口缓冲外面。我一般加一个 ready 握手WiFi 模块上电后主动上报WIFI_READY字符串MCU 收到后才开放转发路径或者直接延时 3 秒再启动主循环简单粗暴但有效。5. 调通之后还要做的事干扰、EMC 与现场验证5.1 RS485 现场干扰的三种典型表现与对策现场最常见的是偶尔一帧错现象是仪表明明正常但周期性的 CRC 错误计数在涨。先查三件事终端电阻是否两端都存在且阻值匹配总线屏蔽层是否单端接地两端接地会形成地环路反而引入共模电流A/B 线是否与动力线同槽敷设。电缆走线距离电源线 30cm 以上是基本要求实在避不开就换屏蔽双绞线TVS 一定接到 A/B 线对地而不是只接在板子输入端。第二种是总线死锁某个节点异常把总线长期置为发送态其他节点无法通信。对策是主站侧在发送请求后开启超时定时器超过设定时间如 500ms没有收到应答就强制把方向脚拉回接收态再发下一轮。RS485 总线上建议串联 10Ω 保护电阻保护收发器防热插拔打火。第三种是干扰只在电机启停时出现这基本就是共地问题。控制器配备双电源在这里是有意义的——总线侧的 DC-DC 隔离电源和 MCU 侧电源分开光耦或隔离收发器如 ADM2483切断地环路。RS485 接口的 EMC 标准电路一般包含TVS、共模电感、终端电阻、偏置电阻、隔离芯片五件套按这个顺序摆放通常在 EMC 实验室一次能过。5.2 串口 1 和串口 3 的差异与引脚复用踩坑STM32F103 的 USART1 挂在 APB2时钟 72MHzUSART3 挂在 APB1时钟 36MHz。115200 波特率下APB1 上分频产生的误差更大尤其在高温下时钟漂移后误码率会先于 USART1 恶化。所以 RS485 这种长线低速的可以放 USART1也可以放 USART3但 LANDER_WiFi 这种高速串口一定放 USART1或者至少实测一下对应波特率的误差在 ±2% 以内。引脚复用也要注意USART3 的 PB10/PB11 同时可能被 SPI2 或其他功能复用PA11/PA12 在最小系统板上可能与 USB D-/D 相连部分低端板子这两个脚做普通 GPIO 时会被 USB 上拉电阻干扰导致方向脚电平异常。把关键的方向控制脚或中断脚安排到不冲突的引脚并在原理图阶段核对每个引脚的第二功能表能让调试期少掉一半头发。5.3 下载失败先查 BOOT1最小系统先活起来DAP 下载失败是新人遇到的第一座山。现象是 Keil 报Cannot access target排错顺序固定板子供电 → 复位电路 → BOOT0/BOOT1 状态 → DAP 接线 → 芯片是否锁死。特别注意 BOOT1 不是传说中的必须接地它是 X任意与 BOOT0 配合决定启动模式BOOT00 时从主 Flash 启动正常模式BOOT01 且 BOOT10 从系统存储器启动bootloader两者都设为 1 则从 SRAM 启动。下载失败时把 BOOT0 拉高、BOOT1 拉低进 ISP重新上电后再把 BOOT0 拉回低多数情况能救回来。最小系统能否先活直接影响后续所有调试。上电后第一件事不是配 LoRa而是用 USART2 输出UART OK每秒一条确认时钟、复位、调试链路三件事同时成立再往下走协议。这也让后续每个环节出问题时多一个可观测的锚点。现场验收的最后一步我习惯用一个回环对测来验证透传完整性上位机用 Modbus Poll 软件作为主站通过 LANDER_WiFi 侧的 TCP 端口下发一条读保持寄存器的报文观察这条报文是否原样出现在远端 RS485 总线上远端仪表的响应又是否原样回到 Modbus Poll 的报文窗口。两边十六进制内容逐字节一致、往返时延可接受整套数据透传链路才算真正闭环。本文还有配套的精品资源点击获取

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价