0x6A Logbook

0x6A Logbook
Shi6a的筆記本
  1. 首頁
  2. 程式開發
  3. 正文

LoRa 長距離通訊完整教學:從 ESP32 + SX1278 到 LoRaWAN 協定實作

2026 年 6 月 12 日 7點熱度 0人點贊 0條評論

LoRa 是什麼?

LoRa 長距離通訊是 IoT 領域最重要的 LPWAN(低功耗廣域網路)技術之一。LoRa 以極低的功耗提供數公里級的通訊距離,使其成為智慧城市、農業監控、工業感測網路等場景的首選方案。

IoT 無線技術比較 距離 vs 速率

從上圖可以看到,LoRa 在通訊距離上遙遙領先 WiFi 和 BLE,同時功耗極低,一顆電池可工作數年。代價是傳輸速率低(0.3~50 kbps),但對 IoT 感測器來說已經足夠。

LoRa 技術原理

LoRa 的核心是 CSS(Chirp Spread Spectrum,線性調頻展頻) 調變技術:

  • Chirp:頻率隨時間線性變化的訊號(向上 = up-chirp,向下 = down-chirp)
  • 展頻增益:訊號在寬頻譜上擴散,對抗干擾和都卜勒效應
  • SF(Spreading Factor):展頻因子(7~12),SF 越高 → 距離越遠、速率越慢
  • BW(Bandwidth):頻寬(125/250/500 kHz),BW 越高 → 速率越快、靈敏度越低

LoRa 調變的關鍵參數關係:

符碼率 Rs = BW / 2^SF
位元率 Rb = SF × Rs × (4 / (4 + CR))

範例(SF=12, BW=125kHz, CR=1):
Rs = 125000 / 4096 ≈ 30.5 symbols/s
Rb = 12 × 30.5 × 0.8 ≈ 293 bps

LoRa 封包格式

LoRa 封包結構

LoRa 封包由三個部分組成:

  • Preamble(前導碼):一串連續的 up-chirp,接收端用於檢測訊號到來並同步時脈。長度可設定(6~65535 symbols),預設 8 個 symbols。
  • SFD(Start Frame Delimiter):固定模式的 down-chirp,標示前導碼結束和資料開始。
  • PHDR(實體層標頭)+ PHDR_CRC:包含 Payload 長度、編碼率、CRC 啟用等資訊(僅在隱式模式下可省略)
  • Payload:實際資料(最大 255 bytes)
  • Payload CRC:16-bit CRC 錯誤檢測

LoRaWAN 通訊協定

LoRa 是實體層調變技術,LoRaWAN 是建立在其上的 MAC 層通訊協定,由 LoRa Alliance 標準化。

裝置類型

Class 說明 下行時機 功耗
Class A 所有 LoRaWAN 裝置必備 上行後開啟 RX1/RX2 視窗 最低
Class B 增加 Beacon 定期接收視窗 Beacon 時間槽 中等
Class C 持續監聽下行 隨時 最高

實務上 90% 的 IoT 感測器使用 Class A:裝置發送上行資料 → 開啟 RX1(1 秒後)和 RX2(2 秒後)視窗接收伺服器回應 → 回到睡眠。

OTAA 啟用流程

裝置加入 LoRaWAN 網路有兩種方式:OTAA(Over-The-Air Activation)和 ABP(Activation By Personalization)。OTAA 是推薦方式:

LoRaWAN OTAA 啟用流程

  1. Join Request:裝置廣播 Join Request,包含 DevEUI(裝置唯一 ID)、AppEUI(應用唯一 ID)、DevNonce(隨機數)
  2. Gateway 轉發:LoRa Gateway 收到後透過 TCP/IP 轉發到 Network Server
  3. Network Server 驗證:檢查 DevNonce 是否重複,用 AppKey 計算 MIC 驗證完整性
  4. Join Accept:Server 回傳 AppNonce、NetID、DevAddr、RX 參數等,使用 AppKey 加密
  5. 裝置解密:裝置用 AppKey 解密 Join Accept,取得 DevAddr 和 Session Keys(NwkSKey + AppSKey)

ESP32 + SX1278 硬體接線

