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

📄 mss_spi.c

📁 KEIL C上的门禁控制器源代码
💻 C
📖 第 1 页 / 共 3 页
字号:
///////////////////////////////////////////////////////////////////////////////
//
// Hopinfo Copyright.
//
// www.chinahopeinfo.com.cn
//
// 2005.04.26
//
// 审阅:黄平生
//
// 指纹模块(MSS)和HOST通信采用SPI通信接口,在该设计中8051作为HOST端,工作模式为
// 主设备,指纹模块工作模式为负设备,接收/发送的时钟由8051提供,通信速率由8051处
// 理速度决定,MSS在时钟的下降沿对齐要发送/接收数据位的中间,MSS在时钟的下降沿有
// 效。
// 基本通信原理是:当MSS有数据发送时向HOST申请中断,置MSS_INT为低电平,HOST决定
// 是否接收数据;HOST有数据要发送时,直接向MSS发送,因为HOST为主设备。
//
///////////////////////////////////////////////////////////////////////////////

#include "Global.h"


///////////////////////////////////////////////////////////////////////////////
// 内部存储区变量	0~256
// 全局变量定义
extern data  uchar checksum;			// 校验和
extern data  uchar testchecksum;		// 接收到的校验和

extern data  uchar key;					// 键盘值

extern data  uchar MSG;					// 信息号
extern data  uchar CSH;					// 校验和ASC高字节
extern data  uchar CSL;					// 校验和ASC低字节
extern data  uint  SOHptr;				// SPI缓冲区头指针
extern data  uint  ETXptr;				// ETX位置
extern data  uint  CommandLen;			// 命令体长度
extern data  uchar pulse;				// 蜂鸣次数
extern data  uint  time_out;			// 通用超时定时器

extern data char groupclass;			// 用户分组信息
extern data char User_id[6];			// 用户编号0~65534

extern data uchar cur_time[15];			// 系统当前时间显示存储区 XXXX年XX月XX日XX时XX分XX秒星期X

extern data uint  index;				// 数据索引

extern data uint  trans_ctr;			// 发送数据指针
extern data uint  trans_size;			// 发送数据大小

extern bdata bit reverse;				// LCD底色显示控制
extern bdata bit HandwareErr;			// 指纹模块工作状态

extern bdata bit managemode;			// 管理员比对操作

// 全局临时变量
extern idata char Start_user_id[6];		// 开始用户编号
extern idata char End_user_id[6];		// 终止用户编号
extern idata char Start_time[5];		// 开始时间
extern idata char End_time[5];			// 终止时间
extern idata char Security_level;		// 安全等级0~4
extern idata char ManageClass;			// 管理分类'M'管理用户'G'普通用户
extern idata char AppClass;				// 应用分类'F'指纹用户'P'密码用户
extern idata char Password[7];			// 密码
extern idata char wieformat;			// 韦根通信格式

///////////////////////////////////////////////////////////////////////////////
// 内部存储区变量	256~1280
// 全局变量定义
extern xdata uchar SPIbuf[BUFSIZE];		// SPI和串行通信缓冲区
extern xdata uchar trans_buf[TRANSBUFSIZE];// 发送数据缓冲区

///////////////////////////////////////////////////////////////////////////////
// 程序存储区变量	0~32K
// SPI通信显示信息
code char Putf[]		=" -按下手指- ";
code char Liftf[]		=" -抬起手指- ";
code char success[]		="  <<成功>>  ";
code char failure[]		="  <<失败>>  ";
code char welcome[]		="欢迎";

code char 							// 指纹模块返回信息显示
disp_err[12][12]=
{
	" -没有手指- ", 
	" -图像太差- ",
	" -手指不同- ",
	" -手指太偏- ",
	" -不能注册- ",
	" -已 注 册- ",
	" -没有注册- ",
	" -比对失败- ",
	" -没有空间- ",
	" -不能使用- ",
	" -系统复位- ",
	" -不能通信- ",
};

///////////////////////////////////////////////////////////////////////////////
// 十毫秒延时函数,累积系统若干条指令
///////////////////////////////////////////////////////////////////////////////
void Wait10ms()
{
	idata uint i;

	for(i=0;i<3600;i++){}
}

