在前面的文章中,我們已經確立了「Linux 閘道器 (Gateway) + RTOS 感測器 (MCU Node)」的異質雙核架構。現在面臨的第一個實務問題是:這兩台設備之間,該怎麼說話?
在物聯網與邊緣運算的領域中,我們有太多酷炫的選擇:BLE (藍牙低功耗)、Wi-Fi、MQTT、甚至是 USB。但在醫療照護或工業高穩定度的場域裡,越「古老」的技術,往往越可靠。
今天,我們來聊聊為什麼我們的 EdgeNode 選擇了最傳統的 UART (Universal Asynchronous Receiver-Transmitter),以及如何用 Python 寫出堅若磐石的通訊解析器。
BLE (藍牙):雖然無線很方便,但在多台設備同時運作的場域 (例如病房),頻段干擾與偶發性的斷線重連機制,會讓軟體架構變得極度複雜。
USB:USB 協定非常嚴謹且快速,但它高度依賴 Host 端的作業系統 (Linux) 來分配資源。只要拔插瞬間發生電氣雜訊,或是 Linux 核心的 USB 驅動稍有打嗝,整個掛載樹 (Device Tree) 就可能崩潰。
I2C / SPI:這兩者通常用於同一塊 PCBA 上的晶片級通訊。若要拉一條 1~2 公尺長的實體線路,訊號衰減與雜訊會讓資料慘不忍睹。
最後勝出的是 UART。它只需要三根線 (TX, RX, GND),完全非同步 (Asynchronous),且硬體成本極低。即使線路瞬間干擾掉了一個 Byte,軟體層的 Checksum 也能輕易攔截,下一秒立刻重新同步,系統容錯率極高。
💡 什麼是 Daisy Chain 通訊? 在這裡指的是資料流的線性傳遞:感測器 (光學/陀螺儀) -> MCU (RTOS 演算) -> UART 實體線 -> Linux Gateway (Python 收集整理) -> Cloud (最終終點)。每一層都只對上一層負責,大幅降低了非同步通訊的耦合度。
[錯誤嘗試]:依賴固定長度讀取
早期開發時,我們可能會寫出這樣的程式碼:
python
import serial
ser = serial.Serial('/dev/ttyS0', 115200)
while True:
# 假設我們知道每筆資料都是 18 Bytes
packet = ser.read(18)
process_data(packet)
災難場景:只要硬體因為任何原因漏送了 1 個 Byte,ser.read(18) 就會卡住,或者讀到「上一筆的結尾 + 下一筆的開頭」,從此資料全面錯位 (Shift),再也解不回來。
[底層原理]:狀態機解析 (State Machine Parser)
為了克服這個問題,我們必須在 MCU 與 Linux 之間約定好強健的封包結構,通常包含: [Start Byte] + [Command] + [Payload] + [Checksum]
並且在 Python 端實作一個「狀態機 (State Machine)」,逐 Byte 檢查:
python
class ProtocolParser:
def __init__(self):
self.buffer = bytearray()
def process_stream(self, data: bytes):
"""處理源源不絕的 UART 串流"""
self.buffer.extend(data)
packets = []
while len(self.buffer) > 0:
start_byte = self.buffer[0]
# 1. 尋找合法的標頭 (例如 0x04)
if start_byte not in [0x02, 0x03, 0x04, 0xF0]:
self.buffer.pop(0) # 丟棄雜訊
continue
# 2. 決定動態長度
frame_size = self._get_frame_size(start_byte)
if len(self.buffer) < frame_size:
break # 封包還沒收完,等待下一次 Serial Read
# 3. 取出完整封包並驗證 Checksum
frame = self.buffer[:frame_size]
if self._verify_checksum(frame):
packets.append(self._decode(frame))
# 4. 推進 Buffer
self.buffer = self.buffer[frame_size:]
return packets
因此,在 DataGateway 專案中,我們實作了 SerialWorker 繼承自 threading.Thread。這個背景執行緒唯一的工作,就是死命地讀取 UART /dev/ttyS0,將收到的 Bytes 丟給 ProtocolParser。 一旦解碼出完整的 VitalSignPacket (生命徵象封包),才透過 Queue (或 Thread-safe Signal) 拋給主系統。
這種**「讓髒活留在背景,讓純淨資料進入核心」**的設計,正是我們能讓邊緣設備 24 小時不間斷運作的第一個秘密。
明日預告
現在我們已經打通了任督二脈,能透過 UART 拿到資料了。但是,我們的 DataGateway 是一個沒有螢幕、沒有鍵盤的「無頭設備 (Headless)」。當系統發生錯誤,或是 UART 斷線時,硬體該如何告訴我們? 明天,我們將來探討:沒有螢幕,硬體該如何說話?(LED 狀態機的軟即時控制)。