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

📄

📁 用一个以PC机作为主控机,多个单片机作为从机构成485总线现场检测系统.
💻
字号:
#include <reg52.h>			    // 引用标准库的头文件
#include <stdio.h>
#include <string.h>

#define uchar unsigned char 
#define uint unsigned int
 
#define ACTIVE  	0x11
#define GETDATA  	0x22
#define READY  		0x33
#define SENDDATA	0x44	

#define RECFRMMAXLEN 16 		// 接收帧的最大长度,超过此值认为帧超长错误
#define STATUSMAXLEN 10			// 设备状态信息最大长度	  

uchar DevNo;					// 设备号
xdata uchar StatusBuf[STATUSMAXLEN];

//为简化起见,假设了10位固定的采集数据
#define DATA0  	0x10
#define DATA1  	0x20
#define DATA2  	0x30
#define DATA3  	0x40
#define DATA4  	0x50
#define DATA5  	0x60
#define DATA6  	0x70
#define DATA7  	0x80
#define DATA8  	0x90
#define DATA9  	0xA0

sbit DE = P1^6;			//驱动器使能,1有效
sbit RE = P1^7;			//接收器使能,0有效

void init();					// 系统初始化
void Get_Stat();				// 简化的数据采集函数
bit Recv_Data(uchar *type);		// 接收数据帧函数
void Send(uchar m);					// 发送单字节数据
void Send_Data(uchar type,uchar len,uchar *buf);				// 发送数据帧函数	
void Clr_StatusBuf();			//  清除设备状态信息缓冲区函数   

void main(void)
{
	uchar type;

	/* 初始化 */
	init();
	
	while (1) 
	{
		if (Recv_Data(&type)==0)			// 接收帧错误或者地址不符合,丢弃
			continue;
		switch (type)
		{
			case ACTIVE:				// 主机询问从机是否在位
				Send_Data(READY,0,StatusBuf);	// 发送READY指令
				break;
			case GETDATA:				// 主机读设备请求
				Clr_StatusBuf();
				Get_Stat();				// 数据采集函数
				Send_Data(SENDDATA,strlen(StatusBuf),StatusBuf);
				break;
			default:
				break;					// 指令类型错误,丢弃当前帧
		}
	}
}

/* 初始化 */
void init(void)
{
	P1 = 0xff;
	DevNo = (P1&0x00111111);			// 读取本机设备号

	TMOD = 0x20;
	SCON = 0x50;
	TH1 = 0xfd;
	TL1 = 0xfd;
	TR1 = 1;
	PCON = 0x00;						// SMOD=0
	EA = 0;
						
}

/* 接收数据帧函数,实际上接收的是主机的指令 */
bit Recv_Data(uchar *type)
{
	uchar tmp,rCount,i;
	uchar r_buf[RECFRMMAXLEN];			// 保存接收到的帧
	uchar Flag_RecvOver;				// 一帧接收结束标志	
	uchar Flag_StartRec;				// 一帧开始接收标志
	uchar CheckSum;						// 校验和
	uchar DataLen;						// 数据字节长度变量
		
	/* 禁止发送,允许接收 */
	DE = 0;
	RE = 0;

	/* 接收一帧数据 */
	rCount = 0;
	Flag_StartRec = 0;
    Flag_RecvOver = 0;
	while (!Flag_RecvOver)
	{
		RI = 0;
		while (!RI);
		tmp = SBUF;
		RI=0;

		/* 判断是否收到字符'$',其数值为0x24 */          
		if ((!Flag_StartRec) && (tmp == 0x24))
		{
			Flag_StartRec = 1;	
		}

		if (Flag_StartRec) 
		{
			r_buf[rCount] = tmp;
			rCount ++;		
			
			/* 判断是否收到字符'*',其数值为0x2A,根据接收的指令设置相应标志位 */
			if (tmp == 0x2A)
				Flag_RecvOver = 1;
		}

		if (rCount == RECFRMMAXLEN)		// 帧超长错误,返回0
			return 0;
	}
	
	/* 计算校验和字节 */
	CheckSum = 0;
	DataLen = r_buf[3];
	for (i=0;i++;i<3+DataLen)
	{
		CheckSum = CheckSum + r_buf[i+1];
	}
	
	/* 判断帧是否错误 */
	if (rCount<6)						// 帧过短错误,返回0,最短的指令帧为6个字节						
		return 0;
	if (r_buf[1]!=DevNo)  				// 地址不符合,错误,返回0
		return 0;
	if (r_buf[rCount-2]!=CheckSum)		// 校验错误,返回0
    	return 0;

	*type = r_buf[2];					// 获取指令类型

	return 1;							// 成功,返回1
}

/* 发送数据帧函数 */
void Send_Data(uchar type,uchar len,uchar *buf)
{
	uchar i,tmp;
	uchar CheckSum = 0;
	
	/* 允许发送,禁止接收 */
	DE = 1;
	RE = 1;
	
	/* 发送帧起始字节 */
	tmp = 0x24;
	Send(tmp);
	
	Send(DevNo);						// 发送地址字节,也即设备号
	CheckSum = CheckSum + DevNo;
 
	Send(type);							// 发送类型字节
	CheckSum = CheckSum + type;

	Send(len);							// 发送数据长度字节
	CheckSum = CheckSum + len;
 
	/* 发送数据 */
	for (i=0;i<len;i++)			
	{
		Send(*buf);
		CheckSum = CheckSum + *buf;
		buf++;
	}
	
	Send(CheckSum);						// 发送校验和字节

	/* 发送帧结束字节 */
	tmp = 0x2A;
	Send(tmp);
}

/* 采集数据函数经过简化处理,取固定的10个字节数据 */
void Get_Stat(void)
{
	StatusBuf[0]=DATA0;
	StatusBuf[1]=DATA1;
	StatusBuf[2]=DATA2;
	StatusBuf[3]=DATA3;
	StatusBuf[4]=DATA4;
	StatusBuf[5]=DATA5;
	StatusBuf[6]=DATA6;
	StatusBuf[7]=DATA7;
	StatusBuf[8]=DATA8;
	StatusBuf[9]=DATA9;
}

/* 发送单字节数据 */
void Send(uchar m)
{
	TI = 0;
	SBUF = m;
    while(!TI);
	TI = 0;	
}

/* 清除设备状态信息缓冲区函数*/
void Clr_StatusBuf(void)
{
	uchar i;
	for (i=0;i<STATUSMAXLEN;i++)
		StatusBuf[i] = 0;	
}			

⌨️ 快捷键说明

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