0009基于51单片机智能门禁系统设计

2023-05-16

资料下载地址

单片机原理教程--初级(视频,源仿真源代码)

功能
(60%)    可输入密码进行解锁。        
    可以对IC卡进行注册或注销。         
    可用已注册的IC卡解锁。         
    可实现液晶显示当前时间。      
    密码连续输错三次时能强制退出并报警。         
    具有指示灯温和蜂鸣器提示功能,开锁时亮绿灯。         
参数(20%)    开锁后自动恢复闭锁时间≤15s         
    实现开锁的反应时间≤2s    

//包含头文件
#include <REG52.h>
#include<intrins.h>
#include "main.h"
#include<rc522.c> 
#include<eeprom52.h> 
//宏定义
#define LCM_Data  P0		  //将P0口定义为LCM_Data
#define uchar unsigned char 
#define uint  unsigned int

#define WRITE_SECOND    0x80    //DS1302内部的相关地址
#define WRITE_MINUTE    0x82
#define WRITE_HOUR      0x84
#define WRITE_DATE      0x86
#define WRITE_MONTH     0x88
#define WRITE_WEEK		0x8a
#define WRITE_YEAR      0x8c

#define READ_SECOND     0x81
#define READ_MINUTE     0x83
#define READ_HOUR       0x85
#define READ_DATE       0x87
#define READ_MONTH      0x89
#define READ_WEEK		0x8b
#define READ_YEAR       0x8d
uchar second1;
uchar minute1;
uchar hour1;
uchar week1;
uchar day1;
uchar month1;
uchar year1;

struct time
{
   uchar second;
   uchar minute;
   uchar hour;
   uchar week;
   uchar day;
   uchar month;
   uchar year;
}
current_time;
#define ctime current_time

sbit RST=P3^0;
sbit SCLK=P3^1;
sbit SDA=P2^6;

//1602的控制脚
sbit lcd1602_rs=P2^7;
sbit lcd1602_en=P2^5;

sbit Scl=P3^4;			//24C02串行时钟
sbit Sda=P3^5;			//24C02串行数据

sbit ALAM = P2^1;		//报警	
sbit KEY = P3^6;		//开锁

bit  operation=0;		//操作标志位
bit  pass=0;			//密码正确标志
bit  ReInputEn=0;		//重置输入充许标志	
bit  s3_keydown=0;		//3秒按键标志位
bit  key_disable=0;		//锁定键盘标志
bit  chushihua=0;       //可以注册卡标志位

unsigned char countt0,second,s1num,flag;	//t0中断计数器,秒计数器

void Delay5Ms(void);		//声明延时函数
unsigned char xdata CardRevBuf[16] = { 0 };

unsigned char code a[]={0xFE,0xFD,0xFB,0xF7}; 				//控盘扫描控制表
//液晶显示数据数组
unsigned char code start_line[]	= {"password:       "};
unsigned char code name[] 	 	= {"===Coded Lock==="};	//显示名称
unsigned char code Correct[] 	= {"     correct    "};		//输入正确
unsigned char code Error1[]   	= {"      error     "};  	//输入错误
unsigned char code codepass[]	= {"      pass      "}; 
unsigned char code LockOpen[]	= {"      open      "};		//OPEN
unsigned char code SetNew[] 	= {"SetNewWordEnable"};
unsigned char code Input[]   	= {"input:          "};		//INPUT
unsigned char code ResetOK[] 	= {"ResetPasswordOK "};
unsigned char code initword[]	= {"Init password..."};
unsigned char code Er_try[]		= {"error,try again!"};
unsigned char code again[]		= {"input again     "};
unsigned char code table[]="      :  :     ";

unsigned char InputData[6];									//输入密码暂存区
unsigned char CurrentPassword[6]={0,0,0,0,0,0}; 			//读取EEPROM密码暂存数组
unsigned char TempPassword[6];
unsigned char N=0;				//密码输入位数记数
unsigned char ErrorCont;			//错误次数计数
unsigned char CorrectCont;			//正确输入计数
unsigned char ReInputCont; 			//重新输入计数
unsigned char code initpassword[6]={0,0,0,0,0,0};			//输入管理员密码后将密码初始为000000
unsigned char code adminpassword[6]={1,3,1,4,2,0};			//输入管理员密码后将密码初始为000000
unsigned char code adminpassword1[6]={1,3,1,4,2,1};
unsigned char current_id;
char xdata DisplayBuf[10];  //当前读出卡的ID
char xdata DisplayBuf_c[10];  //当前单片机里存的卡ID

