首先想說,12MHZ真的是有問題。
我使用的是
STC89C52RC的單片機,他的最小系統板的的晶振是12Mhz,但是這個開發板上買的晶振就沒寫頻率!!!我一直以為這是默認的11.0592Mhz,因為之前用的最小系統板都是這個頻率。在沒有使用串口通信的時候,不管是11.0592M還是12M,都對程序的影響不是很大,所以一直沒有太注意這方面的問題。
直到今天,需要用到UART串口通信,搞了快兩天,輸出到電腦端一直是亂碼!!!真的差點都放棄了。現在想想幸好當時沒有放棄。現在終於想通了。
其實就是晶振的問題。實際上我的這個板子上是12Mhz,而書上和我在網上找到的例程上面都是按照11.0592M計算的。所以我在一個錯誤的基礎上面,肯定找不到正確的出路。
首先,通信波特率的定時器初值的計算公式:
TH1 = TL1 = 256 - 晶振/12/16/波特率/2.
如果寫了PCON=0X80,就不需除2.,PCON為電源管理寄存器,他的最高位可以把波特率提高一倍。
在這里 ,256是8位定時器的溢出值,也就是TL1的溢出值。12是說一個一個機器周期等於12個時鍾周期,值得關注的是16,在51單片機內置的串口模塊中,他采取的方式是把一位信號采集16次,然后把第7、8、9次取出來,如果這三次中其中有兩次是高電平的話,就認定這一位數據是1,如果兩次數據是低電平,就認為是0.這樣可以提高通信的容錯率。
首先先說一下為什么波特率 要設置成4800,9600,19200等等類似這樣的 數?為什么不是12345?我在一片博客中找到了可能的答案。
傳送門:http://blog.sina.com.cn/s/blog_6202cb4101011udd.html
1:根據電、傳輸介質等的物理特性結合串口設備使用的要求
為了保證有效通訊,根據電、傳輸介質等的物理特性結合串口設備使用的要求,確定RS232最大傳輸速率只能是115200,然后逐級二分得到57600,28800,19200……為適應這些速率,設計相應的晶振頻率。
2:這是由電信線路特性決定的
電話線路的帶通是300--3KHz,當時HAYES先搞的modem,所以用的2400HZ信號,對應波特率是2400。由於基本頻率確定了,以后采用的提高通訊速率的方法都是在2400基礎上倍頻的,所以形成了9600,19200。
不管哪種說法,都是先有波特率再有晶振頻率。重點:先有波特率再有晶振頻率!!!!
也就是說,人們首先通過實驗發現了合適的傳輸波特率,然后根據這個波特率及其倍頻,計算出了合適的單片機時鍾頻率,也即是我們的晶振頻率。
使用多了會發現,采用這個公式計算的時候,有時候會出現小數點的情況。這也是為什么晶振使用11.0592的原因。當使用這個頻率的晶振,計算的時候,基本不會出現小數點 。而使用12M的時候,很多小數點。
那么我們先不管這個11.0592到底是怎么來的?我們就看一下這個頻率和12M的頻率的對比,他們分別使用的時候,計算出來的TH1的初值到底是多少。
下面表格的數據是我通過上面的公式計算出來的。
可以看出,在12M的時候,只有把波特率2400bps/s最合適,誤差是0.16%,這樣就不會產生亂碼了,TH1和TL1都設為0xf3。其他小數點都不合適,四舍五入的話,誤差率也比較大。9600的情況下會有7.8%的誤差,所以會產生亂碼,其實我試了一次,9600波特率的時候,無法實現傳輸。但是我不是很清楚他的這個誤差是怎么算出來的,如果你看到這個,又恰巧你知道 這個問題,那么想麻煩你在下面回復一下,謝謝。
在12M晶振下,我嘗試了用2400波特率和4800波特率進行傳輸,結果如下,
這是4800波特率的,可以看到,誤差還是挺大的了。
這是2400波特率的傳輸,發現基本沒有錯誤:
還有一點,就是我發現,在程序里面 是直接把那個公式寫進去還是先自己算出來值化為16進制,在賦給TH1和TL1,這兩種情況的傳輸效果是不同的。我估計就是因為12M晶振的問題,因為用公式算出來 的值小數點挺多的,會產生誤差 ,而自己給的是一個確定的值。所以盡量自己先算出來,然后賦值,這樣比較精確,實在不知道的話,就把小數點的尾數是進位還是舍去都試一遍,看看哪個的傳輸效率更高一點。
下面是直接用公式的,發現誤差很大。基本上收不到數據。
2400的波特率計算公式也是一樣,基本收不到數據,只有自己計算出來才行
下面是在另一篇博客里的發現的相關內容:
傳送門:http://blog.163.com/cobain_731/blog/static/2060972022012330115642462/
為什么51單片機的晶振一般使用11.0592?
用11.0592晶振的原因是51單片機的定時器導致的。用51單片機的定時器做波特率發生器時,如果用11.0592Mhz的晶振,根據公式算下來需要定時器設置的值都是整數;如果用12Mhz晶振,則波特率都是有偏差的,比如9600,用定時器取0XFD,實際波特率10000,一般波特率偏差在4%左右都是可以的,所以也還能用STC90C516 晶振12M 波特率9600 ,倍數時誤差率6.99%,不倍數時誤差率8.51%,數據肯定會出錯。 這也就是串口通信時大家喜歡用11.0592MHz晶振的原因,在波特率倍速時,最高可達到57600,誤差率0.00%。 用12MHz,最高也就4800,而且有0.16%誤差率,但在允許范圍,所以沒多大影響。
總結:
1、檢查你的晶振頻率,盡量自己先算出定時器初始值。然后賦給TH1。
2、如果你的晶振是12Mhz的,那么很遺憾,雖然你的頻率很高,但是當你使用UART串口的時候會很難受。只能選取2400, 0xf3,有一個小技巧,你也可以使用倍頻,把PCON| = 0x80,然后使用4800.計算出來的值和2400一樣,但是快了一倍。
3、如果你的晶振是11.0592Mhz的話。也慢不到哪里去,普通需求還是可以滿足的。但是他的優勢體現在你使用UART串口的時候,很多波特率可以選擇。所以就很nice。