#include<reg52.h>
//------------------串口通信的數據包協議-----------------//
/*
此程序的串口字符串通信使用到下面的一個自定義協議,每次通信都是發送或接收一個數據包,數據包格式解釋如下(長度恒為15):
例如:A01_fmq_01Off___#
A--------數據包的開始標記(可以為A到Z,意味著數據包可以有26種)
01-----設備代號
fmq_01Off___--------指令(長度恒為10),指令的前4個人字符是指令頭部,指令的后6個字符是指令尾部
#---------數據包的結束標記
例如:A02_SenT010250#
A--------數據包的開始標記(可以為A到Z,意味著數據包可以有26種)
02-----設備代號
SenT010250--------指令(長度恒為10),指令的前4個人字符是指令頭部,指令的后6個字符是指令尾部
#---------數據包的結束標記
*/
char RecvString_buf[16]; //定義數據包長度為15個字符
#define deviceID_1Bit '0' //用于串口通信時,定義本地設備ID的第1位
#define deviceID_2Bit '2' //用于串口通信時,定義本地設備ID的第2位
#define datapackage_headflag 'A' //用于串口通信時,定義數據包頭部的驗證標記
char DataPackage_DS18B20[16]={datapackage_headflag,deviceID_1Bit,deviceID_2Bit,'_','S','e','n','T','X','X','X','X','X','X','#'}; //這個是曾經用來控制溫度傳感模塊(DS18B20)的數據包
char HeartBeat[16]={datapackage_headflag,deviceID_1Bit,deviceID_2Bit,'_','B','e','a','t','X','X','X','X','X','X','#'}; //我隨便定義了一個數據包用來做"心跳包",比如單片機系統向電腦每2秒發送一次該數據包,如果電腦沒有按時接收到,就認為單片機死掉了
//----------------------------------------------//
/*******************************
串口通信
MCU:89C52RC 11.0592MHz
//11.0592MHz 0xd0 1200bps
//12MHz 0xcc 1200bps
//11.0592MHz 0xfa 9600bps
//0xf4 11.0592MHz 0xf3 12MHz 4800bps
//均在SMOD=1的情況下(波特率倍增模式)
*******************************/
//串口發送函數
void PutString(unsigned char *TXStr)
{
ES=0;
while(*TXStr!=0)
{
SBUF=*TXStr;
while(TI==0);
TI=0;
TXStr++;
}
ES=1;
}
//串口接收函數
bit ReceiveString()
{
char * RecStr=RecvString_buf;
char num=0;
unsigned char count=0;
loop:
*RecStr=SBUF;
count=0;
RI=0;
if(num<14) //數據包長度為15個字符,嘗試連續接收15個字符
{
num++;
RecStr++;
while(!RI)
{
count++;
if(count>130)return 0; //接收數據等待延遲,等待時間太久會導致CPU運算閑置,太短會出現"數據包被分割",默認count=130
}
goto loop;
}
return 1;
}
//定時器1用作波特率發生器
void Init_USART()
{
SCON=0x50; //串口方式1,使能接收
TMOD|=0x20; //定時器1工作方式2(8位自動重裝初值)
TMOD&=~0x10;
TH1=0xfa; //9600bps
TL1=0xfa;
PCON|=0x80; //SMOD=1
TR1=1;
TI=0;
RI=0;
//PS=1; //提高串口中斷優先級
ES=1; //開啟串口中斷使能
}
//比較指令頭部
bit CompareCMD_head(char CMD_head[])
{
unsigned char CharNum;
for(CharNum=0;CharNum<4;CharNum++) //指令長度為10個字符
{
if(!(RecvString_buf[CharNum+4]==CMD_head[CharNum]))
{
return 0; //指令頭部匹配失敗
}
}
return 1; //指令頭部匹配成功
}
//比較指令尾部(start:從哪里開始比較,quality:比較多少個字符,CMD_tail[]:要比較的字符串)
bit CompareCMD_tail(unsigned char start,unsigned char quality,char CMD_tail[])
{
unsigned char CharNum;
for(CharNum=0;CharNum<quality;CharNum++)
{
if(!(RecvString_buf[start+CharNum]==CMD_tail[CharNum]))
{
return 0;
}
}
return 1;
}
bit Deal_UART_RecData() //處理串口接收數據包函數(成功處理數據包則返回1,否則返回0)
{
//PutString(RecvString_buf);
if(RecvString_buf[0]==datapackage_headflag&&buf_string[14]=='#') //進行數據包頭尾標記驗證
{
switch(RecvString_buf[1]) //識別發送者設備ID的第1位數字
{
case '0':
switch(RecvString_buf[2]) //識別發送者設備ID的第2位數字
{
case '3':
if(CompareCMD_head("Ligt")) //判斷指令頭部是否為"Ligt"
{
//下面是指令尾部分析
switch(RecvString_buf[8])
{
case '0':
switch(RecvString_buf[9])
{
case '0':
return 0;
case '1':
if(CompareCMD_tail(10,3,"Off")) //判斷整個數據包是否為:A03_Ligt01Off_#
{
//如果是則執行以下代碼
return 1;
}
if(CompareCMD_tail(10,3,"On_")) //判斷整個數據包是否為:A03_Ligt01On__#
{
//如果是則執行以下代碼
return 1;
}
return 0;
default:
return 0;
}
default:
return 0;
}
}
return 0;
default:
return 0;
}
default:
return 0;
}
}
return 0;
}
/************************
中斷函數
************************/
//串口中斷服務函數-----------
void USART() interrupt 4 //標志位TI和RI需要手動復位,TI和RI置位共用一個中斷入口
{
if(ReceiveString())
{
//數據包長度正確則執行以下代碼
Deal_UART_RecData();
}
else
{
//數據包長度錯誤則執行以下代碼
//LED1=~LED1;
}
RI=0; //接收并處理一次數據后把接收中斷標志清除一下,拒絕響應在中斷接收忙的時候發來的請求
}
/***************************
主函數
***************************/
void main()
{
EA=1;
Init_USART(); //初始化串口中斷通信,當串口接受完數據包后,如果檢測到數據包包含有效指令,則自動執行對應的代碼,執行完自動返回到主函數,為了盡可能不影響主函數的時序,串口中斷函數的執行代碼不要過復雜
while(1)
{
//下面可以放要經常運行的用戶代碼,使用PutString()函數來發送數據包,如PutString(HeartBeat); 注:空格的ASCLL碼是:0x20,回車是:0x0D
}
} |