📡 ESP32 LoRa 无线通信:SX1278 远距离数据传输实战

2026-05-23 · 硬件编程 · 阅读时间 12 分钟

📺 B站推荐视频:ESPLoRa 低成本LoRa网关制作 | 颜七岁er · Arduino开发 · 毕设必备

📖 概述:什么是 LoRa?

LoRa(Long Range)是一种低功耗广域网(LPWAN)无线通信技术,由 Semtech 公司开发。它能在城市环境 2~5 km、郊区 10~15 km 的范围内传输数据,同时功耗极低——一节电池能让传感器节点工作数年。

SX1278 是 Semtech 的 LoRa 射频收发芯片,工作在 433 MHz 频段(中国允许的 ISM 频段),通过 SPI 接口与 ESP32 通信。你只需要两个 ESP32 + 两个 SX1278 模块,就能搭建一套点对点远距离通信系统。

应用场景:智慧农业(田间传感器→基站)、环境监测(河流/森林数据回传)、远程抄表、无人机数传、户外探险定位等。

💡 前置知识:本教程假设你已经熟悉 ESP32 的 Arduino 开发环境配置。如果还没有,请参考往期「ESP32 环境搭建」教程。
联动课程:上节课我们学了 MQTT 物联网上云——今天学完 LoRa 后,你可以把 LoRa 接收端的数据通过 MQTT 推送到云端,实现「远距离传感器→LoRa→ESP32网关→WiFi→MQTT→云端」的完整链路!

🛒 物料清单

物料型号/参数数量参考价格
ESP32 开发板ESP32-WROOM-32(CH340 版)2¥18~25/个
LoRa 模块SX1278(Ra-02),433 MHz2¥12~18/个
弹簧天线433 MHz,SMA 接口2¥2~4/个
杜邦线母对母,20 cm14 条¥3/组
面包板830 孔2¥5~8/个
DHT22 温湿度传感器可选(用于实战场景)1¥6~9/个
OLED 显示屏SSD1306 0.96寸 I2C1¥8~12/个

🔌 接线图

┌──────────────────────────────────────────────────────┐
│            ESP32 ←→ SX1278 (Ra-02) 引脚连接            │
├────────────┬─────────────────────────────────────────┤
│  ESP32     │  SX1278 (Ra-02)        说明              │
├────────────┼─────────────────────────────────────────┤
│  3.3V      │  VCC (3.3V)           供电(勿接5V!)  │
│  GND       │  GND                  共地               │
│  GPIO5     │  SCK                  SPI 时钟            │
│  GPIO18    │  MISO                 SPI 主入从出         │
│  GPIO23    │  MOSI                 SPI 主出从入         │
│  GPIO14    │  NSS (CS)             SPI 片选            │
│  GPIO2     │  RST (RESET)          复位引脚(可接3.3V)  │
│  GPIO26    │  DIO0                 中断引脚             │
├────────────┴─────────────────────────────────────────┤
│  注意:SX1278 是 3.3V 器件,绝对不能接 5V!          │
│  模块上的 ANT 引脚焊接 SMA 座或直接焊弹簧天线。           │
└──────────────────────────────────────────────────────┘
🔧 接线验证:上电后用万用表测 SX1278 的 VCC 引脚,确认是 3.3V ± 0.1V。如果模块发热异常,立即断电检查是否有短路。
天线警告:未接天线时切勿长时间发送数据——射频能量无法辐射出去会反射回功放,可能烧毁 SX1278 芯片!

💻 基础代码:点对点通信

发送端每隔 3 秒发送一条 "Hello from ESP32 #1 — packet: N",接收端收到后打印并通过板载 LED 闪烁确认。

// ========== 发送端 (Sender) ==========
#include <SPI.h>
#include <LoRa.h>

#define SS      14
#define RST     2
#define DIO0    26
#define FREQ    433E6   // 433 MHz

int packetCounter = 0;