void write_eeprom_j(unsigned char j)		  //将对应的ID写入到单片机
{
   
	SectorErase(0x2200+j*0x0200);		   //清空
 	byte_write(0x2200+j*0x0200,DisplayBuf[0]);		
 	byte_write(0x2201+j*0x0200,DisplayBuf[1]);
	byte_write(0x2202+j*0x0200,DisplayBuf[2]);
	byte_write(0x2203+j*0x0200,DisplayBuf[3]);
	byte_write(0x2204+j*0x0200,DisplayBuf[4]);
	byte_write(0x2205+j*0x0200,DisplayBuf[5]);
	byte_write(0x2206+j*0x0200,DisplayBuf[6]);
	byte_write(0x2207+j*0x0200,DisplayBuf[7]); 
}
void write_eeprom_jj(unsigned char j)	 //将对应的ID清空
{
   
	SectorErase(0x2200+j*0x0200);		   //清空
 	byte_write(0x2200+j*0x0200,' ');		
 	byte_write(0x2201+j*0x0200,' ');
	byte_write(0x2202+j*0x0200,' ');
	byte_write(0x2203+j*0x0200,' ');
	byte_write(0x2204+j*0x0210,' ');
	byte_write(0x2205+j*0x0200,' ');
	byte_write(0x2206+j*0x0200,' ');
	byte_write(0x2207+j*0x0200,' '); 
}
void read_eeprom_j(uchar j)
{
  DisplayBuf_c[0]= byte_read(0x2200+j*0x0200);
  DisplayBuf_c[1]= byte_read(0x2201+j*0x0200); 
  DisplayBuf_c[2]= byte_read(0x2202+j*0x0210); 
  DisplayBuf_c[3]= byte_read(0x2203+j*0x0200); 
  DisplayBuf_c[4]= byte_read(0x2204+j*0x0200); 
  DisplayBuf_c[5]= byte_read(0x2205+j*0x0200); 
  DisplayBuf_c[6]= byte_read(0x2206+j*0x0200); 
  DisplayBuf_c[7]= byte_read(0x2207+j*0x0200);   
 
}
//=====================5ms延时==============================
void Delay5Ms(void)
{
	unsigned int TempCyc = 5552;
	while(TempCyc--);
}

//===================400ms延时==============================
void Delay400Ms(void)
{
 unsigned char TempCycA = 5;
 unsigned int TempCycB;
 while(TempCycA--)
 {
  TempCycB=7269;
  while(TempCycB--);
 }
}

//=============================================================================================
//================================24C02========================================================
//=============================================================================================

void mDelay(uint t) //延时
{ 
	uchar i;
   	while(t--)
   	{
   		for(i=0;i<125;i++)
   		{;}
   	}
}
   

void Nop(void)		  //空操作
{
 	_nop_();		  //仅作延时用一条语句大约1us
 	_nop_();
 	_nop_();
 	_nop_();
}

/*****24c02程序参照24c02时序图*****/
/*起始条件*/

void Start(void)
{
 	Sda=1;
 	Scl=1;
 	Nop();
 	Sda=0;
 	Nop();
}


 /*停止条件*/
void Stop(void)
{
 	Sda=0;
 	Scl=1;
 	Nop();
 	Sda=1;
 	Nop();
}

/*应答位*/
void Ack(void)
{
	Sda=0;
	Nop();
	Scl=1;
	Nop();
	Scl=0;
}

/*反向应答位*/
void NoAck(void)
{
 	Sda=1;
 	Nop();
 	Scl=1;
 	Nop();
 	Scl=0;
}

 /*发送数据子程序,Data为要求发送的数据*/
void Send(uchar Data)
{
   	uchar BitCounter=8;
   	uchar temp;
   	do
   	{
   		temp=Data;					   //将待发送数据暂存temp
   		Scl=0;
   		Nop();
   		if((temp&0x80)==0x80)		   //将读到的数据&0x80
   		Sda=1;
   		else 
   		Sda=0;
   		Scl=1;
   		temp=Data<<1;				   //数据左移
   		Data=temp;					   //数据左移后重新赋值Data
   		BitCounter--;				   //该变量减到0时,数据也就传送完成了
   	}
   	while(BitCounter);				   //判断是否传送完成
   	Scl=0;
}

/*读一字节的数据,并返回该字节值*/
uchar Read(void)
{
    uchar temp=0;
	uchar temp1=0;
	uchar BitCounter=8;
	Sda=1;
	do
	{
		Scl=0;
		Nop();
		Scl=1;
		Nop();
		if(Sda)				   //数据位是否为1
			temp=temp|0x01;	   //为1 temp的最低位为1(|0x01,就是将最低位变为1)
		else				   //如果为0
			temp=temp&0xfe;	   //temp最低位为0(&0xfe(11111110)最低位就是0)
		if(BitCounter-1)	   //BitCounter减1后是否为真
		{
			temp1=temp<<1;	   //temp左移
			temp=temp1;
		}
		BitCounter--;		   //BitCounter减到0时,数据就接收完了
	}
	while(BitCounter);		   //判断是否接收完成
	return(temp);
}

void WrToROM(uchar Data[],uchar Address,uchar Num)
{
  uchar i;
  uchar *PData;
  PData=Data;
  for(i=0;i<Num;i++)
  {
  Start();
  Send(0xa0);
  Ack();
  Send(Address+i);
  Ack();
  Send(*(PData+i));
  Ack();
  Stop();
  mDelay(20);
  }
}

