原創:51單片機串口通信(字符串接收和發送)


下面的示例代碼基於51單片機,用於快速二次開發實現基於串口字符串通信控制程序(比如要實現電腦控制單片機的開燈和關燈),示例很言簡意賅,並附上了詳盡的注釋,

本示例代碼經過了更新,新版本代碼更加友好了,

尊重作者的勞動,轉載請記得注明來源:http://www.cnblogs.com/weifeng727/p/5617924.html

 

  1 #include<reg52.h>
  2 
  3 //------------------串口通信的數據包協議-----------------//
  4 /*
  5     此程序的串口字符串通信使用到下面的一個自定義協議,每次通信都是發送或接收一個數據包,數據包格式解釋如下(長度恆為15):
  6     例如:A01_fmq_01Off___#
  7     A--------數據包的開始標記(可以為A到Z,意味着數據包可以有26種)
  8     01-----設備代號
  9     fmq_01Off___--------指令(長度恆為10),指令的前4個人字符是指令頭部,指令的后6個字符是指令尾部
 10     #---------數據包的結束標記
 11 
 12     例如:A02_SenT010250#
 13     A--------數據包的開始標記(可以為A到Z,意味着數據包可以有26種)
 14     02-----設備代號
 15     SenT010250--------指令(長度恆為10),指令的前4個人字符是指令頭部,指令的后6個字符是指令尾部
 16     #---------數據包的結束標記
 17 */
 18 char RecvString_buf[16];            //定義數據包長度為15個字符
 19 #define deviceID_1Bit '0'                //用於串口通信時,定義本地設備ID的第1位
 20 #define deviceID_2Bit '2'                //用於串口通信時,定義本地設備ID的第2位
 21 #define datapackage_headflag 'A'        //用於串口通信時,定義數據包頭部的驗證標記
 22 
 23 char DataPackage_DS18B20[16]={datapackage_headflag,deviceID_1Bit,deviceID_2Bit,'_','S','e','n','T','X','X','X','X','X','X','#'};    //這個是曾經用來控制溫度傳感模塊(DS18B20)的數據包
 24 char HeartBeat[16]={datapackage_headflag,deviceID_1Bit,deviceID_2Bit,'_','B','e','a','t','X','X','X','X','X','X','#'};            //我隨便定義了一個數據包用來做"心跳包",比如單片機系統向電腦每2秒發送一次該數據包,如果電腦沒有按時接收到,就認為單片機死掉了
 25 //----------------------------------------------//
 26 /*******************************
 27             串口通信
 28     MCU:89C52RC        11.0592MHz
 29 
 30 //11.0592MHz 0xd0 1200bps
 31 //12MHz 0xcc 1200bps
 32 //11.0592MHz 0xfa 9600bps
 33 //0xf4 11.0592MHz  0xf3 12MHz 4800bps
 34 //均在SMOD=1的情況下(波特率倍增模式)
 35 *******************************/
 36 //串口發送函數
 37 void PutString(unsigned char *TXStr)  
 38 {                
 39     ES=0;     
 40      while(*TXStr!=0) 
 41     {                      
 42         SBUF=*TXStr;
 43         while(TI==0);
 44         TI=0;    
 45         TXStr++;
 46     }
 47     ES=1; 
 48 }                                                     
 49 //串口接收函數
 50 bit ReceiveString()    
 51 {
 52     char * RecStr=RecvString_buf;
 53     char num=0;
 54     unsigned char count=0;
 55     loop:    
 56     *RecStr=SBUF;
 57     count=0;
 58     RI=0;    
 59     if(num<14)  //數據包長度為15個字符,嘗試連續接收15個字符
 60     {
 61         num++;
 62         RecStr++;    
 63         while(!RI)
 64         {
 65             count++;
 66             if(count>130)return 0;    //接收數據等待延遲,等待時間太久會導致CPU運算閑置,太短會出現"數據包被分割",默認count=130
 67         }
 68         goto loop;
 69     }
 70     return 1;
 71 }
 72 //定時器1用作波特率發生器
 73 void Init_USART()  
 74 {
 75     SCON=0x50;  //串口方式1,使能接收
 76     TMOD|=0x20;  //定時器1工作方式2(8位自動重裝初值)
 77     TMOD&=~0x10;
 78     TH1=0xfa;   //9600bps
 79     TL1=0xfa;  
 80     PCON|=0x80;  //SMOD=1
 81     TR1=1;
 82     TI=0;
 83     RI=0;
 84     //PS=1;   //提高串口中斷優先級
 85     ES=1;  //開啟串口中斷使能
 86 }
 87 //比較指令頭部
 88 bit CompareCMD_head(char CMD_head[])    
 89 {
 90     unsigned char CharNum;
 91     for(CharNum=0;CharNum<4;CharNum++)  //指令長度為10個字符
 92     {
 93         if(!(RecvString_buf[CharNum+4]==CMD_head[CharNum]))
 94         {
 95             return 0;  //指令頭部匹配失敗
 96         }
 97     }
 98     return 1;        //指令頭部匹配成功
 99 }
