|
View Categories

認識UART界面#1—訊號格式

閱讀時間: 3 min read

作者:Bird

接下來幾篇文章,我們會來談談在數位系統設計上常用到的一些界面,如 UART、I2C、SPI 等。這些常見的界面用起來雖然不難,但背後其實有很多有趣的原理和機制可以細細研究。

就讓我們從串列界面的老祖宗:UART 開始聊起吧。

串列通訊的始祖 #

「把一整排的資料按照順序排列,逐一送到遠方,接收方再用同樣的順序將資料排回去」,這就是串列通訊的原始精神。

那爲什麼要這麼麻煩呢?爲了節省線路。

假設我有一個 byte,也就是 8 個 bit 的資料要送到遠方,如果想要一次就把 8 個 bit 都送過去,就需要 8 根電路連線,但如果用上面說的方法,利用邏輯電路上的移位暫存器來排列資料,就只要… 一根線?不,至少要兩根線。

(圖片來源:Bird 提供)

移位暫存器需要一個 clock 訊號才能工作:它在每個 clock 的上升緣(或下降緣—如果是比較搞怪的設計)將資料移入或移出,因此除了 data 訊號外,至少還需要一根 clock 訊號才能運作,而如果移位暫存器的工作夠可靠,兩邊的初始狀態都一樣且傳輸的過程中保證沒有出錯,那麼 reset 訊號並不是必需的。

Clock 訊號是用來確保傳送和接收方能同步的一種方法,所謂同步就是兩者在一個說好的時間收送資料。比方說移位暫存器,接收方會在 clock 的上升緣取樣資料,傳送方就會確保在 clock 的上升緣時資料是穩定且有效的。

以上這種傳送方法其實就是 UART 的哥哥,叫做 USRT:Universal Synchronous Receiver/Transceiver。

再省一根線 #

有沒有辦法再省掉一根線,不要用 clock 也能把串列資料傳送到遠方呢?如果沒有 clock,接收方要如何知道要用什麼速度來接收資料呢?

兩邊先講好,用一樣的速度來傳送、接收資料就好了!

於是在 UART 上就出現了 baud rate 這個概念。Baud 這個字指的是串列傳送時的基本符號,其實就是 bit,傳送方和接收方必需要設定一樣的 baud rate(傳送速度),比方說我們很常用的 115200 bps ,就代表每秒鐘傳送十一萬五千兩百個 bit(聽起來很厲害!),每一個 bit 的時間就是 1/115200 = 8.68 us,也就是說,接收方每隔 8.68us 就讀一個 bit。

傳送方和接收方必需要設定一樣的傳送速度(圖片來源:Bird 提供)

這就是 UART 爲什麼要設定 baud rate 才能使用的原因,因爲它沒有 clock 訊號,傳送、接收兩邊必需要用這種「事先約好」的方式來協調,才能正常工作。如果你用 9600 bps 的速度來接收用 115200 bps 傳送的訊號,什麼都不會收到。

隨著微處理器的處理速度進步,現在有一些 UART 界面可以藉由觀察收到的訊號來猜測它的 baud rate,然後自動設定對應的速度,這個機制叫做 auto baud。

好,我們知道要用什麼速度來接收了,那怎麼知道要從什麼時候開始接收呢?

這時候就輪到 start bit 上場了。

UART 的 bus 在沒有傳送資料時,是維持在 high 的狀態,也就是所謂的「idle high」。

找到起點 #

在 UART 上每一個被傳送的字元,都是由 start bit、資料、檢查位元、以及 stop bit 構成。這其中 start bit 固定是 1,資料的長度可以設定,一般來說多半是 8-bit,但在一些特殊的應用中,只要硬體支援,也有可能設定成 7 bit 或 12 bit 這種非典型的資料長度。檢查位元是用來查核資料的正確性,其所使用的演算法稱為 parity,這是在早期通訊理論還不是很發達時,很常用的一種方式。

Parity 的計算很簡單,它有兩個模式:even 和 odd。Even 是偶數的意思,even parity 就是包含 parity bit, 要讓整個資料字元中的「1」個數爲偶數。比方說我們傳送的資料是 0011100,總共 7 個 bit,其中有 3 個 1,如果此時 parity 的模式是 even parity,parity bit 就要設爲 1,好讓整組字元變成 00111001,(裡面總共包含了 4 個,也就是偶數個 1)。

如果這組資料在傳送過程當中出現錯誤,其中一個 bit 從 0 變成了 1,比方說整個字元包含 parity 變成 10111001,接收端在接收時會發現整個字元裡 1 的個數不是偶數,就知道傳輸過程出錯了,代表這筆資料可能是有問題的。