void RdFromROM(uchar Data[],uchar Address,uchar Num)
{
  uchar i;
  uchar *PData;
  PData=Data;
  for(i=0;i<Num;i++)
  {
  Start();
  Send(0xa0);
  Ack();
  Send(Address+i);
  Ack();
  Start();
  Send(0xa1);
  Ack();
  *(PData+i)=Read();
  Scl=0;
  NoAck();
  Stop();
  }
}
//===================2us延时==============================
void delayus()	 //延时2us
{
  _nop_();
  _nop_();
}


//===================DS1302=================================//
//==========================================================//
/************************************************
*名称:DS1302WriteByte
*说明:无
*功能:写入8bit数据
*调用:delayus()
*输入:dat:要写入的数据
*输出:无
*************************************************/
void DS1302WriteByte(uchar dat)
{
    uchar i;
    SCLK=0;//初始时钟线置为0
    delayus();
    for(i=0;i<8;i++)//开始传输8个字节的数据
      {
         SDA=dat&0x01;//取最低位,注意DS1302的数据和地址都是从最低位开始传输的
         delayus();
         SCLK=1;//时钟线拉高,制造上升沿,SDA的数据被传输
         delayus();
         SCLK=0;//时钟线拉低,为下一个上升沿做准备
         dat>>=1;//数据右移一位,准备传输下一位数据
      }
}

/************************************************
*名称:DS1302ReadByte()
*说明:无 
*功能:读取8bit的数据
*调用:delayus()
*输入:无 
*输出:dat:读取的数据 
*************************************************/
uchar DS1302ReadByte()
{
   uchar i,dat;
   delayus();
   for(i=0;i<8;i++)
    { 
       dat>>=1;//要返回的数据右移一位 
       if(SDA==1)//当数据线为高时,证明该位数据为1 
         dat|=0x80;//要传输数据的当前值置为1,若不是,则为0
       SCLK=1;//拉高时钟线
       delayus(); 
       SCLK=0;//制造下降沿
       delayus();
     }
       SDA=0;
	   return dat;//返回读取出的数据

}

/************************************************
*名称:ucharDS1302Read()
*说明:先写地址,后读数据
*功能:从cmd相应地址中读取一个字节的数据
*调用:DS1302WriteByte(),DS1302ReadByte()
*输入:cmd:要写入的控制字节
*输出:dat:读取的数据
*************************************************/
uchar DS1302Read(uchar cmd)
{

   uchar dat;
   RST=0;//初始CE线置为0
   SCLK=0;//初始时钟线置为0
   RST=1;//初始CE置为1,传输开始
   DS1302WriteByte(cmd);//传输命令字,要读取的时间/日历地址   
   dat=DS1302ReadByte();//读取要得到的时间/日期
   SCLK=1;//时钟线拉高
   RST=0;//读取结束,CE置为0,结束数据的传输
   return dat;//返回得到的时间/日期
}

/************************************************
*名称:DS1302Write
*说明:先写地址,后写数据
*功能:向cmd相应地址中写一个字节的数据
*调用:DS1302WriteByte()
*输入:cmd:要写入的控制字,dat:要写入的数据
*输出:无

*************************************************/
void DS1302Write(uchar cmd,uchar dat)
{
   RST=0;//初始CE线置为0
   SCLK=0;//初始时钟线置为0
   RST=1;//初始CE置为1,传输开始
   DS1302WriteByte(cmd);//传输命令字,要写入的时间/日历地址
   DS1302WriteByte(dat);//写入要修改的时间/日期
   SCLK=1;//时钟线拉高
   RST=0;//读取结束,CE置为0,结束数据的传输
}


void Init_DS1302()
{
  DS1302Write(0x8e,0x00);
  /* DS1302Write(WRITE_SECOND,0x00);
  DS1302Write(WRITE_MINUTE,0x33);
  DS1302Write(WRITE_HOUR,0x07);
  DS1302Write(WRITE_DATE,0x07);
  DS1302Write(WRITE_MONTH,0x12);   //	 首次下载定时 2016.12.07  7:33:00 星期三
  DS1302Write(WRITE_WEEK,0x03);
  DS1302Write(WRITE_YEAR,0x16);*/
  DS1302Write(0x90,0x01);
  DS1302Write(0x8e,0x80); 
}
 


//==================================================================================================
//=======================================LCD1602====================================================
//==================================================================================================

#define yi 0x80 //LCD第一行的初始位置,因为LCD1602字符地址首位D7恒定为1(100000000=80)
#define er 0x80+0x40 //LCD第二行初始位置(因为第二行第一个字符位置地址是0x40)


//----------------延时函数,后面经常调用----------------------
void delay(uint xms)//延时函数,有参函数
{
	uint x,y;
	for(x=xms;x>0;x--)
	 for(y=110;y>0;y--);
}

//--------------------------写指令---------------------------
void write_1602com(uchar com)//****液晶写入指令函数****
{
	lcd1602_rs=0;//数据/指令选择置为指令
	P0=com;//送入数据
	delay(1);
	lcd1602_en=1;//拉高使能端,为制造有效的下降沿做准备
	delay(1);
	lcd1602_en=0;//en由高变低,产生下降沿,液晶执行命令
}