SX1278 ESP32 說明
3.3V 3.3V 電源(注意電流 > 100mA)
GND GND 共地
NSS GPIO 5 SPI Chip Select
SCK GPIO 18 SPI 時脈
MOSI GPIO 23 SPI 資料輸入
MISO GPIO 19 SPI 資料輸出
DIO0 GPIO 2 中斷(封包接收完成)
RST GPIO 14 重置(低電位觸發)

SX1278 SPI 暫存器讀寫時序

Arduino 程式碼:LoRa 點對點通訊

使用 LoRa.h 函式庫(基於 SX1278),最簡單的發送與接收範例:

// ESP32 LoRa 發送端(Sender)
#include 
#include 

// SPI 腳位定義(ESP32 預設 VSPI)
#define SS    5
#define RST   14
#define DIO0  2

void setup() {
    Serial.begin(115200);

    LoRa.setPins(SS, RST, DIO0);

    if (!LoRa.begin(915E6)) {  // 頻率:915 MHz(北美)/ 868 MHz(歐盟)/ 923 MHz(亞洲)
        Serial.println("LoRa 初始化失敗");
        while (1);
    }

    LoRa.setSpreadingFactor(12);    // SF12:最遠距離
    LoRa.setSignalBandwidth(125E3); // BW 125 kHz
    LoRa.setCodingRate4(5);         // CR = 4/5
    LoRa.setTxPower(20);            // 發射功率 20 dBm(最大值)

    Serial.println("LoRa Sender 啟動");
}

void loop() {
    float temp = 25.0 + random(-50, 50) / 10.0;
    float hum  = 60.0 + random(-30, 30) / 10.0;

    LoRa.beginPacket();
    LoRa.print("TEMP:");
    LoRa.print(temp, 1);
    LoRa.print(",HUM:");
    LoRa.print(hum, 1);
    LoRa.endPacket();

    Serial.printf("已發送:T=%.1f H=%.1f\n", temp, hum);
    delay(60000);  // 每分鐘發送一次
}
// ESP32 LoRa 接收端(Receiver)
#include 

void setup() {
    Serial.begin(115200);
    LoRa.setPins(5, 14, 2);

    if (!LoRa.begin(915E6)) {
        Serial.println("LoRa 初始化失敗");
        while (1);
    }

    LoRa.setSpreadingFactor(12);
    LoRa.setSignalBandwidth(125E3);
    LoRa.setCodingRate4(5);

    Serial.println("LoRa Receiver 啟動,等待資料...");
}

