久久久久久久999_99精品久久精品一区二区爱城_成人欧美一区二区三区在线播放_国产精品日本一区二区不卡视频_国产午夜视频_欧美精品在线观看免费

 找回密碼
 立即注冊

QQ登錄

只需一步,快速開始

搜索
查看: 2553|回復: 0
打印 上一主題 下一主題
收起左側

犧牲半個定時器,得到一個串口

[復制鏈接]
跳轉到指定樓層
樓主
ID:99615 發表于 2015-12-20 00:39 | 只看該作者 回帖獎勵 |倒序瀏覽 |閱讀模式

傳統的8051 系列單片機一般都配備一個串口,尤其是PIC系列的低端單片機根本就沒有串口。這樣就出問題了,假如當前單片機系統要求二個串口或多個串口進行同時通信,單片機只有一個串口可供通信就顯得十分尷尬,但是在實際的應用中,有兩種方法可以選擇。

方法1:使用能夠支持多串口通信的單片機,不過通過更換其他單片機多串口單片機會接導致成本的增加。優點就是編程簡單,而且通信穩定可靠。

方法2:在IO 資源比較充足的情況下,可以通過IO 來模擬串口的通信,雖然這樣會增加編程的難度,模擬串口的波特率會比真正的串口通信低一個層次,但是唯一優點就是成本上得到控制,而且通過不同的IO 組合可以實現更加之多的模擬串口,在實際應用中往往會采用模擬串口的方法來實現多串口通信。

普遍使用串口通信的數據流都是1 位起始位、8 位數據位、1 位停止位的格式的。

要注意的是,起始位作為識別是否有數據到來,停止位標志數據已經發送完畢。起始位固定值為0,停止位固定值為1,那么為什么起始位要是0,停止位要是1 呢?這個很好理解,假設停止位固定值為1,為了更加易識別數據的到來,電平的跳變最為簡單也最容易識別,那么當有數據來的時候,只要在規定的時間內檢測到發送過來的第一位的電平是否0 值,就可以確定是否有數據到來;另外停止位為1 的作用就是當沒有收發數據之后引腳置為高電平起到抗干擾的作用。

在平時使用紅外無線收發數據時,一般都采用模擬串口來實現的,但是有個問題要注意,波特率越高,傳輸距離越近;波特率越低,傳輸距離越遠。對于這些通過模擬串口進行數據傳輸,波特率適宜為1200b/s來進行數據傳輸。

下面,就調試一個模擬串口通訊的例程,模擬串口接收引腳為P3.0,發送引腳為P3.1

 

說明:

為了達到精確的定時,減少模擬串口時收發數據的累積誤差,有必要通過對T/C 進行頻繁的使能和禁止等操作。例如宏TIMER_ENABLE 為使能T/C,宏TIMER_DISABLE 禁止T/C,宏TIMER_WAIT 等待T/C 超時。

模擬串口的工作波特率為9600b/s,在串口收發的數據流當中,每一位的時間為1/9600104us,若單片機工作在12MHz 頻率下,使用T/C0 工作在方式2,那么為了達到104us 的定時時間,TH0TL0的初值為256-104=152,在實際的模擬串口中,往往出現收發數據不正確的現象。原因就在于TH0TL0的初值,或許很多人會疑惑,按道理來說,計算T/C0 的初值是沒有錯的。對,是沒有錯,但是在SendByteRecv 的函數當中,執行每一行代碼都要消耗一定的時間,這就是所謂的“累積誤差”導致收發數據出現問題,因此我們必須通過實際測試得到TH0TL0 的初值,最佳值256-99=157。那么在T/C 初始化TimerInit 函數中,TH0TL0 的初值不能夠按照常規來計算得到,實際初值在正常初值附近,可以通過實際測試得到。

模擬串口主要復雜在模擬串口發送與接收,具體實現函數在SendByte RecvByte 函數,這兩個函數必須要遵循“1 位起始位、8 位數據位、1 位停止位”的數據流。

SendByte 函數用于模擬串口發送數據,以起始位“0”作為移位傳輸的起始標志,然后將要發送的自己從低字節到高字節移位傳輸,最后以停止位“1”作為移位傳輸的結束標志。

RecvByte 函數用于模擬串口接收數據,一旦檢測到起始位“0”,就立刻將接收到的每一位移位存儲,最后以判斷停止位“1”結束當前數據的接收。

main 函數完成T/C 的初始化,在while(1)死循環以檢測起始位“0”為目的,當接收到的數據達到宏RECEIVE_MAX_BYTES 的個數時,將接收到的數據返發到外設。
    STC12C5A32S2調試通過,臨時沒有發現錯誤。其他類型的單片機可根據此算法移植。
UART.C:
#include "stc.h"
#include "S_UART.h"

unsigned char fTimeouts=0;//定時器超時溢出標志位
unsigned char RecvBuf[16];
unsigned char RecvCount=0;

void Delay100ms()  //@12.000MHz
{
 unsigned char i, j, k;

 i = 5;
 j = 144;
 k = 71;
 do
 {
  do
  {
   while (--k);
  } while (--j);
 } while (--i);
}

