新聞中心

EEPW首頁 > 嵌入式系統(tǒng) > 設(shè)計(jì)應(yīng)用 > 單片機(jī)模擬串口發(fā)送和波特率問題

單片機(jī)模擬串口發(fā)送和波特率問題

作者: 時(shí)間:2016-11-27 來源:網(wǎng)絡(luò) 收藏
傳統(tǒng)的8051系列單片機(jī)一般都配備一個(gè)串口,而STC 89C52RC增強(qiáng)型單片機(jī)也不例外,只有一個(gè)串口可供使用,這樣就出問題了,假如當(dāng)前單片機(jī)系統(tǒng)要求二個(gè)串口或多個(gè)串口進(jìn)行同時(shí)通信,8051系列單片機(jī)只有一個(gè)串口可供通信就顯得十分尷尬,但是在實(shí)際的應(yīng)用中,有兩種方法可以選擇。
方法1:使用能夠支持多串口通信的單片機(jī),不過通過更換其他單片機(jī)來代替8051系列單片機(jī),這樣就會(huì)直接導(dǎo)致成本的增加,優(yōu)點(diǎn)就是編程簡(jiǎn)單,而且通信穩(wěn)定可靠。
方法2:在IO資源比較充足的情況下,可以通過IO來模擬串口的通信,雖然這樣會(huì)增加編程的難度,模擬串口的波特率會(huì)比真正的串口通信低一個(gè)層次,但是唯一優(yōu)點(diǎn)就是成本上得到控制,而且通過不同的IO組合可以實(shí)現(xiàn)更加之多的模擬串口,在實(shí)際應(yīng)用中往往會(huì)采用模擬串口的方法來實(shí)現(xiàn)多串口通信。
普遍使用串口通信的數(shù)據(jù)流都是1位起始位、8位數(shù)據(jù)位、1位停止位的格式的,如表1。
表1
起始位8位數(shù)據(jù)位停止位
0Bit0Bit1Bit2Bit3Bit4Bit5Bit6Bit71

要注意的是,起始位作為識(shí)別是否有數(shù)據(jù)到來,停止位標(biāo)志數(shù)據(jù)已經(jīng)發(fā)送完畢。起始位固定值為0,停止位固定值為1,那么為什么起始位要是0,停止位要是1呢?這個(gè)很好理解,假設(shè)停止位固定值為1,為了更加易識(shí)別數(shù)據(jù)的到來,電平的跳變最為簡(jiǎn)單也最容易識(shí)別,那么當(dāng)有數(shù)據(jù)來的時(shí)候,只要在規(guī)定的時(shí)間內(nèi)檢測(cè)到發(fā)送過來的第一位的電平是否0值,就可以確定是否有數(shù)據(jù)到來;另外停止位為1的作用就是當(dāng)沒有收發(fā)數(shù)據(jù)之后引腳置為高電平起到抗干擾的作用。
在平時(shí)使用紅外無線收發(fā)數(shù)據(jù)時(shí),一般都采用模擬串口來實(shí)現(xiàn)的,但是有個(gè)問題要注意,波特率越高,傳輸距離越近;波特率越低,傳輸距離越遠(yuǎn)。對(duì)于這些通過模擬串口進(jìn)行數(shù)據(jù)傳輸,波特率適宜為1200b/s來進(jìn)行數(shù)據(jù)傳輸。
例子:在使用單片機(jī)的串口接收數(shù)據(jù)實(shí)驗(yàn)當(dāng)中,使用串口調(diào)試助手發(fā)送16字節(jié)數(shù)據(jù),單片機(jī)采用模擬串口的方法將接收到的數(shù)據(jù)返發(fā)到PC機(jī)。
模擬串口實(shí)驗(yàn)代碼:



1#include"stc.h"
2
3#defineRXD P3_0//宏定義:接收數(shù)據(jù)的引腳
4#defineTXD P3_1//宏定義:發(fā)送數(shù)據(jù)的引腳
5#defineRECEIVE_MAX_BYTES 16//宏定義:最大接收字節(jié)數(shù)
6
7#defineTIMER_ENABLE() {TL0=TH0;TR0=1;fTimeouts=0;}//使能T/C
8#defineTIMER_DISABLE() {TR0=0;fTimeouts=0;}//禁止T/C
9#defineTIMER_WAIT() {while(!fTimeouts);fTimeouts=0;}//等待T/C超時(shí)
10
11
12unsignedcharfTimeouts=0;//T/C超時(shí)溢出標(biāo)志位
13unsignedcharRecvBuf[16];//接收數(shù)據(jù)緩沖區(qū)
14unsignedcharRecvCount=0;//接收數(shù)據(jù)計(jì)數(shù)器
15
16
17
23voidSendByte(unsignedcharb)
24{
25unsignedchari=8;
26
27TXD=0;
28
29TIMER_ENABLE();
30TIMER_WAIT();
31
32
33while(i--)
34{
35if(b&1)TXD=1;
36elseTXD=0;
37
38TIMER_WAIT();
39
40b>>=1;
41
42}
43
44
45TXD=1;
46
47TIMER_WAIT();
48TIMER_DISABLE();
49}
50
56unsignedcharRecvByte(void)
57{
58unsignedchari;
59unsignedcharb=0;
60
61TIMER_ENABLE();
62TIMER_WAIT();
63
64for(i=0;i<8;i++)
65{
66if(RXD)b|=(1<67
68TIMER_WAIT();
69}
70
71TIMER_WAIT();//等待結(jié)束位
72TIMER_DISABLE();
73
74returnb;
75
76}
77
83voidPrintfStr(char*pstr)
84{
85while(pstr&&*pstr)
86{
87SendByte(*pstr++);
88}
89}
90
96voidTimerInit(void)
97{
98TMOD=0x02;
99TR0=0;
100TF0=0;
101TH0=(256-99);
102TL0=TH0;
103ET0=1;
104EA=1;
105}
106
112unsignedcharStartBitCome(void)
113{
114return(RXD==0);
115}
116
122voidmain(void)
123{
124unsignedchari;
125
126TimerInit();
127
128PrintfStr("Hello 8051rn");
129
130while(1)
131{
132if(StartBitCome())
133{
134RecvBuf[RecvCount++]=RecvByte();
135
136if(RecvCount>=RECEIVE_MAX_BYTES)
137{
138RecvCount=0;
139
140for(i=0;i141{
142SendByte(RecvBuf[i]);
143}
144}
145}
146
147}
148}
149
155voidTimer0IRQ(void) interrupt1using0
156{
157fTimeouts=1;
158}
159

代碼分析
在模擬串口實(shí)驗(yàn)代碼中,宏的使用占用了相當(dāng)?shù)囊徊糠帧?br />#define RXD P3_0//宏定義:接收數(shù)據(jù)的引腳
#define TXD P3_1//宏定義:發(fā)送數(shù)據(jù)的引腳
#define TIMER_ENABLE(){TL0=TH0;TR0=1;fTimeouts=0;}//使能T/C
#define TIMER_DISABLE() {TR0=0;fTimeouts=0;}//禁止T/C
#define TIMER_WAIT(){while(!fTimeouts);fTimeouts=0;}//等待T/C超時(shí)

模擬串口接收引腳為P3.0,發(fā)送引腳為P3.1。為了達(dá)到精確的定時(shí),減少模擬串口時(shí)收發(fā)數(shù)據(jù)的累積誤差,有必要通過對(duì)T/C進(jìn)行頻繁的使能和禁止等操作。例如宏TIMER_ENABLE為使能T/C,宏TIMER_DISABLE禁止T/C,宏TIMER_WAIT等待T/C超時(shí)。
模擬串口的工作波特率為9600b/s,在串口收發(fā)的數(shù)據(jù)流當(dāng)中,每一位的時(shí)間為1/9600≈104us,
若單片機(jī)工作在12MHz頻率下,使用T/C0工作在方式2,那么為了達(dá)到104us的定時(shí)時(shí)間,TH0、TL0的初值為256-104=152,在實(shí)際的模擬串口中,往往出現(xiàn)收發(fā)數(shù)據(jù)不正確的現(xiàn)象。原因就在于TH0、TL0的初值,或許很多人會(huì)疑惑,按道理來說,計(jì)算T/C0的初值是沒有錯(cuò)的。對(duì),是沒有錯(cuò),但是在SendByte和Recv的函數(shù)當(dāng)中,執(zhí)行每一行代碼都要消耗一定的時(shí)間,這就是所謂的“累積誤差”導(dǎo)致收發(fā)數(shù)據(jù)出現(xiàn)問題,因此我們必須通過實(shí)際測(cè)試得到TH0、TL0的初值,最佳值256-99=157。那么在T/C初始化TimerInit函數(shù)中,TH0、TL0的初值不能夠按照常規(guī)來計(jì)算得到,實(shí)際初值在正常初值附近,可以通過實(shí)際測(cè)試得到。
模擬串口主要復(fù)雜在模擬串口發(fā)送與接收,具體實(shí)現(xiàn)函數(shù)在SendByte和RecvByte函數(shù),這兩個(gè)函數(shù)必須要遵循“1位起始位、8位數(shù)據(jù)位、1位停止位”的數(shù)據(jù)流。
SendByte函數(shù)用于模擬串口發(fā)送數(shù)據(jù),以起始位“0”作為移位傳輸?shù)钠鹗紭?biāo)志,然后將要發(fā)送的自己從低字節(jié)到高字節(jié)移位傳輸,最后以停止位“1”作為移位傳輸?shù)慕Y(jié)束標(biāo)志。
RecvByte函數(shù)用于模擬串口接收數(shù)據(jù),一旦檢測(cè)到起始位“0”,就立刻將接收到的每一位移位存儲(chǔ),最后以判斷停止位“1”結(jié)束當(dāng)前數(shù)據(jù)的接收。
main函數(shù)完成T/C的初始化,在while(1)死循環(huán)以檢測(cè)起始位“0”為目的,當(dāng)接收到的數(shù)據(jù)達(dá)到宏RECEIVE_MAX_BYTES的個(gè)數(shù)時(shí),將接收到的數(shù)據(jù)返發(fā)到外設(shè)。