void setup() {
  Serial.begin(115200);
  delay(1000);
  Serial.println("🚀 LoRa Sender 启动中...");

  LoRa.setPins(SS, RST, DIO0);
  if (!LoRa.begin(FREQ)) {
    Serial.println("❌ LoRa 初始化失败!检查接线");
    while (1);
  }
  LoRa.setSpreadingFactor(7);   // SF7 = 最快
  LoRa.setSignalBandwidth(125E3); // 125 kHz
  LoRa.setCodingRate4(5);         // 4/5
  Serial.println("✅ LoRa 初始化成功!");
}

void loop() {
  char msg[64];
  sprintf(msg, "Hello #%d | RSSI将在接收端显示", packetCounter);

  LoRa.beginPacket();
  LoRa.print(msg);
  LoRa.endPacket();

  Serial.printf("📤 发送 #%d: %s\n", packetCounter, msg);
  packetCounter++;
  delay(3000);
}
// ========== 接收端 (Receiver) ==========
#include <SPI.h>
#include <LoRa.h>

#define SS      14
#define RST     2
#define DIO0    26
#define FREQ    433E6
#define LED     2  // 板载 LED

void setup() {
  Serial.begin(115200);
  pinMode(LED, OUTPUT);
  digitalWrite(LED, LOW);
  delay(1000);
  Serial.println("📡 LoRa Receiver 启动中...");

  LoRa.setPins(SS, RST, DIO0);
  if (!LoRa.begin(FREQ)) {
    Serial.println("❌ LoRa 初始化失败!");
    while (1);
  }
  LoRa.setSpreadingFactor(7);
  LoRa.setSignalBandwidth(125E3);
  LoRa.setCodingRate4(5);
  Serial.println("✅ 等待数据...");
}

void loop() {
  int packetSize = LoRa.parsePacket();
  if (packetSize == 0) return;

  // 读取数据
  char buf[128] = {0};
  int i = 0;
  while (LoRa.available() && i < 127) {
    buf[i++] = (char)LoRa.read();
  }
  buf[i] = '\0';

  // 获取信号质量
  int rssi = LoRa.packetRssi();
  float snr = LoRa.packetSnr();

  Serial.printf("📥 收到: %s | RSSI:%d dBm | SNR:%.1f dB\n",
                  buf, rssi, snr);

  // LED 闪烁确认
  digitalWrite(LED, HIGH); delay(100);
  digitalWrite(LED, LOW);
}
🔑 LoRa 关键参数说明:
· Spreading Factor(SF,扩频因子):SF7~SF12。SF7 最快距离最短,SF12 最慢距离最远。速率每增加 1,空中时间翻倍。
· Bandwidth(带宽):125 kHz / 250 kHz / 500 kHz。带宽越大速率越快,但灵敏度越低。
· Coding Rate(编码率):4/5、4/6、4/7、4/8。分子是有效数据,分母是总数据。4/8 抗干扰最强但有效数据仅一半。
· 频率一致性:发送端和接收端的频率、SF、BW、CR 必须完全一致,否则收不到!

🚀 进阶应用

1. 双向通信:发送端也能收确认

LoRa 模块是半双工的——同一时刻只能发或收。你可以在发送后立即切换到接收模式等待 ACK:

// 发送后等待确认
LoRa.beginPacket();
LoRa.print("DATA:26.5,65.2");
LoRa.endPacket(true);  // true = 发送完后立即进入接收模式

// 等待 500ms 内的 ACK
unsigned long start = millis();
while (millis() - start < 500) {
  if (LoRa.parsePacket()) {
    String ack = LoRa.readString();
    if (ack == "ACK") {
      Serial.println("✅ 收到确认");
      break;
    }
  }
}

2. 多节点组网:星型拓扑

一个接收端(网关)监听多个发送端(节点)。每个节点在消息中带上自己的 ID,网关根据 ID 区分来源:

// 节点端 — 带 ID 发送
#define NODE_ID 3
char msg[64];
sprintf(msg, "NODE:%d|T:%.1f|H:%.1f", NODE_ID, temp, hum);
LoRa.beginPacket();
LoRa.print(msg);
LoRa.endPacket();

