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

          新聞中心

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

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

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

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



          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超時
          10
          11
          12unsignedcharfTimeouts=0;//T/C超時溢出標志位
          13unsignedcharRecvBuf[16];//接收數(shù)據(jù)緩沖區(qū)
          14unsignedcharRecvCount=0;//接收數(shù)據(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();//等待結束位
          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ù)囊徊糠帧?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超時

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

          波特率的研究


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

          假若現(xiàn)在單片機外接的晶振為12MHz時,以T/C2作波特率發(fā)生器,根據(jù)波特率公式:
          波特率=Fosc/2x16x(65536-t)
          9600=12MHz/2x16x(65536-t)
          t=65496.9375
          “65496.9375”不是一個整數(shù)值,是一個帶有小數(shù)點的數(shù)值。對于常用的8位、9位、11位一幀的數(shù)據(jù)接收與傳輸,最大的允許誤差分別是6.25%、5.56%、4.5%。雖然波特率允許誤差,但是這樣通信時便會產(chǎn)生積累誤差,進而影響數(shù)據(jù)的正確性。唯一的解決辦法就是更改單片機外接的晶振頻率,更改為常用于產(chǎn)生精確波特率的晶振如11.0592MHz、22.1184MHz。
          假若現(xiàn)在單片機外接的晶振為11.0592MHz時,以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)精確的定時服務不是十分的理想。例如單片機外接11.0592MHz晶振時,指令周期=12/11.0592MHz≈1.085us,是一個無限循環(huán)的小數(shù)。當單片機外接22.1184MHz晶振時,指令周期=12/22.1184MHz≈0.5425us,也是一個無限循環(huán)的小數(shù)。

          串口工作在方式1時分別采用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

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



          評論


          技術專區(qū)

          關閉
          看屁屁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); })();