//-------------------------写数据-----------------------------
void write_1602dat(uchar dat)//***液晶写入数据函数****
{
	lcd1602_rs=1;//数据/指令选择置为数据
	P0=dat;//送入数据
	delay(1);
	lcd1602_en=1; //en置高电平,为制造下降沿做准备
	delay(1);
	lcd1602_en=0; //en由高变低,产生下降沿,液晶执行命令
}
//-------------------------写时分秒-----------------------------
void write_sfm(uchar add,char date)	//写时分秒函数
{
   char shi,ge;
   shi=date/16;
   ge=date%16;
   
   write_1602com(0x80+add);
   write_1602dat(0x30+shi);
   write_1602dat(0x30+ge);
}
//-------------------------初始化-------------------------
void lcd_init(void)
{

	write_1602com(0x38);//设置液晶工作模式,意思:16*2行显示,5*7点阵,8位数据
	write_1602com(0x0c);//开显示不显示光标
	write_1602com(0x06);//整屏不移动,光标自动右移
	write_1602com(0x01);//清显示

}


//========================================================================================
//=========================================================================================
//==============将按键值编码为数值=========================
unsigned char coding(unsigned char m)	 
{
	unsigned char k;
	switch(m)
	{
		case (0x11): k=1;break;
		case (0x21): k=2;break;
		case (0x41): k=3;break;
		case (0x81): k='A';break;
		case (0x12): k=4;break;
		case (0x22): k=5;break;
		case (0x42): k=6;break;
		case (0x82): k='B';break;
		case (0x14): k=7;break;
		case (0x24): k=8;break;
		case (0x44): k=9;break;
		case (0x84): k='C';break;
		case (0x18): k='*';break;
		case (0x28): k=0;break;
		case (0x48): k='#';break;
		case (0x88): k='D';break;
	}
	return(k);
}
//=====================按键检测并返回按键值===============================
unsigned char keynum(void)
{
 	unsigned char row,col,i;
 	P1=0xf0;
 	if((P1&0xf0)!=0xf0)
 	{
	   	Delay5Ms();
        Delay5Ms();
   		if((P1&0xf0)!=0xf0)
		{
    		row=P1^0xf0;          //确定行线
			i=0;
			P1=a[i];	          //精确定位
			while(i<4)
			{
	 			if((P1&0xf0)!=0xf0)
	  			{
	   				col=~(P1&0xff);	  //确定列线
	   				break;            //已定位后提前退出   
	  			}
				else 
	  			{
	   				i++;
	   				P1=a[i];
	  			}
			}
		}
		else 
		{
			return 0;
		}
		while((P1&0xf0)!=0xf0);
		return (row|col);	 		//行线与列线组合后返回
 	}
 	else return 0;	         		//无键按下时返回0
}
//=======================一声提示音,表示有效输入========================
void OneAlam(void)
{
	ALAM=0;
	Delay5Ms();
    ALAM=1;
}
//========================二声提示音,表示操作成功========================
void TwoAlam(void)
{
	ALAM=0;
	Delay5Ms();
    ALAM=1;
    Delay5Ms();
	ALAM=0;
	Delay5Ms();
    ALAM=1;
}
//========================三声提示音,表示错误========================
void ThreeAlam(void)
{
	ALAM=0;
	Delay5Ms();
    ALAM=1;
    Delay5Ms();
	ALAM=0;
	Delay5Ms();
    ALAM=1;
    Delay5Ms();
	ALAM=0;
	Delay5Ms();
    ALAM=1;
}
//=======================显示提示输入=========================
void DisplayChar(void)
{
	unsigned char i;
	if(pass==1)
	{

		write_1602com(er);				   //在二行开始显示
		for(i=0;i<16;i++)
		{
			write_1602dat(LockOpen[i]);	   //显示open 开锁成功
		}
	}
	else
	{
		if(N==0)
		{

			write_1602com(er);
			for(i=0;i<16;i++)
			{
				write_1602dat(Error1[i]);	//显示错误
			}
		}
		else
		{

			write_1602com(er);
			for(i=0;i<16;i++)
			{
				write_1602dat(start_line[i]);//显示开始输入	
			}
		}
	}
}

