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

📄 uart.c

📁 门禁控制器源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
///////////////////////////////////////////////////////////////////////////////
// 门禁终端与上位服务器通信
// 门禁终端与上位服务器通信采用RS485总线方式连接,每台门禁终端分配固定设备
// 地址。
// 需要注意的是在处理串行通信的时候,可以关闭其它中断
// idata=19
///////////////////////////////////////////////////////////////////////////////

#include "Global.h"


///////////////////////////////////////////////////////////////////////////////
// 内部存储区变量	0~128字节
extern data uchar cur_time[15];			// 系统当前时间显示存储区 XXXX年XX月XX日XX时XX分XX秒星期X

extern data uchar pulse;				// 蜂鸣
extern data uint  time_out;				// 通用超时定时器

extern data uint  recv_ctr;				// 接收数据起始指针
extern data uint  trans_time;			// 发送数据超时保护
extern data uint  trans_ctr;			// 发送数据指针
extern data uint  trans_size;			// 发送数据大小

extern idata uint SOH_crt;				// 数据包开始指针

extern idata char  wieformat;			// 韦根通信格式

extern bdata bit maxtrans;				// 大/小数据量传输状态
extern idata uchar baudrate;			// 波特率
extern bdata bit comm_ok;				// 通信状态
extern idata uchar laddr;				// 地址低字节ASC码
extern idata uchar haddr;				// 地址高字节ASC码
extern idata uchar currecno;			// 当前已读取的实时记录索引
extern idata uchar sumrecno;			// 所有实时记录索引

extern data  uchar checksum;			// 校验和
extern data  uchar testchecksum;		// 接收到的校验和

///////////////////////////////////////////////////////////////////////////////
// 外部存储区变量	256~1280字节
extern xdata uchar SPIbuf[BUFSIZE];			// SPI和串行通信缓冲区
extern xdata uchar recv_buf[RCVBUFSIZE];	// 接收数据缓冲区
extern xdata uchar trans_buf[TRANSBUFSIZE];	// 发送数据缓冲区
extern xdata uchar RTrecord[MAX_REALREC_SIZE];	// 实时记录缓冲区

void sendmessage(uchar message);			// 发送信息
void ClearRcvBuf();							// 清接收缓冲区

///////////////////////////////////////////////////////////////////////////////
// 中断4服务列程
// 串行中断服务
///////////////////////////////////////////////////////////////////////////////
void ser() interrupt 4
{
	idata uchar c;

	if(_testbit_(TI))			// 检测发送完成位
	{
		if(maxtrans)				// 大数据量传输
		{
			trans_ctr++;			// 发送指针下移
			if(trans_ctr<trans_size)
				SBUF=SPIbuf[trans_ctr];	// 发送数据
			else
			{
				trans_ctr=0;
				trans_size=0;
				Dir=0;				// 停止发送
			}
		}
		else						// 小数据量传输
		{
			trans_ctr++;			// 发送指针下移
			if(trans_ctr<trans_size)
				SBUF=trans_buf[trans_ctr];	// 发送数据
			else
			{
				trans_ctr=0;
				trans_size=0;
				Dir=0;				// 停止发送
			}
		}
	}

	if(_testbit_(RI))			// 检测接收完成位
	{
		c=SBUF;
		if(c!=0x00)
		{
			if(maxtrans)			// 大数据量传输
			{
				SPIbuf[recv_ctr]=c;
				recv_ctr++;
				if(recv_ctr>BUFSIZE)
					recv_ctr=0;
			}
			else					// 小数据量传输
			{
				recv_buf[recv_ctr]=c;
				recv_ctr++;
				if(recv_ctr>RCVBUFSIZE)
					recv_ctr=0;
			}
		}
	}
}

///////////////////////////////////////////////////////////////////////////////
// 检查接收缓冲区是否有完整的数据包
// 如果有返回成功,如果数据包不完整可能数据有部分丢失或者没有完整的数据返回失败
// 检查SOH和EOT来判断
///////////////////////////////////////////////////////////////////////////////
bit checkmessage()
{
	bdata bit  SOHfound;
	bdata bit  EOTfound;
	idata uchar temp;
	idata uint i;

	SOHfound=FALSE;
	EOTfound=FALSE;
		
	if(recv_ctr==0)
		return FALSE;			// 缓冲区中无数据

	if(maxtrans)
	{
		if(recv_ctr>BUFSIZE)	// 接收缓冲区溢出
		{
			ClearRcvBuf();
			return FALSE;
		}
	}
	else
	{
		if(recv_ctr>RCVBUFSIZE)	// 接收缓冲区溢出
		{
			ClearRcvBuf();
			return FALSE;
		}
	}

	for(i=0; i<recv_ctr; i++)
	{
		if(maxtrans)
			temp=SPIbuf[i];
		else
			temp=recv_buf[i];

		if(temp==SOH)
		{
			SOHfound=TRUE;		// 发现SOH
			SOH_crt=i;
		}
		if(temp==EOT)
			EOTfound=TRUE;		// 发现 EOT
	}

	if(SOHfound&&EOTfound)
	{
		COMDISABLE;				// 不允许再接收数据
		return TRUE;			// 接收到完整的数据包
	}

	return FALSE;
}