但 parity 演算法最大的問題是,如果你的運氣真的非常不好,資料裡面有 2 個位元都出了問題,那麼它就會負負得正,反而讓 parity bit 維持正確,因此可以說它只對單一 bit 出錯的錯誤有敏感性。

隨著通訊硬體越來越可靠,上層的資料檢查或處理協定也隨著硬體的計算能力進步而越來越強大,單靠 parity bit 來檢查資料傳輸的正確性已經不太有意義,因此現今在使用 UART 時已經鮮少使用 parity bit。我們常見的「9600,8,N,1」這種設定,意思就是 9600 bps 的 baud rate、8 個資料位元,N 則代表沒有 parity bit,1 則是 1 個停止位元的意思;更準確來說,現在其實已經很少看到後面不是「8,N,1」的設定,原因就是 parity bit 已經幾乎不再使用,而 8 個 data bit 和 1 個 stop bit 也幾乎成爲標準。

假設我們要透過 UART 以 115200, 8, N, 1 的模式傳送一個內容是 0x3A 的字元,它的波形會長什麼樣子呢?0xC5 換成二進位就是 11000101,再加上一個 start bit 和一個 stop bit,就會變成:

由於 UART 在沒有傳送資料時,邏輯位準是維持 high 的,因此當 start bit 一來時,UART 的電壓就會變低,變成 logic low 的位準。當接收端偵測到 start bit 造成的電壓變化,就知道「哦!有資料要傳送過來了」。根據事先設定好的 baud rate,接收端會知道 start bit 應該要維持多久,比方說如果 baud rate 是 115200 bps,那每一個 bit 的長度就是 8.68 us,因此從 start bit 造成的那個電壓下降緣開始算 8.68 us,之後就是第一個 data bit 的開始。

接收器應該在什麼時候去讀取 data bit 呢?最佳的位置當然是在每一個 bit 時間的中心點,這樣的話就算 baud rate 稍微不準,也還是有機會取樣到正確的資訊。

(圖片來源:Bird 提供)

取樣了第一個 bit 後,接著就根據固定的時間間隔,把之後的 7 個 bit 接續取樣,就能拿到完整的資料了;至於 stop bit,它其實沒有什麼用處,在通訊原理上它是一個安全的時間間隔,用來分隔不同的字元。

事實上現在大部分的 UART 硬體都會在每個 bit 的時間中心點取樣 3 次。在絕大部分的情況下,這 3 次的取樣得到的結果應該要相同,但如果 UART 訊號受到干擾而被破壞,或是 baud rate 根本設錯,就有可能讓同一個 bit 裡的 3 次取樣拿到不同的數值,這時 UART 的接收端就會知道事有蹊蹺,一定有哪裡出錯了。

有沒有發現,在 UART 上傳輸 8 個 bit,還要加上一前一後總共 2 個額外的位元?因此 115200 bps 的 UART 上能傳送的頻寬並不是 115200/8 = 14400 byte/sec,而是115200/10 = 11520 byte/sec。當你在估算 UART 的最大頻寬時,這個因素很重要。

小結 #

我們小結一下。UART 靠事先約好的 baud rate 決定資料傳送的速度,並用 start bit 來確定每一次傳送開始的時間,如此可以省去 clock 訊號,只靠一根線就傳送串列的資料。

而且 UART 每一個字元的傳送都會重新靠 start bit 來同步字元的開始位置,因此 baud rate 的誤差不會累積,反而可以容忍相當大的誤差。假設我們用 115200 bps 來傳送資料,那麼接收端取樣每一個 bit 的位置應該是下圖中上方的箭頭位置:

但如果接收端的 baud rate 不準,快了 10%,變成 126720 bps,那麼每個 bit 的取樣位置就會變成途中下方的箭頭,因爲每個 bit 都用稍快 10% 的速度取樣,越到後面,取樣的位置偏差就會越早。

神奇的是,這下方的箭頭居然還是可以在每一個 bit 取樣到正確的值,最後收到的字元也是正確的。以 8-bit 的資料格式來說,UART 可以容忍到將近 12.5 % 的 baud rate 誤差,這大幅增加了 UART 這個界面的可靠度和實用性,因爲它不要求接收端和發射端都要有很準的時脈訊號來產生 baud rate。

這次我們從串列界面的濫觴出發,聊了 UART 的訊號格式,以及它之所以叫做「非同步」(asynchronous)的主要原因。下一回我們就來聊聊 UART 的實體電氣訊號應該長什麼樣子,以及它跟常見的 RS-232C、RS-422、RS-485 這些界面之間有什麼愛恨糾葛。

(責任編輯:賴佩萱)

Powered by BetterDocs

Submit a Comment

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *