帶你認識物聯網基礎 Serial 通訊(二)-- UART 篇

2023/11/03閱讀時間約 11 分鐘

Serial Communication

在上一篇文章帶你認識物聯網基礎 Serial 通訊(ㄧ)裡面,我們站在上層視角來看 Serial 通訊數據必須先在 UART 元件把 Parallel 轉成 Serial,EIA Driver 會把 Serial 轉成特定的 Serial 訊號。UART 數據轉換要考慮兩個關鍵點,如何讓資料從直行變橫列(躺平)的方法,還要考慮如何控制 Serial 訊號輸出。這次我們要深入看一下這兩部分的細節。不囉嗦,開始吧。

Buffer 區是資料躺平的關鍵

UART 的全名是 Universal Asynchronize Receiver/Transmitter 中文翻成「通用非同步收發傳輸器」,從名稱實在很難聯想到跟它就是 Serial 通訊運作核心。

高速公路與隧道

先稍微打住,關於Parallel 與 Serial 的概念在生活中我覺得有一個蠻不錯的例子可以類比,就是高速公路與隧道。

都會區的高速公路單向可達五線道以上,可以讓五個駕駛人同時在各自的車道上等速併排行駛,這就是 Parallel (並排)的概念;隧道設計跟高速公路不一樣車道數較少,想要穿過隧道的五台車子就必須在進隧道前「想辦法」變成一列才能安全通過。讓並行變成一前一後排列就是 Parallel 轉 Serial 的概念。

分段處理、先進先出(FIFO)

回到電腦這邊,電腦資料不具備駕駛人可以互相協調變成一列的能力,「想辦法」讓並排的資料變成一列就交給專門的 UART 來負責,實現的方式是分段處理、先進先出。它會把來源的 Parallel 資料蒐集到自己的暫存區內按照先進先出(FIFO,First In First Out)的原則進行管理,重複著每次從暫存區提取一筆 Parallel 資料進行 Serial 的訊號轉換的動作。

數據轉換流水線

假設來源來源的 Parallel 匯流排(data bus)上有 8 個數據通道好了,資料傳輸的時候每次都會有 8 個數據訊號會同時抵達 UART 這邊, 它會將數據安排到第一個暫存區 THR (Transmit Hold Register) 資料在這裡排隊等待,THR 大小多少不固定要看產品規格,以現在的例子至少要 1 byte。當 UART 發現 THR 有資料要處理,排在 THR 最前面(最早進來)的資料就會被提取出來到下一個暫存區 TSR (Transmit Shift Register) 進行轉換,在 TSR 完成轉換的 Serial 訊號就可以準備從 TX 出口離開了,一站接著一站就像流水線一般。資料發送的過程大概這樣:

Data Bus → Transmitter FIFO (THR) → Transmit Shift Register (TSR) → Serial
Parallel 2 Serial

Parallel 2 Serial

資料接收的過程就是把上面的箭頭全部反過來,Transmit 變成 Receive 就像這樣

Serial → Receive Shift Register (BSR) → Receiver FIFO (BHR) → Data Bus

Serial 2 Parallel

Serial 2 Parallel

單工、半雙工、全雙工

對 UART 來說通訊只要一組兩條線,要發送的資料走 TX,要接收的資料就走 RX。一組傳輸線按照傳輸的行為可以進一步區分單工(Simplex),半雙工(Half-Duplex) 。

一組傳輸線就像一條車道,單工像是我們的單行道,規定資料往一個方向移動,例如只送不收。如果允許把收跟送的時間分開互相等待,同一組線路 (RX/TX) 就能做到半雙工(half-duplex),就是單線道可以雙向通車,例如 RS232/RS485 基本都是半雙工。

有半雙工就有全雙工(Full-Duplex),只要再多提供一組訊號線就可以了,有兩組 RX TX 的 4 線 RS485 就是一個經典範例。

通訊參數 9600, N, 8, 1

通訊參數的一致性是發送與接收兩端能否成功通訊的關鍵。通訊參數代表成功通訊的前提條件跟我們說話類似,例如: 兩個人溝通需要用共通的語言、語法規則、聲量、語速等等都要考慮進來... 同樣的,電腦間通訊也是如此,要用多快的速度傳遞訊息,要如何打包訊息封包,都要通訊前先設定好通訊參數。

通訊速率 Baud Rate

通訊速率叫做 Baud (鮑) 也叫做 Baud Rate,定義是一秒鐘可以傳送或接收多少個符號,相當於我們說話的速度。二進位的電腦能用的符號只有兩個 0 (低電位) or 1 (高電位)

Baud Rate 9600 就是每秒可以傳送或接收 9600 個 0 or 1

可以計算出來傳送或接收 1 bit 的資料所需的時間是 1/9600 = 0.10417ms。

目前 Baud Rate 的設定從 50 到 921600 都有,理論上 Baud Rate 數值越高,傳輸資料時間越短(難度越高),能傳輸的資料數量也更多(相當於頻寬增加了)。實際應用要設定多少 Baud Rate 還是要看於設備的規格,我以前比較常碰到的 Baud Rate 大概就是 9600, 19200, 38400 跟 115200 這幾種。

試想一下,如果兩邊 Baud Rate 設定不一樣會發生甚麼情形? 假設傳送端的 Baud Rate 設定是 19200 ,接收端設定是 9600 ,每隔 0.05208ms 就有一個 bit 資料傳過來,接收端每隔 0.10417ms 才會讀取一次,讀取速度比傳送速度慢了一倍,結果是接收端只會收到奇數 bit 或偶數 bit,組合起來就會變成沒有意義的亂碼。

