分类: 嵌入式
2012-01-13 09:33:49
#include
#include
#define uchar unsigned char
#define uint unsigned int
/*通信命令*/
#define _ACTIVE_ 0x01 // 主机询问从机是否存在
#define _GETDATA_ 0x02 //主机发送读设备请求
#define _OK_ 0x03 //从机应答
#define _STATUS_ 0x04 //从机发送设备状态信息
#define _MAXSIZE 0x08 //缓冲区长度
#define _ERRLEN 12 //任何通信帧长度超过12则表示出错
uchar dbuf[MAXSIZE] ; //该缓冲区用于保存设备状态信息
uchar dev; //该字节用于保存本机设备号
sbit M_DE = P1^0; //驱动器使能,1有效
sbit M_RE = P1^1; //接收器使能,0 有效
void get_status(); //调用该函数获得设备状态信息,函数全码未给出
void send_data(uchar type,uchar len,uchar *buf); //发送数据帧
bit recv_cmd(uchar *type); //接收主机命令,主机请求包含命令信息。
void send_byte(uchar da); //该函数发送一帧数据中的一个字节,由send_data()函数调用
void main()
{
uchar type;
uchar len;
/*系统初始化*/
P1 = 0xff ; //读取本机设备号
dev = (P1>>2);
TMOD = 0x20; //定时器T1使用方式2
TH1 = 250;
TL1 = 250;
TR1 = 1; //开始计时
PCON = 0x80; //SMOD = 1;
SCON = 0x50; //工作方式1,波特优选法9600bps,允许接收
ES = 0; // 关闭串品中断
IT0 = 0; //外部中断0使有电平触发模式
EX0 = 1; // 开启外部中断0
EA = 0; //开启总中断
/*主程序流程*/
while(1)
{
if(recv_cmd(&type) ==0) //发送帧错误或帧地址与本机地址不符,丢弃当前帧后返回
continue;
switch(type)
{
case _ACTIVE_: //主机询问从机是否存在
send_data(_OK_,0,dbuf); // 发送应答信息,这里的buf 的内容并未用到
break;
case _GETDATA_: //主机发送读设备请求
len = strlen(dbuf);
snd_data(_STATUS_,len,dbuf) ; // 发送设备信息
break;
default:
break; //命令类型错误,丢弃当前帧返回
}
}
}
}
void READSTATUS() interrput 0 using 1 //产生外部中断0时表示设备状态发生改变,该函数使用寄存器组1
{
get_status(); //获得设备状态信息,并将其存入dbuf指向的存储区,数据最后一个字节置0表示数据结束
}
}
/*该函数接收一帧数据度进行检测,无论该帧是否错误,函数均会返回。
*函数参数type保存接收到的命令字
*当接收的数扭帧错误或其地址位不为0时(非主机发送帧),快活数返回0,反之返回1
*/
bit recv_cmd(uchar *type)
{
bit db = 0; //当接收到的上一个字节为0xdb时,该位置位
bit c0 = 0; //当接慢到的上一个字节为0xc0时,该位置位
uchar data_buf[_ERRLEN]; //保存接收到的帧
uchar tmp;
uchar ecc = 0;
uchar i;
M_DE =0; //置发送禁止,接收允许
M_RE = 0;
/*接收一帧数据*/
i =0;
while(!c0) //循环直至帧接收完毕
{
RI = 0;
while(RI);
tmp = SBUF;
RI = 0;
if(db ==1) //接收到的上一个字节为0xdb
{
swithc(tmp)
{
case 0xdd:
data_buf[i] = 0xdb; //0xdbdd 表示0xdb
ecc = ecc^0xdb;
db = 0;
break;
case 0xdc:
data_buf[i] = 0xc0; //0xdbdc 表示0xc0
ecc = 0;
db = 0;
break;
default:
return 0 ; // 帧错误,返回
}
i++;
}
switch(tmp) //正常 情况下
{
case 0xc0: //帧结束
c0 = 1;
break;
case 0xdb: // 检测到转义字符
db = 1;
break;
default : // 普通数据
data_buf[i] = tmp ; //保存数据
ecc = ecc^tmp; // 计算校验字节
i ++;
}
if(i ==_ERRLEN) //帧超长,错误,返回
return 0;
}
/*判断帧是否错误*/
if(i<4) //帧过短,错误,返回
return 0;
if(ecc!=0) //校验错误,返回
return 0;
if(data_buf[i!= dev) //非访问本机命令,错误,返回
return 0;
*type = data_buf[1]; //获得命令字
return 1; //函数成功返回
}
/*该函数发送一数据帧,参数type为命令字,len为数据长度,buf 为要发送的数据内容*/
void send_data(uchar type,uchar len,uchar *buf)
{
uchar i ;
uchar ecc = 0;
M_DE = 1 ;// 置发送允许,接收禁止
M_RE = 1;
send_byte(dev); //发送本机地址
ecc = dev;
send_byte(type); //发送命令字
ecc = ecc^type;
send_byte(len); // 发送长度
ecc = ecc^len;
for(i =0;i<len;i++)
{
send_byte(*buf);
ecc = ecc^(*buf);
buff++;
}
send_byte(ecc); // 发送校验字节
TI = 0; //发送帧结束标志
SBUF = 0xc0;
while(!TI);
TI = 0;
}
/*该函数发送一个数据字节,若该字节为0xdb,则发送0xdbdd,若该字节为0xc0,则发送0xdbdc*/
void send_byte(uchar da)
{
switch(da)
{
case 0xdb: //字节为0xdb,发送0xdbdd
TI = 0;
SBUF = 0xdb;
while(!TI);
TI = 0;
SBUF = 0xdd;
while(!TI);
TI = 0;
break;
case 0xc0: //字节为0xc0,则发送0xdbdc
TI = 0;
SBUF = 0xdb;
while(!TI);
TI = 0;
SBUF = 0xdc;
while(!TI);
TI = 0;
break;
default: //普通数据刚直接发送
TI = 0;
SBUF = da;
while(!TI);
TI = 0;
}
}