LoRa自组网协议设计:从帧结构、信道接入到参数调优实践

发布时间:2026/9/15 4:47:01
LoRa自组网协议设计:从帧结构、信道接入到参数调优实践 简介一套基于STM32的LoRa组网实现参考资料包围绕自有协议设计涵盖终端配置、自定义帧格式、网关转发、服务器解析等关键环节适合按需定制通信协议的嵌入式开发者。资源共467个文件压缩包约11.91MB以75个C源文件、85个头文件为源码主体带有85个目标文件、hex/axf等编译产物以及uvprojx/uvoptx、map等MDK工程文件并集成STM32F10x标准外设库驱动可在MDK环境中直接打开工程、编译并烧录验证。已有975人学习浏览说明该主题具备实践关注度。通过分析协议分层、消息确认、底层定时器与射频驱动代码可掌握设备入网、数据上行到网关交互的完整自有协议组网路径同时学习网络管理、安全加密与性能调优的落地思路为农业监测、工业数据采集等低功耗广域网场景提供可复用工程模板。1. 为什么 LoRa 组网要自带协议LoRa 本身只解决物理层通信不解决组网。很多人第一次接触 LoRa 都会用两个模块点对点透传但节点一多谁先发、发给谁、丢了怎么补就成了问题。LoRaWAN 面向运营商级覆盖注册激活、密钥管理、下行窗口这些机制对小规模私有网络来说过于笨重而且不少模块对完整协议栈支持有限。使用自有协议并不是从头发明射频而是自己定义帧格式、目标地址、确认重传和信道接入让组网从大家都能收到变成该收的收到并且能确认。这篇文章就是要讲清楚这套思路先定协议再写实现最后调参数适合做工业采集、农业监控、园区抄表这类中小规模 LoRa 应用的工程师。2. 自有协议的核心设计帧结构、地址与信道接入2.1 先想清楚你要组的是星形、树形还是 Mesh 网组网方案的第一件事不是写代码而是确定拓扑。星形网最简单所有节点直接连网关覆盖范围受链路预算限制但时隙管理和确认机制都很直接。树形网在链路不足时引入中继节点每增加一跳要占用两倍的空中时隙因为中继节点要先接收再转发。Mesh 网允许任意邻居转发覆盖更灵活但 LoRa 的空中速率通常只有几 kbps 到几十 kbps跳数超过 3 之后实际吞吐量会低到难以接受。我一般先估算业务量再选拓扑。例如 100 个节点每 5 分钟上报 50 字节负载用 SF10、125kHz 带宽时一包空中时间约 100ms一分钟一个节点只需要 40ms 左右的信道占用100 个节点分到 60 秒里一个信道完全足够。这种低密度上报场景星形就够。如果节点上报频繁或者要求秒级响应就需要考虑分槽机制或限制节点数量。先算吞吐量再定拓扑能省掉后面大量重试和排错。2.2 帧结构从能发到能组网自有协议要解决的第一个问题是这一包是给谁的。没有地址的 LoRa 帧只能在同一个串口调试终端里看到一堆原始字节有了帧格式每个节点才能决定是丢弃还是回复。帧格式不需要像 LoRaWAN 那样复杂但至少要覆盖三个信息节点地址、帧类型、数据完整性校验。下面这张表是一个最小帧格式也是我在多个项目里用过的基线。字段大小字节值/范围说明Preamble40xAA 0xAA 0xAA 0xAA接收端锁频和识别帧起始DestAddr10x00 为广播0x01-0xFE目的节点地址SrcAddr10x01-0xFE源节点地址FrameType10x01 数据0x02 确认0x03 路由区分控制帧与业务帧Length1最大 64负载字节数PayloadN业务数据或控制参数应用层内容CRC162多项式 0x1021从 DestAddr 到 Payload 的校验帧头 0xAA 用来让接收端判断一个完整包的开始。如果两个不同子网在同一个频点附近工作一定要把 LoRa 模块的同步字 SyncWord 改掉否则 0xAA 打头会让对方被误唤醒白白浪费接收功耗。2.2.1 用代码定义并发送最小帧LoRa 模块的 FIFO 是按字节读写的用结构体映射帧格式虽然直观但字节对齐会带来麻烦。我习惯直接用字节数组组帧发送函数就是按上面表格顺序填充。下面这段 C 代码可以作为协议的基础层。/* 组帧并发送返回 0 表示成功 */ int lora_send_frame(uint8_t dest, uint8_t type, const uint8_t *payload, uint8_t len) { uint8_t frame[72]; int idx 0; frame[idx] 0xAA; /* 帧头 */ frame[idx] dest; /* 目的地址 */ frame[idx] local_addr; /* 本机地址 */ frame[idx] type; /* 帧类型 */ frame[idx] len; /* 负载长度 */ for (int i 0; i len; i) { frame[idx] payload[i]; /* 业务负载 */ } uint16_t crc crc16(frame 1, idx - 1); /* 从目的地址开始计算 */ frame[idx] (crc 8) 0xFF; frame[idx] crc 0xFF; return lora_modem_send(frame, idx); }目的地址和源地址放在负载之前接收端就能快速判断这一包是否需要处理不用等整包接收完。CRC 计算范围不包含帧头因为帧头用于前导检测不参与数据完整性校验。lora_modem_send是驱动层接口实际调用时要先检查模块是否处于接收空闲状态再清掉 TxDone 标志写入 FIFO 并触发发送。2.3 信道接入简化 CSMA 和分槽 ALOHA 怎么选LoRa 在同一频点上同时发送必然冲突必须规定什么时候能发。纯 ALOHA 最省事但信道利用率只有约 18%分槽 ALOHA 能把时间切分利用率到 37%带 CAD 的 CSMA 类似 Wi-Fi 的载波侦听能进一步减少碰撞。然而 LoRa 的 CAD 检测要花掉约一包空中时间的几分之一包短时反而拖累吞吐。选择逻辑不复杂节点上报周期在 1 分钟以上用分槽 ALOHA有突发业务、周期不固定用带随机退避的 CSMA-CAD。分槽 ALOHA 实现时由网关周期性广播信标每个节点的发送窗口 本地地址 % 总时隙数。时隙长度要覆盖最大包空中时间加确认等待时间。下面的代码是一个简化的 CSMA-CAD 发送流程/* 简化的 CSMA-CAD 发送最多尝试 3 次 */ int lora_send_csma(uint8_t dest, uint8_t *payload, uint8_t len) { for (int attempt 0; attempt 3; attempt) { if (lora_modem_cad() CHANNEL_CLEAR) { return lora_send_frame(dest, 0x01, payload, len); } delay(rand() % 100); /* 随机退避 0-100ms */ } return -1; /* 信道忙交给上层丢包处理 */ }lora_modem_cad使用 SX1276 的 Channel Activity Detection它会在当前信道检测 LoRa 前导码返回信道是否忙。注意 CAD 并不是耗时操作但在 125kHz 带宽和 SF10 下大概需要 20ms 级别因此发送退避不能写得太短否则 CAD 还没出结果就重发同样会碰撞。2.4 地址分配、确认与重传机制小规模私有网络不需要动态地址分配直接让每个节点在烧录时写入一个短地址。广播地址 0x00 保留用于网关发送全局信标或配置命令。数据帧默认需要确认网关收到数据后立即回一个不携带负载的确认帧源节点只有收到确认才算发送成功。广播帧不回确认上层应用自己决定是否信任广播结果。确认帧的帧类型是 0x02目的地址填原帧的源地址源地址填网关地址。重传次数我会控制在 2 到 3 次第三次失败后直接丢弃并上报错误。更多的重传只会让碰撞概率线性上升尤其在多节点同时掉线恢复的情况下重传风暴能把信道完全打满。3. 用 SX1276 模块和主控把协议跑起来3.1 硬件连接与 LoRa 物理层参数实现这套协议的硬件可以分成两层主控 MCU 和 LoRa 模块。MCU 这边我用过 STM32L0、ESP32 和低端 Cortex-M0推荐 STM32L0 这类带低功耗模式且能操作 SPI 的芯片ESP32 功耗偏高适合需要 WiFi 回传的网关节点。LoRa 模块选用 SX1276/SX1278 及其兼容方案它们通过 SPI 接口收发数据还提供 CAD、RSSI 等状态读取。模块与主控的连接是标准的 SPI 四线加 DIO0 中断引脚DIO0 在发送完成或接收完成时产生电平跳变主控用外部中断处理。物理层参数必须收发一致。下面的配置是一个典型值适合 470MHz 频段的中远距离场景lora_radio_config_t cfg { .frequency 470000000, /* 470MHz 中国短距离设备可用频段 */ .spreading_factor 10, /* SF10 */ .bandwidth_khz 125, /* 125kHz 带宽 */ .coding_rate 5, /* 编码率 4/5 */ .sync_word 0x12, /* 私有子网同步字 */ .output_power 20 /* 发射功率 20dBm */ }; lora_radio_init(cfg);SF10 的经验覆盖距离在郊区环境下能看到 1 到 3 公里城市楼宇下会降到几百米。这里把 SyncWord 设置成 0x12同一区域内其它使用默认同步字的 LoRa 设备不会错误参与我们的组网。3.2 节点端收发代码怎么写节点端功能包括定时采集、发送数据、等待确认以及在接收中断里过滤帧。发送带确认的函数如下bool send_data_with_ack(uint8_t dest, uint8_t *data, uint8_t len) { for (int i 0; i 3; i) { int sent lora_send_frame(dest, 0x01, data, len); if (sent 0) continue; ack_received false; /* 等待确认帧最长等待 200ms */ if (wait_ack(200) true) { return true; } } return false; }这段代码把重传逻辑独立出来每次发送后清掉全局ack_received标志再进入等待。wait_ack里实际上是一个循环查标志位加超时控制避免阻塞调用的同时保证最坏响应时间。3.2.1 接收中断里完成帧过滤接收完成中断需要尽快判断是不是给自己的包否则睡眠节点会被无关帧唤醒。DIO0 中断触发后读取 FIFO然后做地址匹配/* 在接收完成中断里调用 */ void on_rx_done(uint8_t *buf, uint8_t size) { if (size 6) return; uint8_t frame_type buf[3]; if (buf[1] ! local_addr buf[1] ! 0x00) return; /* 过滤 */ if (frame_type 0x01) { /* 收到数据帧 */ if (buf[1] local_addr) { send_ack(buf[2]); /* 回确认给源地址 */ } /* 交给上层处理 */ handle_application_payload(buf[2], buf[5], size - 6); } else if (frame_type 0x02) { /* 收到确认帧 */ ack_received true; } }注意size - 6是去掉帧头、地址、类型、长度和 CRC 之后的负载长度这里假设 CRC 已经在底层校验过。如果底层没有校验必须在on_rx_done里重新算一次否则错包会被当成有效业务数据。3.3 网关端把收到的数据转发出去网关和节点代码的主要区别是网关不参与业务采集而是把节点数据转换成另一种格式回传至上位机或云平台。常见做法是通过 UART 以 JSON 格式输出原始帧再让边缘网关去解析。也可以用下面的结构把地址和负载提取出来void gateway_handle_frame(uint8_t *buf, uint8_t size) { if (size 6) return; uint8_t dest buf[1]; uint8_t src buf[2]; uint8_t type buf[3]; uint8_t len buf[4]; if (dest ! gateway_addr dest ! 0x00) { return; } if (type 0x01) { send_ack(src); /* 网关立即回确认 */ char output[96]; snprintf(output, sizeof(output), {\src\:%u,\len\:%u,\payload\:\%s\}, src, len, bytes_to_hex(buf 5, len)); uart_send_string(output); } }网关节点的发射功率和天线高度决定了整个网络的覆盖上限不建议把网关放在配电箱内壁尽量放在顶部或室外。如果网关和节点之间始终丢包优先看网关端 RSSI低于 -110dBm 时考虑增加中继。4. LoRa 组网参数调优扩频因子、带宽、超时与丢包测试4.1 扩频因子、带宽、编码率怎么配LoRa 的调制参数直接决定链路预算和空中时间这是自有协议最需要反复调的部分。下面这张表汇总了我常用的参数选择参数可选值速率影响灵敏度/距离影响常用建议扩频因子 SFSF7~SF12SF12 速率约为 SF7 的 1/6SF 越高灵敏度越高初调先用 SF10带宽 BW125/250/500kHz带宽越高速率越高带宽越低抗干扰越好私有多网用 125kHz编码率 CR4/5~4/8冗余越多速率越低冗余提升抗干扰能力室内可用 4/6室外 4/5这三个参数组合产生不同的空中时间空中时间越长网络里同时存在的节点数越少。例如 SF10 125kHz 4/5 的 20 字节包大约耗时 100ms换成 SF7 后能降到 30ms 左右但距离也会大幅缩短。我通常先用 SF10 跑通组网再根据实际 RSSI 余量去降 SF。4.2 重传超时和重试次数重传超时不能随便写一个固定值。如果网关处理确认帧很快超时设为 200ms 通常够用但在网关负载高或中继场景下确认帧要经过多跳才能回来超时必须重新计算。一个常用公式超时时间 单跳空中时间 × 两倍跳数 网关处理时间 余量例如单跳空中时间 100ms两跳路径回确认需要 2×100ms 再加上网关 10ms 处理和余量超时至少设到 450ms。下面的测试脚本用来验证不同参数下的实际丢包率配置文件和协议栈都不用改import serial, time total 0 ok 0 with serial.Serial(/dev/ttyUSB0, 115200, timeout1) as ser: for i in range(100): ser.write(bping\n) resp ser.readline() total 1 if resp.strip() bpong: ok 1 time.sleep(0.2) print(f丢包率: {(total - ok) / total * 100:.1f}%)测试时把节点放在实际部署位置连续发 100 个 ping。如果丢包率超过 5%先看信号强度和干扰再看是否有多个节点在同时发。脚本里timeout1是串口读超时超过 1 秒没有 pong 就认为这一包丢失。4.3 从丢包数据反推参数问题丢包率和 RSSI 对应关系很直观RSSI 在 -90dBm 以上时丢包率应该接近 0-110dBm 以下时丢包率会迅速上升。如果 RSSI 很好但丢包率依然高优先级最高的是检查同步字和扩频因子是否一致。另一个常被忽略的问题是天线馈线损耗模块到天线的线如果太长等于平白降低灵敏度。还有一个常见误用是频繁改带宽来提升速率。带宽从 125kHz 改到 500kHz速率翻倍但灵敏度会损失约 6dB覆盖距离可能从 3 公里缩到不到 1 公里。对组网来说稳定性比峰值速率重要建议只在链路余量充足的情况下提高带宽。5. 进阶技巧把自有协议扩展到 Mesh 与低功耗5.1 用路由表把星形改成 Mesh当节点无法直接够到网关时可以让邻居节点转发数据帧但转发不能无限制。我在节点上维护一个简单的路由表只记录到目标地址的下一跳避免广播风暴。组网的初始阶段每个上电节点先发送路由请求收到路由回复后记录下一跳。路由表实现只需一个数组例如记录目标地址 下一跳地址 跳数更新策略是最小跳数优先。实际部署中我将 Mesh 跳数限制在 3 跳以内。超过 3 跳时LoRa 的低速率乘上每跳重发时间吞吐量会跌到不可用。如果需要更大范围更务实的做法是增加网关或改用更低 SF而不是堆跳数。5.2 用 CAD 做低功耗侦听电池供电节点不能一直开接收。SX1276 的 CAD 模式能以远低于接收模式的功耗判断是否有 LoRa 前导码因此可以实现真正的低功耗侦听。节点流程是平时进入 Sleep定时唤醒后用 CAD 扫描信道如果检测到前导码再切换成接收模式收完整包如果信道空闲立刻继续睡眠。CAD 检测时间取决于带宽和 SF125kHz、SF10 时大约 20ms这比一直开接收省掉很多功耗。结合分槽 ALOHA节点只要在自己的时隙附近唤醒 CAD其余时间都保持睡眠一组 2200mAh 电池理论上能支持数个月到一年的工作周期。5.3 三个验证协议健壮性的习惯第一个习惯是打开模块内部的 CRC 错误计数器。SX1276 在接收失败时会递增 CRC 错误标志通过 SPI 读取这个寄存器能区分链路误码和协议丢包。如果 CRC 错误很高而 RSSI 正常说明有同频干扰或硬件问题。第二个习惯是让每个节点定期上报自身的 RSSI 和重传次数把这些诊断字段放进 Payload 末尾网关统一收集。这样能提前发现某个节点在真实环境中即将超出覆盖边界而不是等到采集失败再排查。第三个习惯是刻意做断电恢复测试。同时断开 10 个节点的电源再重新上电观察它们是否会在同一时刻发起重传。如果协议栈没有随机退避这批节点会同时抢占信道造成拥堵正确做法是节点上电后先等待随机(500ms~3s)再尝试连接。把这三种情况都测过一遍自有协议才算真正能上现场。本文还有配套的精品资源点击获取

关于本文作者

来自尧图内容编辑团队

尧图内容编辑团队 内容团队

尧图内容编辑团队

本文由尧图网络内容编辑团队执笔。团队由资深项目经理、前端工程师与设计师组成,所有内容均来自亲手交付的真实项目,先讲清问题、再给出可落地的解法。尧图深耕北京网站建设十年,服务过京华建材集团、智造科技等各行业客户,把一线经验沉淀为可复用的行业观察。

  • 十年建站经验,覆盖建材、制造、服务、文创等
  • 项目经理把关选题与事实准确性
  • 工程师与设计师联合撰写专业细节
  • 统一编辑规范,保证文风与排版一致
  • 每月复盘转化数据,迭代选题方向

延伸阅读

相关资讯与近期热门内容

深度阅读推荐

建站决策前值得细读的三篇

网站改版的5个关键决策
2024-08-12

网站改版的5个关键决策

什么时候该改版、改到什么程度、如何避免流量掉光,京华建材集团改版复盘给出答案。

获取专属建站方案

看完文章,把您的行业与预算告诉我们,免费获取一份量身定制的官网建设方案与报价。

立即免费咨询