
1. LoRa 自组网到底在解决什么问题LoRa 自组网这个词刚接触的朋友容易把它和“LoRa 网关云平台”那套架构搞混。我先把边界划清楚LoRa 自组网指的是终端节点之间不依赖公网、不依赖中心网关自己组织成一张能互相转发数据的网状网络。它解决的核心问题是——在完全没有蜂窝信号、没有宽带、甚至没有固定供电的现场让几十到几百个传感器节点把数据一跳一跳地传回汇聚点。我做过几个典型的现场山区果园的土壤墒情监测、地下管廊的温湿度采集、厂区外围的周界报警。这些地方的共同点是拉线成本极高、公网覆盖稀烂、设备靠电池撑。LoRa 的物理层特性——扩频调制、-137dBm 级别的接收灵敏度、单包几十到两百多字节——天然适合这种“低速率、长距离、低功耗”的活。但物理层只解决了“点对点能通”真正让一张网活起来的是自组网协议谁跟谁连、数据怎么绕、节点掉线了怎么办、新节点怎么入网。这篇文章我会从原理讲到实操重点拆 RS485 在 LoRa 自组网里的角色、IAP 远程升级怎么做、嵌入式端协议栈怎么落地。适合已经会点 STM32、玩过串口、想把这套东西真正部署到现场的人。如果你只是想知道“LoRa 能不能传 10 公里”那看完第一节就够了如果你想自己搭一张能跑起来的网后面的内容建议逐段对照着做。2. 核心架构拆解为什么是 LoRa RS485 IAP 这套组合2.1 LoRa 自组网的拓扑选型逻辑自组网拓扑常见三种星型、树型、网状Mesh。很多人一上来就想上 Mesh觉得“多跳最牛”但实际选型要看现场。星型最简单所有节点直连汇聚点。优点是协议极简、延迟确定、功耗最低缺点是汇聚点覆盖半径就是全网半径一般城区 1-2 公里、郊区 3-5 公里、视距开阔能到 10 公里以上。如果现场是个直径 2 公里的果园星型完全够用别折腾 Mesh。树型是星型的扩展中间加一级中继。适合狭长地形比如沿着一条河道或公路布点。中继节点需要常供电或大容量电池因为它要一直开着接收。Mesh 是真正的多跳自组网节点既能当终端也能当路由器。优点是覆盖可以无限延伸、有冗余路径缺点是协议复杂、路由维护开销大、功耗高、延迟不可控。我踩过的坑是在一个 60 节点的 Mesh 网里路由表收敛要几十秒期间数据丢得厉害。后来改成“分簇两级中继”稳定性立刻上来了。选型的判断标准我总结成一张表拓扑适用半径节点数功耗协议复杂度典型场景星型5km50最低低小园区、单栋楼树型5-15km50-200中中河道、公路沿线Mesh不限100高高大范围、有冗余要求提示不要为了“技术先进”选 Mesh。现场能星型就星型能树型就树型Mesh 是最后的手段。2.2 RS485 在自组网里的真实定位这里要澄清一个常见误解RS485 不是 LoRa 的替代品两者是互补的。LoRa 负责“无线远距离”RS485 负责“有线短距离、多设备、抗干扰”。实际部署里RS485 通常出现在两个位置第一汇聚点侧。LoRa 汇聚节点收到无线数据后通过 RS485 总线把数据转给本地工控机或 PLC。为什么不用 USB 或网口因为工业现场 RS485 是标配一根双绞线能挂 32 个设备、跑 1200 米、抗共模干扰强接线端子一拧就行比网口皮实得多。第二节点侧。一个 LoRa 节点盒子往往要接多个 RS485 传感器。比如一个环境监测节点下面挂温湿度、CO2、光照三个 RS485 传感器节点用 Modbus RTU 轮询采集再打包通过 LoRa 发出去。这样节点数量少、无线信道占用少成本也低。RS485 的电气特性决定了它的边界差分信号、共模范围 -7V 到 12V、终端匹配 120Ω、总线型手拉手拓扑。这些细节后面第 4 节会展开。2.3 IAP 为什么是自组网的刚需IAPIn-Application Programming指的是程序在运行中自己给自己刷固件。对于部署在山上、井下、厂区外围的 LoRa 节点你不可能每次都爬上去插下载器。没有 IAP一个 bug 就能让整个项目变成“一次性工程”。LoRa 自组网 IAP 的组合逻辑是汇聚点通过 LoRa 把固件分包广播/组播下去节点收到后写入 Flash 的备份区校验通过后跳转 Bootloader 完成自更新。整个过程不需要人到现场。但 IAP 有几个硬骨头分包传输的可靠性、断电续传、版本回滚、Boot 里变量复位问题。热搜词里“iap boot里面定义的变量复位后会怎样”就是典型困惑——Bootloader 和 App 是两个独立的程序复位后 RAM 里的变量当然全没了跨程序传参只能靠 Flash 里的标志位或备份寄存器。这个后面第 5 节详细讲。3. 嵌入式端协议栈的核心实现要点3.1 物理层参数怎么定LoRa 的物理层参数直接决定通信距离、速率和抗干扰能力。核心四个参数扩频因子 SF、带宽 BW、编码率 CR、发射功率。SF 从 7 到 12每加 1灵敏度提升约 2.5dB但空中时间翻倍。BW 常用 125kHz、250kHz、500kHz带宽越大速率越高但灵敏度越低。CR 一般 4/5 到 4/8抗干扰换速率。我一般这样定城区/干扰大SF9、BW125、CR4/5、功率 17dBm郊区/视距SF7、BW125、CR4/5、功率 14dBm山区/远距离SF12、BW125、CR4/8、功率 20dBm空中时间要算清楚。以 SF12、BW125、CR4/5、负载 32 字节为例单包空中时间约 1.5 秒。如果 100 个节点每 5 分钟上报一次信道占用率 100 × 1.5 / 300 50%已经很高了。这时候要么降 SF要么拉长上报周期要么上 TDMA。注意国内 470-510MHz 频段有功率和占空比限制实际项目要按当地规定来别照搬国外参数。3.2 自组网协议栈的分层设计我在嵌入式端一般分四层物理层驱动封装 SX1276/SX1262/LLCC68 的寄存器操作提供 send/recv 接口。这层要处理 DIO 中断、FIFO 读写、CRC 校验。MAC 层负责信道接入。简单场景用 CSMA/CA先听后发复杂场景用 TDMA时隙分配。TDMA 需要全网时间同步一般由汇聚点周期性发信标节点收到后校准本地时钟。网络层负责路由。星型不需要路由树型维护父子关系Mesh 需要路由表。我倾向用“按需路由 邻居表”的简化方案避免维护全网路由表。应用层定义数据帧格式、命令字、上报周期、传感器采集逻辑。数据帧我习惯这样设计typedef struct { uint8_t magic; // 0xA5 帧头 uint8_t version; // 协议版本 uint16_t src_addr; // 源地址 uint16_t dst_addr; // 目的地址 uint8_t hop_count; // 跳数 uint8_t cmd; // 命令字 uint8_t seq; // 序列号 uint8_t payload_len; // 负载长度 uint8_t payload[64]; // 负载 uint16_t crc16; // 校验 } lora_frame_t;帧头 magic 用来快速同步seq 用来去重hop_count 用来防环。这些字段看着简单但现场调试时能省大量时间。3.3 地址分配与入网流程节点地址我一般用 2 字节高字节表示簇号低字节表示簇内编号。比如 0x0105 表示 1 号簇第 5 个节点。这样路由时先看簇号再看节点号逻辑清晰。入网流程设计成三步新节点上电后广播入网请求dst_addr 0xFFFF汇聚点或中继收到后回复入网响应分配地址和时隙节点保存地址进入正常工作状态入网请求要带节点唯一 ID比如 MCU 的 UID 或 Flash 里的序列号防止地址冲突。我见过一个项目因为没做唯一 ID两个节点拿到同一地址数据互相覆盖查了三天才发现。4. RS485 电路设计与组网实操4.1 RS485 典型电路的关键细节RS485 收发器常用 MAX485、SP3485、ADM2483隔离型。典型电路看着简单但有几个坑终端匹配电阻。总线两端各接一个 120Ω 电阻中间节点不接。很多人图省事每个节点都焊 120Ω结果总线负载过重通信距离大幅缩短。判断方法用万用表量 A-B 之间电阻应该是 60Ω 左右两个 120Ω 并联。偏置电阻。总线空闲时差分电压不确定容易误触发。需要在 A 上拉、B 下拉一般 4.7kΩ 到 10kΩ。偏置电阻和终端电阻配合保证空闲时 A-B 电压大于 200mV。保护电路。现场雷击、浪涌、静电是常态。TVS 管如 SMBJ6.5CA、自恢复保险丝、共模电感这三件套建议都加上。我有个项目在厂区没加 TVS一个雷雨天烧了 8 个节点。自动换向电路。RS485 半双工需要控制 DE/RE 引脚。用 MCU 的 GPIO 控制最简单但软件要精确控制换向时机。也可以用 555 或三极管做自动换向省一个 GPIO但时序不好调。热搜词里“rs485自动换向电路”和“用反向器设计rs485”都是这个需求。4.2 RS485 总线型串联的接线规范总线型拓扑是 RS485 的标准接法手拉手串联不能星型或树型分支。分支长度超过 30cm 就会引起反射导致误码。接线步骤主干线用 120Ω 特性阻抗的双绞线如 RVSP 2×0.5所有节点的 A 接 A、B 接 B不能交叉终端两个节点各接 120Ω 匹配电阻屏蔽层单端接地不要两端都接否则形成地环流节点分支线尽量短最好直接从主线上焊接提示A/B 线序没有绝对标准但同一总线必须统一。我习惯 A 接正、B 接负接反了通信全乱。4.3 Modbus RTU 轮询的实操技巧RS485 上跑 Modbus RTU 是最常见的组合。节点作为主机轮询多个传感器要点轮询周期。每个传感器响应时间不同一般 10-50ms。如果挂 10 个传感器一轮至少 500ms。加上 LoRa 发送时间整个上报周期要留够余量。超时重试。单次超时设 200ms重试 2 次。连续 3 轮失败标记传感器离线。寄存器映射。把每个传感器的数据映射到统一的内部结构体方便打包发送。typedef struct { uint16_t temp; // 温度 ×10 uint16_t humidity; // 湿度 ×10 uint16_t co2; // CO2 ppm uint16_t light; // 光照 lux uint8_t status; // 在线状态 } sensor_data_t;CRC 校验。Modbus RTU 用 CRC16多项式 0xA001。别自己写用查表法快且不易错。5. IAP 远程升级的完整实现5.1 Flash 分区规划以 STM32F103 为例128KB Flash 这样分区域起始地址大小用途Bootloader0x0800000016KB引导程序App0x0800400080KB应用程序Backup0x0801800016KB固件备份Flag0x0801C0002KB升级标志Config0x0801C8002KB配置参数Bootloader 只做三件事检查升级标志、决定跳转 App 还是进入升级模式、执行固件搬运。App 负责正常业务和接收升级数据。5.2 Boot 与 App 之间的变量传递热搜词里“iap boot里面定义的变量复位后会怎样”这个问题答案是复位后 RAM 全部重新初始化Boot 里定义的变量在 App 里根本访问不到。两个程序是独立编译的链接地址不同变量地址也不同。跨程序传参只有三个可靠途径Flash 标志区在固定地址写标志字Boot 和 App 都按这个地址读写备份寄存器STM32 的 BKP 寄存器掉电不丢但数量有限No-init 段把变量放到不初始化的 RAM 段复位后保留但断电丢失我一般用 Flash 标志区简单可靠。标志字设计#define FLAG_ADDR 0x0801C000 #define FLAG_UPGRADE 0x5A5A5A5A #define FLAG_NORMAL 0x00000000 void set_upgrade_flag(void) { HAL_FLASH_Unlock(); HAL_FLASH_Program(FLASH_TYPEPROGRAM_WORD, FLAG_ADDR, FLAG_UPGRADE); HAL_FLASH_Lock(); }Boot 启动时读这个地址等于 0x5A5A5A5A 就进升级模式否则跳 App。5.3 LoRa 分包传输与断电续传固件一般几十 KBLoRa 单包最多 255 字节要分成几百包。设计要点分包协议。每包带固件总长度、包序号、包内数据、CRC。接收方按序号写入 Backup 区。确认与重传。每包发完等 ACK超时重传最多 3 次。连续失败则暂停升级等下一轮。断电续传。每收到一包把当前包序号写入 Flash。重新上电后从上次序号继续。这个功能看着简单但现场断电是常态没有续传就得从头再来。整体校验。所有包收完后对 Backup 区做 CRC32 校验通过才置升级标志否则丢弃。typedef struct { uint32_t total_len; uint16_t pkt_index; uint16_t pkt_total; uint8_t data[200]; uint16_t crc16; } fw_packet_t;注意升级过程中要关闭看门狗或及时喂狗否则搬运固件时超时复位前功尽弃。6. 常见问题与排查技巧实录6.1 通信距离不达标这是最高频的问题。排查顺序看天线。是不是 470MHz 专用天线有没有拧紧天线周围有没有金属遮挡看参数。SF 是不是太低BW 是不是太宽功率是不是没设满看环境。有没有同频干扰用频谱仪扫一下。看电源。发射瞬间电流能到 120mA电源带不动会导致功率下降。我遇到过一次距离只有 200 米最后发现是天线座虚焊。所以硬件问题永远先查。6.2 RS485 通信时好时坏典型原因是总线反射或地环流。排查量 A-B 电阻应该是 60Ω 左右检查终端电阻是不是只装了两个检查屏蔽层是不是两端都接地了用示波器看 A-B 波形有没有过冲或振铃热搜词里“rs485的ab波形哪种才是正确的”正确波形应该是干净的差分方波上升沿陡峭、无振铃、空闲时电压差大于 200mV。6.3 IAP 升级失败常见原因和解决现象可能原因解决跳转 App 后死机中断向量表没重映射App 里设置 SCB-VTOR升级后不启动标志字没清Boot 跳转前清标志升级中途卡死看门狗复位升级时喂狗或关狗固件校验失败分包丢包加重传和整体校验断电后从头开始没做续传每包写序号到 Flash6.4 节点功耗超标电池节点要求待机微安级。常见漏电点LoRa 模块没进 Sleep还在接收RS485 收发器没关静态电流几毫安传感器一直供电没做电源开关MCU 没进 Stop 模式跑着主循环我的做法是采集完立刻关传感器电源、关 RS485、LoRa 进 Sleep、MCU 进 Stop用 RTC 定时唤醒。这样整机待机能做到 10μA 以下。7. 现场部署的经验与参数速查7.1 部署前的检查清单频段和功率是否符合当地规定每个节点的地址是否唯一天线是否匹配、朝向是否合理RS485 终端电阻和偏置电阻是否到位固件版本是否统一IAP 升级通道是否测试通过电池电压是否充足7.2 关键参数速查表参数推荐值说明SF7-12越大越远越慢BW125kHz平衡距离和速率CR4/5抗干扰够用功率14-20dBm按规定和距离调上报周期5-30min按业务需求RS485 波特率9600/19200工业常用终端电阻120Ω × 2只在两端偏置电阻4.7kΩA 上拉 B 下拉7.3 我踩过的几个坑第一个坑Mesh 网络里节点频繁掉线。原因是路由表老化时间设太短节点刚建立的路由很快失效。后来把老化时间从 30 秒改成 5 分钟稳定了。第二个坑RS485 和 LoRa 共电源LoRa 发射瞬间拉低电压导致 RS485 误码。解决方法是电源加 1000μF 大电容或者 LoRa 和 RS485 分开供电。第三个坑IAP 升级时没关看门狗搬运 80KB 固件要几秒看门狗 2 秒就复位了。后来在 Boot 里先关狗搬运完再开。第四个坑节点地址用随机数生成结果两个节点撞地址。改成用 MCU UID 哈希彻底解决。这套 LoRa 自组网方案我从最早的星型单跳做到现在的分簇两级中继前后迭代了四五个版本。核心体会是协议越简单越可靠现场环境永远比实验室恶劣能有线就别无线能单跳就别多跳。RS485 和 IAP 这两个看似边缘的技术点实际上是决定项目能不能长期稳定运行的关键。后面如果要做更大规模可以考虑上 TDMA 时隙和自适应速率但那是另一个话题了。