///////////////////////////////////////////////////////////////////////////////
// 一秒钟延时函数,累积10ms计数
///////////////////////////////////////////////////////////////////////////////
void OneSecond()
{
	idata uchar i;

	for(i=0;i<100;i++)
	{
		Wait10ms();	
	}
}

///////////////////////////////////////////////////////////////////////////////
// MSS和HOST通信包结构采用标准不定长信息包结构
//
// 信息包结构定义如下:
// SOH  地址4字节ASC码      信息号1字节ASC码 STX  命令体ASC码3~   ETX  校验2字节AC码 EOT
// 0B   1B   2B   3B   4B   5B               6B   NB              N+1B N+2B N+3B     N+4B
// 01H  30H  31H  30H  32H  30H~39H          02H                  03H                04H
//
///////////////////////////////////////////////////////////////////////////////

///////////////////////////////////////////////////////////////////////////////
// SPI_Transfer
// 使用SPI 协议同时发送<SPI_byte>
// SCK 空闲为高 在SCK 下降时位锁存
//
// 此程序的时序如下
//
// 参数 时钟数
// MOSI 有效到SCK 下降沿 6
// SCK 上升到 MISO 锁存 2
// SCK 下降到 MOSI 有效 7
// SCK 高时间 13
// SCK 低时间 8
///////////////////////////////////////////////////////////////////////////////
char SPItrans(char SPI_byte)
{
	idata uchar i;

	MSS=0;				// SPI选通
	for(i=8;i>0;i--)
	{
		MOSI=SPI_byte&0x80; 	// 移下一位到 MSB
        SPI_byte=SPI_byte<<1;
		SCK=0;					// 时钟下降沿接收
		SPI_byte|=MISO;
		SCK=1; 					// 时钟上升沿发送
	}
	MSS=1;

	key=0;

	return(SPI_byte);
}

///////////////////////////////////////////////////////////////////////////////
// 生成信息包的信息号'0~'9'
///////////////////////////////////////////////////////////////////////////////
void NewMsgNum()
{
	MSG++;
	if(MSG>0x39){MSG=0x30;}
}

///////////////////////////////////////////////////////////////////////////////
// 将16进制数据校验和转换为ASC码校验和,以便发送
///////////////////////////////////////////////////////////////////////////////
void CS_ASCII()
{
	checksum=~checksum+1;			// 校验和求补
	CSH=((checksum>>4)&0x0f)+0x30;
	if(CSH>0x39)
	{CSH+=0x07;}
	CSL=(checksum&0x0f)+0x30;
	if(CSL>0x39)
	{CSL+=0x07;}					// 校验和转换成两位ASCII码 高位CSH 低位 CSL					
}

///////////////////////////////////////////////////////////////////////////////
// 将ASC码校验和转换为16进制校验和,以便比较
///////////////////////////////////////////////////////////////////////////////
void HEX_CS()	           
{	
	CSH-=0x30;
	if(CSH>9){CSH-=0x07;}
	CSL-=0x30;
	if(CSL>9){CSL-=0x07;}
	checksum=((CSH<<4)&0xf0)+CSL;
}

///////////////////////////////////////////////////////////////////////////////
// 将ASC码数据转换为16进制数据
///////////////////////////////////////////////////////////////////////////////
uchar Asc_hex(char alpha)
{
	alpha=alpha-0x30;
	if(alpha>0x09)alpha=alpha-0x07;
	return alpha;
}

///////////////////////////////////////////////////////////////////////////////
// 将16进制数据转换为ASC码数据
///////////////////////////////////////////////////////////////////////////////
char Hex_ascii(uchar h)
{
	h=h+0x30;
	if(h>0x39)
	{h+=0x07;}
	return h;
}

///////////////////////////////////////////////////////////////////////////////
// 组织发送命令头
///////////////////////////////////////////////////////////////////////////////
void Preamble()
{
	Rstwdt();				// 喂狗
	SPItrans(SOH);
	SPItrans('0');
	SPItrans('1');
	SPItrans('0');
	SPItrans('2');
	SPItrans(MSG);
	checksum=MSG;
	SPItrans(STX);
	checksum+=0xc6;			// 校验和
	Rstwdt();				// 喂狗
}

