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

 找回密碼
 立即注冊

QQ登錄

只需一步,快速開始

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

玩轉單片機之--串口通信,接收數據

[復制鏈接]
跳轉到指定樓層
樓主
ID:90014 發表于 2015-9-15 20:23 | 只看該作者 回帖獎勵 |倒序瀏覽 |閱讀模式
單片機接收代碼

#include <reg51.h>
#define uchar unsigned char    //byte
#define uint unsigned int    //word
sbit led1=P0^0;     
sbit fir=P2^4; //fir=0;工作
sbit sec=P2^5; //sec=0;工作
sbit thi=P2^6; //thi=0;工作
sbit fot=P2^7; //fot=0;工作
uchar table[]={0x28,0xeb,0x32,0xa2,0xe1,0xa4,0x24,0xea,0x20,0xa0};
//P1=table[ i];/* 0    1    2   3    4    5    6    7    8    9 */
static uchar dispbuf[5];
//動態顯示數字的函數
void scandisp(void)
{
       unsigned int i;
       fir=0;
       P1=table[ dispbuf[0] ];
       for(i=0;i<200;i++);
fir=1;
       sec=0;
       P1=table[ dispbuf[1] ];
       for(i=0;i<200;i++);
sec=1;
       thi=0;
       P1=table[ dispbuf[2] ];
       for(i=0;i<200;i++);
thi=1;
       fot=0;
       P1=table[ dispbuf[3] ];
       for(i=0;i<200;i++);
fot=1;
}   
//十六進制轉十進制存儲
void HEX_TO_BCD(unsigned int n)
{
       dispbuf[3]=n/1000;
       dispbuf[2]=(n/100)%10;
       dispbuf[1]=(n/10)%10;
       dispbuf[0]=n%10;
}
void main(void)
{   
     uchar a;
       uint mydata;
       mydata=0x00;
       TMOD=0x20;
       PCON=0x00;
       SCON=0x50;
       TL1=0xfd;
       TH1=0xfd;
       TR1=1;
       while(1)  //動態現實是接收的數據
       {     //如果沒有接收到數據,RI=0,一直循環顯示原值
              //如果有接收到數據,RI=1,跳出循環重新計算并再次進入循環
              HEX_TO_BCD(mydata);
              while(RI==0)  scandisp();
              RI=0;     //重新置0
              a=SBUF;   //從緩沖區獲取數據
           mydata=a;
                    
              //HEX_TO_BCD(mydata);
              //scandisp();
              //SBUF=a;
              //while(TI==0)
              //TI=0;
       }
}
1. 自定義數據通信協議
    這里所說的數據協議是建立在物理層之上的通信數據包格式。所謂通信的物理層就是指我們通常所用到的RS232、RS485、紅外、光纖、無線等等通信方式。在這個層面上,底層軟件提供兩個基本的操作函數:發送一個字節數據、接收一個字節數據。所有的數據協議全部建立在這兩個操作方法之上。
通信中的數據往往以數據包的形式進行傳送的,我們把這樣的一個數據包稱作為一幀數據。類似于網絡通信中的TCPIP協議一般,比較可靠的通信協議往往包含有以下幾個組成部分:幀頭、地址信息、數據類型、數據長度、數據塊、校驗碼、幀尾。
    幀頭和幀尾用于數據包完整性的判別,通常選擇一定長度的固定字節組成,要求是在整個數據鏈中判別數據包的誤碼率越低越好。減小固定字節數據的匹配機會,也就是說使幀頭和幀尾的特征字節在整個數據鏈中能夠匹配的機會最小。通常有兩種做法,一、減小特征字節的匹配幾率。二、增加特征字節的長度。通常選取第一種方法的情況是整個數據鏈路中的數據不具有隨即性,數據可預測,可以通過人為選擇幀頭和幀尾的特征字來避開,從而減小特征字節的匹配幾率。使用第二種方法的情況更加通用,適合于數據隨即的場合。通過增加特征字節的長度減小匹配幾率,雖然不能夠完全的避免匹配的情況,但可以使匹配幾率大大減小,如果碰到匹配的情況也可以由校驗碼來進行檢測,因此這種情況在絕大多說情況下比較可靠。
    地址信息主要用于多機通信中,通過地址信息的不同來識別不同的通信終端。在一對多的通信系統中,可以只包含目的地址信息。同時包含源地址和目的地址則適用于多對多的通信系統。
    數據類型、數據長度和數據塊是主要的數據部分。數據類型可以標識后面緊接著的是命令還是數據。數據長度用于指示有效數據的個數。
    校驗碼則用來檢驗數據的完整性和正確性。通常對數據類型、數據長度和數據塊三個部分進行相關的運算得到。最簡單的做法可是對數據段作累加和,復雜的也可以對數據進行CRC運算等等,可以根據運算速度、容錯度等要求來選取。
2. 上位機和下位機中的數據發送
    物理通信層中提供了兩個基本的操作函數,發送一個字節數據則為數據發送的基礎。數據包的發送即把數據包中的左右字節按照順序一個一個的發送數據而已。當然發送的方法也有不同。
    在單片機系統中,比較常用的方法是直接調用串口發送單個字節數據的函數。這種方法的缺點是需要處理器在發送過程中全程參與,優點是所要發送的數據能夠立即的出現在通信線路上,能夠立即被接收端接收到。另外一種方法是采用中斷發送的方式,所有需要發送的數據被送入一個緩沖區,利用發送中斷將緩沖區中的數據發送出去。這種方法的優點是占用處理器資源小,但是可能出現需要發送的數據不能立即被發送的情況,不過這種時延相當的小。對于51系列單片機,比較傾向于采用直接發送的方式,采用中斷發送的方式比較占用RAM資源,而且對比直接發送來說也沒有太多的優點。以下是51系列單片機中發送單個字節的函數。
void SendByte(unsigned char ch)
{
     SBUF = ch;
     while(TI == 0);
     TI = 0;
}
    上位機中關于串口通信的方式也有多種,這種方式不是指數據有沒有緩沖的問題,而是操作串口的方式不同,因為PC上數據發送基本上都會被緩沖后再發送。對于編程來說操作串口有三種方式,一、使用windows系統中自帶的串口通信控件,這種方式使用起來比較簡單,需要注意的是接收時的阻塞處理和線程機制。二、使用系統的API直接進行串口數據的讀取,在windows和linux系統中,設備被虛擬為文件,只需要利用系統提供的API函數即可進行串口數據的發送和讀取。三、使用串口類進行串口操作。在此只介紹windows環境下利用串口類編程的方式。
CSerialPort是比較好用的串口類。它提供如下的串口操作方法:
void WriteToPort(char* string, int len);
    串口初始化成功后,調用此函數即可向串口發送數據。為了避免串口緩沖所帶來的延時,可以開啟串口的沖刷機制。
3. 下位機中的數據接收和協議解析
    下位機接收數據也有兩種方式,一、等待接收,處理器一直查詢串口狀態,來判斷是否接收到數據。二、中斷接收。兩種方法的優缺點在此前的一篇關于串口通信的文章中詳細討論過。得出的結論是采用中斷接收的方法比較好。
    數據包的解析過程可以設置到不同的位置。如果協議比較簡單,整個系統只是處理一些簡單的命令,那么可以直接把數據包的解析過程放入到中斷處理函數中,當收到正確的數據包的時候,置位相應的標志,在主程序中再對命令進行處理。如果協議稍微復雜,比較好的方式是將接收的數據存放于緩沖區中,主程序讀取數據后進行解析。也有兩種方式交叉使用的,比如一對多的系統中,首先在接收中斷中解析“連接”命令,連接命令接收到后主程序進入設置狀態,采用查詢的方式來解析其余的協議。
    以下給出具體的實例。在這個系統中,串口的命令非常簡單。所有的協議全部在串口中斷中進行。數據包的格式如下:
0x55, 0xAA, 0x7E, 0x12, 0xF0, 0x02, 0x23, 0x45, SUM, XOR, 0x0D
    其中0x55, 0xAA, 0x7E為數據幀的幀頭,0x0D為幀尾,0x12為設備的目的地址,0xF0為源地址,0x02為數據長度,后面接著兩個數據0x23, 0x45,從目的地址開始結算累加、異或校驗和,到數據的最后一位結束。
    協議解析的目的,首先判斷數據包的完整性,正確性,然后提取數據類型,數據等數據,存放起來用于主程序處理。代碼如下:
if(state_machine == 0)       // 協議解析狀態機
{
      if(rcvdat == 0x55)       // 接收到幀頭第一個數據
          state_machine = 1;
      else
          state_machine = 0;      // 狀態機復位
}
else if(state_machine == 1)
{
      if(rcvdat == 0xAA)       // 接收到幀頭第二個數據
          state_machine = 2;
      else
          state_machine = 0;      // 狀態機復位
}
else if(state_machine == 2)
{
      if(rcvdat == 0x7E)       // 接收到幀頭第三個數據
          state_machine = 3;
     else
          state_machine = 0;      // 狀態機復位
}
else if(state_machine == 3)
{
      sumchkm = rcvdat;       // 開始計算累加、異或校驗和
      xorchkm = rcvdat;
      if(rcvdat == m_SrcAdr)      // 判斷目的地址是否正確
          state_machine = 4;
      else
          state_machine = 0;
}
else if(state_machine == 4)
{
      sumchkm += rcvdat;
      xorchkm ^= rcvdat;
      if(rcvdat == m_DstAdr)      // 判斷源地址是否正確
          state_machine = 5;
      else
          state_machine = 0;
   }