//========================重置密码==================================================
//==================================================================================
void ResetPassword(void)
{
	unsigned char i;	
	unsigned char j;
	if(pass==0)
	{
		pass=0;			   
		DisplayChar();	   //显示错误
		ThreeAlam();	   //没开锁时按下重置密码报警3声
	}
	else				   //开锁状态下才能进行密码重置程序
	{
    	if(ReInputEn==1)   //开锁状态下,ReInputEn置1,重置密码允许
		{
			if(N==6)	   //输入6位密码
			{
				ReInputCont++;			//密码次数计数	
				if(ReInputCont==2)		//输入两次密码
				{
					for(i=0;i<6;)
					{
						if(TempPassword[i]==InputData[i])	//将两次输入的新密码作对比
							i++;
						else								//如果两次的密码不同
						{

							write_1602com(er);
							for(j=0;j<16;j++)
							{
								write_1602dat(Error1[j]);	//显示错误Error
							}
							ThreeAlam();			//错误提示	
							pass=0;					//关锁
							ReInputEn=0;			//关闭重置功能,
							ReInputCont=0;
							DisplayChar();
							break;
						}
					} 
					if(i==6)
					{

						write_1602com(er);
						for(j=0;j<16;j++)
						{
							write_1602dat(ResetOK[j]);	  //密码修改成功,显示
						}

						TwoAlam();				//操作成功提示
					 	WrToROM(TempPassword,0,6);		//将新密码写入24C02存储
						ReInputEn=0;
					}
					ReInputCont=0;
					CorrectCont=0;
				}
				else					  //输入一次密码时
				{
					OneAlam();

					write_1602com(er);
					for(j=0;j<16;j++)
					{
						write_1602dat(again[j]);			//显示再输入一次
					}					
					for(i=0;i<6;i++)
					{
						TempPassword[i]=InputData[i];		//将第一次输入的数据暂存起来						
					}
				}

			N=0;						//输入数据位数计数器清零
		   }
	    }
	}
}
//=======================输入密码错误超过三过,报警并锁死键盘======================
void Alam_KeyUnable(void)
{
	P1=0x00;
	{
		ALAM=~ALAM;				 //蜂鸣器一直闪烁鸣响
		Delay5Ms();
	}
}
//=======================取消所有操作============================================
void Cancel(void)
{	
	unsigned char i;
	unsigned char j;
	//DisplayListChar(0, 1, start_line); 
	write_1602com(er);
	for(j=0;j<16;j++)
	{
		write_1602dat(start_line[j]);	  //显示开机输入密码界面
	}
	TwoAlam();				//提示音
	for(i=0;i<6;i++)
	{
		InputData[i]=0;		//将输入密码清零
	}
	KEY=1;					//关闭锁
	ALAM=1;					//报警关
	pass=0;					//密码正确标志清零
	ReInputEn=0;			//重置输入充许标志清零
	ErrorCont=0;			//密码错误输入次数清零
	CorrectCont=0;			//密码正确输入次数清零
	ReInputCont=0;			//重置密码输入次数清零 
	s3_keydown=0;
	key_disable=0;			//锁定键盘标志清零
	N=0;					//输入位数计数器清零
}

