
1. 先搞清楚一件事搜LoRa的时候你搜到的可能是另一堆东西直接说个有意思的现象。你去看各大平台的搜索记录输入LoRa这个词跳出来的结果大致会分成两类一类是我今天要说的长距离低功耗无线通信技术Long Range 的缩写另一类则是AI绘画和模型微调圈子里的LoRA 低秩适配Low-Rank Adaptation。这俩英文同名但完全是两个世界的产物。很多新手在搜资料时被带偏到AI模型训练那边去对着压根不相关的教程干瞪眼这种体验我太熟了。我这次做的项目是正儿八经用 LoRa 无线通信技术做一套空气质量监测系统。核心目的很明确布几个监测节点能够长期放在户外或者室内角落定期把 PM2.5、CO2、温湿度这些数据传回网关再送进数据库和看板中间不依赖 WiFi也不依赖蜂窝网络靠一对电池就能撑很久。这套东西适合谁参考如果你是做物联网方案选型的工程师、想在校内做环境监测课题的学生或者自己家里/园区有跨房间跨楼栋的数据采集需求那这篇文章应该能帮你省掉不少弯路。我会把硬件选型、通信参数设置、功耗控制、网关数据链路、实测坑点全部拆开讲让一个有点单片机基础的人也能照着搭出能跑的原型。在开始之前必须先纠正一个误区LoRa 不等于 LoRaWAN。前者是物理层的扩频通信技术负责把数据从一个点传到另一个点后者是建立在 LoRa 物理层之上的组网协议定义了终端怎么入网、怎么分时隙、怎么跟服务器交互。很多教程一开始就把这层窗户纸捅破了但你去看评论区依然有大量人混着用。我这次做的是LoRa 点对点和简单的星型轮询结构没有上完整的 LoRaWAN 协议栈因为对于中小规模的空气监测场景LoRaWAN 的入网管理和频段占用反而显得笨重后面我会详细说明为什么。2. 空气监测为什么偏偏要用LoRa而不是WiFi、蓝牙或者NB-IoT2.1 先看WiFi和蓝牙方案的死穴做环境监测最常见的方案是 ESP8266/ESP32 挂传感器走 WiFi 上报。这方案开发快、资料多、成本低但有个绕不开的问题覆盖范围和功耗的硬矛盾。我最早试着在办公室两个楼层各放一个 ESP32 节点数据往一楼的路由器传。节点本身功耗不低WiFi 连接时电流轻松到 80~100mA如果你用 18650 电池供电乐观估计也就撑一两天。为了省电你只能让设备睡觉、定时醒来连 WiFi 上传但醒来连网的瞬间功耗也很大而且路由器覆盖不到的角落重连逻辑会让人崩溃。更麻烦的是一旦现场没有可用 WiFi整个方案直接报废。蓝牙 Beacon 或者 BLE 广播稍好一点功耗低、组网灵活但它的通信距离通常只有几十米穿墙能力也一般。如果你要监测一个厂房、一片园区、一排大棚BLE mesh 的调试成本和节点数量会让你怀疑人生。WiFi 和 BLE 在室内单点采集这个场景下够用但一旦上升到空间分散、距离上百米、还要长期无人值守的综合监测它们都不是合适的物理层技术。2.2 LoRa在这套系统里的核心价值LoRa 最打动我的就三点远、省、抗干扰。先说远。LoRa 用的是 Chirp 扩频技术把信号在很窄的频段上展宽接收灵敏度可以低到 -137dBm 甚至更低。在开阔环境下同样的发射功率LoRa 能跑出几公里在城市楼宇环境下几百米到一两公里也常见。我实测下来在有建筑遮挡的园区里SF9、14dBm 发射功率稳定传了约 700 米这是 WiFi 和蓝牙完全不敢想的数字。再说省。LoRa 模组在休眠状态下电流可以压到 1~2μA 这个级别发送时电流也只有几十毫安且持续时间极短。这让整个节点用两节 18650 电池或者一块小太阳能板就能连续跑几个月甚至一年基本符合装上去就不用管的定位。最后说抗干扰。LoRa 的扩频增益让它在同样频段有其他窄带信号时依然能解调出有效数据。在 470~510MHz 这个民用频段环境噪声和偶发干扰是存在的但 LoRa 的链路预算余量比一般的 FSK/OOK 调制大得多。实测中即使小区里有人用无线遥控设备我的数据丢包率也没有明显恶化。2.3 那为什么不直接用NB-IoT或者4G这问题我被人问过很多次。NB-IoT 和物联网卡方案的优势是覆盖广、不用自己搭网关但它有两个痛点第一需要插卡和缴纳流量费每个节点一年下来也是一笔开销第二部署依赖运营商网络覆盖地下室、偏远仓库、农业大棚这些地方经常没信号而且 NB-IoT 模组功耗虽然比 4G 低但比 LoRa 还是高不少。在一些不允许外网设备接入的园区或实验室或者数据不想出本地网络的场景LoRa 这种自己建链、自己收数的模式反而更合适。数据从传感器到网关全程在你可控的链路里到网关之后再决定是本地存储还是走有线/4G上云。这种最后一公里私网化、上游灵活化的架构才是 LoRa 在物联网里最常见的定位。3. 硬件选型传感器、主控、LoRa模组的搭配方案3.1 传感器选择不能只看精度还要看功耗和采样方式空气质量监测的传感器种类很多最常见的四个参数是 PM2.5、CO2、温湿度、TVOC。我根据实际项目需求做了一个取舍选择方案如下表监测参数传感器型号关键特性采样电流说明PM2.5/PM10攀藤 PMS5003激光散射UART输出自带风扇约100mA风扇运行精度不错但风扇必须间歇运行CO2Sensirion SCD40光学NDIRI2C接口平均约0.7mA周期测量相比SCD30功耗低很多精度在±(50ppm5%)温湿度SHT30I2C接口平均约2μA待机性价比高互换性好TVOC/甲醛Sensirion SGP30MOX原理I2C接口约48mA加热周期需要定期校准基线不适合绝对精度这里要提醒一下传感器选型最容易被忽略的是用电大头和预热周期。比如 PMS5003 内部有个小风扇不转的时候不产生气流数据就没有意义但一开风扇就是 100mA如果每秒采一次电池再大也扛不住。所以我在设计采样策略时把 PM2.5 的采样周期拉长到 5 分钟每次让模块稳定运行 30 秒取平均值后立刻断电。CO2 传感器 SCD40 本身有低功耗模式可以配置为 30 秒一次自动测量平均电流很低适合长期开机。3.2 主控选择低功耗MCU是底线主控我选了 STM32L0 系列。为什么不用 ESP32因为 ESP32 的 WiFi 射频部分在深度睡眠下很难做到 μA 级别而 LoRa 节点要长期待机主控的睡眠电流直接决定了系统的待机底线。STM32L0 在 STOP 模式下的典型电流可以到 3.4μARAM 数据保持唤醒时间微秒级这个特性用来配合 LoRa 模组的定时唤醒再好不过。如果你不熟悉 STM32L0也可以选 Nordic 的 nRF52 系列或者国产的华大 HC32L0原则是支持多种低功耗模式、片上外设丰富、唤醒源可靠。有人用 Arduino Nano 或者 STM32F103 也做出来了但整体待机电流会高一个数量级短期玩玩无所谓长期部署不推荐。回到项目本身我的节点主控方案是MCUSTM32L071CBT648MHz主频20KB RAM192KB FlashRTC片内 RTCLFCLK 用 32.768kHz 晶振电源管理TPS62742 超低功耗 DC-DC静态电流低于 1μALoRa 模组E32-900T20D国内对应 470M 频段版本 E32-470T20D3.3 LoRa模组选择串口透传 vs SPI寄存器操作这是很多新手会纠结的点。市面上的 LoRa 模块分两类一类是带 MCU 的串口透传模块比如亿佰特 E32 系列你只需要把串口数据发过去模块自己完成组包和射频收发配置通过指令完成开发简单另一类是纯射频前端模块如 SX1268、SX1276 核心模组需要通过 SPI 配置寄存器灵活性高、可控性强但开发量也大得多。我这次选的是串口透传模块理由是对于空气质量监测这种低速率、低频次、数据量小的场景你根本不需要去抠 LoRa 物理层的寄存器细节。串口模块的内部 MCU 已经帮你完成了数据缓冲、超时重发、地址过滤等逻辑开发周期至少缩短一半。如果你后续要做 LoRaWAN 节点、要做自适应速率、要跟 LoRa 网关直接通信那才需要走 SPI 模式自己啃 SX1268 的数据手册。有一个细节要注意串口透传模块的空中速率和串口速率是独立的。串口可以配 9600 或 115200空中速率则由射频参数决定。传输时模块会先把串口数据收进缓冲区再按空中速率发出去所以你把串口调成高速率并不会直接降低射频传输时间真正决定传输耗时的是空中速率、扩频因子和带宽。3.4 供电方案小太阳能板加电池还是纯电池根据安装位置不同我做了两个供电方案。如果是室内节点直接用两节 18650 并联加一个 TP4056 充电板配合低功耗设计满电状态跑几个月没问题。注意 18650 选择容量大一点的建议 3400mAh 以上并且要选带保护板的型号防止过放。如果是户外节点加一块 6V/2W 的小太阳能板和 CN3065 太阳能充电管理芯片。实测在阴天条件下太阳能板每天也能补回不少电量晴天时基本能保证节点长期不亏电。太阳能板和电池之间要加一个肖特基二极管防止倒灌充电板的地要和整个系统的地共地避免电位差导致充电管理异常。千万别直接拿 5V 的 USB 充电板去接太阳能板因为太阳能板的输出电压会随光照变化USB 充电板不是为这种输入设计的长期使用容易把充电电路烧掉。4. LoRa通信参数配置与CAD模式功耗波形的那些事4.1 频段、扩频因子、带宽、编码率怎么配这一节是整篇文章的通信核心我尽量讲得细一点。频段国内合法可用的 LoRa 频段是 470~510MHz也就是 CN470。不同模块版本要注意区分有些卖家卖的 868M/915M 模块在国内不能直接用一是频率越界二是本身会被周围环境噪声干扰。选型时一定看准频段版本。扩频因子SFSF7 到 SF12 可选。SF 越大链路预算越高、传输距离越远但传输速率越低、占用信道时间越长。我在系统里默认配了 SF9。原因是SF7 在城市遮挡环境下余量稍紧张SF10 以上单包占用无线信道时间接近一秒轮询多个节点时排队时间太长。SF9 是我在距离、速率、稳定性的折中。带宽BW常用 125kHz 和 250kHz。带宽越窄接收灵敏度越高但对晶振频偏越敏感。点对点情景我用的 125kHz这是 LoRa 最经典配置。编码率CR默认 4/5 就行。这是纠错开销数值越小代表冗余越多4/8 最多冗余但传输效率低。对于小数据包4/5 已经够用如果测试时发现环境干扰强可以升到 4/6。发射功率模块通常支持 5~22dBm 可调。国内短距离微功率设备有发射功率上限要求实际部署建议不超过 14dBm。我实测 14dBm 在园区里已经够用。我把这套参数固化到配置里顺便写了个参数速查表方便调试的时候查参数配置值对性能的影响中心频率485.0MHzCN470需要避开本地强干扰源扩频因子SF9距离与速率折中带宽125kHz灵敏度优先编码率4/5标准纠错发射功率14dBm合规且够用空中速率约1.76kbps单包约300ms4.2 CAD模式的功耗波形为什么它比纯RX更省电很多人在热词里搜lora模组的cad模式功耗波形说的就是这里。CAD 全称 Channel Activity Detection中文叫信道活动检测。它的用途是让接收端以极低的占空比周期性地探听信道里有没有 LoRa 前导码一旦探听到才切换到完整的接收模式去收包如果没探听到就继续睡。这比一直开着接收机RX mode省电得多。纯 RX 状态下 SX1268 的接收电流在 5~6mA 左右看起来不高但如果节点长期开着接收机等数据电池很快会被抽干。CAD 模式的工作方式是这样的MCU 定时唤醒给模组发一个 CAD 命令模组在短短几个毫秒内完成一次信道采样然后返回有前导码或没前导码的中断结果整个过程模块平均电流远低于连续接收。从示波器或者功耗分析仪上看一次完整的 CAD 监听波形大约是这样唤醒拉升MCU 和模组进入工作状态电流从 μA 级跳到 mA 级持续 1~2msCAD 采样窗口模块的射频前端开启监听前导码电流大约 5~6mA持续 3~7ms无信号时立即回到 Sleep电流跌落回 μA 级有信号时模块继续停留在 RX 状态直到把完整数据包收完再回到 Sleep这个一短一长的电流波形就是 CAD 模式的核心。它比连续 RX 的功耗优势在于大部分时间节点处于短探听而不是全接收状态。如果一个节点每分钟探听一次单次探听 5ms那么平均电流大约只有连续 RX 的 1/12000 左右省电效果极其明显。要注意的是CAD 模式的省电效果完全建立在发送端的前导码足够长的前提上。因为接收端是探听-睡眠-探听-睡眠的节奏如果发送端的前导码太短接收端可能恰好处于睡眠期错过了前导码等它醒来再探听时真正的数据包都已经过去了。所以我在发送端把前导码长度调到 20ms 左右并且在发送前增加了先发一长串前导码再进行 CAD 匹配的机制实测丢包率明显下降。4.3 数据帧格式设计与重传机制LoRa 模块本身可以传任意字节但如果你不做帧结构接收端就不知道怎么解析。我定义了一个很简单的帧格式字段长度说明帧头2字节固定 0xAA 0x55用于帧同步节点ID1字节节点编号数据类型1字节0x01 表示PM2.50x02 表示环境帧负载8字节不同参数按固定偏移放CRC1字节对负载的异或校验简单实用发送端每 5 分钟发一次数据包如果接收端发现帧头不对或 CRC 校验失败就丢弃当前包并请求重传或者靠下一次定时上报兜底。对于空气质量监测实时性要求并不高所以我没有做复杂的 TCP 式确认重传而是采用盲发 多次重发策略每轮数据发送 2 次中间间隔 1 秒接收端对相同节点 ID 和时间戳的数据只取第一包。这个方案实现简单可靠性对于低频数据完全够用。这里有个细节CRC 不要用模块自带的透明传输校验当唯一防线。很多串口透传模块内部有 LRC 校验但如果收发双方的波特率和格式配置一致普通错误可以被内部机制挡掉可一旦数据内容本身被环境干扰造成了合法包内的非法值模块内部校验是发现不了的。所以我坚持在业务层再叠一层简单校验宁可费一个字节也要保证数据可靠性。5. 网关侧的搭建从串口数据到本地数据库5.1 网关硬件选型树莓派还是PC加USB转接网关的职责是把 LoRa 接收模块收到的串口数据转成更上层能用的格式再送进数据库或者云平台。最简单的方式是找一个 Linux 设备通过 USB-TTL 线连接 LoRa 接收模块然后运行一个 Python 脚本监听串口。我选的网关是树莓派 4B理由很简单Linux 环境、Python 生态、性能完全够用、供电方便。如果你手头有闲置的 NUC 或者旧笔记本效果也一样。不建议用太弱的 MCU 做网关因为后续可能还要跑 influxdb、Node-RED 这类服务MCU 的资源撑不住。接收端 LoRa 模块必须和发送端配置完全一致同一频段、相同扩频因子、相同带宽、相同编码率、相同串口速率。这一点经常有人踩坑可以做一个配置文件的注释清单确保所有节点和网关都基于同一份配置。5.2 Python脚本怎么解析数据并入库我平时习惯用 Python pyserial 做数据采集再用 paho-mqtt 把数据发布到本地 MQTT broker然后由 Telegraf 订阅 MQTT 并写入 InfluxDBGrafana 负责可视化。这套链路里每一环都可以替换但整体思路是通用的。串口解析的核心逻辑大致是这样的import serial import struct ser serial.Serial(/dev/ttyUSB0, 9600, timeout2) while True: data ser.read(14) # 按帧长度读取 if len(data) 14: continue if data[0] 0xAA and data[1] 0x55: node_id data[2] data_type data[3] # 负载从 data[4] 到 data[11]共8字节 values struct.unpack(4H, data[4:12]) crc_received data[12] crc_calc 0 for b in data[:12]: crc_calc ^ b if crc_received crc_calc: # 发布到MQTT mqtt_publish(node_id, values) ser.reset_input_buffer()这段代码不是完整工程但可以给你一个起点。实际开发里建议加一个看门狗机制如果串口长时间没有数据自动重开串口或者重启脚本避免设备长时间运行后串口被系统挂死。5.3 数据可视化与告警触发数据进了 InfluxDB 之后我顺手搭了 Grafana 面板展示每个节点的 PM2.5 曲线、CO2 曲线、温湿度曲线以及电池电压。这里有个经验分享不要把电池电压当普通数值展示而要在 Grafana 里设置阈值线当电池低于某一数值时自动变红。这样做的好处是运维人员瞄一眼面板就能判断哪个节点快没电了。告警方面我用了 Grafana Alerting当某个节点的 PM2.5 超过 75μg/m³ 持续 10 分钟以上或者 CO2 超过 1000ppm就推送一条 Webhook 到企业微信机器人。这一块配置不算复杂但确实是很多初做监测系统的人容易忽略的——只做数据展示不做阈值告警那这系统只完成了一半价值。按我的经验一个完整的空气质量监测系统最核心的交付不是能看到数据而是异常时能通知到人。所以告警规则建议在项目一开始就定义好别等数据攒了一堆再补。6. 实测结果、功耗数字与踩坑复盘6.1 传输距离实测:数字背后的限制条件我把节点分别放在三个位置测试室内同楼层、跨楼层、园区开阔地带。测试条件是SF9、125kHz、14dBm 发射功率、接收端用 3dBi 胶棒天线。测试场景距离丢包率实际体验同一楼层隔两堵墙约50m0%很稳定跨一层楼板约15m垂直0%稳定园区广场有树木和路灯杆约700m2%~3%偶尔丢包重发兜底园区更远点有建筑遮挡约1.1km8%~12%勉强可用建议提高天线增益这个数据仅供参考。天线位置、高度、周围金属物体都会影响结果。实测中最能提升距离的往往不是增大发射功率而是把天线尽量架高、远离金属物体和地面。我的节点天线初始贴着铁皮配电箱外壁安装距离只能拉到三四百米后来换了一根玻璃钢吸盘天线并架到两米高距离直接翻倍。6.2 待机和发射时的实测功耗我用一个低功耗电流表Joulescope 或者 uCurrent Gold 都行记录了系统在完整运行周期内的电流变化。关键数据如下深度睡眠主控传感器断电RTC运行约 4.2μAMCU 唤醒初始化约 2.1mA持续 3msPM2.5 传感器采样风扇开启约 92mA持续 30 秒CO2 传感器测量约 12mA持续约 6 秒周期自动模式LoRa 发送平均约 40mA14dBm 发射持续约 300msLoRa CAD 监听平均约 6.2mA单次持续 5ms以室内节点为例假设每 5 分钟一轮完整采样和上报平均电流大约 0.6mA 左右。用两节 18650约 6800mAh供电理论上能跑 10000 小时以上也就是一年多。这个数据说服力很强也是我坚持用 LoRa 方案而不改用其他无线技术的最大理由。6.3 三个最值得记录的坑第一个坑CAD 模式前导码太短导致丢包严重。这个前面已经提过。我在最开始测试点对点收发时把发送端前导码按默认 8ms 配置接收端 CAD 每秒钟探听一次结果丢包率达到 30% 以上。后来把前导码拉到 20ms丢包率立刻降到 3% 以下。这个问题在连续 RX 模式下不存在只在低功耗 CAD 模式下才突出建议大家在设计低功耗链路时优先检查前导码长度。第二个坑太阳能板直接给电池充电导致过压。有一次户外节点连续晴天电池电压被冲到 4.25V 以上保护板虽然没触发但传感器的基准电压明显飘了。后来加装了太阳能充电管理芯片并把充电截止电压限制在 4.1V问题解决。同样的问题也出现在室内节点——如果你用 USB 充电器直充充满后不拔长期挂着电池也会浮充损坏。低功耗系统里充电管理不是可有可无的。第三个坑串口模块的波特率配置不统一造成网关收到乱码。发送端串口改成 115200但网关端 Python 脚本里还写着 9600结果解析出来的数据全是乱码。这个错误很低级但在多节点调试时特别容易发生。我的建议是项目的所有配置文件里统一写明波特率并且在网关脚本启动时做一次自检发送一个固定测试帧确认链路正常再开始业务逻辑。6.4 后续扩展从轮询节点到自动模式目前的系统是节点自发上报网关被动接收。如果再往下扩展可以引入网关主动下发指令让节点调整采样频率或者进入校准模式。LoRa 是支持双向通信的串口透传模块也支持指令下发只是我在第一版里没做。这个扩展逻辑不难在数据帧里加一个下行类型字段网关定时广播配置节点收到后自动修改采样间隔。等哪天我改完这版再写篇文章把下行链路也讲透。最后聊点实际的体会。做这套系统时最花时间的其实不是硬件连接和代码调试而是各种以为能通却没通的状况天线方向不对、接地毛刺、CAD 前导码没匹配上、传感器数据偶尔冒出一个负值……每一步的排查都让我对 LoRa 的物理特性理解更深。我的建议是如果你打算从零复刻这套系统先别急着追求多节点、多远距离老老实实把点对点链路跑通拿着示波器或者电流表看清楚每一段电流波形再逐步加节点。这个基本功打扎实之后后面的所有功能都是水到渠成的事。