
LoRa 是什麼?一句話:拿速率換距離,而且換得很兇
如果你只想要「一顆電池撐好幾年、資料送到幾公里外」,那 LoRa 幾乎是標準答案。它是 LPWAN(低功耗廣域網路)裡最紅的技術之一,智慧城市、農業監控、工業感測網路都在用。
先講清楚它的取捨:LoRa 用很低的速率(0.3~50 kbps)換到數公里的距離,同時功耗低到可以撐數年。對一個每分鐘才回報一次溫度的感測器來說,這個速率完全夠用 —— 反正你也不需要用它來看影片。
我自己第一次接觸時最驚訝的不是距離,而是它居然可以在沒有電信商的情況下自己架網路。這件事在後面談到 LoRaWAN 時會變得很關鍵。
LoRa 技術原理:核心是 CSS,不是「低頻訊號」
很多人以為 LoRa 傳得遠是因為頻率低。不是,關鍵是調變方式:CSS(Chirp Spread Spectrum,線性調頻展頻)。
它的做法是把一小段資料攤開到很寬的頻譜上(展頻),代價是速率變慢,好處是抗干擾、抗都卜勒效應。四個你一定要記住的參數:
- Chirp:頻率隨時間線性變化的訊號(往上掃 = up-chirp,往下掃 = down-chirp)
- 展頻增益:訊號攤在寬頻譜上,對抗干擾與都卜勒效應
- SF(Spreading Factor):展頻因子(7~12),SF 越高 → 距離越遠、速率越慢
- BW(Bandwidth):頻寬(125/250/500 kHz),BW 越高 → 速率越快、靈敏度越低
這兩個參數的關係可以直接算出來,公式就這三行:
符碼率 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
看到那個 293 bps 了嗎?SF12 加上 125 kHz,速率就是這麼低。但換來的是最遠的距離 —— 這筆交易划不划算是你自己決定的。
LoRa 封包格式:前導碼在幫你「對時脈」
封包長得像這樣,五段各司其職:

整串資料裡,最容易被忽略但最重要的是 Preamble(前導碼):它是一串連續的 up-chirp,接收端靠它偵測「有訊號來了」並且同步時脈。前導碼預設 8 個 symbols(長度可設 6~65535)。
接著 SFD 用一個固定模式的 down-chirp 宣告「前導碼結束、資料開始」。後面才是 PHDR + PHDR_CRC(帶 Payload 長度、編碼率、CRC 是否啟用)、Payload(最大 255 bytes)與 Payload CRC(16-bit 錯誤檢測)。
實務上我會這樣看:PHDR 只有隱式模式才能省掉,而省掉它你就得自己保證兩邊參數完全一致 —— 除非你在壓那幾個 byte,不然別自找麻煩。
LoRaWAN 通訊協定:LoRa 是實體層,LoRaWAN 才是規矩
這裡一定要分清楚:LoRa 只是調變技術(實體層),LoRaWAN 是蓋在它上面的 MAC 層協定,由 LoRa Alliance 標準化。你自己拿兩顆 SX1278 對傳叫做「LoRa 點對點」,那不叫 LoRaWAN。
裝置類型
LoRaWAN 把裝置分成三類,差別只有一件事:什麼時候醒著聽下行。
| Class | 說明 | 下行時機 | 功耗 |
|---|---|---|---|
| Class A | 所有 LoRaWAN 裝置必備 | 上行後開啟 RX1/RX2 視窗 | 最低 |
| Class B | 增加 Beacon 定期接收視窗 | Beacon 時間槽 | 中等 |
| Class C | 持續監聽下行 | 隨時 | 最高 |
實務上九成的感測器都是 Class A:送完上行資料 → 開 RX1(上行後 1 秒)和 RX2(2 秒)兩個視窗 → 收完就回睡眠。它的下載反應慢,但省電到極致。如果你的應用需要「伺服器隨時叫你」,那你要付的代價就是電。
OTAA 啟用流程
裝置要加入網路有兩種方式:OTAA(Over-The-Air Activation)和 ABP(Activation By Personalization)。沒有懸念,用 OTAA —— ABP 是把 Session Key 直接寫死在程式裡,裝置遺失或被複製就是安全問題,而且換金鑰得一台一台重燒。

