LoRaMac-node移植到SX1268:驱动改造、调试与回环验证实战
发布时间:2026/10/6 8:30:40 作者:尧图编辑部 阅读量:1,286

简介面向 LoRa 物联网开发者的 SX1268 驱动工程基于 LoRaMac-node 协议栈提供 C 语言实现的端到端通信代码实测设备与服务器间 10KM 距离传输正常适合需要快速搭建远距离低功耗链路的嵌入式工程师。压缩包共 2000 个文件以 .c 源码、.h 头文件、.sisc 工程文件为主另有 .ld 链接脚本、.txt 说明、.md 文档及少量 PDF 参考总计 19.02MB源码内含 LoRaMac.c、STM32L4/L1/L0 系列 HAL 驱动等覆盖协议栈、射频控制与硬件抽象层。资料已有 565 人学习下载对于正在调试 SX1268 或研究 LoRaWAN 入网、收发流程的开发者可直接对照驱动代码修改信道、数据速率与扩频因子并借助 STM32 工程模板减少移植工作量。整体目录结构清晰既能作为学习 LoRa 物理层与 MAC 层的参考也可在自有硬件上二次开发。1. 这块板子要跑 LoRaMac-node为什么官方 C 代码不能直接烧给 SX1268拿到一块板载 SX1268 的 LoRa 模块第一件事往往不是焊天线而是面对 LoRaMac-node 这一大坨 C 语言驱动代码不知道从哪下手。LoRaMac-node 是 LoRa 生态里最常被拉下来的开源协议栈里面包含了完整的 LoRaWAN MAC 状态机、sx126x 系列 radio 驱动和 board 适配层但仓库默认的 target 是 SX1261/SX1262 评估板。SX1268 作为 470-510MHz 频段模块里的主力芯片寄存器虽然和 SX1262 高度重合板级配置却要自己改。这篇笔记就讲怎么把这套 C 驱动改造成 SX1268 能跑的落地版本先分层看代码再动板级引脚然后调频点和功率最后用两个模块在桌面上把链路打通。2. 移植前先读代码LoRaMac-node 的分层结构与 SX1268 的板级接线2.1 目录分层知道 sx126x.c 不用动boards 和 mac 才是主要战场LoRaMac-node 仓库顶层的代码结构基本是四块projects 目录放各 IDE 和工具链的工程入口里面有 GCC、Keil、IAR 的工程文件src/radio 下面是 sx126x.c 和 sx126x.h负责 SX1261/SX1262/SX1268 三款芯片的命令封装比如 SetPacketType、SetRfFrequency、SetTxParams 这些底层 APIsrc/mac 是 LoRaWAN 协议栈的主体入网、确认、重传、ADR 这些状态机都在 LoRaMac.c 里跑src/boards 是真正需要动手的地方board.c 里要实现 SPI 读写、GPIO 读写、定时器 tick 和串口打印。SX1268 和 SX1262 的寄存器级命令基本一致差异主要在频率范围和个别射频参数上所以拿到源码后不必大改 sx126x.c。真正的移植顺序是先改 board.h 的引脚定义再实现 board.c 里的 BSP 函数最后在 LoRaMac 初始化的地方把 region 选成 CN470、把频点写成 470-510MHz 之间的实际值。这个顺序反了会出现一种常见场面radio 层调得很欢但板级时序不对芯片根本不响应最后浪费一整天查 SPI。另外要留意 src/boards 下不同评估板的代码不能直接套用。Nucleo 板、SX1262DVK 板、你自己的小板子GPIO 端口、SPI 外设、时钟树都不一样。我一般会把 board.c 里所有硬件相关函数重新梳理一遍不是只改引脚号还要确认 SPI 的片选极性、DIO1 是否复用到其他外设、RESET 是不是被调试口占用。2.2 引脚映射RESET、BUSY、DIO1、DIO2 四根线决定驱动能不能起来SX1268 与 MCU 之间除了标准 SPI 的 SCK/MOSI/MISO/NSS还有四根控制线必须接对。RESET 用于复位芯片低电平有效BUSY 是状态输出表示芯片正在处理上一条命令DIO1 是中断输出发送完成、接收完成、前导码检测都会在这里拉电平DIO2 在不少模块上负责控制射频开关或给 TCXO 供电。LoRaMac-node 的 board.h 里会用一组宏把引脚定义出来常见做法是直接改这些宏而不是去动 board.c 里的逻辑。/* board.h 中针对 SX1268 模块的引脚宏定义以 STM32 为例 */ #define RADIO_RESET_PORT GPIOB #define RADIO_RESET_PIN GPIO_PIN_12 #define RADIO_BUSY_PORT GPIOB #define RADIO_BUSY_PIN GPIO_PIN_13 #define RADIO_DIO1_PORT GPIOB #define RADIO_DIO1_PIN GPIO_PIN_10 #define RADIO_DIO2_PORT GPIOB #define RADIO_DIO2_PIN GPIO_PIN_11这些宏会被 board.c 里的底层函数引用接线时最容易被忽略的是 BUSY。SX1268 的 BUSY 引脚必须配置为输入SPI 每发一条命令前都要等待 BUSY 拉低。如果这个引脚忘了配、或者被初始化成了推挽输出重启后芯片不会响应任何命令现象就是 LoRaMac 初始化直接卡死。DIO2 的 TXCO 控制也要看模块原理图有些模块内部已经把 DIO2 接到了射频开关有些则是外部 TCXO 供电脚配置错了会表现为发射功率明显偏低或接收灵敏度异常。有些国产模块把 DIO1 和 BUSY 做在同一个排针上拿到的转接板上丝印还容易标反。我会在写 board.c 前先用万用表量一下引脚到模块焊盘的连接关系没有把握就用杜邦线飞线验证避免把时间耗在“代码没病、接线有病”上。2.3 用 HAL 库实现 SPI 时序忙等待、NSS 拉低与字节交接常见做法是在 board.c 里写一个 RadioSpiReadWrite 函数SX1268 的所有命令都通过它进出。核心点有三个片选拉低前要确认 BUSY 处于空闲命令和参数一次性传输结束后把 NSS 拉高。贴一段用 STM32 HAL 阻塞模式封装的读写/* radio_spi.c用 STM32 HAL 阻塞模式封装的 SPI 全双工读写 */ uint8_t RadioSpiReadWrite(uint8_t *txBuf, uint8_t *rxBuf, uint16_t size) { // 每发一条命令前先等 BUSY 低电平避免命令被芯片丢弃 WaitRadioBusy(); HAL_GPIO_WritePin(RADIO_NSS_PORT, RADIO_NSS_PIN, GPIO_PIN_RESET); HAL_SPI_TransmitReceive(hspi2, txBuf, rxBuf, size, 1000); HAL_GPIO_WritePin(RADIO_NSS_PORT, RADIO_NSS_PIN, GPIO_PIN_SET); return 0; }WaitRadioBusy 里要加一个超时上限不能死等。有些板子 BUSY 在复位后会有长达几百微秒的高电平卡在这里是正常的但超过 10ms 还拉不低就有问题了这时需要检查复位是否生效、BUSY 引脚是否接反。SPI 时钟建议从保守值起步SX1268 手册允许的 SPI 速率很高但国产模块对毛刺的容忍度不一时钟超过 8MHz 后误码率可能上升我一般先把分频放到 4-5MHz 把功能跑通再逐步提速。SPI 模式和极性也要对上多数 SX1268 模块跑的是 SPI Mode 0CPOL0CPHA0。这种细节往往不会写在 LoRaMac-node 的文档里而是在芯片数据手册的 SPI 章节里。如果你是从 STM32 标准外设库或 Arduino 库搬过来的代码注意确认相位极性默认值不一样会表现为“能写寄存器但读回来全是 0xFF”。2.4 配置 DIO1 外部中断任意沿触发比固定上升沿更省心DIO1 在发送完成、接收完成、接收超时等多个事件时都会动作。LoRaMac-node 的 radio 层通过 RadioIrqProcess 去读芯片的中断事件寄存器前提是 DIO1 能把 MCU 从主循环里唤醒。用 HAL 库配置 EXTI 时我建议中断触发方式用“任意沿”而不是只配上升沿。/* radio_gpio.cDIO1 外部中断初始化 */ void RadioDio1ExtiInit(void) { GPIO_InitTypeDef gpio {0}; gpio.Pin RADIO_DIO1_PIN; gpio.Mode GPIO_MODE_IT_RISING_FALLING; gpio.Pull GPIO_NOPULL; HAL_GPIO_Init(RADIO_DIO1_PORT, gpio); HAL_NVIC_SetPriority(EXTI15_10_IRQn, 5, 0); HAL_NVIC_EnableIRQ(EXTI15_10_IRQn); }中断回调里只做一件事通知协议栈去处理。不要在回调里做日志输出、延时、或调用可能阻塞的 HAL 函数否则会影响接收窗口的时间精度。/* stm32xxx_it.c 中的 EXTI 回调 */ void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin) { if (GPIO_Pin RADIO_DIO1_PIN) { RadioIrqProcess(); // 读取事件标志并清中断 } }RadioIrqProcess 内部会访问 SPI所以这个回调所在的中断优先级不能太高。LoRaMac 的定时器中断如果被 DIO1 抢占接收窗口可能偏移反过来 DIO1 被定时器中断卡住又可能漏掉 RX_DONE。一般把 DIO1 的外部中断优先级放在普通业务中断级别确保主循环和定时器能有喘息空间。3. 入网与发射参数CN470 频段、功率与 ADR 的取舍3.1 CN470 的 96 个上行信道频率不是填一个数那么简单LoRaWAN 在中国区域常用的是 CN470 频段覆盖 470-510MHz。SX1268 的 RF 频率寄存器虽然是 32 位但 LoRaMac-node 对频道的管理是基于 region 配置表的不是简单写一个 490000000 了事。协议栈默认会按 96 个上行信道加 4 个下行信道来组织频点每个信道间隔 200kHz。入网时的 Join 过程会在这些信道里跳如果只配置了一个频点网关那边会收不到你的入网请求。/* 入网前设置本机使用的频点和信道单位 Hz */ LoRaMacSetChannelFrequency(0, 490000000); // 上行信道 0 使用 490MHz LoRaMacSetChannelFrequency(1, 490200000); // 上行信道 1 使用 490.2MHz这里有个参数含义要讲清楚LoRaMacSetChannelFrequency 的第一个参数是信道编号第二个是绝对频率。往后如果要在不同信道间跳频需要按 region 表把所有期望使用的信道都设置一遍。很多国产模块出厂默认频点在 490MHz 附近但如果你的应用只在室内测试其实把信道 0 到信道 7 都设成同一个物理频点也合法只是抗干扰能力变差。实际项目里我更倾向于只放开一小段信道比如 490-491MHz 之间的 5 个信道在 LoRaMac 初始化后调用 LoRaMacSetChannelFrequency 逐个设过去。这样做的好处是现场排查时干扰源容易定位坏处是如果网关配置了完整 96 信道的跳频表入网响应可能要等较长时间。3.2 TX 功率与 ADR开发板标的 22dBm 不等于模块真能发出去SX1268 的最大发射功率可以从寄存器层面配到 22dBm但实际能出多少取决于模块的 PA 电路、电源能力和天线匹配。LoRa 模块行业里有个不写进数据手册的共识标称 22dBm 的模块在高频段或电池供电场景下实际输出可能只有 17-19dBm。C 代码里写多大功率要跟模块厂家确认而不是照着评估板源码抄。/* 设置发射功率单位为 dBm0 到 22 可调 */ RadioSetTxConfig(MODEM_LORA, 20, 0, 0, 0, 0, false); RadioSetModem(MODEM_LORA); RadioSetRfFrequency(490000000);RadioSetTxConfig 的第一个参数是调制方式第二个是功率。这里如果写 20芯片内部会按 0.5dBm 步进去设置 DAC 和 PA 寄存器。LoRaMac-node 自带的 SX1262 评估板默认使用 22dBm如果你的模块没有好的散热条件连续发射几包后频率会漂移表现为网关收到包但 RSSI 不稳定。我一般先把功率调到 17dBm 做链路摸底确认通信距离再往上加。ADR 也要谨慎对待。ADRAdaptive Data Rate依赖网关节点的链路余量反馈如果网关没有开 ADR 或没有正确上报链路余量终端会把 SF 从 12 一路降到 7距离优势就没了。做桌面回环测试时最好先把 ADR 关死用固定 SF12 验证无线链路等到接入真实网关再做 ADR 决策。/* 固定使用 SF12/BW125关闭 ADR适合回环测试 */ LoRaMacSetAdrOn(false); RadioSetTxConfig(MODEM_LORA, 20, 0, 0, SF12, BW125, CR48, 8, 0, false);参数里 SF12 和 BW125 是 LoRa 调制的核心组合红色代码块中 LoRa 调制参数顺序是调制方式、功率、频率偏移、调制参数、包参数。如果传参顺序错位最直观的现象是发射出去之后对端收到的 SNR 异常。3.3 Class 模式、RX 窗口与占空比SX1268 的低功耗不是光靠 Sleep 指令LoRaWAN 终端最常用的是 Class A发送完成后打开 RX1 和 RX2 两个接收窗口。RX1 在发送结束后 1 秒开启RX2 在 RX1 后 1 秒开启。SX1268 在发射时会自动进入接收状态如果 MCU 没有在这个时间窗口里把射频切到 RX就会错过下行 ACK。LoRaMac-node 的状态机里这个窗口由板级定时器管理所以 board.c 的 tick 精度直接影响入网成功率。/* Class A 模式下设置接收窗口偏移单位毫秒 */ LoRaMacSetRx2Frequency(505000000); LoRaMacSetRx2Channel(505000000);RX2 的频率在 CN470 里通常固定为 505MHz如果你把上行信道改到了 490MHz下行 RX2 也要对应调整。这个参数很多人不改结果入网时发送成功但收不到 Join Accept排查半天发现在 505MHz 上监听的网关根本没往下发。占空比那块很容易忽略。CN470 频段有占空比限制LoRaMac 提供了 DutyCycle 相关的开关和上限设置。如果代码里开启了占空比控制连续发送会触发协议栈的禁止发射状态表现为串口日志里出现“Duty cycle”相关打印主循环还在跑但不发数据。现场测试时我会先按法规要求把占空比参数改大或直接关闭等调通后再把真实限制加回去。/* 关闭占空比限制仅用于实验室测试 */ LoRaMacDutyCycleOn(false); LoRaMacSetMaxDutyCycle(0);这两个函数在不同版本的 LoRaMac-node 里名字可能略有差异但语义一致。注意关闭占空比限制后实际生产和认证测试还是要按当地法规来实验室图方便可以不要带着这个配置去现场长期跑。3.4 日志与状态观察把 ACK、重传、RSSI 打出来调试才有着力点LoRaMac-node 默认自带一套打印机制但很多人在板级移植时没把串口重定向接好导致 LORAMAC_PRINTF 全部哑火。在调驱动阶段至少要保证三行日志能看到入网状态、发送完成、ACK 是否收到。给一段在主循环里观察状态的简例/* 主循环中的状态观察点 */ switch (LoRaMacGetState()) { case LORAMAC_IDLE: debug_log(MAC idle, RSSI%d dBm\n, (int16_t)RadioGetRssiInst()); break; case LORAMAC_TX_ONGOING: debug_log(TX ongoing\n); break; case LORAMAC_RX_TIMEOUT: debug_log(RX timeout, will retry\n); break; }RadioGetRssiInst 返回的是当前信道瞬时 RSSI空闲时能看到底噪水平。如果底噪在 -105dBm 以上说明现场干扰较大同频干扰会让随机数退避白白浪费很多重传机会。日志的优先级也很重要串口打印放在高优先级里会拖慢 LoRaMac 的定时器一般建议用一个环形缓冲主循环里统一输出。4. 离了网关也能验证两个 SX1268 模块的裸 Radio 回环4.1 绕过 LoRaWAN 协议直接调 radio 层 API减少变量在把 LoRaWAN 协议栈完整跑起来之前先用裸 radio 做点对点回环能快速确认 SX1268 的驱动层、SPI 时序和天线通道是好的。做法是绕过 LoRaMac 协议直接调用 sx126x.c 里暴露出来的 Radio API。两个模块一个配成发送一个配成接收在同一频点同一参数下互发。/* 模块 A初始化并进入连续接收模式 */ RadioInit(); RadioSetModem(MODEM_LORA); RadioSetRfFrequency(490000000); RadioSetRxConfig(MODEM_LORA, SF12, BW125, CR48, 8, 0, 0, 0, 0, false); RadioRx(0); // 0 表示持续监听/* 模块 B初始化后发送一包 12 字节数据 */ RadioInit(); RadioSetModem(MODEM_LORA); RadioSetRfFrequency(490000000); RadioSetTxConfig(MODEM_LORA, 17, 0, 0, SF12, BW125, CR48, 8, 0, false); RadioSend(hello sx1268, 12);这里的关键是 RadioSetRxConfig 和 RadioSetTxConfig 的参数要完全对得上。收发参数不一致时接收端会卡在“检测不到前导码”或“CRC 校验失败”日志里看不到任何有效包。RF 频率也要一致SX1268 的频率寄存器是 24 位步进如果发送 490.000MHz 接收 490.001MHz看起来差得不多但实际已经超出了 LoRa 解调带宽的一小部分误码率会急剧上升。4.2 回环收发与 RSSI 读数用数值判断链路余量回环测试的目的不是“能收到”就好而是要拿到 RSSI 和 SNR 来评估链路余量。接收端在收到一包有效数据后通过 RadioGetPacketStatus 可以读到这包数据时的 RSSI 和 SNR。发送端也可以用 RadioGetRssiInst 看当前信道的底噪。/* 接收回调里读取 RSSI 与 SNR */ RadioPacketStatus_t st; RadioGetPacketStatus(st); debug_log(RSSI%d dBm, SNR%d\n, st.Rssi, st.Snr);把两个模块放在同一张桌子上RSSI 通常在 -30 到 -50dBm 之间这属于“信号过载”区域反而可能因为接收饱和而出现误码。正确做法是把发射功率降到 2dBm 甚至加衰减器让接收端 RSSI 落在 -70 到 -90dBm 区间才更接近真实使用场景。4.3 参数配对对照表SF、BW、CRC、Preamble 四要素回环中最常见的问题是改了一端参数忘了另一端。下面的表列了必须保持一致的四个要素每次改参数都照着核对一遍参数发送端接收端不一致的后果SF1212接收端检测不到前导码BW125kHz125kHz频谱失配解码失败CRC开开收包被丢弃统计不到Preamble88短包前导码识别超时CRC 这个坑最隐蔽。LoRa 的 CRC 是在物理层做的如果发送端开了 CRC 而接收端没开接收端能解出数据但上层协议可能收到错包反过来发送端没开 CRC 而接收端开了接收端会直接丢包。SX1268 的裸 radio 测试里我一定会在 RadioSetRxConfig 和 RadioSetTxConfig 里保持 CRC 的开关状态一致。4.4 把回环固化成自测函数后续改驱动不用反复手敲命令每次改完 board.c 或更新封装库后都要重新验证一次驱动没被改坏。我会把回环测试做成一个独立的自测函数编译时用一个宏开关控制方便随时调用。/* 自测函数周期发送并统计收包成功率 */ void RadioLoopbackTest(uint32_t count) { uint32_t ok 0, fail 0; for (uint32_t i 0; i count; i) { RadioSend(test, 4); if (RadioGetPacketStatus(st) 0) ok; else fail; HAL_Delay(100); } debug_log(loopback ok%d fail%d\n, ok, fail); }这个函数没有依赖 LoRaWAN 状态机只要驱动层 SPI 通、DIO1 中断通它就能跑。如果这个自测都过不了就别急着去查 LoRaMac 协议栈的入网问题回头先把驱动层修好。这类“小步验证”的习惯能省下大量无效调试时间。5. SX1268 驱动调试避坑五个现场案例与排查顺序5.1 现象一初始化卡死LoRaMac 停在等待 BUSY现象程序烧进去后板子没有任何输出调试器看到代码卡在 WaitRadioBusy 的 while 循环里不退出。原因最常见的是 BUSY 引脚配置错误。很多国产模块的 BUSY 是开漏输出MCU 那边必须配置为上拉输入如果配成了推挽输出两者会互相打架电平永远拉不低。也有的是 RESET 时序没有满足芯片根本没完成复位。解决先断开所有线用示波器看 BUSY 引脚在复位后的波形确认 MCU 的 GPIO 模式为输入上拉把 RESET 拉低 5ms 再拉高等待 10ms 再调 SPI。最后用 SX126xGetStatus 读取状态寄存器能读到正常返回码再往下走。5.2 现象二DIO1 中断不触发发送完成后主循环干等现象RadioSend 执行后DIO1 引脚没有产生任何电平变化协议栈一直停在发送未完成状态。原因SX1268 的中断事件没有映射到 DIO1。radio 层初始化时有一段代码负责设置 DIO IRQ 掩码如果这段被跳过或参数写错芯片内部已经完成发送但不会通过 DIO1 通知 MCU。解决重新调用 RadioSetDioIrqParams把 TX_DONE、RX_DONE、RX_TIMEOUT 这几个关键事件使能。代码形式类似这样/* 把发送完成和接收完成事件映射到 DIO1 */ RadioSetDioIrqParams(SX126X_IRQ_TX_DONE | SX126X_IRQ_RX_DONE | SX126X_IRQ_RX_TIMEOUT, SX126X_IRQ_TX_DONE | SX126X_IRQ_RX_DONE | SX126X_IRQ_RX_TIMEOUT);5.3 现象三发送成功但接收端报 CRC 错误现象回环测试中接收端的中断里能读到 RX_DONE但读取 packet status 时 CRC 状态是错的上层收不到完整包。原因收发双方的 CRC 开关不一致或者 Preamble 长度不匹配。还有一种情况是 SX1268 处于可变长度包模式而发送端用了固定长度模式导致接收端在解析长度字段时错乱。解决对照 4.3 节的参数表逐项核对。把两端都设为固定长度模式长度值保持一致CRC 开关都打开Preamble 设成同一个值。改完再测如果还报 CRC 错误用示波器抓 SPI 命令确认发送端的 CRC 配置命令确实写进去了。5.4 现象四模块进入睡眠后再唤醒第一包数据发不出去现象低功耗产品在定时唤醒后LoRaMac 状态机恢复但 RadioSend 调用后没有 TX_DONE 中断整个系统像被冻住。原因SX1268 从 Sleep 模式唤醒后射频前端的状态寄存器没有恢复到工作模式调制参数、频点、包配置可能处于复位后的默认值。协议栈的定时器虽然唤醒了 MCU但 radio 的上下文没有重建。解决唤醒后先调用 RadioSetTxConfig 和 RadioSetRfFrequency 重新初始化再执行发送。更稳妥的做法是在进 Sleep 前把整个 radio 上下文保存下来唤醒后按顺序恢复。不要在唤醒后直接调用 RadioSend寄存器里残留的无意义数据会造成发射异常。5.5 现象五串口日志乱码或第一行日志缺失现象驱动正常入网也能成功但串口打印出来的调试信息是乱码或者前几行日志被吞掉。原因board.c 里的系统时钟没有按实际晶振配置串口波特率对不上也有的是 printf 重定向没有实现导致 LoRaMac-node 内部打印走了默认的 semihosting 方式。解决先确认板级时钟树外部晶振是 8MHz 还是 25MHz 都要写进时钟初始化里。把串口改为直接调用 HAL_UART_Transmit 实现的 debug 输出函数不走半主机模式。日志的问题虽然不影响无线链路但会把协议栈状态机观察渠道堵死排查问题时非常吃亏。6. 现场回归的最后一步24 小时连续对打验证套路把协议栈调通、入网成功、回环测完还不能直接交付。我自己的习惯是做一个 24 小时连续对打验证把两个 SX1268 模块放在实际安装位置一个做终端一个做简易网关跑一整夜看数据。验证的核心指标不是单包成功率而是长时间运行时有没有“假死”。LoRaMac 的定时器依赖 MCU tick如果 tick 溢出或中断优先级配置不当连续运行几小时后会出现协议栈不调度的情况。具体做法终端每秒发一包 12 字节的非确认数据网关端记录每秒是否收到每 10 分钟汇总一次成功率、平均 RSSI、丢包次数。日志里一旦看到连续 10 包以上丢失就停下来抓现场。这个压力比真实业务场景大很多真实业务可能一分钟才发一包每秒一包能把驱动层的资源竞争问题提前暴露出来。除了可靠性还要看频率漂移。连续发射会让 SX1268 的晶振升温如果模块没有 TCXO频点会逐渐偏离。对打日志里的 RSSI 会缓慢下降然后突然恢复到正常这种周期性的波动多半是晶振温漂。用 24 小时数据画一条曲线比单次测试更能说明问题。我早年调 SX1268 时吃过一次亏回环测试只跑了半小时就以为没问题结果产线连续工作了 5 个小时后终端开始频繁掉线原因就是 DIO1 中断和 LoRaMac 定时器中断优先级配置不当长时间运行后中断嵌套累积导致接收窗口错过。后来把验证时间拉长到 24 小时这类问题基本都能暴露出来。做长测时日志要带上时间戳不能用 “RSSI-70” 这种无上下文输出。将场景、功率、SF、日志间隔都固定下来复现问题才能有的放矢。希望这篇笔记能帮你少走几步弯路把时间留给真正难缠的射频问题。本文还有配套的精品资源点击获取