以文本方式查看主题 - uC技术交流社区 (http://bbs.mcu123.net/bbs/index.asp) -- 【 源程序共享中心 】 (http://bbs.mcu123.net/bbs/list.asp?boardid=16) ---- [转帖]一个C51串口通讯程序 (http://bbs.mcu123.net/bbs/dispbbs.asp?boardid=16&id=479) |
-- 作者:boy123 -- 发布时间:2005-1-24 11:10:08 -- [转帖]一个C51串口通讯程序 这是我自己编的一个C51串口通讯程序,请大家指教!水平有限,贴出来为的是高手指教我,也能让初学者直接那去用,(如果有人需要PC上的对应程序请EMAIL给我,我发给你。)我其中的一个项目就用这个希望大家点评,谢谢!QQ75011221,EMAIL:niuyimail@126.com //PC读MCU指令结构:(中断方式,ASCII码表示) //帧: 帧头标志|帧类型|器件地址|启始地址|长度n|效验和|帧尾标志 //值: \'n\' \'y\'| \'r\' | 0x01 | x | x | x |0x13 0x10 //字节数: 2 | 1 | 1 | 1 | 1 | 1 | 2 //求和: ///////////////////////////////////////////////////////////////////// //公司名称:*** //模 块 名:protocol.c //创 建 者:牛毅 //修 改 者: //功能描述:中断方式:本程序为mcu的串口通讯提供(贞结构)函数接口,包括具体协议部分 //其他说明:只提供对AT89c51具体硬件的可靠访问接口 //版 本:1.0 //信 息:QQ 75011221 C51BBS匿名:niuyi ///////////////////////////////////////////////////////////////////// #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) {while(RI==0);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;//1200 case 2400: TL1=0xf4;TH1=0Xf4;break;//2400 case 4800: TL1=0xfa;TH1=0Xfa;break;//4800 case 9600: TL1=0xfd;TH1=0Xfd;break;//9600 case 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://是读指令帧r if(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_RESEND break;}//效验和错误 }//地址不正确 break; case F_W://是PC写指令帧w if(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_RESEND break;}//结束标志错误 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_RESEND break;} if(F_END!=receive()) {ERR_NOCNTMAX_RESEND break;} 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){ /*可以处理非串口任务*/ } } |
文章评论(0条评论)
登录后参与讨论