流程拆開來看是這樣:
- Join Request:裝置廣播,內容包含 DevEUI(裝置唯一 ID)、AppEUI(應用唯一 ID)與 DevNonce(隨機數)
- Gateway 轉發:LoRa Gateway 收到後,透過 TCP/IP 轉發給 Network Server
- Network Server 驗證:檢查 DevNonce 是否重複,並用 AppKey 計算 MIC 驗證完整性
- Join Accept:Server 回傳 AppNonce、NetID、DevAddr 與 RX 參數,並用 AppKey 加密
- 裝置解密:裝置用 AppKey 解開 Join Accept,取得 DevAddr 與 Session Keys(NwkSKey + AppSKey)
DevNonce 那個「不能重複」的規則很容易踩:如果你每次重開機都拿到同一組 DevNonce,Server 會直接拒絕你。所以別把 DevNonce 寫死,也別在重開機後從頭數。
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 | 重置(低電位觸發) |
幾個我會特別提醒的地方:DIO0 接 GPIO 2 當中斷源,這樣封包收完它會直接通知你,不用在 loop 裡一直問「收到了沒」。另外 3.3V 那條線不能省 —— SX1278 發射瞬間的電流會超過 100 mA,用開發板上的 LDO 硬撐,很容易遇到「近距離正常、一加大功率就重置」的怪現象。
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); // 每分鐘發送一次
}
設定那幾行值得多看一眼:SF12 + BW 125 kHz + CR 4/5 + 20 dBm,這是「最遠距離」的組合,代價就是速率慢、空傳時間長(下一節會算給你看)。
然後是接收端 —— 重點是它會回報 RSSI 與 SNR,這兩個數字是你在調天線跟判斷距離時唯一的依據:
// 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)
如果你想接 TTN 或 ChirpStack,就得走 LoRaWAN,程式碼會變成事件驅動的寫法:
// 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();
}
這段跟前面的差別不只是「換一套函式庫」:LoRaWAN 把「什麼時候可以發送」的決定權交給了 LMIC 與伺服器。你的工作變成處理事件(EV_JOINED、EV_TXCOMPLETE),而不是自己數 delay。一開始會覺得彆扭,但這正是它能跟別人的網路共存的理由。
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 |
我自己調參數的順序是:先決定要多遠,再決定要多快,最後才看空傳時間。極遠距離那組的 51 bytes 要佔掉 2.3 秒的無線電時間,這在佔空比有法規限制的地區(例如歐盟的 1%)會非常痛。
天線設計注意事項:這是最容易被當成「玄學」的一段
先講結論:天線是類比電路,不是插上去就會動的零件。幾個關鍵:
- 匹配阻抗:SX1278 輸出阻抗 50Ω,天線也必須是 50Ω,不匹配就是功率反射
- 天線長度:λ/4 單極天線最簡單(915 MHz → 約 8.2 cm,868 MHz → 約 8.6 cm)
- 地平面:單極天線需要接地平面,PCB 上要預留足夠面積
- SWR 測試:用網路分析儀調整匹配網路(L/C 元件),不要憑感覺換電容
- 法規限制:各國對 ISM 頻段的發射功率規定不同(台灣 915 MHz ≤ 1W EIRP)
我個人的看法是:花在 SWR 上的時間,報酬率遠高於換一顆更貴的模組。天線沒調好,你在軟體上怎麼調參數都是在補洞。
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 的位置很明確 —— 免費頻段加自建 Gateway,代價是速率低、而且你得自己維運。要雙向又懶得顧網路,那 NB-IoT 走電信商更省事,只是成本高。
實務經驗:LoRa 通訊距離測試
參數講再多,不如實際量一次。下面這段程式就是持續發送測試封包,並把 RSSI 印出來:
// 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、20 dBm、空曠環境。結果長這樣:
- 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 以下,僅視距可見時可收到

這張圖給我的結論是:500 公尺到 2 公里之間,才是 LoRa 真正好用的區間。超過 2 公里,SNR 已經掉到 0~3 dB,你必須在協定層加上重傳與確認機制;5 公里那種數字是「視距可見 + 天線調好」才成立的實驗室成績,市區不要當常態。
總結
LoRa 用極低功耗換到數公里通訊距離,配合 ESP32 + SX1278,從點對點到 LoRaWAN 都有一條完整的實作路徑。整篇的重點收斂成四句:
- 原理:CSS 展頻,SF 越高越遠越慢,BW 越高越快越不靈敏
- 協定:LoRa 是實體層,LoRaWAN 是 MAC 層;用 OTAA,裝置用 Class A
- 調校:先決定距離,再決定速率,最後才看空傳時間與佔空比
- 硬體:3.3V 要夠力、DIO0 接中斷、天線一定要匹配 50Ω
如果你只是要玩點對點通訊,LoRa.h 半天就能上手;要正式部署,直接上 MCCI LoRaWAN + TTN/ChirpStack,別自己發明輪詢機制。剩下的,就交給天線了。
文章評論