給用手機瀏覽的讀者


很抱歉, 這一篇因為用了 MathJax 套件來顯示分數, 目前設定和痞客邦的 "手機版模式" 有點小衝突 (它把行高設定死了), 要等改天有空才能修正. 請先改用 "電腦版模式" 或者換用 PC/平板 來閱讀. 已經修正好了, 如果閱讀上還有問題請留言告知.

UART 接收同步機制


下圖所示是經由 UART 輸送一個 ASCII 字元 'r' (0x72) 的 TTL 輸出 (未經過 RS-232 Transceiver). 圖上的小箭號所指的是接收端取樣訊號的相對時序位置, 上半部是理想狀況下接收 UART 資料的時序圖. 我們設定了鮑率之後, UART 在第一個向下訊號邊緣取得同步 (開始計時) 是為啟始位元, 然後以設定的鮑率開始取樣接收資料. 不過事情總不會如此美好. 萬一接收者和發送者的計時精準度不同 (即使是同樣的廠牌、型號, 總還是有製造上的誤差, 及操作溫度...等等因素的影響), 致使二者不完全一致, 下圖的下半部刻意把誤差放大, 我們很容易就看出一共有 4 個位元的資料錯了.

RS-232 unsync

不過只要稍微修改一下: 把開始取樣接收資料的時間點偏移一些, 就可以順利避免這個問題了. 由於這個時間差可能是提早, 也可能是落後, 因此把偏移時間設定成取樣週期的一半. 也就是同步之後的 1.5 倍取樣週期時間後, 再開始取樣接收第一個位元資料.

RS-232 Sync