void loop() {
    int packetSize = LoRa.parsePacket();
    if (packetSize) {
        String data = "";
        while (LoRa.available()) {
            data += (char)LoRa.read();
        }

        int rssi = LoRa.packetRssi();
        float snr = LoRa.packetSnr();

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

使用 LoRaWAN 協定(MCCI LoRaWAN Library)

若使用 LoRaWAN 協定(需註冊 TTN / ChirpStack),程式碼如下:

// ESP32 LoRaWAN Class A 範例(MCCI LoRaWAN 函式庫)
#include 
#include <hal/hal.h>
#include 

// OTTA 憑證(來自 TTN Console)
static const u1_t PROGMEM APPEUI[8]  = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
static const u1_t PROGMEM DEVEUI[8]  = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
static const u1_t PROGMEM APPKEY[16] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
                                          0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };

void os_getArtEui (u1_t* buf) { memcpy_P(buf, APPEUI, 8); }
void os_getDevEui (u1_t* buf) { memcpy_P(buf, DEVEUI, 8); }
void os_getDevKey (u1_t* buf) { memcpy_P(buf, APPKEY, 16); }

// SPI 腳位
const lmic_pinmap lmic_pins = {
    .nss = 5,
    .rxtx = LMIC_UNUSED_PIN,
    .rst = 14,
    .dio = {2, LMIC_UNUSED_PIN, LMIC_UNUSED_PIN},
};

static uint8_t txData[] = "Hello LoRaWAN!";
static osjob_t sendjob;

void do_send(osjob_t* j) {
    if (LMIC.opmode & OP_TXRXPEND) {
        Serial.println("上一個傳送還未完成");
    } else {
        LMIC_setTxData2(1, txData, sizeof(txData)-1, 0);
        Serial.println("傳送中...");
    }
    os_setTimedCallback(&sendjob, os_getTime() + sec2osticks(60), do_send);
}

void onEvent(ev_t ev) {
    switch (ev) {
        case EV_JOINED:
            Serial.println("已加入 LoRaWAN 網路");
            LMIC_setLinkCheckMode(0);
            break;
        case EV_TXCOMPLETE:
            Serial.println("傳送完成");
            if (LMIC.dataLen) {
                Serial.printf("收到下行: %s\n", LMIC.frame + LMIC.dataBeg);
            }
            break;
        default:
            break;
    }
}

void setup() {
    Serial.begin(115200);
    LMIC_reset();
    LMIC_startJoining();
    do_send(&sendjob);
}

void loop() {
    os_runloop_once();
}

LoRa 參數調校指南

場景 SF BW CR TP (dBm) 範圍 空傳時間
極遠距離 12 125 4/5 20 ~15 km ~2.3s (51 bytes)
平衡 9 125 4/5 17 ~5 km ~0.3s
高速 7 250 4/8 14 ~1 km ~0.04s

天線設計注意事項

  • 匹配阻抗:SX1278 輸出阻抗 50Ω,天線也須 50Ω
  • 天線長度:λ/4 單極天線最簡單(915MHz → ~8.2cm,868MHz → ~8.6cm)
  • 地平面:單極天線需要接地平面,PCB 上預留足夠面積
  • SWR 測試:使用網路分析儀調整匹配網路(L/C 元件)
  • 法規限制:各國對 ISM 頻段發射功率有不同規定(台灣 915MHz ≤ 1W EIRP)

LoRa vs 其他 IoT 通訊技術

特性 LoRa/LoRaWAN NB-IoT Sigfox WiFi BLE
頻段 Sub-GHz ISM LTE 授權頻段 Sub-GHz ISM 2.4/5 GHz 2.4 GHz
範圍(市區) 2~5 km 1~3 km 3~10 km ~50 m ~100 m
資料速率 0.3~50 kbps ~200 kbps ~100 bps Mbps~Gbps ~2 Mbps
電池壽命 ~10 年 ~5 年 ~10 年 數天~數週 數月
雙向 ✓(受限) ✓ ✗(上行為主) ✓ ✓
建置成本 低(自建 Gateway) 高(需 SIM) 中(年費) 低 低
適合場景 感測器網路 車聯網、電表 極簡感測器 串流、網頁 穿戴裝置

實務經驗:LoRa 通訊距離測試

// LoRa 距離測試 — 持續發送 RSSI 封包
void loop() {
    LoRa.beginPacket();
    LoRa.print("RSSI_TEST");
    LoRa.endPacket();

    delay(5000);

    // 每秒檢查是否收到回應
    if (LoRa.parsePacket()) {
        Serial.printf("收到回應 | RSSI: %d SNR: %.1f\n",
                      LoRa.packetRssi(), LoRa.packetSnr());
    }
}

實測結果(SF12, BW125, 20dBm, 空曠環境):

  • 500m:RSSI -85~-95 dBm,SNR 8~12 dB(穩定連線)
  • 1km:RSSI -100~-110 dBm,SNR 5~8 dB(偶爾掉封包)
  • 2km:RSSI -115~-125 dBm,SNR 0~3 dB(需重傳機制)
  • 5km:RSSI -130 dBm 以下,僅視距可見時可收到

總結

LoRa 以極低的功耗和遠距離通訊能力,成為 IoT 感測器網路的首選方案。ESP32 + SX1278 的組合提供了完整的 LoRa 節點實作路徑,從簡單的點對點通訊到 LoRaWAN 協定都能勝任。

選擇建議:

  • 簡單原型:使用 LoRa.h 函式庫做點對點通訊
  • 正式部署:使用 MCCI LoRaWAN 函式庫 + TTN / ChirpStack
  • 高容量場景:LoRaWAN Class B/C + 多 Gateway 部署
標籤: 教學
最後更新:2026 年 6 月 12 日

shi6a

這個人很懶,什麼都沒留下

點贊
< 上一篇

文章評論

razz evil exclaim smile redface biggrin eek confused idea lol mad twisted rolleyes wink cool arrow neutral cry mrgreen drooling persevering
取消回覆

COPYRIGHT © 2026 0x6A Logbook. ALL RIGHTS RESERVED.

Theme Kratos Made By Seaton Jiang