//==========================确认键,并通过相应标志位执行相应功能===============================
void Ensure(void)
{	
	unsigned char i,j;
	RdFromROM(CurrentPassword,0,6); 					//从24C02里读出存储密码
    if(N==6)
	{
	    if(ReInputEn==0)							//重置密码功能未开启
		{
					
               if((InputData[0]==adminpassword[0])&&(InputData[1]==adminpassword[1])&&(InputData[2]==adminpassword[2])&&(InputData[3]==adminpassword[3])&&(InputData[4]==adminpassword[4])&&(InputData[5]==adminpassword[5]))
		  	 	{
					WrToROM(initpassword,0,6); 				//强制将初始密码写入24C02存储
					write_1602com(er);
					for(j=0;j<16;j++)
					{
						write_1602dat(initword[j]);				//显示初始化密码
					}
					TwoAlam();									//成功提示音
					Delay400Ms();								//延时400ms
					TwoAlam();									//成功提示音
					N=0;										//输入位数计数器清零
					//TR0=1;										
				}

			else if((InputData[0]==adminpassword1[0])&&(InputData[1]==adminpassword1[1])&&(InputData[2]==adminpassword1[2])&&(InputData[3]==adminpassword1[3])&&(InputData[4]==adminpassword1[4])&&(InputData[5]==adminpassword1[5]))
		  	 	{

					TwoAlam();									//成功提示音
					Delay400Ms();								//延时400ms
					TwoAlam();									//成功提示音
					N=0;										//输入位数计数器清零
					chushihua=1;										
				}


			else if((CurrentPassword[0]==InputData[0])&&(CurrentPassword[1]==InputData[1])&&(CurrentPassword[2]==InputData[2])&&(CurrentPassword[3]==InputData[3])&&(CurrentPassword[4]==InputData[4])&&(CurrentPassword[5]==InputData[5]))	//判断输入密码和24c02中的密码是否相同
				{
					CorrectCont++;	
					if(CorrectCont==1)				//正确输入计数,当只有一次正确输入时,开锁
					{
						//DisplayListChar(0,1,LockOpen);
						write_1602com(er);
						for(j=0;j<16;j++)
						{
							write_1602dat(LockOpen[j]);		  //显示open开锁画面
						}
						TwoAlam();			//操作成功提示音
						KEY=0;											//开锁
						pass=1;											//置正确标志位
						TR0=1;											//开启定时
						for(j=0;j<6;j++)								//将输入清除
						{
							InputData[i]=0;								//开锁后将输入位清零
						}
					}	
					else if(CorrectCont==2)												//当两次正确输入时,开启重置密码功能
					{
						write_1602com(er);
						for(j=0;j<16;j++)
						{
							write_1602dat(SetNew[j]);					//显示重置密码界面
						}
						TR0=0;
						TwoAlam();									    //操作成功提示
						ReInputEn=1;									//允许重置密码输入
						CorrectCont=0;									//正确计数器清零
					}												//相同一位 i就+1
				}
				else 									//如果有密码不同
				{										
					write_1602com(er);
					for(i=0;i<16;i++)
					{
						write_1602dat(Error1[i]);	
					}
					ThreeAlam();
					ErrorCont++;						//错误次数++
					if(ErrorCont==3)			//错误输入计数达三次时,报警并锁定键盘
					{
						write_1602com(er);
						for(i=0;i<16;i++)
						{
							write_1602dat(Error1[i]);	
						}
						TR0=1;				//开启定时
						key_disable=1;			//锁定键盘
						pass=0;					//pass位清零
						Alam_KeyUnable();
		
					}

				}

	
	


		}

		else											//当已经开启重置密码功能时,而按下开锁键,
		{

			write_1602com(er);
			for(j=0;j<16;j++)
			{
				write_1602dat(Er_try[j]);			  //错误,请重新输入
			}
			ThreeAlam();							  //错误提示音
		}
	}

	else				   //密码没有输入到6位时,按下确认键时
	{
		
		write_1602com(er);
		for(j=0;j<16;j++)
		{
			write_1602dat(Error1[j]);		 //显示错误
		}

 		ThreeAlam();										//错误提示音
		pass=0;	
	}
	
	N=0;													//将输入数据计数器清零,为下一次输入作准备
operation=1;
}
void display_id( unsigned char xdata * SrcBuf )
{

	char xdata *pDisplayChar;
	unsigned char xdata Tmp, i;

	pDisplayChar = DisplayBuf;

	for( i = 0; i < 4; i++ )
	{
		Tmp = ( ( *SrcBuf ) << 4 ) & 0x0F;	
		if( ( Tmp >=0 ) && ( Tmp <= 9 )	)
		{
			*pDisplayChar ++ = '0' + Tmp;	
		}
		else
		{
			*pDisplayChar ++ = 'A' + Tmp - 10;
		}

		Tmp = ( *SrcBuf ) & 0x0F;	
		if( ( Tmp >=0 ) && ( Tmp <= 9 )	)
		{
			*pDisplayChar ++ = '0' + Tmp;	
		}
		else
		{
			*pDisplayChar ++ = 'A' + Tmp - 10;
		}

		SrcBuf ++;
	}
	*pDisplayChar ++ = '\0';

//	DisplayListChar( 0, 4, DisplayBuf );   
	if(chushihua==1)
	{
    write_1602com(0xc0);
	write_1602dat('I');
	write_1602dat('D');
	write_1602dat(current_id+0x30);
	write_1602dat(':');
	write_1602dat(DisplayBuf[0]);
	write_1602dat(DisplayBuf[1]);
	write_1602dat(DisplayBuf[2]);
	write_1602dat(DisplayBuf[3]);
	write_1602dat(DisplayBuf[4]);
	write_1602dat(DisplayBuf[5]);
	write_1602dat(DisplayBuf[6]);
	write_1602dat(DisplayBuf[7]);
	write_1602dat(' ');
	write_1602dat(' ');write_1602dat(' ');write_1602dat(' ');write_1602dat(' ');
	}
}
void display_no_id()
{
 
  write_1602com(0xc0);
  	write_1602dat('I');
	write_1602dat('D');
	write_1602dat(current_id+0x30);
	write_1602dat(':');
 	write_1602dat(DisplayBuf_c[0]);
	write_1602dat(DisplayBuf_c[1]);
	write_1602dat(DisplayBuf_c[2]);
	write_1602dat(DisplayBuf_c[3]);
	write_1602dat(DisplayBuf_c[4]);
	write_1602dat(DisplayBuf_c[5]);
	write_1602dat(DisplayBuf_c[6]);
	write_1602dat(DisplayBuf_c[7]);
		write_1602dat(' ');
	write_1602dat(' ');write_1602dat(' ');write_1602dat(' ');write_1602dat(' ');
}
void ctrl( void )
{
    uchar j,i;
	if( PcdRequest( PICC_REQIDL, &CardRevBuf[0] ) != MI_OK )//寻天线区内未进入休眠状态的卡,返回卡片类型 2字节	
	{
		if( PcdRequest( PICC_REQIDL, &CardRevBuf[0] ) != MI_OK )//寻天线区内未进入休眠状态的卡,返回卡片类型 2字节	
		{
		 if(chushihua==1)
		 {
		 read_eeprom_j(current_id);
 		 display_no_id();
		 }
			return;
		}	
	}

	if( PcdAnticoll( &CardRevBuf[2] ) != MI_OK ) //防冲撞,返回卡的序列号 4字节 
	{
	if(chushihua==1)
	{
	read_eeprom_j(current_id);
 	display_no_id();
	}
		return;	
	}

	if( PcdSelect( &CardRevBuf[2] ) != MI_OK )//选卡
	{
	if(chushihua==1)
	{
	 read_eeprom_j(current_id);
 	  display_no_id();
	 }
		return;
	}

	display_id( &CardRevBuf[2] );
	if(CorrectCont==0&&pass==0)
	{
	  for(j=0;j<6;j++)
	  {
	  read_eeprom_j(j);
	   if(DisplayBuf[0]==DisplayBuf_c[0]&&DisplayBuf[1]==DisplayBuf_c[1]&&DisplayBuf[2]==DisplayBuf_c[2]&&DisplayBuf[3]==DisplayBuf_c[3]&&DisplayBuf[4]==DisplayBuf_c[4]&&DisplayBuf[5]==DisplayBuf_c[5])
	   {
	  
		  CorrectCont=1;
		  write_1602com(er);
			for(j=0;j<16;j++)
			{
				write_1602dat(LockOpen[j]);	
			}
			TwoAlam();			//操作成功提示音
			ErrorCont=0;
			KEY=0;											//开锁
			pass=1;											//置正确标志位
			TR0=1;											//开启定时
			for(j=0;j<6;j++)								//将输入清除
			{
				InputData[i]=0;
			}
		return;
	   }
	  }
	}
}