///////////////////////////////////////////////////////////////////////////////
// 组织发送命令体,命令不同,对应的命令体内容和长度也不相同
///////////////////////////////////////////////////////////////////////////////
void Command()
{
	idata uchar i;

	for(i=0;i<CommandLen;i++)
	{
		Rstwdt();					// 喂狗
		SPItrans(SPIbuf[i]);		// 发送命令体
		checksum+=SPIbuf[i];  	// 校验和
	}
}

///////////////////////////////////////////////////////////////////////////////
// 组织发送命令尾
///////////////////////////////////////////////////////////////////////////////
void Postamble()
{
	Rstwdt();			// 喂狗
	SPItrans(ETX);
	checksum+=ETX;		// 校验和
	CS_ASCII();
	SPItrans(CSH);	
	SPItrans(CSL);
	SPItrans(EOT);
	Rstwdt();			// 喂狗
}

///////////////////////////////////////////////////////////////////////////////
// 组织发送整个命令包
///////////////////////////////////////////////////////////////////////////////
void SendMsg()
{
	Preamble();			// SPI前导数据结构
	Command();			// 命令体
	Postamble();		// SPI校验和结束符
}

///////////////////////////////////////////////////////////////////////////////
// 向MSS发送"ACK"或"NAK"
///////////////////////////////////////////////////////////////////////////////
void SendNACK(uchar NACK)
{
	Rstwdt();			// 喂狗
	SPItrans(SOH);
	SPItrans('0');
	SPItrans('1');
	SPItrans('0');
	SPItrans('2');
	SPItrans(MSG);
	SPItrans(NACK);
	SPItrans(EOT);
	Rstwdt();			// 喂狗
}

///////////////////////////////////////////////////////////////////////////////
// HOST接收MSS数据,按照标准信息包进行检查
// 如果接收错误向MSS发送NAK,如果3次发送错误返回失败
// 如果接收成功向MSS发送ACK
// 如果15秒内不能检测到MSS的数据发送中断,那么MSS可能故障
///////////////////////////////////////////////////////////////////////////////
bit SPIReceive()
{
	idata uchar temp;		// 临时变量
	idata uchar NAKcounter;	// NAK计数器
	idata uint  R_BUF;		// 接收缓冲区指针
	idata uint  i;			// 计数器

	for(R_BUF=0; R_BUF<BUFSIZE; R_BUF++)
		SPIbuf[R_BUF]=0;	// 接收缓冲区清零

	time_out=1500;			// 如果15秒内MSS无数据返回退出错误
	do
	{
		Rstwdt();			// 喂狗
		if(time_out==0)
		{
			HandwareErr=ERROR;		// MSS可能故障
			time_out=0;
			return ERROR;	// 返回
		}
	}while(MSS_INT);		// 检测MSS通信中断


	NAKcounter=3;		// NAK计数器
	do
	{	
		R_BUF=0;		// 接收缓冲区计数
		SOHptr=0;
		ETXptr=0;
		MSS=1;

		time_out=1200;				// 12000msSPI数据传输一个包时间
		do
		{
			do
			{	
				Rstwdt();			// 喂狗
				if(time_out==0)
				{
					HandwareErr=ERROR;		// MSS可能故障
					return ERROR;	// 返回
				}
				temp=SPItrans(0);	// 接收数据
			}while(temp==0);

			SPIbuf[R_BUF++]=temp;	// 非零数据存入缓冲区

			if(R_BUF>BUFSIZE)break;	// 缓冲区满

			if(time_out==0)
			{
				HandwareErr=ERROR;		// MSS可能故障
				return ERROR;	// 返回
			}
	  	}while(temp!=EOT);			// 通信结束

		i=0;
		do
		{
			if(SPIbuf[i]==SOH)		// 定位数据头
			{
				SOHptr=i;
				break;			
			}
			i++;
			Rstwdt();				// 喂狗
		}while(i<R_BUF);

		if(SOHptr==R_BUF)
		{
			goto SPIerr;			// 缓冲区满,数据错误
		}
		else if(SPIbuf[SOHptr+6]!=STX)
		{
			goto SPIerr;			// STX错误
		}
		else if(SPIbuf[R_BUF-4]!=ETX)
		{
			goto SPIerr;			// ETX错误
		}
		else
		{
			MSG=SPIbuf[SOHptr+5];	// 保存信息号
			ETXptr=R_BUF-4;
			Rstwdt();				// 喂狗
			CSH=SPIbuf[ETXptr+1];
			CSL=SPIbuf[ETXptr+2];
			HEX_CS();								
			testchecksum=0;

			for(i=0;i<ETXptr-SOHptr+1;i++)	// 计算校验和
			{
				Rstwdt();				// 喂狗
				testchecksum+=SPIbuf[SOHptr+i];	
			}

			temp=testchecksum+checksum;
			temp=temp&0xff;
			if(temp!=0)
				goto SPIerr;			// 校验

			SendNACK(ACK);				// 发送 ACK

			return OK;
		}
SPIerr:
		Rstwdt();
		SendNACK(NAK);					// 发送 NAK 重新接收DSP数据														
		NAKcounter--;
	}while(NAKcounter>0);

	HandwareErr=ERROR;		// MSS可能故障
	return ERROR;
}