/****************************************
*函數名稱:UARTSendByte
*輸    入:byte 要發送的字節
*輸    出:無
*功    能:串口發送單個字節
******************************************/
void SendByte(unsigned char b)
{
     unsigned char i=8;    
     TXD=0;

     TIMER_ENABLE();
     TIMER_WAIT();   

     while(i--)
  {
        if(b&1)TXD=1;
        else   TXD=0;
        TIMER_WAIT();       
        b>>=1;
     }    
     TXD=1;
     TIMER_WAIT();
     TIMER_DISABLE();
}
/****************************************
*函數名稱:RecvByte
*輸    入:無
*輸    出:單個字節
*功    能:串口 接收單個字節
******************************************/
unsigned char RecvByte(void)
{
     unsigned char i;
  unsigned char b=0;
    
     TIMER_ENABLE();
     TIMER_WAIT();

     for(i=0;i<8;i++)
  {
      if(RXD)b|=(1<<i);

   TIMER_WAIT();
  }

     TIMER_WAIT();  //等待結束位
     TIMER_DISABLE();
 
  return b;

}
/****************************************
*函數名稱:PrintfStr
*輸    入:pstr 字符串
*輸    出:無
*功    能:串口 打印字符串
******************************************/
void PrintfStr(char * pstr)
{
     while(pstr && *pstr)
  {
        SendByte(*pstr++);
  }
}
/****************************************
*函數名稱:TimerInit
*輸    入:無
*輸    出:無
*功    能:定時器初始化
******************************************/
void TimerInit(void)
{
 AUXR &= 0x7F;  //定時器時鐘12T模式
 TMOD &= 0xF0;  //設置定時器模式
 TMOD |= 0x02;  //設置定時器模式
 TL0 = 0x98;  //設置定時初值
 TH0 = 0x98;  //設置定時重載值
 TF0 = 0;  //清除TF0標志
 TR0 = 1;  //定時器0開始計時
 ET0=1;
    EA=1;
}
/****************************************
*函數名稱:StartBitCome
*輸    入:無
*輸    出:0/1
*功    能:是否有起始位到達
******************************************/
unsigned char StartBitCome(void)
{
 return (RXD==0);
}
/****************************************
*函數名稱:main
*輸    入:無
*輸    出:無
*功    能:函數主體
******************************************/
void main(void)
{
     unsigned char i;

     TimerInit();

  PrintfStr("Hello 8051\r\n");

  while(1)
  {
     if(StartBitCome())
     {                 
           RecvBuf[RecvCount++]=RecvByte();          
           if(RecvCount>=RECEIVE_MAX_BYTES)
           {
              RecvCount=0;
              for(i=0;i<RECEIVE_MAX_BYTES;i++)
              {
                  SendByte(RecvBuf[i]);
              }
           }   
        }
     PrintfStr("Hello 8051\r\n");
    Delay100ms();
  }
}
/****************************************
*函數名稱:TimerIRQ
*輸    入:無
*輸    出:無
*功    能:定時器中斷服務程序
******************************************/
void TimerIRQ(void) interrupt 1 using 0
{
     fTimeouts=1;
}


UART.h
#ifndef __S_UART_H__
#define __S_UART_H__

#define RXD P3_0            //宏定義:接收數據的引腳
#define TXD P3_1            //宏定義:發送數據的引腳
#define RECEIVE_MAX_BYTES 16//宏定義:最大接收字節數
#define TIMER_ENABLE()  {TL0=TH0;TR0=1;fTimeouts=0;}//使能定時器
#define TIMER_DISABLE() {TR0=0;fTimeouts=0;}//禁止定時器
#define TIMER_WAIT()    {while(!fTimeouts);fTimeouts=0;}//等待定時器超時
extern unsigned char fTimeouts;//定時器超時溢出標志位
extern unsigned char RecvBuf[16];
extern unsigned char RecvCount;

#endif 

分享到:  QQ好友和群QQ好友和群 QQ空間QQ空間 騰訊微博騰訊微博 騰訊朋友騰訊朋友
收藏收藏 分享淘帖 頂 踩
回復

使用道具 舉報

您需要登錄后才可以回帖 登錄 | 立即注冊

本版積分規則

手機版|小黑屋|51黑電子論壇 |51黑電子論壇6群 QQ 管理員QQ:125739409;技術交流QQ群281945664

Powered by 單片機教程網

快速回復 返回頂部 返回列表
主站蜘蛛池模板: 男女羞羞免费视频 | 日韩精品在线一区 | 日韩亚洲视频在线 | 欧美视频免费 | 天堂视频中文在线 | 欧美久久国产精品 | 九九九视频在线观看 | 一区二区三区四区免费视频 | 成人在线一区二区三区 | 玖玖国产 | 久久精品视频一区二区三区 | 成人在线一区二区三区 | 91精品在线播放 | 美女国产精品 | 精品蜜桃一区二区三区 | 九九视频在线观看视频6 | 亚洲社区在线 | 亚洲一区二区三区视频 | 久久黄网 | 欧美精品91 | 国产欧美视频一区二区三区 | 中文字幕国产视频 | 情侣酒店偷拍一区二区在线播放 | 欧美日韩亚洲国产 | hdfreexxxx中国妞| 欧美亚洲高清 | 午夜精品久久 | 91精品国产91久久久久久吃药 | 日韩精品一区二区三区在线播放 | 婷婷久久五月 | 国产精品99久久久久久动医院 | www操操 | 国产精品成人品 | 一区二区久久精品 | 一区二区免费在线观看 | 一区观看 | 国产日韩欧美在线播放 | 五月综合激情网 | 国产视频精品在线观看 | www.色五月.com| 一区二区三区四区五区在线视频 |