//==============================主函数===============================
void main(void)
{
 	unsigned char KEY,NUM;
	unsigned char i,j;
 	P1=0xFF; 				   //P1口复位
	TMOD=0x11;				   //定义工作方式
 	TL0=0xB0;
 	TH0=0x3C;				   //定时器赋初值
 	EA=1;					   //打开中断总开关
 	ET0=1;					   //打开中断允许开关
 	TR0=0;					   //打开定时器开关
 	Delay400Ms(); 	//启动等待,等LCM讲入工作状态
 	lcd_init(); 	//LCD初始化
	Init_DS1302();
	init_rc522();
	write_1602com(yi);//日历显示固定符号从第一行第0个位置之后开始显示
	for(i=0;i<15;i++)
	{
		write_1602dat(table[i]);//向液晶屏写开机画面
	}
	write_1602com(er);
	for(i=0;i<16;i++)
	{
		write_1602dat(start_line[i]);//写输入密码等待界面
	}
	write_1602com(er+9);	//设置光标位置
//	write_1602com(0x0f);	//设置光标为闪烁
 	Delay5Ms(); //延时片刻(可不要)

 	N=0;														//初始化数据输入位数
 	while(1)		 //进入循环
 	{
//     keyscan();
	 if(flag==0)
	 {
	    ctime.second=DS1302Read(READ_SECOND);
  	    ctime.minute=DS1302Read(READ_MINUTE);
  	    ctime.hour=DS1302Read(READ_HOUR);
	    write_sfm(10,ctime.second);  //送液晶显示
	    write_sfm(7,ctime.minute);
	    write_sfm(4,ctime.hour);
	 }
		ctrl();
		if(key_disable==1)						//锁定键盘标志为1时
			Alam_KeyUnable();					//报警键盘锁
		else
			ALAM=1;								//关报警

		KEY=keynum();							//读按键的位置码
		if(KEY!=0)								//当有按键按下时
		{	
			if(key_disable==1)					//锁定键盘标志为1时
			{
				second=0;						//秒清零
			}
			else								//没有锁定键盘时
			{
				NUM=coding(KEY);				//根据按键的位置将其编码,编码值赋值给NUM
				{
					switch(NUM)					//判断按键值
					{
						case ('A'):if(chushihua==1)
						            {
						             current_id++;
						                if(current_id>5)
									      current_id=0; 
									 }
									 else
									 {
									 	  s1num++;
	                                      flag=1;
									  	  switch(s1num)
											  {
											     case 1:
												       TR1=0;
													   write_1602com(yi+11);
													   write_1602com(0x0f);
													   DS1302Write(0x8e,0x00);
													   DS1302Write(WRITE_SECOND,0x80);
													   DS1302Write(0x8e,0x80);
													   break;
												 case 2:
												       write_1602com(0x80+8);
													   break;
												 case 3:
												       write_1602com(0x80+5);
													   break;
												 case 4:
												       s1num=0;
											  		   write_1602com(0x0c);
													   flag=0;
													   DS1302Write(0x8e,0x00);
													   DS1302Write(WRITE_SECOND,0x00);
													   DS1302Write(0x8e,0x80);
													   break;
											  
											  }
									 }
								 					break;
						case ('B'):		if(chushihua==1)   
						                  write_eeprom_jj(current_id);
										else if(s1num!=0)
												{
												  		 switch(s1num)
															 {
															   case 1:
															          second1=ctime.second/16*10+ctime.second%16;
																	  second1++;
																	  if(second1==60)
																	     second1=0;
																	  ctime.second=second1/10*16+second1%10;
																	  DS1302Write(0x8e,0x00);
																	  DS1302Write(WRITE_SECOND,ctime.second);
																	  DS1302Write(0x8e,0x80);
																	  write_sfm(10,ctime.second);
																	  write_1602com(0x80+10);
																	  break;
															   case 2:
															          minute1=ctime.minute/16*10+ctime.minute%16;
																	  minute1++;
																	  if(minute1==60)
																	     minute1=0;
																	  ctime.minute=minute1/10*16+minute1%10;
																	  DS1302Write(0x8e,0x00);
																	  DS1302Write(WRITE_MINUTE,ctime.minute);
																	  DS1302Write(0x8e,0x80);
																	  write_sfm(7,ctime.minute);
																	  write_1602com(0x80+7);
																	  break;
															   case 3:
															          hour1=ctime.hour/16*10+ctime.hour%16;
																	  hour1++;
																	  if(hour1==24)
																	     hour1=0;
																	  ctime.hour=hour1/10*16+hour1%10;
																	  DS1302Write(0x8e,0x00);
																	  DS1302Write(WRITE_HOUR,ctime.hour);
																	  DS1302Write(0x8e,0x80);
																	  write_sfm(4,ctime.hour);
																	  write_1602com(0x80+4);
																	  break;
															 
															 }
												}  
										   	    				break;
						case ('C'):if(chushihua==1)
						              write_eeprom_j(current_id);
								   else if(s1num!=0)
								   {
								   		 switch(s1num)
											 {
											   case 1:
											          second1=ctime.second/16*10+ctime.second%16;
													  second1--;
													  if(second1==-1)
													     second1=59;
													  ctime.second=second1/10*16+second1%10;
													  DS1302Write(0x8e,0x00);
													  DS1302Write(WRITE_SECOND,ctime.second);
													  DS1302Write(0x8e,0x80);
													  write_sfm(10,ctime.second);
													  write_1602com(0x80+10);
													  break;
											   case 2:
											          minute1=ctime.minute/16*10+ctime.minute%16;
													  minute1--;
													  if(minute1==-1)
													     minute1=59;
													  ctime.minute=minute1/10*16+minute1%10;
													  DS1302Write(0x8e,0x00);
													  DS1302Write(WRITE_MINUTE,ctime.minute);
													  DS1302Write(0x8e,0x80);
													  write_sfm(7,ctime.minute);
													  write_1602com(0x80+7);
													  break;
											   case 3:
											          hour1=ctime.hour/16*10+ctime.hour%16;
													  hour1--;
													  if(hour1==-1)
													     hour1=23;
													  ctime.hour=hour1/10*16+hour1%10;
													  DS1302Write(0x8e,0x00);
													  DS1302Write(WRITE_HOUR,ctime.hour);
													  DS1302Write(0x8e,0x80);
													  write_sfm(4,ctime.hour);
													  write_1602com(0x80+4);
													  break;
											 
											 }
								   
								   }	break;
						case ('D'):chushihua=0; ResetPassword();		break;      //重新设置密码
						case ('*'): chushihua=0;Cancel();				break;      //取消当前输入
						case ('#'): chushihua=0;Ensure(); 				break;   	//确认键,
						default: 										//如果不是功能键按下时,就是数字键按下
						{	
							//DisplayListChar(0,1,Input);
							if(N<6)                   					//当输入的密码少于6位时,接受输入并保存,大于6位时则无效。
							{ 
								write_1602com(er);
								for(i=0;i<16;i++)
								{
									write_1602dat(Input[i]);				//显示输入画面
								} 
								OneAlam();								//按键提示音	
						 		for(j=0;j<=N;j++)
								{
									write_1602com(er+6+j);				//显示位数随输入增加而增加
									write_1602dat('*');					//但不显示实际数字,用*代替
								}
								InputData[N]=NUM;						//将数字键的码赋值给InputData[]数组暂存
								N++;									//密码位数加
							}
							else										//输入数据位数大于6后,忽略输入
							{
								N=6;									//密码输入大于6位时,不接受输入
						 		break;
							}
						}
					}
				}
			}
	 	} 
	}
}

//*********************************中断服务函数**************************************
void  time0_int(void) interrupt 1 		   //定时器T0
{
 	TL0=0xB0;
 	TH0=0x3C;		  //定时器重新赋初值
 	//TR0=1;
 	countt0++;			   //计时变量加,加1次时50ms
  	if(countt0==20)		   //加到20次就是1s
   	{
		countt0=0;		   //变量清零
		second++;		   //秒加
		if(pass==1)		   //开锁状态时
		{
			if(second==3)			//秒加到1s时
			{
				KEY=1;
				TR0=0;				//关定时器
				Cancel();
				TL0=0xB0;
 				TH0=0x3C;			//再次赋初值
				second=0;			//秒清零
			}
		}
		else						//不在开锁状态时
		{
			if(second==3)			//秒加到3时
			{
				TR0=0;				//关闭定时器
				second=0;			//秒清零
				key_disable=0;		//锁定键盘清零
				s3_keydown=0;	
				TL0=0xB0;
				TH0=0x3C;			//重新赋初值
			}
			else
			    TR0=1;				//打开定时器
		}
			
   	}
}

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

0009基于51单片机智能门禁系统设计 的相关文章

随机推荐