串行通信波特率的一種自動檢測方法
串行通信是終端和主機之間的主要通信方式,通信波特率一般選擇1800、4800、9600和
19200等。終端的類型有很多種,其通信速率也有很多種選擇。主機怎樣確定終端的通信速率呢?本文給出了一種簡單、易行的方法:設定主機的接收波特率(以9600波特為例),終端發送一個特定的字符(以回車符為例),主機根據接收到的字符信息就可以確定終端的通信波特率。本文對這種方法予以詳述。
1 基本方法
回車符的ASCII值為0x0D。串行通信時附加一個起始位和終止位,位的傳輸順序一般是
先傳低位再傳高位。此時回車符的二進制表示方式為:

圖1 回車符的位序列
串行通信中一個二進制位的傳輸時間(記為T)取決于通信的波特率,9600波特時一個
二進制位的傳輸時間是19200波特時一個二進制位傳輸時間的兩倍,即:2*T19200=T
9600。因此,9600波特時一個位的傳輸時間,19200波特時可以傳輸兩個位。同樣地
,9600波特傳輸兩個位的時間在4800波特時只能傳送一個位。主機設定接收波特率為9600,
終端只有也以9600波特發送的字符,主機才能正確地接收。發送波特率高于或低于9600都會
使主機接收到的字符發生錯誤。接收波特率為9600,終端以不同的波特率發送回車符時,主
機接收到的二進制序列如表1所示。
從表1中可以看出,除了19200和1800波特時兩種特例情況,其他情形的二進制序列都是
9600波特時二進制序列的變換。取前十個二進制位與9600波特時的二進制位相對應。忽略缺
少停止位‘1’引發的數據幀錯誤,把接收到的字符表示成字節方式(如表1的最右列所示)
。例如:在發送速率為1200波特,接收速率為9600波特時,主機得到的字節是0x80,而不
是正確的回車符0x0D。因為在不同的發送速率下(9600,4800,2400,1200)得到的字節
不同,所以通過接收字符的判定就可以確定發送波特率。
發送波特率為19200時,其發送速度正好是接收速度(9600波特)的兩倍,因此發送端
的兩個二進制位會被接收端看作一個。取決于不同的串行接口硬件,‘01’和‘10’這兩種
二進制位組合可能被認為是‘1’或者‘0’。幸運的是,只有0~4位存在這樣的歧義問題,
后面的位因為都是停止位,所以都是‘1’。因此,發送速率為19200波特時接收到的字符其高半個字節為0xF。低半個字節可能是多個值中的一個,但不會是0x0,因為0x0D中有相鄰
的兩個‘1’,這就會至少在低半個字節中產生一個‘1’。因此,整個字節的形式為0xF?,
且低半個字節不為0。
表1 不同波特率下的二進制序列
波特率
|
接收到的二進制位序列
|
字節表示
|
19200
|
0 1 0 1 1 0 0 0 0 1 1 1 1 1
1 1 1 1 1 1
|
0xF?
|
9600
|
0 1 0 1 1 0 0
0 0 1
|
0x0D
|
4800
|
0 0 1 1 0 0 1 1 1 1 0 0 0 0
0 0 0 0 1 1
|
0xE6
|
2400
|
0 0 0 0 1 1 1 1 0 0 0 0 1 1
1 1 1 1 1 1
|
0x78
|
1800
|
0 0 0 0 0 x 1 1 1 1 x 0 0 0
0 0 1 1 1 1
|
0xE0
|
1800
|
0 0 0 0 0 x 1 1 1 1 x 0 0 0
0 0 1 1 1 1
|
0xF0
|
1200
|
0 0 0 0 0 0 0 0 1 1 1 1 1 1
1 1 0 0 0 0
|
0x80
|
600
|
0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 1 1 1 1
|
0x00
|
300
|
0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0
|
0x00
|
150
|
0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0
|
0x00
|
110
|
0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0
|
0x00
|
發送速率為1800波特時,因為
T1800=T9600*16/3,
而16/3不是整數,接收端二進制位的狀態轉換時刻和9600波特不一一對應,引起在接收端
的一個位接收周期內有狀態發生變化的可能。表1中給出的第六個位(表示為x)就是這種情
況。因為x有可能被看作‘1’,也有可能被看作‘0’,所以發送速率為1800波特時接收到
的字節可能是0xE0或者0xF0。波特率為3600和7200時也有同樣的問題,也可以采用同樣的方
法,但不確定的位數會增加,需要檢測的字節種類也會更多。3600波特和7200波特的傳輸速
率幾乎不采用,因此這個問題并不嚴重。只要發送波特率在1200~19200之間,我們都可以
通過接收到的一個字符對此波特率進行唯一的判定。
2 低波特率的檢測
當發送速率低于1200波特時,接收端收到的字節都是0x00,因此只能確定其速率低于12
00波特,而不可能再得到更多的信息。為了解決這個問題,可以在9600波特的速率下繼續接
收下一個字節信息。發送速率為600波特或更低時,一個位的發送時間要大于9600波特時整
個字節的接收時間。因此,發送端每一個從‘1’(終止位)到‘0’(起始位)的跳變都會
讓接收端認為一個新的字節開始了。表2所示為600波特或更低的傳輸速率時接收端回車符的
二進制序列(只給出開始的一些位)。
表2
低波特率回車符的接收方式
波特率
|
9600波特二進制序列
|
時間差
(周期)
|
時間差
(實時間)
|
600
|
16 0's 16 1's 16 0's
|
32
|
3.33ms
|
300
|
32 0's 32 1's 32 0's
|
64
|
6.66ms
|
150
|
64 0's 64 1's 64 0's
|
128
|
13.33ms
|
110
|
87 0's 87 1's 87 0's
|
174
|
18.13ms
|
75
|
128 0's 128 1's 128 0's
|
256
|
26.66ms
|
50
|
192 0's 192 1's 192 0's
|
384
|
4 0.00ms
|
600波特時,第一個從‘1’到‘0’的跳變在初始化以后即刻發生。這個跳變讓接收端
得到字節0x00。第二個跳變在初始化(16+16)*T9600秒以后發生,這會讓接收端認
為另外一個字節開始接收了。一個二進制位的接收時間是T9600,所以串行接口電路
會在第一個跳變以后10* T9600秒提示第一個字節接收完畢,在(16+16+10)*
T96 00秒以后提示第二個字節接收完畢。因此600波特時,第一個字節接收完畢和第二個字節
接收完畢的時間差是(16+16+10-10)* T9600=32* T9600秒。表2的第三列所示
是把這個時間差以T9600的個數表示。因為T9600=1/9600秒=104.16毫秒,相
乘可以得到兩個字節接收完畢的實時間差。不同發送波特率的時間差如表2的最后一列所示
。有了這個時間差信息,就可以確定低傳輸速率時的波特率了:測定第一個和第二個字節的
接收時間差,然后在時間差常數表(表2)里查出哪個波特率下的時間差與之最相近,對應
的就是終端發送波特率。即使測定的時間差有些誤差,一般也可以正確地確定波特率。
3 實現方式
通過以上分析,各種波特率都可以通過回車符的發送和接收信息來測定,算法實現的偽
代碼在本文的最后給出。應用實踐證明了這種方法的有效性。
; Pseudo code to determine what baud rate a transmitter is at,on
the b asis of a single
; RETURN (0x0D) character received
from it.
Initialise receive baud rate to 9600
Wait for Byte to be received
IF Byte = 0x00 THEN
Start Timer
REPEAT
UNTIL (Timer > 50 ms OR New Byte Received)
CASE Timer IN
1 ms-4 ms: 600 Baud
5 ms-10 ms: 300 Baud
11 ms-15 ms: 150 Baud
16 ms-22 ms: 110 Baud
23 ms-32 ms: 75 Baud
33 ms-49 ms: 50 Baud
ELSE: Timed out; reset
END CASE;
ELSIF Byte >= 0xF1 THEN
19200 Baud
ELSE
CASE Byte IN
0x0D: 9600 Baud
0xE6: 4800 Baud
0x78: 2400 Baud
0xE0,0xF0: 1800 Baud
0x80: 1200 Baud
ELSE: Line noise; reset
END CASE
END IF
|