// 网关端 — 解析来源
String payload = LoRa.readString();
int nodeId;
float temp, hum;
sscanf(payload.c_str(), "NODE:%d|T:%f|H:%f", &nodeId, &temp, &hum);
Serial.printf("节点%d → 温度%.1f°C 湿度%.1f%%\n", nodeId, temp, hum);
⚠️ 多节点碰撞问题:LoRa 没有内置 CSMA/CA(载波监听)。两个节点同时发送时会发生碰撞,数据丢失。简单的解决方案是让节点用随机延迟发送,或使用 LoRaWAN 协议的 ALOHA 机制。生产环境建议使用随机的发送间隔(如 3~5 秒随机)。

🏭 实战场景

场景一:远程温湿度监测站(联动 DHT22 + MQTT)

场景描述:你在楼顶放置一个 ESP32+LoRa+DHT22 的太阳能供电节点,室内放另一个 ESP32+LoRa 作为网关。网关收到数据后通过 WiFi+MQTT 推送到手机 App,足不出户就能看到楼顶的实时温湿度。

物料组合:发送端:ESP32 + SX1278 + DHT22 + 锂电池;接收端:ESP32 + SX1278 + OLED 显示屏

数据流:DHT22 → ESP32-Sender → LoRa → ESP32-Gateway → WiFi → MQTT Broker → 手机 App

联动已学模块:结合 5月22日的 MQTT 教程,在网关端的 loop() 中收到 LoRa 数据后调用 client.publish("home/rooftop", payload) 即可完成数据上云。

场景二:户外探险队位置共享

场景描述:徒步小队成员每人携带一个 ESP32+LoRa+GPS(NEO-6M) 口袋节点,队长的设备作为网关+显示屏。所有成员的位置每 5 秒通过 LoRa 汇集到队长屏幕,超出范围自动提醒。

物料组合:每人:ESP32 + SX1278 + NEO-6M GPS;队长额外:OLED 显示屏

LoRa 参数建议:户外空旷环境用 SF12 + 125kHz,可获得最佳通信距离(理论 > 5km)。

⚠️ 常见问题与踩坑指南

❌ 问题1:接收端完全收不到任何数据
原因排查(按顺序):
① 发送和接收的频率、SF、BW、CR 必须完全一致——最常见的错误是两端频率不同(433 vs 868 vs 915 MHz);
未接天线——SX1278 没有内置天线,必须外接,否则通信距离不到 50 cm;
③ SPI 引脚接错——用 LoRa.begin() 返回值检查初始化是否成功;
④ 供电不足——SX1278 发射瞬间电流可达 120 mA,不要用 USB-TTL 的 3.3V 供电。
❌ 问题2:近距离能收到,超过 10 米就断
原因:天线不匹配或焊接不良。SX1278 Ra-02 模块通常需要自己焊弹簧天线或 SMA 座。焊点虚焊、天线谐振频率偏差都会导致距离骤降。
解决:确保天线焊点饱满光亮;弹簧天线的螺旋部分悬空,不要贴着金属或PCB;有条件的话用驻波表测试天线匹配。
❌ 问题3:SX1278 模块发烫
原因:最常见是 5V 直接供电——SX1278 是 3.3V 器件,接了 5V 会立即烧毁或过热。另一个可能是天线未接导致功放级发热。
解决:立即断电!确认 VCC 接的是 ESP32 的 3.3V 引脚,不是 5V(Vin/VUSB)。如果模块已烧毁,更换后务必先测电压再上电。
❌ 问题4:LoRa.h 库编译报错 "multiple definition" 或找不到头文件
解决:使用 Sandeep Mistry 的 LoRa 库(Arduino Library Manager 搜索 "LoRa" by Sandeep Mistry,版本 0.8.0+)。不要同时安装多个 LoRa 库(如 RadioLib 和 LoRa 库可能冲突)。如果已安装多个,在 ~/Arduino/libraries/ 目录中删除多余的。