///////////////////////////////////////////////////////////////////////////////
// HOST接收MSS发送的NAK或ACK数据,按照标准信息包进行检查
// 如果2秒内不能检测到MSS的数据发送中断,那么MSS可能故障
///////////////////////////////////////////////////////////////////////////////
uchar ACKReceive()
{
	idata uchar temp;		// 临时变量
	idata uchar R_BUF;		// 接收缓冲区计数

	for(R_BUF=0; R_BUF<255; R_BUF++)
		SPIbuf[R_BUF]=0;	// 接收缓冲区清零

	time_out=200;			// 如果2秒内MSS无数据返回退出错误
	do
	{
		Rstwdt();			// 喂狗
		if(time_out==0)
		{
			HandwareErr=ERROR;		// MSS可能故障
			time_out=0;
			return ERROR;	// 返回
		}
	}while(MSS_INT);		// 检测MSS通信中断


	R_BUF=0;
	time_out=50;				// 500ms接收SPI数据包
	do
	{
		do
		{
			temp=SPItrans(0);	// 接收SPI字节

			if(time_out==0)
			{
				HandwareErr=ERROR;		// MSS可能故障
				return ERROR;	// 返回
			}
		}while(temp==0);		// 空字符不接收

		SPIbuf[R_BUF++]=temp;
		if(R_BUF>20)
		{
			break;				// ACK或NAK命令长度不超过20
		}

		if(time_out==0)
		{
			HandwareErr=ERROR;		// MSS可能故障
			return ERROR;	// 返回
		}
	}while(temp!=EOT);			// 接收到EOT结束符

	if(SPIbuf[R_BUF-2]==ACK)
	{
		return ACK;		// 返回ACK
	}
	else if(SPIbuf[R_BUF-2]==NAK)
	{
		return NAK;		// 返回NAK
	}

	HandwareErr=ERROR;	// MSS可能故障
	return ERROR;
}

///////////////////////////////////////////////////////////////////////////////
// 显示公共错误信息
///////////////////////////////////////////////////////////////////////////////
void disperr(uchar id)
{
	Rstwdt();			// 喂狗

	GLCD_Locate(16,32);
	reverse=1;
	dprintf(failure,12);					// 失败			
	reverse=0;

	GLCD_Locate(0,48);
	dprintf("               ",15);			// 清行
	GLCD_Locate(16,48);

	if(id<'A')
	{
		dprintf(disp_err[id-0x30],12);	// 显示正常错误信息
	}
	else
	{
		if(id<='F')
		{
			HandwareErr=ERROR;	// MSS不能正常工作
			dprintf(disp_err[10],12);	// 显示模块复位
			TURN_ON();
		}
		else
		{
			dprintf(disp_err[11],12);	// 显示ACK错误
		}

⌨️ 快捷键说明

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