製作usb轉串口固件

定時器相關

最近在用 ch552 芯片做 usb 轉串口的調試板

串口需要設置波特率,在 ch552 上需要給串口提供設定的波特率,這裏使用定時器產生

初值計算問題

一般使用定時器的模式2,8位自動重裝,使用 TL 計數,使用 TH 重裝

波特率初值的計算公式如下

THn = TLn = 256 - fsys/12/16/波特率/2

ch552 有 1T 的模式,所以可以不用除以 12,還可以設置波特率倍頻,也不用除以 2,這樣的話,計算公式改爲

THn = TLn = 256 - fsys/16/波特率

這裏順便提一下除以 16 的原因。在51單片機內置的串口模塊中,他採取的方式是把一位信號採集16次,然後把第7、8、9次取出來,如果這三次中其中有兩次是高電平的話,就認定這一位數據是1,如果兩次數據是低電平,就認爲是0。這樣可以提高通信的容錯率。【參考來源】
(PS:STC12C5A60S2 的 datasheet 8.2.2 節有更詳細的介紹)

波特率誤差問題

異步串口有起始和停止位,再加校驗位,8位字節最多可有12位。51單片機的串口模塊通常在位中間採樣,如此12位偏差50%就可能採樣錯誤造成通信失敗,對應通信雙方波特率偏差約50%/12=4%。

串口通信誤碼率與通信雙方波特率高低無關,不過波特率和通信距離的乘積有上限。【參考來源】

本文中使用的 ch552 ,系統時鐘爲 16M,下面對是使用的常見的波特率進行誤差分析。因爲 ch552 不支持浮點波特率,所以對於小數部分進行截斷

波特率 THn 誤差 THn 誤差
2400 416 0.16% 417 0.08%
9600 104 0.16% 105 0.79%
19200 52 0.16% 53 1.73%
38400 26 0.16% 27 3.55%
43000 23 1.11% 24 3.1%
56000 17 5% 18 0.79%
57600 17 2.12% 18 3.55%
115200 8 8.5% 9 3.55%
128000 7 11.6% 8 2.3%

雖然說理論上 5% 的誤差對於異步串口通信來說都是可以容忍的,但是可能存在收發雙方都存在偏差的情況,所以需要控制偏差在 2.5% 以下。

本次實驗中使用發現,表中誤差達到 3.55% 的波特率,在接收數據的時候都會亂碼

usb 相關

既然 ch552 上的串口波特率需要定時器的支持,那在 host 設備上設置波特率的時候,如何將 host 設備上對於波特率的需求傳達給 ch552 呢

ch552 的 usb 驅動是 ftdi 的,通過對 ftdi 的 usb 驅動反彙編可以知道設置波特率的 usb 非標準請求編碼(當然不是我反彙編的☺),然後通過這個編碼獲取 usb 驅動送過來的一個 divisor 值。計算公式如下

divisor = 48M/16/波特率

這個計算是在 usb 驅動中完成的

在接收 host 端發送過來的 divisor 時要注意,自己的串口在什麼接口,需要進行判斷

if(UsbSetupBuf->wIndexL == 1)
    // inf1
else
    // inf2

由於 ch552 不支持浮點波特率,因此可以忽略 host 端傳送過來的 divisor 的小數部分, divisor 的低 14 位是整數部分,高兩位是小數部分。

divisor = UsbSetupBuf->wValueL |
        (UsbSetupBuf->wValueH << 8);
divisor &= 0x3fff;

在接收到 divisor 後,還需要對這個數進行處理。因爲 ftdi 驅動中使用的是 48M 的時鐘進行波特率的計算的,這裏我們需要轉換成自己的系統時鐘,然後再進行定時器的 THn 進行設置

divisor = divisor / 3; // 16M CPU時鐘
if(UsbSetupBuf->wIndexL == 1) // 串口位於接口1
    TH1 = 0 - divisor;

知乎鏈接

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章