波特率的研究


通常情況下,8051系列單片機(jī)外接晶振頻率一般是12MHz、24MHz、48MHz如圖7-6-1,為什么會(huì)這樣選取呢?從前面的章節(jié)已經(jīng)介紹8051系列單片機(jī)的每12個(gè)時(shí)鐘周期為一個(gè)指令周期,當(dāng)8051系列單片機(jī)外接12MHz晶振時(shí),指令周期=12/12MHz=1us;若外接24MHz晶振時(shí),指令周期=12/24MHz=0.5us;若外接48MHz晶振時(shí),指令周期=12/48MHz=0.25us。8051系列單片機(jī)外接能夠被除盡的晶振,在使用單片機(jī)內(nèi)部的定時(shí)器/計(jì)數(shù)器資源時(shí)作定時(shí)器使用時(shí)能夠得到精確定時(shí)應(yīng)用;當(dāng)使用匯編語言編程時(shí),可以清楚知道當(dāng)前每一行代碼執(zhí)行的時(shí)間。
8051系列單片機(jī)外接能夠被除盡的晶振即12MHz、24MHz、48MHz這些晶振時(shí),波特率的精確性就得不到保證。

假若現(xiàn)在單片機(jī)外接的晶振為12MHz時(shí),以T/C2作波特率發(fā)生器,根據(jù)波特率公式:
波特率=Fosc/2x16x(65536-t)
9600=12MHz/2x16x(65536-t)
t=65496.9375
“65496.9375”不是一個(gè)整數(shù)值,是一個(gè)帶有小數(shù)點(diǎn)的數(shù)值。對(duì)于常用的8位、9位、11位一幀的數(shù)據(jù)接收與傳輸,最大的允許誤差分別是6.25%、5.56%、4.5%。雖然波特率允許誤差,但是這樣通信時(shí)便會(huì)產(chǎn)生積累誤差,進(jìn)而影響數(shù)據(jù)的正確性。唯一的解決辦法就是更改單片機(jī)外接的晶振頻率,更改為常用于產(chǎn)生精確波特率的晶振如11.0592MHz、22.1184MHz。
假若現(xiàn)在單片機(jī)外接的晶振為11.0592MHz時(shí),以T/C2作波特率發(fā)生器,根據(jù)波特率公式:
波特率=Fosc/2x16x(65536-t)
9600=11.0592MHz/2x16x(65536-t)
t=65500=0xFFDC

雖然使用11.0592MHz、22.1184MHz的晶振能夠產(chǎn)生精確的波特率,但是用于系統(tǒng)精確的定時(shí)服務(wù)不是十分的理想。例如單片機(jī)外接11.0592MHz晶振時(shí),指令周期=12/11.0592MHz≈1.085us,是一個(gè)無限循環(huán)的小數(shù)。當(dāng)單片機(jī)外接22.1184MHz晶振時(shí),指令周期=12/22.1184MHz≈0.5425us,也是一個(gè)無限循環(huán)的小數(shù)。

串口工作在方式1時(shí)分別采用T/C1和T/C2產(chǎn)生常用波特率初值表如下。
波特率
(11.0592MHz)
初值波特率
(12MHz)
初值
TH1、TL1
(SMOD=0)
TH1、TL1
(SMOD=1)
TH1、TL1
(SMOD=0)
TH1、TL1
(SMOD=1)
12000xE70xD012000xE50xCB
24000xF30xE724000xF20xE5
48000xF90xF348000xF90xF2
96000xFC0xF996000xFC0xF9
144000xFD0xFB144000xFD0xFB
192000xFE0xFC192000xFE0xFC


波特率
(11.0592MHz)
初值波特率
(12MHz)
初值
RCAL2HRCAL2LRCAL2HRCAL2L
12000xFE0xE012000xFE0xC8
24000xFF0x7024000xFF0x64
48000xFF0xD848000xFF0xB2
96000xFF0xDC96000xFF0xD9
144000xFF0xE8144000xFF0xE6
192000xFF0xEE192000xFF0xED

如果大家想通過設(shè)置不同的晶振獲取更加多的波特率的值,可以下載以下工具進(jìn)行計(jì)算:
軟件下載地址:http://files.cnblogs.com/wenziqi/單片機(jī)多功能助手.rar



評(píng)論


技術(shù)專區(qū)

關(guān)閉