485通信程序(51單片機)
#include
#defineucharunsignedchar
#defineuintunsignedint
/*通信命令*/
#define_ACTIVE_0x01//主機詢問從機是否存在
#define_GETDATA_0x02//主機發(fā)送讀設(shè)備請求
#define_OK_0x03//從機應答
#define_STATUS_0x04//從機發(fā)送設(shè)備狀態(tài)信息
#define_MAXSIZE0x08//緩沖區(qū)長度
#define_ERRLEN12//任何通信幀長度超過12則表示出錯
uchardbuf[MAXSIZE]; //該緩沖區(qū)用于保存設(shè)備狀態(tài)信息
uchardev;//該字節(jié)用于保存本機設(shè)備號
sbitM_DE=P1^0;//驅(qū)動器使能,1有效
sbitM_RE=P1^1;//接收器使能,0有效
voidget_status();//調(diào)用該函數(shù)獲得設(shè)備狀態(tài)信息,函數(shù)全碼未給出
voidsend_data(uchartype,ucharlen,uchar*buf);//發(fā)送數(shù)據(jù)幀
bitrecv_cmd(uchar*type);//接收主機命令,主機請求包含命令信息。
voidsend_byte(ucharda);//該函數(shù)發(fā)送一幀數(shù)據(jù)中的一個字節(jié),由send_data()函數(shù)調(diào)用
voidmain()
{
uchartype;
ucharlen;
/*系統(tǒng)初始化*/
P1=0xff;//讀取本機設(shè)備號
dev=(P1>>2);
TMOD=0x20;//定時器T1使用方式2
TH1=250;
TL1=250;
TR1=1;//開始計時
PCON=0x80;//SMOD=1;
SCON=0x50;//工作方式1,波特優(yōu)選法9600bps,允許接收
ES=0; //關(guān)閉串品中斷
IT0=0;//外部中斷0使有電平觸發(fā)模式
EX0=1;//開啟外部中斷0
EA=0;//開啟總中斷
/*主程序流程*/
while(1)
{
if(recv_cmd(&type)==0)//發(fā)送幀錯誤或幀地址與本機地址不符,丟棄當前幀后返回
continue;
switch(type)
{
case_ACTIVE_://主機詢問從機是否存在
send_data(_OK_,0,dbuf);//發(fā)送應答信息,這里的buf的內(nèi)容并未用到
break;
case_GETDATA_://主機發(fā)送讀設(shè)備請求
len=strlen(dbuf);
snd_data(_STATUS_,len,dbuf);//發(fā)送設(shè)備信息
break;
default:
break;//命令類型錯誤,丟棄當前幀返回
}
}
}
}
voidREADSTATUS()interrput0using1//產(chǎn)生外部中斷0時表示設(shè)備狀態(tài)發(fā)生改變,該函數(shù)使用寄存器組1
{
get_status();//獲得設(shè)備狀態(tài)信息,并將其存入dbuf指向的存儲區(qū),數(shù)據(jù)最后一個字節(jié)置0表示數(shù)據(jù)結(jié)束
}
}
/*該函數(shù)接收一幀數(shù)據(jù)度進行檢測,無論該幀是否錯誤,函數(shù)均會返回。
*函數(shù)參數(shù)type保存接收到的命令字
*當接收的數(shù)扭幀錯誤或其地址位不為0時(非主機發(fā)送幀),快活數(shù)返回0,反之返回1
*/
bitrecv_cmd(uchar*type)
{
bitdb=0;//當接收到的上一個字節(jié)為0xdb時,該位置位
bitc0=0;//當接慢到的上一個字節(jié)為0xc0時,該位置位
uchardata_buf[_ERRLEN];//保存接收到的幀
uchartmp;
ucharecc=0;
uchari;
M_DE=0;//置發(fā)送禁止,接收允許
M_RE=0;
/*接收一幀數(shù)據(jù)*/
i=0;
while(!c0)//循環(huán)直至幀接收完畢
{
RI=0;
while(RI);
tmp=SBUF;
RI=0;
if(db==1)//接收到的上一個字節(jié)為0xdb
{
swithc(tmp)
{
case0xdd:
data_buf[i]=0xdb;//0xdbdd表示0xdb
ecc=ecc^0xdb;
db=0;
break;
case0xdc:
data_buf[i]=0xc0;//0xdbdc表示0xc0
ecc=0;
db=0;
break;
default:
return0;//幀錯誤,返回
}
i++;
}
switch(tmp)//正常情況下
{
case0xc0://幀結(jié)束
c0=1;
break;
case0xdb: //檢測到轉(zhuǎn)義字符
db=1;
break;
default://普通數(shù)據(jù)
data_buf[i]=tmp;//保存數(shù)據(jù)
ecc=ecc^tmp;//計算校驗字節(jié)
i++;
}
if(i==_ERRLEN)//幀超長,錯誤,返回
return0;
}
/*判斷幀是否錯誤*/
if(i<4)//幀過短,錯誤,返回
return0;
if(ecc!=0)//校驗錯誤,返回
return0;
if(data_buf[i!=dev) //非訪問本機命令,錯誤,返回
return0;
*type=data_buf[1];//獲得命令字
return1;//函數(shù)成功返回
}
/*該函數(shù)發(fā)送一數(shù)據(jù)幀,參數(shù)type為命令字,len為數(shù)據(jù)長度,buf為要發(fā)送的數(shù)據(jù)內(nèi)容*/
voidsend_data(uchartype,ucharlen,uchar*buf)
{
uchari;
ucharecc=0;
M_DE=1;//置發(fā)送允許,接收禁止
M_RE=1;
send_byte(dev);//發(fā)送本機地址
ecc=dev;
send_byte(type);//發(fā)送命令字
ecc=ecc^type;
send_byte(len);//發(fā)送長度
ecc=ecc^len;
for(i=0;i { send_byte(*buf); ecc=ecc^(*buf); buff++; } send_byte(ecc);//發(fā)送校驗字節(jié) TI=0;//發(fā)送幀結(jié)束標志 SBUF=0xc0; while(!TI); TI=0; } /*該函數(shù)發(fā)送一個數(shù)據(jù)字節(jié),若該字節(jié)為0xdb,則發(fā)送0xdbdd,若該字節(jié)為0xc0,則發(fā)送0xdbdc*/ voidsend_byte(ucharda) { switch(da) { case0xdb://字節(jié)為0xdb,發(fā)送0xdbdd TI=0; SBUF=0xdb; while(!TI); TI=0; SBUF=0xdd; while(!TI); TI=0; break; case0xc0://字節(jié)為0xc0,則發(fā)送0xdbdc TI=0; SBUF=0xdb; while(!TI); TI=0; SBUF=0xdc; while(!TI); TI=0; break; default://普通數(shù)據(jù)剛直接發(fā)送 TI=0; SBUF=da; while(!TI); TI=0; } }
評論