100 //比較指令尾部(start:從哪里開始比較,quality:比較多少個字符,CMD_tail[]:要比較的字符串)
101 bit CompareCMD_tail(unsigned char start,unsigned char quality,char CMD_tail[]) 
102 {
103     unsigned char CharNum;
104     for(CharNum=0;CharNum<quality;CharNum++)
105     {
106         if(!(RecvString_buf[start+CharNum]==CMD_tail[CharNum]))
107         {
108             return 0; 
109         }
110     }
111     return 1;
112 }
113 bit Deal_UART_RecData()   //處理串口接收數據包函數(成功處理數據包則返回1,否則返回0)
114 {
115     //PutString(RecvString_buf);
116     if(RecvString_buf[0]==datapackage_headflag&&buf_string[14]=='#')  //進行數據包頭尾標記驗證
117     {        
118         switch(RecvString_buf[1])        //識別發送者設備ID的第1位數字
119         {
120             case '0':
121                 switch(RecvString_buf[2])        //識別發送者設備ID的第2位數字
122                 {
123                     case '3':
124                         if(CompareCMD_head("Ligt"))    //判斷指令頭部是否為"Ligt"
125                         {
126                             //下面是指令尾部分析
127                             switch(RecvString_buf[8])
128                             {
129                                 case '0':
130                                     switch(RecvString_buf[9])
131                                     {
132                                         case '0':            
133                                             
134                                             return 0;
135                                         case '1':
136                                             if(CompareCMD_tail(10,3,"Off"))   //判斷整個數據包是否為:A03_Ligt01Off_#
137                                             {
138                                                 //如果是則執行以下代碼
139                                                 return 1;
140                                             }
141                                             if(CompareCMD_tail(10,3,"On_"))    //判斷整個數據包是否為:A03_Ligt01On__#
142                                             {
143                                                 //如果是則執行以下代碼
144                                                 return 1;
145                                             }
146                                             return 0;
147                                         default:
148                                             return 0;
149                                     }
150                                 default:
151                                     return 0;
152                             }            
153                         }
154                         return 0;
155                     
156                     default:
157                         return 0;
158                 }
159             default:
160                 return 0;
161         }
162     }
163     return 0;
164 }
165 /************************
166         中斷函數
167 ************************/
168 //串口中斷服務函數-----------
169 void USART() interrupt 4   //標志位TI和RI需要手動復位,TI和RI置位共用一個中斷入口
170 {
171     if(ReceiveString())    
172     {
173         //數據包長度正確則執行以下代碼
174         Deal_UART_RecData();   
175     }
176     else
177     {
178         //數據包長度錯誤則執行以下代碼
179         //LED1=~LED1;                
180     }
181     RI=0;  //接收並處理一次數據后把接收中斷標志清除一下,拒絕響應在中斷接收忙的時候發來的請求
182 }
183 /***************************
184         主函數
185 ***************************/
186 void main()
187 {
188     EA=1;  
189     Init_USART();    //初始化串口中斷通信,當串口接受完數據包后,如果檢測到數據包包含有效指令,則自動執行對應的代碼,執行完自動返回到主函數,為了盡可能不影響主函數的時序,串口中斷函數的執行代碼不要過復雜
190     while(1)
191     {
192     //下面可以放要經常運行的用戶代碼,使用PutString()函數來發送數據包,如PutString(HeartBeat);    注:空格的ASCLL碼是:0x20,回車是:0x0D
193         
194         
195     }
196 }

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM