⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 serrio.c

📁 一个串行口通讯程序c51
💻 C
字号:
//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 //错误标志22 
//常数 
#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]=i; 
	com_init(38400); 
	while(1)
	{ 
	/*可以处理非串口任务*/ 
	} 
} 

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -