拓十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

LoRa自组网实战:RS485与IAP远程升级嵌入式协议栈实现

LoRa自组网实战:RS485与IAP远程升级嵌入式协议栈实现

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 网里,路由表收敛要几十秒,期间数据丢得厉害。后来改成“分簇+两级中继”,稳定性立刻上来了。

选型的判断标准我总结成一张表:

拓扑适用半径节点数功耗协议复杂度典型场景
星型<5km<50最低低小园区、单栋楼
树型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 为什么是自组网的刚需

IAP(In-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 个节点。这样路由时先看簇号,再看节点号,逻辑清晰。

入网流程设计成三步:

  1. 新节点上电后广播入网请求(dst_addr = 0xFFFF)
  2. 汇聚点或中继收到后回复入网响应,分配地址和时隙
  3. 节点保存地址,进入正常工作状态

入网请求要带节点唯一 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 就会引起反射,导致误码。

接线步骤:

  1. 主干线用 120Ω 特性阻抗的双绞线(如 RVSP 2×0.5)
  2. 所有节点的 A 接 A、B 接 B,不能交叉
  3. 终端两个节点各接 120Ω 匹配电阻
  4. 屏蔽层单端接地,不要两端都接,否则形成地环流
  5. 节点分支线尽量短,最好直接从主线上焊接

提示: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 里根本访问不到。两个程序是独立编译的,链接地址不同,变量地址也不同。

跨程序传参只有三个可靠途径:

  1. Flash 标志区:在固定地址写标志字,Boot 和 App 都按这个地址读写
  2. 备份寄存器:STM32 的 BKP 寄存器,掉电不丢,但数量有限
  3. 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 分包传输与断电续传

固件一般几十 KB,LoRa 单包最多 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 通信距离不达标

这是最高频的问题。排查顺序:

  1. 看天线。是不是 470MHz 专用天线?有没有拧紧?天线周围有没有金属遮挡?
  2. 看参数。SF 是不是太低?BW 是不是太宽?功率是不是没设满?
  3. 看环境。有没有同频干扰?用频谱仪扫一下。
  4. 看电源。发射瞬间电流能到 120mA,电源带不动会导致功率下降。

我遇到过一次,距离只有 200 米,最后发现是天线座虚焊。所以硬件问题永远先查。

6.2 RS485 通信时好时坏

典型原因是总线反射或地环流。排查:

  • 量 A-B 电阻,应该是 60Ω 左右
  • 检查终端电阻是不是只装了两个
  • 检查屏蔽层是不是两端都接地了
  • 用示波器看 A-B 波形,有没有过冲或振铃

热搜词里“rs485的ab波形哪种才是正确的”,正确波形应该是干净的差分方波,上升沿陡峭、无振铃、空闲时电压差大于 200mV。

6.3 IAP 升级失败

常见原因和解决:

现象可能原因解决
跳转 App 后死机中断向量表没重映射App 里设置 SCB->VTOR
升级后不启动标志字没清Boot 跳转前清标志
升级中途卡死看门狗复位升级时喂狗或关狗
固件校验失败分包丢包加重传和整体校验
断电后从头开始没做续传每包写序号到 Flash

6.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 时隙和自适应速率,但那是另一个话题了。

返回列表