# 「[Avionic 101](https://hackmd.io/@Jackiempty/avionic-101-list)」:LoRa應用 本文將會帶你了解 **LoRa 模組** 以及兩種不同的使用方式。 1. **AT 指令型模組**(內建 MCU,UART 控制) 2. **裸 LoRa 模組**(晶片級,需要 MCU 控制 SPI) 首先還是需要先了解什麼是LoRa你才知道為什麼要用他。 ## 什麼是LoRa LoRa(Long Range) 是一種專為 低功耗廣域網路(LPWAN, Low Power Wide Area Network) 設計的無線調變技術。由 Semtech 公司開發,LoRa 的核心特色在於: * 遠距離傳輸(可達數公里) * 低功耗運作(電池可持續數年) * 低資料傳輸率(適合小量數據) * 低成本部署 * 使用不須申請許可的次GHz射頻頻段,例如433 MHz、868 MHz(歐洲)、915 MHz(澳大利亞及北美洲)及923 MHz(亞洲),**台灣則是可以使用920 - 925 MHz**。 ### LoRa 的特性 | 特性 | 說明 | |----------------|------| | *長距離傳輸* | 幾公里到十公里(依環境、天線、功率而定) | | *低功耗* | 適合電池供電裝置 | | *低速率* | 傳輸速率約 0.3 kbps ~ 50 kbps,不適合傳大檔 | | *穿透能力強* | 比 Wi-Fi、藍牙更能穿透牆壁、建築物 | | *Mesh / Point-to-Point / Gateway 支援* | 可用於點對點或 LoRaWAN 網路 | ### 為什麼要用 LoRa 1. *長距離點對點控制* - 比如遙控火箭點火、農田感測、山區設備控制 2. *低功耗應用* - 電池裝置可運作數月甚至數年 3. *不需電信費用* - 用免執照頻段,不必申請基地台或付月租 4. *抗干擾能力強* - 在雜訊環境下仍能傳輸成功 5. *可結合 LoRaWAN* - 建構大範圍感測網路 ### 什麼是 LoRaWAN LoRaWAN(Long Range Wide Area Network)是一種基於 LoRa 調變技術的高層網路通訊協定,專為低功耗廣域網路(LPWAN)設計。它規範了設備之間如何進行資料交換、網路如何管理節點,以及如何確保資料安全與可靠性。 主要特點包括: - **分層架構**:由終端節點(Sensors/Actuators)、閘道器(Gateways)、網路伺服器(Network Servers)與應用伺服器(Application Servers)組成 - **節點管理**:支援節點的註冊、認證與管理 - **安全性**:提供端對端加密與資料完整性驗證 - **省電設計**:支援非同步上行通訊與長休眠模式,適合電池供電的物聯網裝置 - **擴充性強**:可支持數千甚至數萬個終端節點,適合大型感測網路部署 簡而言之,LoRa 是物理層的無線技術,而 LoRaWAN 是建立在 LoRa 之上的完整網路協定,讓多個 LoRa 裝置可以安全、有效率地組成大型物聯網網路。 --- 簡單介紹完LoRa的特點以及應用,接下來會開始說明 **AT指令模組** 跟 **裸LoRa模組** 在使用上有什麼差別。 ## LoRa 模組的兩種型態 | 類型 | 說明 | 例子 | 優點 | 缺點 | |------|------|------|------|------| | **AT 指令模組** | 模組內建 MCU,封裝好 LoRa 協定,透過 UART 下 AT 指令即可使用 | RYLR998、E32 系列 | 簡單易用,不需懂 LoRa 細節 | 彈性不足、可調參數少 | | **裸 LoRa 模組** | 僅有 RF 晶片(如 SX1278),需 MCU 透過 SPI 控制 | SX1276 / SX1278 / SX1262 | 可完全掌握 LoRa 參數,靈活客製化 | 程式設計較複雜,需要使用 SPI | ## LoRa 模組互動流程與設定 在使用 LoRa 模組時,無論是搭配 **ESP32** 、 **Arduino** 或是其他 MCU 來搭配,關鍵在於**透過 UART 發送 AT 指令**來設定參數,讓兩個甚至以上的模組能夠在無限的環境中互相溝通。 ### 基本概念 - **每個 LoRa 模組都須有一個獨立的位址(ADDRESS)** 用來識別節點,可以當作是電話號碼。 - **同一個 LoRa 網路必須有相同的網路ID(NETWORKID)** 才能收發彼此的資料。 - **通訊前必須先設定參數(位址、網路ID、頻率、功率)**,確保雙方一致。 ### 兩個 LoRa 節點互動示例 假設有兩個 LoRa 模組: - **模組 A**:位址 `1`(ADDRESS=1) - **模組 B**:位址 `2`(ADDRESS=2) - **共用**: - 網路 ID = 18 - 頻率通道 = 12(對應 915 MHz) - 擴頻因子 SF = 7 - 頻寬 = 1(125 kHz) - 功率 = 4 #### 1、設定模組 A ```text AT+ADDRESS=1 AT+NETWORKID=18 AT+PARAMETER=12,7,1,4 ``` #### 2、設定模組 B ```text AT+ADDRESS=2 AT+NETWORKID=18 AT+PARAMETER=12,7,1,4 ``` #### 3、發送訊息 - A → B 發送"Hello" ```text AT+SEND=2,5,Hello ``` #### 4、接收訊息 - 如果 B 收到訊息,可能會自動回覆: ```text +RCV=1,5,Hello,-45,25 ``` - 1 → 發送方位址 - 5 → 資料長度 - Hello → 訊息內容 - -45 → RSSI (訊號強度,dBm) - 25 → SNR (訊號雜訊比,dB) --- ### 常用 AT 指令 | 指令 | 功能 | 範例 | 範例解釋 | |------|------|------|----------| | AT | 測試模組是否正常回應 | AT | 模組會回覆 `OK`,表示 UART 通訊正常、模組可用。 | | AT+ADDRESS=<addr> | 設定模組的位址(1~65535,一般建議 1~255) | AT+ADDRESS=1 | 設定本機 LoRa 模組的通訊位址為 `1`,收發訊息時會用來識別來源與目標。 | | AT+NETWORKID=<id> | 設定 LoRa 網路 ID(0~65535,需相同才能通訊) | AT+NETWORKID=18 | 將本機加入 ID 為 18 的 LoRa 網路,只有相同 Network ID 的模組能互通。 | | AT+PARAMETER=<freq>,<sf>,<bw>,<power> | 設定無線參數 | AT+PARAMETER=12,7,1,4 | 12`=頻率通道(通常對應到實際頻率,模組手冊會列對應表,例如 12`=915MHz)、`7`=擴頻因子(SF7,數字越大傳得越遠但越慢)、`1`=頻寬設定、`4`=發射功率等級。 | | AT+SEND=<addr>,<len>,<data> | 發送資料 | AT+SEND=2,5,Hello | 傳送 Hello`(長度=5字元)到位址 2` 的 LoRa 模組,必須指定字串長度,否則模組不會正確處理。 | | AT+RECV | 讀取接收到的資料(部分模組自動回覆) | AT+RECV | 查詢是否有新封包,模組可能回覆 `+RCV=1,5,Hello,-45,25`(代表來自位址 1,資料長度 5,內容 Hello,RSSI -45 dBm,SNR 25 dB)。 | #### 常見錯誤與排查 - **指令無回應**:檢查 UART 接線、波特率設定是否一致 - **傳送失敗**:確認頻率、Network ID、Address 是否匹配 - **指令格式錯誤**:注意大小寫與逗號、等號等符號 - **使用順序提醒**:記得先設定模組地址、網路 ID、參數後再傳送資料 #### 指令使用流程建議 1. 連線模組,測試 `AT` 指令是否有回應 2. 設定 `ADDRESS`、`NETWORKID`、`PARAMETER` 3. 傳送資料 `AT+SEND` 4. 查收資料 `AT+RECV` #### 傳送資料長度限制與字元處理 - 字串長度需正確指定(否則模組可能無法正常解析) - 避免特殊不可見字元,若要傳送二進位資料,需使用模組支援的特殊格式 #### 進階指令設定(視模組支援) - 重試次數、回應確認設定 - 加密功能設定 --- ### 接線方式 | ESP32 腳位 | LoRa 模組腳位 | 說明 | |------------|--------------|------| | GPIO16 | RX | ESP32 TX → LoRa RX(交叉接) | | GPIO17 | TX | ESP32 RX ← LoRa TX(交叉接) | | 3.3V | VCC | 電源(不可用 5V) | | GND | GND | 接地共用 | ## 什麼是 HardwareSerial - HardwareSerial 是 Arduino Core 提供的類別,用來操作 MCU 內建的 *硬體 UART* - ESP32 有 **3 組硬體 UART**: - **UART0**(`Serial`) → 預設連 USB 供調試用 - **UART1**(`HardwareSerial(1)`) → 可自訂 TX/RX 腳位 - **UART2**(`HardwareSerial(2)`) → 可自訂 TX/RX 腳位 - 硬體 UART 透過 *TX / RX 腳* 傳輸數位訊號(3.3V 邏輯) ## 為什麼用 HardwareSerial 控 LoRa 模組 - LoRa 模組(如 RYLR998、E32 系列)內建 UART 介面 - UART 用來: 1. 傳送 AT 指令給 LoRa 模組 2. 接收 LoRa 模組的回覆或無線接收到的資料 - 你在程式中呼叫 LoRaSerial.print() 或 `.println()`,就能把資料透過 UART 發送到 LoRa 模組 - HardwareSerial → 只是 ESP32 與 LoRa 模組的「有線數據通道」 - LoRa 模組的 MCU 收到 UART 傳來的 AT 指令 / 資料 - 模組 MCU 再用 RF(無線電)依指定頻率與設定去發射 ## HardwareSerial 常用指令 | 指令 | 說明 | 範例 | |------|------|------| | begin(baud, config, rxPin, txPin) | 初始化 UART 並設定鮑率、資料格式、腳位 | `LoRaSerial.begin(115200, SERIAL_8N1, 16, 17);` | | end() | 關閉 UART | `LoRaSerial.end();` | | available() | 回傳可讀取的字元數(>0 代表有資料) | `if (LoRaSerial.available()) { ... }` | | read() | 讀取一個字元(回傳 int,無資料時為 -1) | `char c = LoRaSerial.read();` | | readString() | 讀取整個接收到的字串(直到超時) | `String data = LoRaSerial.readString();` | | readStringUntil(char) | 讀到指定字元為止(常用換行符 \n) | `String line = LoRaSerial.readStringUntil('\n');` | | peek() | 查看下一個可讀字元但不移除它 | `char c = LoRaSerial.peek(); `| | flush() | 等待傳輸緩衝區的資料全部送出 | `LoRaSerial.flush()`; | | print(data) | 傳送資料(不加換行) | `LoRaSerial.print("Hello")`; | | println(data) | 傳送資料並自動換行(加 \r\n) | `LoRaSerial.println("Hello");` | ## 基本程式範例 ```cpp #include <HardwareSerial.h> HardwareSerial LoRaSerial(1); void setup() { Serial.begin(115200); LoRaSerial.begin(115200, SERIAL_8N1, 16, 17); Serial.println("初始化完成,測試 LoRa AT 指令..."); LoRaSerial.println("AT"); } void loop() { if (LoRaSerial.available()) { String msg = LoRaSerial.readStringUntil('\n'); Serial.println("LoRa 回覆: " + msg); } } ``` ### 程式說明 ```cpp #include <HardwareSerial.h> HardwareSerial LoRaSerial(1); ``` - 引入程式庫跟建立 LoRaSerial 物件,指定使用 UART1。 ```cpp LoRaSerial.begin(115200, SERIAL_8N1, 16, 17); ``` - 初始化 UART1,鮑率設為 115200。 - SERIAL_8N1 → 8 位資料、無同位元(N)、1 停止位(常見的 UART 設定)。 - 16, 17 → 指定 UART1 的 RX 腳位為 GPIO16、TX 腳位為 GPIO17。 ```cpp LoRaSerial.println("AT"); ``` - 送出 AT 指令`"AT\r\n"`給 LoRa 模組,測試是否連通。 - LoRa 模組若正常,應回覆 "OK" 或其他對應字串。 ```cpp void loop() { if (LoRaSerial.available()) { String msg = LoRaSerial.readStringUntil('\n'); Serial.println("LoRa 回覆: " + msg); } } ``` - `LoRaSerial.available()` → 檢查 UART1 有沒有資料可讀(LoRa 模組的回覆)。 - `readStringUntil('\n')` → 一直讀到換行符(\n)為止,並回傳成 String。 - `Serial.println()` 把這個回覆印到 USB 序列監視器上。