51串口通信协议(新型篇)C51编程:这是网友牛毅编的一个C51串口通讯程序!//PC读MCU指令结构:(中断方式,ASCII码表示)//帧:帧头标志|帧类型|器件地址|启始地址|长度n|效验和|帧尾标志//值: 'n' 'y'| 'r' | 0x01 | x | x | x |0x13 0x10//字节数: 2 | 1 | 1 | 1 | 1 | 1 | 2//求和:///////////////////////////////////////////////////////////////////////公司名称:***//模块名:protocol.c//创建者:牛毅//修改者://功能描述:中断方式:本程序为mcu的串口通讯提供(贞结构)函数接口,包括具体协议部分//其他说明:只提供对A T89c51具体硬件的可靠访问接口//版本:1.0//信息:QQ 75011221/////////////////////////////////////////////////////////////////////#include <reg51.h>#include <config.h>//预定义//帧#define F_ST1 0x6e //帧头标志n#define F_ST2 0x79 //帧头标志y#define F_R 0x72 //帧类型读r#define F_W 0x77 //帧类型写w#define F_D 0x64 //帧类型数据帧d#define F_B 0x62 //帧类型写回应帧b#define F_C 0x63 //帧类型重发命令帧c#define F_Q 0x71 //帧类型放弃帧q#define F_ADDR 0x31 //器件地址0-9#define F_END 0x7a //帧尾标志z#define F_SPACE 0x30 //空标志0#define F_ERR1 0x31 //错误标志1,flagerr 1#define F_ERR2 0x32 //错误标志2 2//常数#define S_MAXBUF 16 //接收/发送数据的最大缓存量#define FIELD_MAXBUF 48 //最小场缓存,可以大于48字节,因为协议是以20字节为#define communicationing P1_7 //正在通讯(1)标志#define ERRFRAME_MAX 5 //连续NOFRAME_CNT次帧不正确#define ERR_NOCNTMAX_RESEND if(++errframe_cnt<=ERRFRAME_MAX)resend_frame(); else errframe_cnt=communicationing=0;//若超过ERRFRAME_MAX 次则令通讯停止ERR_NOCNTMAX_RESEND//public 变量unsigned char databuf[FIELD_MAXBUF],errframe_cnt;//函数///////////////////////////////////////////////////////////////////////函数名:send()//功能描述:向串口发送一个字符//函数说明://调用函数://全局变量://输入:ch-要发送的ASCII字符//返回:无//设计者:牛毅//修改者://版本://///////////////////////////////////////////////////////////////////void send(unsigned char ch){SBUF=ch;while(TI==0);TI=0;}///////////////////////////////////////////////////////////////////////函数名:receive()//功能描述:从串口接收一个字符//函数说明://调用函数://全局变量://输入:无//返回:一个ASCII字符//设计者:牛毅//修改者://版本://///////////////////////////////////////////////////////////////////unsigned char receive(void){RI=0;return SBUF;}///////////////////////////////////////////////////////////////////////函数名:CharToHex()//功能描述:把ASCII字符转换为16进制//函数说明://调用函数://全局变量://输入:ASCII字符//返回:16进制//设计者:牛毅//修改者://版本:///////////////////////////////////////////////////////////////////// unsigned char CharToHex(unsigned char bChar) {if((bChar>=0x30)&&(bChar<=0x39))bChar -= 0x30;else if((bChar>=0x41)&&(bChar<=0x46))//大写字母bChar -= 0x37;else if((bChar>=0x61)&&(bChar<=0x66))//小写字母bChar -= 0x57;else bChar = 0xff;return bChar;}///////////////////////////////////////////////////////////////////////函数名:HexToChar()//功能描述:把16进制转换为ASCII字符//函数说明://调用函数://全局变量://输入:16进制//返回:ASCII字符//设计者:牛毅//修改者://版本:///////////////////////////////////////////////////////////////////// unsigned char HexToChar(unsigned char bHex) {if((bHex>=0)&&(bHex<=9))bHex += 0x30;else if((bHex>=10)&&(bHex<=15))//大写字母bHex += 0x37;else bHex = 0xff;return bHex;}///////////////////////////////////////////////////////////////////////函数名:com_int()//功能描述:初始化串口//函数说明:默认其他参数为[baud_rate],n,8,1//调用函数://全局变量://输入:baud_rate 波特率//返回:无//设计者:牛毅//修改者://版本://///////////////////////////////////////////////////////////////////void com_init(unsigned int baud_rate){EA=1;ES=1;//ET1=1;SCON = 0x50; /* 0x52;//SCON */TMOD = 0x20; /*0x20;// TMOD */TCON = 0x60; /*0x60;// TCON */PCON=PCON&0x7f;switch(baud_rate){ //波特率设置case 1200:TL1=0xe8;TH1=0Xe8;break; //1200case 2400:TL1=0xf4;TH1=0Xf4;break; //2400case 4800:TL1=0xfa;TH1=0Xfa;break; //4800case 9600:TL1=0xfd;TH1=0Xfd;break; //9600case 19200:PCON=PCON|0x80;TL1=0xfd;TH1=0Xfd;break; //19200 case 38400:PCON=PCON|0x80;TL1=0xfe;TH1=0Xfe;break; //38400 default:TL1=0xfd;TH1=0Xfd;break;//9600}}//函数名:resend_frame()//功能描述:发送重发帧//函数说明:通知PC重发//调用函数://全局变量://输入:无//返回:无//设计者:牛毅//修改者://版本:///////////////////////////////////////////////////////////////////// void resend_frame(void){send(F_ST1);send(F_ST2);send(F_C);send(F_SPACE);send(F_SPACE);//发送效验和send(F_END);}///////////////////////////////////////////////////////////////////// //函数名:quit_frame()//功能描述:发送放弃帧//函数说明:通知PC放弃通讯//调用函数://全局变量://输入:无//返回:无//设计者:牛毅//修改者://版本:///////////////////////////////////////////////////////////////////// void quit_frame(void){send(F_ST1);send(F_ST2);send(F_Q);send(F_ERR1);send(F_ERR1);//发送效验和send(F_END);}//函数名:com_int()//功能描述:串口中断//函数说明://调用函数://全局变量://输入:无//返回:无//设计者:牛毅//修改者://版本://///////////////////////////////////////////////////////////////////void com_int()interrupt 4{unsigned char i,csaddr,clen,csum,tempbuf[S_MAXBUF]; csum=0;if(receive()==F_ST1){//是侦if(receive()==F_ST2){//头判断完communicationing=1;//设置通讯状态为正常即启动通讯switch(receive()){case F_R://是读指令帧rif(receive()==F_ADDR){P1_2=!P1_2;//地址正确csaddr=CharToHex(receive())<<4;csaddr+=CharToHex(receive());clen=CharToHex(receive())<<4;clen+=CharToHex(receive()); csum=csaddr+clen;i=CharToHex(receive())<<4;i+=CharToHex(receive());if(i==csum){//效验和正确if(receive()==F_END){//结束标志正确//开始发送数据帧csum=0;send(F_ST1);send(F_ST2);send(F_D);send(HexToChar((clen&0xf0)>>4));send(HexToChar(clen&0x0f));csum+=clen;for(i=0;i<clen;i++)send(HexToChar((databuf[i+csaddr]&0xf0)>>4)); send(HexToChar(databuf[i+csaddr]&0x0f));csum+=databuf[i+csaddr];}//if(csum>127)csum-=128;send(HexToChar((csum&0xf0)>>4));send(HexToChar(csum&0x0f));send(F_END);//发送数据帧完毕P1_0=!P1_0;}else{ERR_NOCNTMAX_RESEND break;}//结束标志错误}else{ERR_NOCNTMAX_RESENDbreak;}//效验和错误}//地址不正确break;case F_W://是PC写指令帧wif(receive()==F_ADDR){//地址正确csaddr=CharToHex(receive())<<4;csaddr+=CharToHex(receive());clen=CharToHex(receive())<<4;clen+=CharToHex(receive());csum=csaddr+clen;for(i=0;i<clen;i++){tempbuf[i+csaddr]=CharToHex(receive())<<4; tempbuf[i+csaddr]+=CharToHex(receive());csum+=tempbuf[i+csaddr];}i=CharToHex(receive())<<4;i+=CharToHex(receive()); if(csum!=i){ERR_NOCNTMAX_RESEND break;}//效验和错误if(F_END!=receive())ERR_NOCNTMAX_RESENDbreak;}//结束标志错误for(i=csaddr;i<clen+csaddr;i++)databuf[i-csaddr]=tempbuf[i-csaddr];//正确则保存数据}//从PC获得数据写完毕//开始发送写回应帧send(F_ST1);send(F_ST2);send(F_B);send(F_SPACE);send(F_SPACE);//发送效验和send(F_END);//写回应帧发送完毕P1_1=!P1_1;break;case F_Q://检测接收放弃帧csaddr=receive();csum+=csaddr;//csaddr兼做放弃帧码标志if(csaddr!=F_ERR1 && csaddr!=F_ERR2){ERR_NOCNTMAX_RESEND break;}if(csum!=receive()){ERR_NOCNTMAX_RESENDbreak;}if(F_END!=receive()){ERR_NOCNTMAX_RESENDbreak;}communicationing=0;//出错退出通讯break;default:resend_frame();//要求从发}}//忽略}//忽略if(!communicationing)quit_frame();//调用放弃帧,通知PC 放弃通讯}///////////////////////////////////////////////////////////////////主函数/////////////////////////////////////////////////////////////////void main(void){unsigned char i;for (i=0;i<FIELD_MAXBUF;i++) databuf=i+0x30;com_init(38400);while(1){/*可以处理非串口任务*/}。