資料封包 Frame

決定好通訊速率還要決定資料封包 Frame。資料封包有四個要素,按照順序分別起始位元 (Start bit) 、資料位元個數(Data bits)、校驗位元(Parity bit) 以及停止位元(Stop bit)。

Serial Frame

Serial Frame

起始位元 Start bit

起始位元固定是 1 個 bit,排在資料封包的最前面。UART 的通訊設計是高電位 1 低電位 0,平常待機都是維持在高電位的狀態,看起來就是 1111111111….,用示波器來看就是沒有變化的一直線。

起始位元的目的是用一個 bit 的時間要告訴接收端”後面有資料來了”,具體做法是它會拉低 1 bit (低電位) 的時間,當接收端偵測到就知道要開始收資料了。

資料位元 Data bits

接下來是資料位元個數也要預先設定在通訊參數裡面,要傳送的資料放在這邊。以現在例子就是 8。接收端確認到起始位元後,就開始連續讀取 8 個的資料位元。資料位元數可以設定的數值包含 5, 6, 7, 8,不同的數值會影響封包大小跟傳輸時間。

校驗位元 Parity bit

再來是校驗位元是用來檢查資料內容的正確性的,原理是看資料位元裡面總共有多少個 1,可以設定為 Odd (奇同位) 或是 Even (偶同位)或是 None (不需要)。比如上面的 110010100,資料位元裡面有 4 個 1,如果此時我們的通訊參數是 Even,那麼傳送端就會把這校驗位元設為 0 (資料位元加上校驗位元合計已經有偶數個 1 了)。

如果同樣資料通訊參數現在設成 Odd,傳送端必須把校驗位元設定為 1,這樣就有 5 個 1 可以滿足奇數個 1 的要求。校驗位元只要資料位元有超過 1 個 bit 的數值異常就檢測不出來了實用性不高。實務上都設定 None。設定 None 還有個好處,可以讓資料位元長度增加到 9 bits。

結束位元 Stop bit

封包的最後是 Stop bit,有點像無線電對談的時候結束要說 Over 一樣,告訴接收端封包已經送完了,可以設定 1, 1.5, 2 bits 的時間長度。那麼傳送一個 byte 需要多少時間呢? 按照 9600, N, 8, 1 的設定,答案是 1.0417ms,因為 9600 的每個 bit 需要 0.10417ms,一個封包總共有 10 bit (= 1 Start bit + 8 Data bits + 1 Stop bit) 。

Timeout

說到傳輸時間了,不妨也注意一下 timeout 或者叫做延遲時間 Latency,它是用來判斷通訊是否中斷停止的依據,預設長度是 4 bytes,要用 Frame 大小計算大約就是 4ms,只要通訊中發生中斷超過 4ms 就會被認為超時 timeout,就可以決定要停止傳送或重送,寫 code 的時候就可以有明確的 delay 時間。

流量控制 RTS/CTS

通常我們要傳遞的資料不會只有一個封包這麼小,而是會切成很多個封包不斷往通訊線裡面送,如此就產生了資料流,忙碌的時候就是整條馬路都是車的感覺。

CPU 很忙

每個封包之間的時間差不同,CPU 也會有來不及處理資料封包的時候,此時資料就會先放在暫存區裡面,如果資料又一直進來,CPU 還是沒空處理,那麼暫存區就會有擠爆的錯誤(overrun) 發生。所以除了傳送資料的 RX/TX ,還會多加兩條 RTS/CTS 來做流量控制。

看訊號辦事

RTS 全名叫做 Request To Send,CTS 是 Clear to send 都是接收端跟發送端用來控制資料流量的 flag。接收端為了避免暫存區爆掉會在暫存區水位設定一個閥值,比如說 80%。只要資料水位在 80% 以下,就讓傳送端持續把資料送過來,一但發現資料水位超過 80%,就必須通知傳送端先暫停傳輸。

具體的用法是,把接收端跟傳送端的 RTS/CTS 對接。傳送端有資料要送的時候,會先把自己的 RTS 拉起來通知接收端,等接收端回應自己收到 CTS (接收端的 RTS 也打開了)就可以開始把資料傳出去。接收端會持續收資料並監看自己的暫存區資料水位,一旦超過閥值就觸發保護機制,接收端會把自己的 RTS 關掉,發送端看到自己的 CTS 關掉,就知道該停下來了。

RTS to CTS

RTS to CTS

小結論

以上就是這次要跟大家分享的 Serial 通訊 - UART 的部分。我們只要記得 UART 元件的職責就是負責 Parallel 轉成 Serial 的資料就好,畢竟轉換電路都已經被廠商封裝到 chip 裡面了,看不到也摸不著。但是通訊參數設定跟流量控制的概念對於系統整合應用的人來就很重要,設定錯誤的通訊參數會讓你的通訊失敗,不了解也會讓你寫的 code 效率折扣或者很不穩定。

接下來,我們就要準備進入 Serial 通訊的最後一趴,聊聊 EIA Driver,看看 TTL 是怎麼轉成 RS232/RS485 這些實體介面,以及他們是怎麼運作的。敬請期待。

9會員
58內容數
WarrenLo's 軟體設計武功祕笈
留言0
查看全部
發表第一個留言支持創作者!