///////////////////////////////////////////////////////////////////////////////
// 发送信息
///////////////////////////////////////////////////////////////////////////////
void sendmessage(uchar message)
{
	idata uchar i;
	idata uchar temp;

	if(maxtrans)			// 大模式数据传输
	{
		SPIbuf[0]=SOH;
		SPIbuf[1]=haddr;	// 源地址
		SPIbuf[2]=laddr;
		SPIbuf[3]='0';		// 目标地址
		SPIbuf[4]='0';
		SPIbuf[5]='0';		// 信息号
		SPIbuf[6]=message;	// ACK/NAK
		SPIbuf[7]=EOT;		// 结束

		COMENABLE;			// 允许串口中断
		Dir=1;				// 485发送
		time_out=10;		// 100ms完成发送
		trans_ctr=0;
		trans_size=8;
		SBUF=SPIbuf[0];		// 发送
		comm_ok=TRUE;		// 串口通信正常
		while(trans_size)
		{
			if(time_out==0)
			{
				comm_ok=FALSE;	// 串口通信失败
				break;
			}
		}					// 直到数据传输完毕
		Dir=0;				// 关闭485发送
	}
	else
	{
		trans_ctr=0;
		checksum=0;
		trans_buf[trans_ctr]=SOH;
		checksum+=trans_buf[trans_ctr];
		trans_ctr++;
		trans_buf[trans_ctr]=haddr;			// 源地址
		checksum+=trans_buf[trans_ctr];
		trans_ctr++;
		trans_buf[trans_ctr]=laddr;
		checksum+=trans_buf[trans_ctr];
		trans_ctr++;
		trans_buf[trans_ctr]='0';			// 目标地址
		checksum+=trans_buf[trans_ctr];
		trans_ctr++;
		trans_buf[trans_ctr]='0';
		checksum+=trans_buf[trans_ctr];
		trans_ctr++;
		trans_buf[trans_ctr]='0';			// 信息号
		checksum+=trans_buf[trans_ctr];
		trans_ctr++;

		switch(message)
		{
		case ACK:
			trans_buf[trans_ctr++]=ACK;
			break;
		case NAK:
			trans_buf[trans_ctr++]=NAK;
			break;
		case RTL:
			trans_buf[trans_ctr]=STX;
			checksum+=trans_buf[trans_ctr];
			trans_ctr++;

			for(i=0; i<MAX_REALREC_SIZE;i++)	// 发送实时记录
			{
				trans_buf[trans_ctr]=RTrecord[i];
				checksum+=trans_buf[trans_ctr];
				trans_ctr++;
			}

			trans_buf[trans_ctr]=ETX;			
			checksum+=trans_buf[trans_ctr];
			trans_ctr++;

			checksum=~checksum+1;			// 计算校验和

			temp=(checksum&0xF0)>>4;
			trans_buf[trans_ctr]=Hex_ascii(temp);
			trans_ctr++;

			temp=checksum&0x0F;
			trans_buf[trans_ctr]=Hex_ascii(temp);
			trans_ctr++;
			break;
		default:
			break;
		}

		trans_buf[trans_ctr++]=EOT;

		COMENABLE;			// 允许串口中断
		Dir=1;				// 485发送
		trans_size=trans_ctr;
		trans_ctr=0;
		SBUF=trans_buf[0];
		time_out=200;		// 200ms发送完毕
		comm_ok=TRUE;		// 通信正常
		while(trans_size)
		{
			if(time_out==0)
			{
				comm_ok=FALSE;	// 通信失败
				break;
			}
		}					// 直到数据传输完毕
		Dir=0;				// 关闭485发送
	}

	ClearRcvBuf();			// 清接收缓冲区
}

///////////////////////////////////////////////////////////////////////////////
// 读取并分析接收缓冲区数据
///////////////////////////////////////////////////////////////////////////////
uchar readbuf()
{
	idata uchar curstate;		// 当前信息类别
	idata uchar nextstate;		// 下一个信息类别
	idata uchar temp;
	idata uint  i;
	idata uint  strindex;
	bdata bit   endofmessage;	// 数据包是否结束
	bdata bit   errordect;		// 是否有错误检测到
	bdata bit   wrongaddr;		// 地址是否错误

	curstate=STATE_SOH;			// 当前信息状态
	nextstate=STATE_SOH;		// 下一个信息状态

	i=SOH_crt;					// 数据指针索引
	strindex=0;					// 命令体数据指针索引
	errordect=FALSE;
	wrongaddr=FALSE;
	endofmessage=FALSE;

	checksum=0;					// 校验和
	testchecksum=0;

 	while (TRUE)
 	{
		curstate=nextstate;		// 当前状态从SOH开始

		switch(curstate)
		{
		case STATE_SOH:
			if(maxtrans)
				temp=SPIbuf[i];
			else
				temp=recv_buf[i];

			if(temp!=SOH)
			{
				errordect=TRUE;					// 有错误检测到
			}
			else
			{
				checksum+=SOH;
				nextstate=STATE_SRC_ADDR;		// 检查源地址

				i++;							// 数据指针下移
			}
			break;
		case STATE_SRC_ADDR:
			if(maxtrans)
				temp=SPIbuf[i];
			else
				temp=recv_buf[i];

			checksum+=temp;						// 源地址为00
			if(temp!='0')
				wrongaddr=TRUE;					// 源地址错误
			else
			{
				i++;							// 数据指针下移

				if(maxtrans)
					temp=SPIbuf[i];
				else
					temp=recv_buf[i];
				checksum+=temp;

				if(temp!='0')
					wrongaddr=TRUE;				// 源地址错误

				i++;							// 数据指针下移
			}
			nextstate=STATE_DST_ADDR;			// 检查目标地址
			break;
		case STATE_DST_ADDR:
			if(maxtrans)
				temp=SPIbuf[i];
			else
				temp=recv_buf[i];
			checksum+=temp;

			if(temp!=haddr)						// 地址高位
				wrongaddr=TRUE;					// 地址错误
			else
			{

⌨️ 快捷键说明

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