else if(state_machine == 5)
{
      lencnt = 0;            // 接收數據計數器
      rcvcount = rcvdat;        // 接收數據長度
      sumchkm += rcvdat;
      xorchkm ^= rcvdat;
      state_machine = 6;
}
else if(state _machine == 6 || state _machine == 7)
{
      m_ucData[lencnt++] = rcvdat;     // 數據保存
      sumchkm += rcvdat;
      xorchkm ^= rcvdat;
      if(lencnt == rcvcount)      // 判斷數據是否接收完畢
          state_machine = 8;
      else
          state_machine = 7;
}
else if(state_machine == 8)
{
      if(sumchkm == rcvdat)      // 判斷累加和是否相等
          state_machine = 9;
      else
          state_machine = 0;
}
else if(state_machine == 9)
{
      if(xorchkm == rcvdat)      // 判斷異或校驗和是否相等
          state_machine = 10;
      else
          state_machine = 0;
}
else if(state_machine == 10)
{
      if(0x0D == rcvdat)       // 判斷是否接收到幀尾結束符
      {
          retval = 0xaa;    // 置標志,表示一個數據包接收到
      }
      state_machine = 0;     // 復位狀態機
}

    此過程中,使用了一個變量state_machine作為協議狀態機的轉換狀態,用于確定當前字節處于一幀數據中的那個部位,同時在接收過程中自動對接收數據進行校驗和處理,在數據包接收完的同時也進行了校驗的比較。因此當幀尾結束符接收到的時候,則表示一幀數據已經接收完畢,并且通過了校驗,關鍵數據也保存到了緩沖去中。主程序即可通過retval的標志位來進行協議的解析處理。
    接收過程中,只要哪一步收到的數據不是預期值,則直接將狀態機復位,用于下一幀數據的判斷,因此系統出現狀態死鎖的情況非常少,系統比較穩定,如果出現丟失數據包的情況也可由上位機進行命令的補發,不過這種情況筆者還沒有碰到。
    對于主程序中進行協議處理的過程與此類似,主程序循環中不斷的讀取串口緩沖區的數據,此數據即參與到主循環中的協議處理過程中,代碼與上面所述完全一樣。

評分

參與人數 1黑幣 +5 收起 理由
776872241 + 5 絕世好帖!

查看全部評分

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

使用道具 舉報

沙發
ID:237942 發表于 2017-10-25 11:07 | 只看該作者
假如我接收到的數據有四組(1,2,3,4)分別對應要發送的四組數據(5,6,7,8),這個有實現的算法么
回復

使用道具 舉報

板凳
ID:143203 發表于 2017-11-3 08:27 | 只看該作者
state_machine 是在什么時候進行改變 的?
回復

使用道具 舉報

地板
ID:297824 發表于 2018-10-2 15:46 | 只看該作者
好貼
回復

使用道具 舉報

5#
ID:352755 發表于 2021-3-29 19:19 | 只看該作者
領教了,很受啟發
回復

使用道具 舉報

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

本版積分規則

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

Powered by 單片機教程網

快速回復 返回頂部 返回列表
主站蜘蛛池模板: 欧美一级在线 | 自拍偷拍亚洲一区 | 亚洲一区二区三区乱码aⅴ 四虎在线视频 | 免费一级淫片aaa片毛片a级 | 97狠狠干| 国产乱人伦精品一区二区 | 在线婷婷 | 久久99蜜桃综合影院免费观看 | 国产精品一区二区三 | 日日夜夜91| 91精品国产91久久久久久丝袜 | 欧美一级视频 | 亚洲色图综合 | 欧美精品一区二区三区四区五区 | 超碰日本 | 久久网国产 | 一区二区三区欧美 | 国产伦精品一区二区三区在线 | 国内精品视频在线观看 | 日韩中文字幕免费在线 | 一区二区高清 | 中文字幕在线观看一区二区 | 成人国产精品久久久 | 国产在线观看一区二区三区 | 国产激情三区 | 视频一区二区在线观看 | 九九综合 | 不卡一区 | 影音先锋欧美资源 | 国产精品久久久久久久久免费高清 | 精品久久久久国产 | 天天插天天射天天干 | 成人日批视频 | 九七午夜剧场福利写真 | yiren22综合网成人 | 精品国产欧美日韩不卡在线观看 | 国产精品国产成人国产三级 | 亚洲国产精品一区在线观看 | 蜜桃视频一区二区三区 | 国产精品美女一区二区 | 亚洲高清在线 |