<meter id="pryje"><nav id="pryje"><delect id="pryje"></delect></nav></meter>
          <label id="pryje"></label>

          新聞中心

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

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

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

          要注意的是,起始位作為識(shí)別是否有數(shù)據(jù)到來(lái),停止位標(biāo)志數(shù)據(jù)已經(jīng)發(fā)送完畢。起始位固定值為0,停止位固定值為1,那么為什么起始位要是0,停止位要是1呢?這個(gè)很好理解,假設(shè)停止位固定值為1,為了更加易識(shí)別數(shù)據(jù)的到來(lái),電平的跳變最為簡(jiǎn)單也最容易識(shí)別,那么當(dāng)有數(shù)據(jù)來(lái)的時(shí)候,只要在規(guī)定的時(shí)間內(nèi)檢測(cè)到發(fā)送過(guò)來(lái)的第一位的電平是否0值,就可以確定是否有數(shù)據(jù)到來(lái);另外停止位為1的作用就是當(dāng)沒(méi)有收發(fā)數(shù)據(jù)之后引腳置為高電平起到抗干擾的作用。
          在平時(shí)使用紅外無(wú)線收發(fā)數(shù)據(jù)時(shí),一般都采用模擬串口來(lái)實(shí)現(xiàn)的,但是有個(gè)問(wèn)題要注意,波特率越高,傳輸距離越近;波特率越低,傳輸距離越遠(yuǎn)。對(duì)于這些通過(guò)模擬串口進(jìn)行數(shù)據(jù)傳輸,波特率適宜為1200b/s來(lái)進(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ù)的累積誤差,有必要通過(guò)對(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ì)疑惑,按道理來(lái)說(shuō),計(jì)算T/C0的初值是沒(méi)有錯(cuò)的。對(duì),是沒(méi)有錯(cuò),但是在SendByte和Recv的函數(shù)當(dāng)中,執(zhí)行每一行代碼都要消耗一定的時(shí)間,這就是所謂的“累積誤差”導(dǎo)致收發(fā)數(shù)據(jù)出現(xiàn)問(wèn)題,因此我們必須通過(guò)實(shí)際測(cè)試得到TH0、TL0的初值,最佳值256-99=157。那么在T/C初始化TimerInit函數(shù)中,TH0、TL0的初值不能夠按照常規(guī)來(lái)計(jì)算得到,實(shí)際初值在正常初值附近,可以通過(guò)實(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)使用匯編語(yǔ)言編程時(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è)無(wú)限循環(huán)的小數(shù)。當(dāng)單片機(jī)外接22.1184MHz晶振時(shí),指令周期=12/22.1184MHz≈0.5425us,也是一個(gè)無(wú)限循環(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

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



          評(píng)論


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

          關(guān)閉
          看屁屁www成人影院,亚洲人妻成人图片,亚洲精品成人午夜在线,日韩在线 欧美成人 (function(){ var bp = document.createElement('script'); var curProtocol = window.location.protocol.split(':')[0]; if (curProtocol === 'https') { bp.src = 'https://zz.bdstatic.com/linksubmit/push.js'; } else { bp.src = 'http://push.zhanzhang.baidu.com/push.js'; } var s = document.getElementsByTagName("script")[0]; s.parentNode.insertBefore(bp, s); })();