另外大部份晶片為了加強對抗雜訊的能力, 通常是以鮑率的 16 倍頻工作, 並在中心點附近取樣三次, 也就是在原先鮑率週期的 `sf{7/16}`, `sf{8/16}`, `sf{9/16}` 等三個位置取樣, 三次結果一致才視為正確. 現在的 UART 晶片幾乎都是以這樣的機制在運作, 所以我們可以很穩定的接收到正確資料. 不過傳送端和接收端的計時誤差總有個限度: 從同步開始到取得同位檢查位元, 之間的累計誤差不能超過原先鮑率的 ±`sf{7/16}`. 假設傳輸設定是 8+同位檢查位元, 則負誤差中間一共是 `sf{9+7/16}` 個鮑率週期, 正誤差中間一共是 `sf{9+9/16}` 個鮑率週期

  • (9 + 7/16)x(T - ∆T') =  9T --> (9+7/16)∆T'= (7/16)T
  • (9 + 9/16)x(T + ∆T") = 10T --> (9+9/16)∆T"= (7/16)T

所以每個鮑率週期的誤差應該在 -(7/16)/(9+7/16) 到 +(7/16)/(9+9/16) => -`sf{7/151}` ~ +`sf{7/153}~=` -4.63% ~ +4.57%.

RS-232 CLK torrence

如果不傳同位檢查位元則誤差可以稍微寬鬆一些 (`sf{-7/135}` ~ `sf{+7/137}`).

還有一點要注意的是, 這二個數值是和正確的鮑率週期比較的. 如果你拿一個負誤差最大值的設備要和一個正誤差最大值的設備連接, 這二個設備還是連接不起來的.

如果是要求把一個負誤差最大值的設備要和一個正誤差最大值的設備連接, 必需再把上列的數值再各減半, 約在 -2.31% ~ +2.28% 之間.

或許你會說還好吧? 石英震盪晶體運作時應該不會有這麼大的誤差啊! 原來問題出在 UART 使用的石英震盪器的頻率和一般 CPU 或者是單晶片微控制器常用的石英震盪晶體並不相同. UART 使用的石英震盪器的頻率如下表: (詳細請參考 wiki)

  • 1.8432 MHz, 3.6864 MHz, 4.9152 MHz, 5.5296 MHz, 6.1440 MHz, 7.3728 MHz, 9.8304 MHz, 11.0592 MHz
  • 12.2880 MHz, 12.9024 MHz, 14.7456 MHz, 16.5888 MHz, 18.4320 MHz, 19.6608 MHz, 20.2752 MHz, 22.1184 MHz
  • 23.9616 MHz, 25.8048 MHz, 27.6480 MHz, 29.4912 MHz, 31.3344 MHz, 33.1776 MHz, 35.0208 MHz, 36.8640 MHz

基本上這些都是 9600*64 的整數倍. 但是一般的 CPU 或者單晶片微控制器則常用 12MHz, 20MHz, 25MHz, 40MHz... 而且單晶片微控制器為了省成本通常會只用一顆石英震盪晶體. 例如: 早期的 8051 常用的是 12MHz, 但是為了能設定全部常用的鮑率必需犧牲一點效能改用 11.0592MHz 的石英震盪晶體. 所以, 你了解的.

8051 鮑率設定計算


接下來, 我們來看看如何計算 8051 UART 的鮑率 Timer 設定.

首先 8051 的 serial port 共有 4 個模式

8051 Serial Port Mode
模式 SM0 SM1 功能 SMOD 鮑率
0 0 0 固定鮑率, 同步傳輸 - Fosc/12
1 0 1 自定鮑率, 10bit UART
(Start+8bit+Stop)
0 Fosc/12 x 1/32 x 1/(256-TH1)
1 Fosc/12 x 1/16 x 1/(256-TH1)
2 1 0 固定鮑率, 11bit UART
(Start+8bit+Parity+Stop)
0 1/16 x Fosc/4
1 1/16 x Fosc/2
3 1 1 自定鮑率, 11bit
(Start+8bit+Parity+Stop)
0 Fosc/12 x 1/32 x 1/(256-TH1)
1 Fosc/12 x 1/16 x 1/(256-TH1)

Mode 0 及 Mode 2 用的是固定的頻率, 一般 PC 的 UART 無法設定成這二種鮑率, 只適用於和一樣是使用 8051 晶片的設備相互連接. 採用 Mode 1 和 Mode 3, 才能和 PC 互連. 同時除非 8051 CPU 用的是 11.0592 MHz 的石英震盪晶體, 否則和 PC 連接的鮑率無法大於 4800.

因為設定 SMOD=1 可以取得較高的 Baud, 所以我們用 Baud = Fosc/12 x 1/16 x 1/(256-TH1) 來計算 TH1, 前式我們可以導出 (256-TH1) = Fosc/(12*16*Baud), 其中 Fosc 用 11.0592M 代入, Baud 用 19200 代入, 可以求得 (256-TH1) = 3, 所以 TH1 之值為 253 或者 0xFD. 如果鮑率再取高一級的 38400, 則算出 (256-TH1) = 1.5, 四捨五入取整數 2. 但 1.5 和 2 誤差 33% 已經大於可接受範圍, 因此在傳統 8051 上使用 11.0592MHz 的石英震盪晶體最大可設成 19200 的傳輸速率.

但是如果是使用 12MHz 的石英震盪晶體, 在鮑率為 9600 時, 算出 (256-TH1) ~= 6.51, 四捨五入取整數 7. 但 6.51 和 7 誤差 7.52% 已經大於可接受範圍. 在鮑率為 4800 時, 算出 (256-TH1) ~= 13.02, 四捨五入取整數 13. 誤差 0.16% 在可接受範圍. 因此在傳統 8051 上使用 12MHz 的石英震盪晶體最大只能設成 4800 的傳輸速率. 相差有4倍之多.

Atmel ATmega 2560 的鮑率設定計算


我們再來驗算看看 Arduino Mega 2560 的 USART 的鮑率設定. Arduino Mega 2560 的 CPU 晶片選用的是 Atmel ATmega 2560, 振盪晶體則是用 16 MHz.

Atmel ATmega 2560 USART 鮑率公式
Asynchronous
操作模式
鮑率公式 UBRR 計算公式
一般模式
(U2Xn = 0)
BAUD = Fosc/(16 x (UBBRn+1)) UBBRn = Fosc/(16 x BAUD) - 1
雙倍模式
(U2Xn = 1)
BAUD = Fosc/(8 x (UBBRn+1)) UBBRn = Fosc/(8 x BAUD) - 1

Arduino Mega 2560 的 Debug Console 可以設定的最高鮑率是 115200 bps. 我們把數值 115200 代入雙倍模式的公式, 可得 UBBRn+1 ~= 17.3611, UBBRn 應設為 16, 而鮑率誤差為 -0.36111/17 ~= -2.12% 還合乎上面所列的範圍. 不過要再往上提高, 可就會超出範圍了.

arrow
arrow

    MagicJackTing 發表在 痞客邦 留言(3) 人氣()