B48 - Design of student management access control system based on 51 single-chip microcomputer

Task

Design Requirements and Parameters
1. Design requirements:
(1) Ability to identify students based on RFID and fingerprints (successful identification will display the department, class, major, student number, etc.); (2) Ability to use matrix
buttons to input administrator Add new fingerprint authentication information after the password.
(3) It has the functions of student status inquiry: attendance inquiry, campus entry and exit records, conduct records and safety tracking and other functions.
(4) The information can be queried by keys and displayed on the LCD.
2. Design parameters:
(1) RFID: working frequency: 13.56MHz; communication rate: 106Kbps; reading and writing distance: ≤10cm; data transmission time is less than 200ms; (2) fingerprint
module: working voltage: 3.3V; resolution: 500dpi ;Entry time: 0.1S; Number of fingerprints that can be entered: 300;
(3) The system power supply is 5V, with voltage conversion function, and provides a 3.3V power output interface.
(4) Main control single-chip microcomputer: The working voltage is 5V, and the new 8051 single-chip microcomputer of STC (Hongjing) company is used.

Design architecture:
The design of this system includes both software and hardware design of the R&D system. The system hardware mainly includes: STC8A single-chip microcomputer, radio frequency RFID identification module, fingerprint identification module, film matrix key module, LCD liquid crystal display module, clock module, power supply module and alarm module, through the learning design and connection of each module, the final development Out of the total hardware circuit system. The software design is to first encode and match the student information for each registered RFID card. When an RFID card is close to the RFID identification module of the system hardware, the system will read the ID card number and compare the transmitted ID serial number with the original The registered and stored ID serial numbers are compared to check whether the card number is correct. If the ID information matches successfully, the LCD display will display the student information corresponding to the ID, and the green light will also light up at the same time, and the access control will be opened. But once the ID information matches If it fails, the LED will turn red, and the buzzer will also emit an error alarm sound. If the recognition error reaches 3 consecutive times, the system will be locked for 1 minute (for the sake of demonstration, this system is temporarily set to 15S ), the buzzer keeps beeping and the red light is always on during the locking period, which is used to warn the person with the wrong ID and invalid ID to avoid the person from breaking in. Fingerprint identification, prompts, and alarm lights are basically consistent with the RFID process.
insert image description here

in kind

Whole object

insert image description here

System power-on interface logic

The system has multiple interface logics, including normal detection interface, administrator identity login interface, fingerprint adding interface, fingerprint deleting interface, historical information viewing interface, etc. The interface setting of the system has a certain degree of intuition and promptness, which can facilitate users to quickly know what the current interface is for and how to operate it according to the prompts. After the system is powered on, it will first display the designer’s information. After a delay of 3 seconds, the fingerprint module will be detected. When the fingerprint module is detected, it will enter the fingerprint module detection. When the fingerprint module is detected to be normal, it will display the loading success and enter the EEPROM detection read-write interface, because this system needs to store the access control information of the students, so the judgment of the old and new MCU is carried out. If the system is powered on for the first time, that is, the MCU is new, format the EEPROM and set the flag to write in for convenience. The next time it is determined that the microcontroller has been stored. In order to be able to read out the stored student information when the power is turned on next time. After the interface is displayed for 2 seconds, it will enter the normal detection interface.
insert image description here
insert image description here
insert image description here

System management interface logic

In the normal detection interface of this system, you can enter the background management interface through the A key of the film matrix keyboard. In this interface, you need to enter the administrator password. The default password input is * to hide, or you can choose to press the * key of the film matrix keyboard Choose clear code. After entering the administrator password correctly, you can enter the background to add and delete fingerprints, and you can also enter the query interface to enter historical data query.

insert image description here
insert image description here

Fingerprint function interface logic

Add fingerprint:

After the system enters the password successfully and enters the background of the management interface, you can choose to press the A key of the membrane button to enter the fingerprint update interface of the system. In this interface, you can choose to add fingerprints, delete fingerprints, search for fingerprints, and return to the upper-level options. This time, press the A key of the membrane button to enter the fingerprint selection, press the corresponding button of the membrane button to change the ID number, confirm, return and other operations through the screen prompts, and enter the fingerprint adding interface after confirming the ID number. The input of the finger is stored after two collections of finger images. The functional interface design of adding fingerprints is shown in Figure 5.6, and the physical debugging is shown in Figure 5.7.
insert image description here
insert image description here

delete fingerprint

The system enters the fingerprint deletion interface through the selection of the button. Under this function, you can choose to delete all the fingerprint information in the storage by confirming. After the deletion is completed, it will automatically return to the general interface of the fingerprint function. The interface and physical debugging of this design are shown in Figure 5.8.
insert image description here

Search fingerprint interface

After the system has added the fingerprint, it can be tested by searching the fingerprint function to ensure that the fingerprint is added successfully. When searching for the fingerprint, if the search is successful, the fingerprint ID will be returned, and the corresponding prompt will be displayed on the LCD for identification. Figure 5.9 shows the fingerprint search interface design, and Figure 5.10 shows the physical debugging interface.
insert image description here
insert image description here
insert image description here

Historical data query interface logic

This system can query the historical access control records. In the management interface, press the B key to enter the query record interface. In this interface, press the B and C keys to change the person to be checked, and press the D key to enter the corresponding person's query interface, such as checking the entry and exit records of Li Si. In the query interface, use the B and C keys to perform the page-turning operation of the query records. A total of 9 pages of historical access information are recorded, and each page is recorded twice. The interface design of this system is shown in Figure 5.11, and the actual debugging effect is shown in Figure 5.12.
insert image description here
insert image description here

Fingerprint and RFID access control system unlock test

Figure 5.13 shows the normal detection interface. In this interface, the access control system can be unlocked by fingerprint or RFID. If the fingerprint detection ID matches the student information successfully or the RFID reads the student ID card and the card exists in the database, the system will The access control will be unlocked, and the LCD screen will display the information of the unlocking student. After 5 seconds, the system LCD screen will return to the normal detection interface information display. If the unlocking fails, the system will prompt the corresponding information. If the unlocking fails more than 3 times, the system will enter the long alarm interface. As shown in Figure 5.14, the fingerprint unlocking is successful, as shown in Figure 5.15, the RFID unlocking is successful, as shown in Figure 5.16, the fingerprint unlocking fails, as shown in Figure 5.17, the RFID unlocking fails, and as Figure 5.18, the system is locked after multiple unlocking failures.
insert image description here
insert image description here
insert image description here
insert image description here
insert image description here
insert image description here

The design of each interface of this system is relatively complicated. This system needs to design multiple interfaces, and it is necessary to jump between each interface, and each key of the matrix button has different functions in each interface, so this time Emphatically introduces the design, division and jumping of the interface in the debugging process of the real object.

schematic diagram

insert image description here

resource usage

insert image description here

source program

System Design Process

insert image description here

main function

/*******************************************************************************

\* 文件名称:基于51单片机的学生管理门禁系统设计

\* 实验目的:1.

\* 2.

\* 程序说明:完整程序Q:277 227 2579;@: itworkstation@ hotmail.com

\* 日期版本:本项目分享关键细节,熟悉使用单片机的可做参考代码。完整讲解+源代码工程可联系获取,可定制。

*******************************************************************************/
#include "config.h"

#include "led.h"            //调用LED灯头文件
#include "beep.h"
#include "relay.h"
#include "12864_serial.h"  
#include "keyBoard.h"
#include "RC522.h"
#include "Uart4_Timer4.h"
#include "FPM10A.h"
#include "ds1302.h"
#include "eeprom.h"
#include "Uart1_Timer2.h"
/*************************************************************************
                               主函数
**************************************************************************/
#define DISMAXBUFF 30
char disBuff[DISMAXBUFF];

#define EEPROM_STORE 0x0400   //STC下载器设置EEPROM最少为2K !!!!! 注意的是:新程序下载后EEPROM是被下载器清空了的····下载器选项:下次下载用户程序时擦除用户EEPEOM区

unsigned char xdata g_ucTempbuf[20];
uchar xdata Xuhao_Panduan[4];
uchar code Xuhao_SQL[]={
    
    
0x14,0X59,0X0A,0X6F,	// 蓝色卡1
0xDB,0X67,0X89,0X1B,	// 蓝色卡2
0XF3,0XEA,0X67,0X00,   // 白色卡1
//0XC3,0XE0,0X19,0X19,   // 白色卡2	
};
#define NONEClient 0
#define NONECARD   0xff
bit flag_rcReady= FALSE;
uchar Client=NONEClient;	
uchar Xuhao_Check(void);
uchar rc522Read(void);

void Timer0Init(void);		//5毫秒@22.1184MHz

uchar date1302[]={
    
    22,4,19,17,26,30};  //初始化时间

uint IdNumber=NONESTORE;   //指纹ID

typedef struct{
    
    
	uchar dateStore_Stu[18][6];
}STRUCTSTU;
STRUCTSTU stuTimStore[4];
char page_count=0;

char code StuName[4][15]={
    
    
"  张三",
"  李四",
"  王五",
"  赵六",	
};
char code StuNumber[4][15]={
    
    
"201802010001",
"201802010002",
"201802010003",
"201802010004",	
};
typedef enum{
    
    
	NormalMenu,
	InputMenu,
	ChooseMenu,
    ZhiWenMenu,
	ViewHistoryMenu,
	StuHistoryMenu,
	UnlockErrorMenu,
}ENUMDISMENU;
ENUMDISMENU disMenu = NormalMenu;
char ViewId =0;
char ViewPage=0;

void KeyPress_InputMenu(uchar keycode);
const unsigned char muntochar[] = {
    
    '0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};//液晶数字转字符
unsigned char in_password_mun = 255;		//声明1个变量,用来记录密码输入位数.
unsigned char password_bj[6] = {
    
    20,20,20,20,20,20};	//密码比较,密码输入存储
unsigned char code password[6] = {
    
    1,2,3,4,5,6};	//定义初始密码.
bit password_dis = TRUE;					//声明1个变量,用来记录是显示密码还是隐藏密码. true:隐藏状态,显示*
bit password_ok_open = FALSE;				//定义1个变量,用来记录密码输入正确标志,0表示不成功.1表示成功.
unsigned char password_err_mun = 0;	//声明1个变量用来记录密码输入错误次数.
#define TIMEERROR 15
int TimeErrorInput = TIMEERROR;
bit flag_inputError = 0;
bit flagTimer0_1S= FALSE;
uint timer0Count=0;
bit flag_ReceiveCard = FALSE;
int unlockErrorTimes=0,errorTimesCount = 15;
#define UNLOCKERRORTIMES_MAX  3

extern uchar Flag_Receive_Ok;
extern uchar  Buffer_UART1[Buffer_UART1Length];
void main (void)
{
    
    	
	uchar keyNum = KEY_NoTOUCH;	
	uchar is_FingerTouched=0;
	uchar i=0,j=0,k=0;
	uint p=0;
	
	LED_Init();		//LED灯函数初始化
	LED_R = LED_STATE(OFF);
	LED_G = LED_STATE(OFF);	
	
	LCD_Init();
	
	UART4_Init();
	delay_ms(1000);
	Device_Check();		   	//校对指纹模块是否接入正确,液晶做出相应的提示
	
	write_string(3,0,"    存储模块    ");
	write_string(4,0,"正在加载        ");	
	SendCMD(0x98+4);
	for(i=0;i<8;i++)						   //进度条式更新,看起来美观
	{
    
    
		SendDat(42);	                       //42对应ASIC码的 *
		delay_ms(300);						           //控制进度条速度
	}	
	for(k=0;k<4;k++)
	{
    
    
		for(i=0;i<18;i++)  //清空数组
		{
    
    
			for(j=0;j<6;j++)
			{
    
    
				stuTimStore[k].dateStore_Stu[i][j]=0;
			}
		}
	}	
		// 设计标定初值,用于新旧芯片判断  --------------------------------  
	if(IapRead(EEROM_USEADDR) == EEROM_CHECK_VALUE)  // 不是新单片机,内部存有数据
	{
    
    
		EA = 0;		//禁止中断
		p = 0;
		for(k=0;k<4;k++)
		{
    
    
			for(i=0;i<18;i++)  //清空数组
			{
    
    
				for(j=0;j<6;j++)
				{
    
    
					stuTimStore[k].dateStore_Stu[i][j] = IapRead(EEPROM_STORE+p);				
					p++;
					delay_ms(5);  //还是需要延时的!
				}
			}
		}	
		EA = 1;		//重新允许中断
		LED_G = LED_STATE(ON);
		write_string(4,0,"    EEPROM读出!");
	}
	else
	{
    
    		
		EA = 0;		//禁止中断
		IapErase(EEROM_USEADDR); //擦除扇区内容才能重新写入
		IapProgram(EEROM_USEADDR, EEROM_CHECK_VALUE);
		
		IapErase(EEPROM_STORE); //擦除扇区内容才能重新写入
		p = 0;
		for(k=0;k<4;k++)
		{
    
    
			for(i=0;i<18;i++)  
			{
    
    
				for(j=0;j<6;j++)
				{
    
    
					IapProgram(EEPROM_STORE+p,stuTimStore[k].dateStore_Stu[i][j]);  //+p!!!必须为uint型,不然地址不符合!!
					p++;
					delay_ms(5);    //还是需要延时的!
				}
			}
		}	
		EA = 1;		//重新允许中断
		LED_R = LED_STATE(ON);
		write_string(4,0,"    EEPROM写入!");
	}
	delay_ms(2000);
	
	BEEP_Init();
	BEEP_Pin = BEEP_STATE(OFF);
	RELAY_Init();
	RELAY_Pin = RELAY_STATE(OFF);
	
	LED_R = LED_STATE(OFF);
	LED_G = LED_STATE(OFF);	
	
	Init_Ds1302(date1302);
	SendCMD(0x01);//清除显示
	write_string(1,0," 2022 - 04 - 19 ");
	write_string(2,0,"   12 : 02 : 30 ");
	write_string(3,0,"请使用RFID卡验证");
	write_string(4,0,"  或使用指纹验证");
	Read_NowTime_Ds1302(date1302);   // 时钟不能时刻读取,读取速度太快,影响其它进程,尤其是RFID!!!
	memset(disBuff,0,DISMAXBUFF);
	sprintf(disBuff," 20%02d - %02d - %02d ",(int)date1302[0],(int)date1302[1],(int)date1302[2]);   // 51程序中,格式化输入个数不能大于3,否则就出错,很无语!
	write_string(1,0,disBuff);	
	memset(disBuff,0,DISMAXBUFF);
	sprintf(disBuff,"   %02d : %02d : %02d ",(int)date1302[3],(int)date1302[4],(int)date1302[5]);
	write_string(2,0,disBuff);
	
	KEYBOARD_Init();
	
	InitRC522();
	
	Timer0Init();
	
	UART1_Init();
	UART1_SendStr("Please enter the changed time format, such as $20220423162537@\r\n");
	while (1)       //主循环
	{
    
    	
		if(disMenu == NormalMenu)
		{
    
    
			for(i = 0;i < 6;i++)								//循环6次
				password_bj[i] = 20;							//置密码比较数组里的数还原到20.
			in_password_mun = 255;								//记录密码输入位数还原.
			
			keyNum = Getkeyboard();		   //按键判断函数
			if(keyNum != KEY_NoTOUCH)
			{
    
    
				Buzz_Times(1);	
				if(keyNum==10)
				{
    
    
					disMenu = InputMenu;
					SendCMD(0x01);//清除显示				
					write_string(1,0,"请输入管理员密码");
					write_string(2,0,"密码:          ");				
					write_string(3,0,"*:明码    #:删除");
					write_string(4,0,"A:返回    D:确认");
					continue;  //从while重新开始,不再运行下面程序
				}
			}		
			if(flagTimer0_1S == TRUE)
			{
    
    
				flagTimer0_1S = FALSE;
				
				if(Flag_Receive_Ok==1)
				{
    
    
					Flag_Receive_Ok=0;
					date1302[0] = (Buffer_UART1[3]-0x30)*10+(Buffer_UART1[4]-0x30);//$20220423162537@  年月日时分秒
					date1302[1] = (Buffer_UART1[5]-0x30)*10+(Buffer_UART1[6]-0x30);
					date1302[2] = (Buffer_UART1[7]-0x30)*10+(Buffer_UART1[8]-0x30);
					date1302[3] = (Buffer_UART1[9]-0x30)*10+(Buffer_UART1[10]-0x30);
					date1302[4] = (Buffer_UART1[11]-0x30)*10+(Buffer_UART1[12]-0x30);
					date1302[5] = (Buffer_UART1[13]-0x30)*10+(Buffer_UART1[14]-0x30);
					Set_Ds1302(date1302);
					
					UART1_SendStr("Time changed successfully\r\n");
				}
				else if(Flag_Receive_Ok == 2)
				{
    
    
					Flag_Receive_Ok=0;
					UART1_SendStr("Time format setting error, such as $20220423162537@\r\n");
				}
				Read_NowTime_Ds1302(date1302);   // 时钟不能时刻读取,读取速度太快,影响其它进程,尤其是RFID!!!
				
				memset(disBuff,0,DISMAXBUFF);
				sprintf(disBuff," 20%02d - %02d - %02d ",(int)date1302[0],(int)date1302[1],(int)date1302[2]);   // 51程序中,格式化输入个数不能大于3,否则就出错,很无语!
				write_string(1,0,disBuff);	
				memset(disBuff,0,DISMAXBUFF);
				sprintf(disBuff,"   %02d : %02d : %02d ",(int)date1302[3],(int)date1302[4],(int)date1302[5]);
				write_string(2,0,disBuff);	
			}
						
			if(Finger_Touch)  //检测到有手指按下,也跳转到指纹检测
			{
    
    
				is_FingerTouched = FPM10A_Find_Fingerprint_Touch(&IdNumber);		
				if(is_FingerTouched == 1) //有指纹按下,则屏幕内容变化,需恢复屏幕信息
				{
    
    
					if(IdNumber != NONESTORE && IdNumber<4)  //0-3
					{
    
    
						unlockErrorTimes = 0; 
						
						LED_G = LED_STATE(ON);
						RELAY_Pin = RELAY_STATE(ON);	
						LED_R = LED_STATE(OFF);
						BEEP_Pin = BEEP_STATE(OFF);
												
						SendCMD(0x01);//清除显示					
						memset(disBuff,0,DISMAXBUFF);
						sprintf(disBuff,"姓名:    %s",StuName[IdNumber]);
						write_string(1,0,disBuff);	
						memset(disBuff,0,DISMAXBUFF);
						sprintf(disBuff,"学号%s",StuNumber[IdNumber]);
						write_string(2,0,disBuff);	
						write_string(3,0,"电气工程及自动化");
						write_string(4,0,"电气与电子工程系");
						for(i=17;i>0;i--)  //数组移动,记录时间数组内后移
						{
    
    
							for(j=0;j<6;j++)
							{
    
    
								stuTimStore[IdNumber].dateStore_Stu[i][j]=stuTimStore[IdNumber].dateStore_Stu[i-1][j];
							}
						}
						for(j=0;j<6;j++)  //数组0位置存储最近一次记录时间
						{
    
    
							stuTimStore[IdNumber].dateStore_Stu[0][j]=date1302[j];
						}
						
						EA = 0;		//禁止中断
						IapErase(EEPROM_STORE); //擦除扇区内容才能重新写入
						p = 0;
						for(k=0;k<4;k++)
						{
    
    
							for(i=0;i<18;i++)  
							{
    
    
								for(j=0;j<6;j++)
								{
    
    
									IapProgram(EEPROM_STORE+p,stuTimStore[k].dateStore_Stu[i][j]);
									p++;
//									write_string(4,0,"    EEPROM写入!");
									delay_ms(2);
								}
							}
						}
						EA = 1;		//重新允许中断								
					}
					else
					{
    
    
						LED_R = LED_STATE(ON);
						RELAY_Pin = RELAY_STATE(OFF);	
						LED_G = LED_STATE(OFF);
						SendCMD(0x01);//清除显示
						write_string(2,0,"  指纹验证失败!");
						write_string(3,0,"    请重新尝试!");	
						
						Buzz_Times(5);	
						unlockErrorTimes ++;
						if(unlockErrorTimes >= UNLOCKERRORTIMES_MAX) //错误次数达到n次
						{
    
    
							unlockErrorTimes = 0;
							BEEP_Pin = BEEP_STATE(ON);
							LED_R = LED_STATE(ON);
							LED_G = LED_STATE(OFF);
							RELAY_Pin = RELAY_STATE(OFF);	
							
							disMenu = UnlockErrorMenu;	
							SendCMD(0x01);//清除显示
							write_string(2,0,"验证失败错误次数");
							write_string(3,0,"过多!请等待15秒");
							
							timer0Count=0;
							TR0 = 1;
							continue;
						}
					}
					delay_ms(5000);
					RELAY_Pin = RELAY_STATE(OFF);
					LED_G = LED_STATE(OFF);
					LED_R = LED_STATE(OFF);
					BEEP_Pin = BEEP_STATE(OFF);
					SendCMD(0x01);//清除显示
					write_string(1,0," 2021 - 12 - 27 ");
					write_string(2,0,"   12 : 02 : 30 ");
					write_string(3,0,"请使用RFID卡验证");
					write_string(4,0,"  或使用指纹验证");
				}				
			}	
			Client = rc522Read();   //指纹读取最好在所有检测的最后。!
			if(flag_ReceiveCard ==  TRUE)
			{
    
    
				flag_ReceiveCard = FALSE;
				if(Client != NONEClient)
				{
    
    
					unlockErrorTimes = 0;
					
					SendCMD(0x01);//清除显示
					RELAY_Pin = RELAY_STATE(ON);	
					LED_R = LED_STATE(OFF);
					BEEP_Pin = BEEP_STATE(OFF);
					LED_G = LED_STATE(ON);
					
					memset(disBuff,0,DISMAXBUFF);
					sprintf(disBuff,"姓名:    %s",StuName[Client-1]);
					write_string(1,0,disBuff);	
					memset(disBuff,0,DISMAXBUFF);
					sprintf(disBuff,"学号%s",StuNumber[Client-1]);
					write_string(2,0,disBuff);	
					write_string(3,0,"电气工程及自动化");
					write_string(4,0,"电气与电子工程系");		

					for(i=17;i>0;i--)  //数组移动,记录时间数组内后移
					{
    
    
						for(j=0;j<6;j++)
						{
    
    
							stuTimStore[Client-1].dateStore_Stu[i][j]=stuTimStore[Client-1].dateStore_Stu[i-1][j];
						}
					}
					for(j=0;j<6;j++)  //数组0位置存储最近一次记录时间
					{
    
    
						stuTimStore[Client-1].dateStore_Stu[0][j]=date1302[j];
					}
					
					EA = 0;		//禁止中断
					IapErase(EEPROM_STORE); //擦除扇区内容才能重新写入
					p = 0;
					for(k=0;k<4;k++)
					{
    
    
						for(i=0;i<18;i++)  
						{
    
    
							for(j=0;j<6;j++)
							{
    
    
								IapProgram(EEPROM_STORE+p,stuTimStore[k].dateStore_Stu[i][j]);
								p++;
//									write_string(4,0,"    EEPROM写入!");
								delay_ms(5);
							}
						}
					}
					EA = 1;		//重新允许中断
				}
				else
				{
    
    
					LED_R = LED_STATE(ON);
					RELAY_Pin = RELAY_STATE(OFF);	
					LED_G = LED_STATE(OFF);
					SendCMD(0x01);//清除显示
					write_string(2,0,"  RFID验证失败!");
					write_string(3,0,"    请重新尝试!");
					
					Buzz_Times(5);
					
					unlockErrorTimes ++;
					if(unlockErrorTimes >= UNLOCKERRORTIMES_MAX) //错误次数达到n次
					{
    
    
						unlockErrorTimes = 0;
						BEEP_Pin = BEEP_STATE(ON);
						LED_R = LED_STATE(ON);
						LED_G = LED_STATE(OFF);
						RELAY_Pin = RELAY_STATE(OFF);
						
						disMenu = UnlockErrorMenu;	
						SendCMD(0x01);//清除显示
						write_string(2,0,"验证失败错误次数");
						write_string(3,0,"过多!请等待15秒");
						
						timer0Count=0;
						TR0 = 1;
						continue;
					}
				}
				delay_ms(5000);
				RELAY_Pin = RELAY_STATE(OFF);
				LED_G = LED_STATE(OFF);
				LED_R = LED_STATE(OFF);
				BEEP_Pin = BEEP_STATE(OFF);
				SendCMD(0x01);//清除显示
				write_string(1,0," 2021 - 12 - 27 ");
				write_string(2,0,"   12 : 02 : 30 ");
				write_string(3,0,"请使用RFID卡验证");
				write_string(4,0,"  或使用指纹验证");
			}
		}
		else if(disMenu == UnlockErrorMenu)
		{
    
    
			if(flagTimer0_1S == TRUE)
			{
    
    
				flagTimer0_1S = FALSE;  //errorTimesCount = 15;
				if(errorTimesCount >0)
				{
    
    
					errorTimesCount --;
					SendCMD(0x88+6);
					SendDat(0x30+errorTimesCount/10%10);
					SendDat(0x30+errorTimesCount%10);
				}
				else
				{
    
    
					errorTimesCount = 15;
					BEEP_Pin = BEEP_STATE(OFF);
					LED_R = LED_STATE(OFF);
					LED_G = LED_STATE(OFF);
					RELAY_Pin = RELAY_STATE(OFF);	
					
					disMenu = NormalMenu;
					SendCMD(0x01);//清除显示
					write_string(1,0," 2021 - 12 - 27 ");
					write_string(2,0,"   12 : 02 : 30 ");
					write_string(3,0,"请使用RFID卡验证");
					write_string(4,0,"  或使用指纹验证");
					continue;
				}
			}
		}
        else if(disMenu == InputMenu)
        {
    
    
            keyNum = Getkeyboard();		   //按键判断函数 
            if(keyNum != KEY_NoTOUCH)
            {
    
                   
			   Buzz_Times(1);	
               if(keyNum < 10)	//如果输入的键值是数字键
               {
    
    
                    in_password_mun++;										//每输入一位密码,位数自增1.255+1=0
                    if(in_password_mun == 6)								//密码输入位数控制在6位
                        in_password_mun = 5;
                    password_bj[in_password_mun] = keyNum;					//把键值存入密码比较数组
                    if(password_dis == FALSE)									//如果密码是显示的.输入密码显示
                    {
    
    
                        SendCMD(0x90+3);						//液晶AC控制到第2行的第3位置.											
                        for(i = 0;i < 6;i++)								//循环检查6位密码,并且显示在屏上
                        {
    
    
                            if(password_bj[i] != 20)						//如果不是原始数值,说明有新的密码
                                SendDat(muntochar[password_bj[i]]);	//把新的密码显示在屏上
                        }
                    }
                    if(password_dis == TRUE)									//如果密码是隐藏的.就显示*号
                    {
    
    
                        SendCMD(0x90+3);						//液晶AC控制到第2行的第3位置.									
                        for(i = 0;i < 6;i++)								//循环检查6位密码,并且显示在屏上
                        {
    
    
                            if(password_bj[i] != 20)						//如果不是原始数值,说明有新的密码
                                SendDat('*');						//把输入的密码以*号显示出来.
                        }
                    }
                }
				else if(keyNum == 10)
				{
    
    
					LED_R = LED_STATE(OFF);	
					LED_G = LED_STATE(OFF);
					disMenu = NormalMenu;
					SendCMD(0x01);//清除显示
					write_string(1,0," 2021 - 12 - 27 ");
					write_string(2,0,"   12 : 02 : 30 ");
					write_string(3,0,"请使用RFID卡验证");
					write_string(4,0,"  或使用指纹验证");
				}
                else
                {
    
    
                    KeyPress_InputMenu(keyNum);
                } 
				while(flag_inputError == TRUE) //输入错误次数过多,等待15S
				{
    
    
                    if(flagTimer0_1S == TRUE)
					{
    
    
                        flagTimer0_1S = FALSE;                       
                        memset(disBuff,0,DISMAXBUFF);
                        sprintf(disBuff,"密码:稍后重试%02d",TimeErrorInput);
                        write_string(2,0,disBuff);	
                        TimeErrorInput --;
                        if(TimeErrorInput < 0)
                        {
    
    
                            flag_inputError = FALSE;
							TimeErrorInput = TIMEERROR;
							write_string(2,0,"密码:          ");//清空显示
							SendCMD(0x90+3);						//液晶AC控制到第2行的第3位置.
                        }
                    }                 
				}
            }            
			if(password_ok_open == TRUE)
			{
    
    
                password_ok_open = FALSE;
				disMenu = ChooseMenu;
                SendCMD(0x01);//清除显示				
                write_string(1,0,"密码验证成功!  ");
                write_string(2,0,"A:指纹更新      ");				
                write_string(3,0,"B:查阅记录      ");
                write_string(4,0,"C:手动    #:返回");
                continue;  //从while重新开始,不再运行下面程序
			}
        }
        else if(disMenu == ChooseMenu)
        {
    
    
			for(i = 0;i < 6;i++)								//循环6次
				password_bj[i] = 20;							//置密码比较数组里的数还原到20.
			in_password_mun = 255;								//记录密码输入位数还原.
			
            keyNum = Getkeyboard();		   //按键判断函数 
            if(keyNum != KEY_NoTOUCH)
            {
    
    
				Buzz_Times(1);	
                if(keyNum == 10)   //A:指纹更新
                {
    
    
					disMenu = ZhiWenMenu;
                    SendCMD(0x01);//清除显示				
					write_string(1,0,"A:添加指纹      ");
					write_string(2,0,"B:删除指纹      ");
					write_string(3,0,"C:搜索指纹      ");
					write_string(4,0,"#:返回上级      ");
                    continue;  //从while重新开始,不再运行下面程序
                }
                else if(keyNum == 11)  //B:查阅历史
                {
    
    
					disMenu = ViewHistoryMenu;
                    SendCMD(0x01);//清除显示				
					write_string(1,0,"  进出记录查阅  ");
					write_string(2,0,"姓名:          ");
					write_string(3,0,"B:加        C:减");
					write_string(4,0,"#:返回    D:确定");
					continue;  //从while重新开始,不再运行下面程序
                }
                else if(keyNum == 12)  //C:手动
                {
    
    
                    /*---------功能(手动开启/关闭密码锁)-----------*/ 
                    if(RELAY_Pin == RELAY_STATE(ON))						//如果手动关闭锁按键被按下,并且密码锁是打开的.
                        RELAY_Pin = RELAY_STATE(OFF);										//密码锁关闭.
                    else    
                        RELAY_Pin = RELAY_STATE(ON);   
                } 
                else if(keyNum == 15)  //#:返回
                {
    
    
					disMenu = InputMenu;
					LED_G = LED_STATE(OFF);
                    SendCMD(0x01);//清除显示				
					write_string(1,0,"请输入管理员密码");
					write_string(2,0,"密码:          ");				
					write_string(3,0,"*:明码    #:删除");
					write_string(4,0,"A:返回    D:确认");
                    continue;  //从while重新开始,不再运行下面程序
                }
            }
        }
		else if(disMenu == ViewHistoryMenu)
		{
    
    
			keyNum = Getkeyboard();		   //按键判断函数 
            if(keyNum != KEY_NoTOUCH)
			{
    
    
				Buzz_Times(1);	
				if(keyNum == 11)  //加
				{
    
    
					if(ViewId<3)
					{
    
    
						ViewId++;
					}
					else
					{
    
    
						ViewId= 3;
					}
				}
				else if(keyNum == 12)  //减
				{
    
    
					if(ViewId>0)
					{
    
    
						ViewId--;
					}
					else
					{
    
    
						ViewId = 0;
					}
				}
				else if(keyNum == 15)  //#:返回
                {
    
    
					disMenu = ChooseMenu;
					SendCMD(0x01);//清除显示				
					write_string(1,0,"密码验证成功!  ");
					write_string(2,0,"A:指纹更新      ");				
					write_string(3,0,"B:查阅记录      ");
					write_string(4,0,"C:手动    #:返回");
					continue;  //从while重新开始,不再运行下面程序
                }
				else if(keyNum == 13)  //D:确定
                {
    
    
					disMenu = StuHistoryMenu;
					SendCMD(0x01);//清除显示				
					write_string(1,0,"姓名:          ");
					write_string(2,0,"学号            ");				
					write_string(3,0,"B:加        C:减");
					write_string(4,0,"#:返回     No: 0");
					ViewPage = 0;
					continue;  //从while重新开始,不再运行下面程序
                }
			}
			memset(disBuff,0,DISMAXBUFF);
			sprintf(disBuff,"姓名:    %s",StuName[ViewId]);   // char ViewId =0;
			write_string(2,0,disBuff);	
		}
		else if(disMenu == StuHistoryMenu)
		{
    
    
			switch(ViewPage)
			{
    
    
				case 0:
					memset(disBuff,0,DISMAXBUFF);
					sprintf(disBuff,"姓名:    %s",StuName[ViewId]);   // char ViewId =0;
					write_string(1,0,disBuff);	
					memset(disBuff,0,DISMAXBUFF);
					sprintf(disBuff,"学号%s",StuNumber[ViewId]);
					write_string(2,0,disBuff);				
				    write_string(3,0,"B:加        C:减");
					write_string(4,0,"#:返回      No:");
					SendCMD(0x98+6); //如:第四行第6列显示No:1
					SendDat('N');
					SendDat('o');
					SendDat(':');
					SendDat(ViewPage+0x30); 			
					break;
				case 1:			
					memset(disBuff,0,DISMAXBUFF);
					sprintf(disBuff," 20%02d - %02d - %02d ",(int)stuTimStore[ViewId].dateStore_Stu[page_count][0],(int)stuTimStore[ViewId].dateStore_Stu[page_count][1],(int)stuTimStore[ViewId].dateStore_Stu[page_count][2]);
					write_string(1,0,disBuff);	
					memset(disBuff,0,DISMAXBUFF);
					sprintf(disBuff,"%02d:%02d:%02d        ",(int)stuTimStore[ViewId].dateStore_Stu[page_count][3],(int)stuTimStore[ViewId].dateStore_Stu[page_count][4],(int)stuTimStore[ViewId].dateStore_Stu[page_count][5]);
					write_string(2,0,disBuff);	
					memset(disBuff,0,DISMAXBUFF);
					sprintf(disBuff," 20%02d - %02d - %02d ",(int)stuTimStore[ViewId].dateStore_Stu[page_count+1][0],(int)stuTimStore[ViewId].dateStore_Stu[page_count+1][1],(int)stuTimStore[ViewId].dateStore_Stu[page_count+1][2]);
					write_string(3,0,disBuff);	
					memset(disBuff,0,DISMAXBUFF);
					sprintf(disBuff,"%02d:%02d:%02d    ",(int)stuTimStore[ViewId].dateStore_Stu[page_count+1][3],(int)stuTimStore[ViewId].dateStore_Stu[page_count+1][4],(int)stuTimStore[ViewId].dateStore_Stu[page_count+1][5]);
					write_string(4,0,disBuff);	
					
					SendCMD(0x98+6); //如:第四行第6列显示No:1
					SendDat('N');
					SendDat('o');
					SendDat(':');
					SendDat(ViewPage+0x30); 				
					break;
				case 2:
					memset(disBuff,0,DISMAXBUFF);
					sprintf(disBuff," 20%02d - %02d - %02d ",(int)stuTimStore[ViewId].dateStore_Stu[page_count][0],(int)stuTimStore[ViewId].dateStore_Stu[page_count][1],(int)stuTimStore[ViewId].dateStore_Stu[page_count][2]);
					write_string(1,0,disBuff);	
					memset(disBuff,0,DISMAXBUFF);
					sprintf(disBuff,"%02d:%02d:%02d        ",(int)stuTimStore[ViewId].dateStore_Stu[page_count][3],(int)stuTimStore[ViewId].dateStore_Stu[page_count][4],(int)stuTimStore[ViewId].dateStore_Stu[page_count][5]);
					write_string(2,0,disBuff);	
					memset(disBuff,0,DISMAXBUFF);
					sprintf(disBuff," 20%02d - %02d - %02d ",(int)stuTimStore[ViewId].dateStore_Stu[page_count+1][0],(int)stuTimStore[ViewId].dateStore_Stu[page_count+1][1],(int)stuTimStore[ViewId].dateStore_Stu[page_count+1][2]);
					write_string(3,0,disBuff);	
					memset(disBuff,0,DISMAXBUFF);
					sprintf(disBuff,"%02d:%02d:%02d    ",(int)stuTimStore[ViewId].dateStore_Stu[page_count+1][3],(int)stuTimStore[ViewId].dateStore_Stu[page_count+1][4],(int)stuTimStore[ViewId].dateStore_Stu[page_count+1][5]);
					write_string(4,0,disBuff);	
					
					SendCMD(0x98+6); //如:第四行第6列显示No:1
					SendDat('N');
					SendDat('o');
					SendDat(':');
					SendDat(ViewPage+0x30); 				
					break;
				case 3:
					memset(disBuff,0,DISMAXBUFF);
					sprintf(disBuff," 20%02d - %02d - %02d ",(int)stuTimStore[ViewId].dateStore_Stu[page_count][0],(int)stuTimStore[ViewId].dateStore_Stu[page_count][1],(int)stuTimStore[ViewId].dateStore_Stu[page_count][2]);
					write_string(1,0,disBuff);	
					memset(disBuff,0,DISMAXBUFF);
					sprintf(disBuff,"%02d:%02d:%02d        ",(int)stuTimStore[ViewId].dateStore_Stu[page_count][3],(int)stuTimStore[ViewId].dateStore_Stu[page_count][4],(int)stuTimStore[ViewId].dateStore_Stu[page_count][5]);
					write_string(2,0,disBuff);	
					memset(disBuff,0,DISMAXBUFF);
					sprintf(disBuff," 20%02d - %02d - %02d ",(int)stuTimStore[ViewId].dateStore_Stu[page_count+1][0],(int)stuTimStore[ViewId].dateStore_Stu[page_count+1][1],(int)stuTimStore[ViewId].dateStore_Stu[page_count+1][2]);
					write_string(3,0,disBuff);	
					memset(disBuff,0,DISMAXBUFF);
					sprintf(disBuff,"%02d:%02d:%02d    ",(int)stuTimStore[ViewId].dateStore_Stu[page_count+1][3],(int)stuTimStore[ViewId].dateStore_Stu[page_count+1][4],(int)stuTimStore[ViewId].dateStore_Stu[page_count+1][5]);
					write_string(4,0,disBuff);	
					
					SendCMD(0x98+6); //如:第四行第6列显示No:1
					SendDat('N');
					SendDat('o');
					SendDat(':');
					SendDat(ViewPage+0x30); 			
					break;
				case 4:
					memset(disBuff,0,DISMAXBUFF);
					sprintf(disBuff," 20%02d - %02d - %02d ",(int)stuTimStore[ViewId].dateStore_Stu[page_count][0],(int)stuTimStore[ViewId].dateStore_Stu[page_count][1],(int)stuTimStore[ViewId].dateStore_Stu[page_count][2]);
					write_string(1,0,disBuff);	
					memset(disBuff,0,DISMAXBUFF);
					sprintf(disBuff,"%02d:%02d:%02d        ",(int)stuTimStore[ViewId].dateStore_Stu[page_count][3],(int)stuTimStore[ViewId].dateStore_Stu[page_count][4],(int)stuTimStore[ViewId].dateStore_Stu[page_count][5]);
					write_string(2,0,disBuff);	
					memset(disBuff,0,DISMAXBUFF);
					sprintf(disBuff," 20%02d - %02d - %02d ",(int)stuTimStore[ViewId].dateStore_Stu[page_count+1][0],(int)stuTimStore[ViewId].dateStore_Stu[page_count+1][1],(int)stuTimStore[ViewId].dateStore_Stu[page_count+1][2]);
					write_string(3,0,disBuff);	
					memset(disBuff,0,DISMAXBUFF);
					sprintf(disBuff,"%02d:%02d:%02d    ",(int)stuTimStore[ViewId].dateStore_Stu[page_count+1][3],(int)stuTimStore[ViewId].dateStore_Stu[page_count+1][4],(int)stuTimStore[ViewId].dateStore_Stu[page_count+1][5]);
					write_string(4,0,disBuff);	
					
					SendCMD(0x98+6); //如:第四行第6列显示No:1
					SendDat('N');
					SendDat('o');
					SendDat(':');
					SendDat(ViewPage+0x30); 			
					break;
				case 5:
					memset(disBuff,0,DISMAXBUFF);
					sprintf(disBuff," 20%02d - %02d - %02d ",(int)stuTimStore[ViewId].dateStore_Stu[page_count][0],(int)stuTimStore[ViewId].dateStore_Stu[page_count][1],(int)stuTimStore[ViewId].dateStore_Stu[page_count][2]);
					write_string(1,0,disBuff);	
					memset(disBuff,0,DISMAXBUFF);
					sprintf(disBuff,"%02d:%02d:%02d        ",(int)stuTimStore[ViewId].dateStore_Stu[page_count][3],(int)stuTimStore[ViewId].dateStore_Stu[page_count][4],(int)stuTimStore[ViewId].dateStore_Stu[page_count][5]);
					write_string(2,0,disBuff);	
					memset(disBuff,0,DISMAXBUFF);
					sprintf(disBuff," 20%02d - %02d - %02d ",(int)stuTimStore[ViewId].dateStore_Stu[page_count+1][0],(int)stuTimStore[ViewId].dateStore_Stu[page_count+1][1],(int)stuTimStore[ViewId].dateStore_Stu[page_count+1][2]);
					write_string(3,0,disBuff);	
					memset(disBuff,0,DISMAXBUFF);
					sprintf(disBuff,"%02d:%02d:%02d    ",(int)stuTimStore[ViewId].dateStore_Stu[page_count+1][3],(int)stuTimStore[ViewId].dateStore_Stu[page_count+1][4],(int)stuTimStore[ViewId].dateStore_Stu[page_count+1][5]);
					write_string(4,0,disBuff);	
					
					SendCMD(0x98+6); //如:第四行第6列显示No:1
					SendDat('N');
					SendDat('o');
					SendDat(':');
					SendDat(ViewPage+0x30); 		
					break;
				case 6:
					memset(disBuff,0,DISMAXBUFF);
					sprintf(disBuff," 20%02d - %02d - %02d ",(int)stuTimStore[ViewId].dateStore_Stu[page_count][0],(int)stuTimStore[ViewId].dateStore_Stu[page_count][1],(int)stuTimStore[ViewId].dateStore_Stu[page_count][2]);
					write_string(1,0,disBuff);	
					memset(disBuff,0,DISMAXBUFF);
					sprintf(disBuff,"%02d:%02d:%02d        ",(int)stuTimStore[ViewId].dateStore_Stu[page_count][3],(int)stuTimStore[ViewId].dateStore_Stu[page_count][4],(int)stuTimStore[ViewId].dateStore_Stu[page_count][5]);
					write_string(2,0,disBuff);	
					memset(disBuff,0,DISMAXBUFF);
					sprintf(disBuff," 20%02d - %02d - %02d ",(int)stuTimStore[ViewId].dateStore_Stu[page_count+1][0],(int)stuTimStore[ViewId].dateStore_Stu[page_count+1][1],(int)stuTimStore[ViewId].dateStore_Stu[page_count+1][2]);
					write_string(3,0,disBuff);	
					memset(disBuff,0,DISMAXBUFF);
					sprintf(disBuff,"%02d:%02d:%02d    ",(int)stuTimStore[ViewId].dateStore_Stu[page_count+1][3],(int)stuTimStore[ViewId].dateStore_Stu[page_count+1][4],(int)stuTimStore[ViewId].dateStore_Stu[page_count+1][5]);
					write_string(4,0,disBuff);	
					
					SendCMD(0x98+6); //如:第四行第6列显示No:1
					SendDat('N');
					SendDat('o');
					SendDat(':');
					SendDat(ViewPage+0x30); 				
					break;
				case 7:
					memset(disBuff,0,DISMAXBUFF);
					sprintf(disBuff," 20%02d - %02d - %02d ",(int)stuTimStore[ViewId].dateStore_Stu[page_count][0],(int)stuTimStore[ViewId].dateStore_Stu[page_count][1],(int)stuTimStore[ViewId].dateStore_Stu[page_count][2]);
					write_string(1,0,disBuff);	
					memset(disBuff,0,DISMAXBUFF);
					sprintf(disBuff,"%02d:%02d:%02d        ",(int)stuTimStore[ViewId].dateStore_Stu[page_count][3],(int)stuTimStore[ViewId].dateStore_Stu[page_count][4],(int)stuTimStore[ViewId].dateStore_Stu[page_count][5]);
					write_string(2,0,disBuff);	
					memset(disBuff,0,DISMAXBUFF);
					sprintf(disBuff," 20%02d - %02d - %02d ",(int)stuTimStore[ViewId].dateStore_Stu[page_count+1][0],(int)stuTimStore[ViewId].dateStore_Stu[page_count+1][1],(int)stuTimStore[ViewId].dateStore_Stu[page_count+1][2]);
					write_string(3,0,disBuff);	
					memset(disBuff,0,DISMAXBUFF);
					sprintf(disBuff,"%02d:%02d:%02d    ",(int)stuTimStore[ViewId].dateStore_Stu[page_count+1][3],(int)stuTimStore[ViewId].dateStore_Stu[page_count+1][4],(int)stuTimStore[ViewId].dateStore_Stu[page_count+1][5]);
					write_string(4,0,disBuff);	
					
					SendCMD(0x98+6); //如:第四行第6列显示No:1
					SendDat('N');
					SendDat('o');
					SendDat(':');
					SendDat(ViewPage+0x30); 		
					break;
				case 8:
					memset(disBuff,0,DISMAXBUFF);
					sprintf(disBuff," 20%02d - %02d - %02d ",(int)stuTimStore[ViewId].dateStore_Stu[page_count][0],(int)stuTimStore[ViewId].dateStore_Stu[page_count][1],(int)stuTimStore[ViewId].dateStore_Stu[page_count][2]);
					write_string(1,0,disBuff);	
					memset(disBuff,0,DISMAXBUFF);
					sprintf(disBuff,"%02d:%02d:%02d        ",(int)stuTimStore[ViewId].dateStore_Stu[page_count][3],(int)stuTimStore[ViewId].dateStore_Stu[page_count][4],(int)stuTimStore[ViewId].dateStore_Stu[page_count][5]);
					write_string(2,0,disBuff);	
					memset(disBuff,0,DISMAXBUFF);
					sprintf(disBuff," 20%02d - %02d - %02d ",(int)stuTimStore[ViewId].dateStore_Stu[page_count+1][0],(int)stuTimStore[ViewId].dateStore_Stu[page_count+1][1],(int)stuTimStore[ViewId].dateStore_Stu[page_count+1][2]);
					write_string(3,0,disBuff);	
					memset(disBuff,0,DISMAXBUFF);
					sprintf(disBuff,"%02d:%02d:%02d    ",(int)stuTimStore[ViewId].dateStore_Stu[page_count+1][3],(int)stuTimStore[ViewId].dateStore_Stu[page_count+1][4],(int)stuTimStore[ViewId].dateStore_Stu[page_count+1][5]);
					write_string(4,0,disBuff);	
					
					SendCMD(0x98+6); //如:第四行第6列显示No:1
					SendDat('N');
					SendDat('o');
					SendDat(':');
					SendDat(ViewPage+0x30); 	
					break;
				case 9:
					memset(disBuff,0,DISMAXBUFF);
					sprintf(disBuff," 20%02d - %02d - %02d ",(int)stuTimStore[ViewId].dateStore_Stu[page_count][0],(int)stuTimStore[ViewId].dateStore_Stu[page_count][1],(int)stuTimStore[ViewId].dateStore_Stu[page_count][2]);
					write_string(1,0,disBuff);	
					memset(disBuff,0,DISMAXBUFF);
					sprintf(disBuff,"%02d:%02d:%02d        ",(int)stuTimStore[ViewId].dateStore_Stu[page_count][3],(int)stuTimStore[ViewId].dateStore_Stu[page_count][4],(int)stuTimStore[ViewId].dateStore_Stu[page_count][5]);
					write_string(2,0,disBuff);	
					memset(disBuff,0,DISMAXBUFF);
					sprintf(disBuff," 20%02d - %02d - %02d ",(int)stuTimStore[ViewId].dateStore_Stu[page_count+1][0],(int)stuTimStore[ViewId].dateStore_Stu[page_count+1][1],(int)stuTimStore[ViewId].dateStore_Stu[page_count+1][2]);
					write_string(3,0,disBuff);	
					memset(disBuff,0,DISMAXBUFF);
					sprintf(disBuff,"%02d:%02d:%02d    ",(int)stuTimStore[ViewId].dateStore_Stu[page_count+1][3],(int)stuTimStore[ViewId].dateStore_Stu[page_count+1][4],(int)stuTimStore[ViewId].dateStore_Stu[page_count+1][5]);
					write_string(4,0,disBuff);	
					
					SendCMD(0x98+6); //如:第四行第6列显示No:1
					SendDat('N');
					SendDat('o');
					SendDat(':');
					SendDat(ViewPage+0x30); 			
					break;
				default:break;
			}
				
			keyNum = Getkeyboard();		   //按键判断函数 
            if(keyNum != KEY_NoTOUCH)
			{
    
    
				Buzz_Times(1);	
				if(keyNum == 11)  //加
				{
    
    
					ViewPage++;
					if(ViewPage>9)
					{
    
    
						ViewPage=9;
					}
					page_count+=2;
					if(page_count>16)
					{
    
    
						page_count = 16;
					}
					if(ViewPage == 1)
					{
    
    
						page_count = 0;
					}
					SendCMD(0x01);//清除显示		
				}
				else if(keyNum == 12)  //减
				{
    
    
					ViewPage --;
					if(ViewPage<0)
						ViewPage=0;		
					page_count-=2;
					if(page_count<0)
					{
    
    
						page_count = 0;
					}
					SendCMD(0x01);//清除显示		
				}
				else if(keyNum == 15)  //#:返回
                {
    
    
					disMenu = ViewHistoryMenu;
                    SendCMD(0x01);//清除显示				
					write_string(1,0,"  进出记录查阅  ");
					write_string(2,0,"姓名:          ");
					write_string(3,0,"B:加        C:减");
					write_string(4,0,"#:返回    D:确定");
					continue;  //从while重新开始,不再运行下面程序
                }
			}
		}
		else if(disMenu == ZhiWenMenu)
		{
    
    
			keyNum = Getkeyboard();		   //按键判断函数
			if(keyNum != KEY_NoTOUCH)
			{
    
    	
				Buzz_Times(1);	
				if(keyNum==10)
				{
    
    				
					FPM10A_Add_Fingerprint();
					SendCMD(0x01);//清除显示				
					write_string(1,0,"A:添加指纹      ");
					write_string(2,0,"B:删除指纹      ");
					write_string(3,0,"C:搜索指纹      ");
					write_string(4,0,"#:返回上级      ");
				}
				if(keyNum==11)
				{
    
    
					FPM10A_Delete_All_Fingerprint();
					SendCMD(0x01);//清除显示				
					write_string(1,0,"A:添加指纹      ");
					write_string(2,0,"B:删除指纹      ");
					write_string(3,0,"C:搜索指纹      ");
					write_string(4,0,"#:返回上级      ");
				}
				if(keyNum==12)
				{
    
    
					FPM10A_Find_Fingerprint();	
					SendCMD(0x01);//清除显示				
					write_string(1,0,"A:添加指纹      ");
					write_string(2,0,"B:删除指纹      ");
					write_string(3,0,"C:搜索指纹      ");
					write_string(4,0,"#:返回上级      ");
				}
				if(keyNum==15)
				{
    
    
					disMenu = ChooseMenu;
					write_string(1,0,"密码验证成功!  ");
                    write_string(2,0,"A:指纹更新      ");				
                    write_string(3,0,"B:查阅历史      ");
                    write_string(4,0,"C:手动    #:返回");
                    continue;  //从while重新开始,不再运行下面程序
				}
			}
		}
	}
}
void Timer0Init(void)		//5毫秒@11.0592MHz
{
    
    
	AUXR &= 0x7F;		//定时器时钟12T模式
	TMOD &= 0xF0;		//设置定时器模式
	TL0 = 0x00;		//设置定时初值
	TH0 = 0xEE;		//设置定时初值
	TF0 = 0;		//清除TF0标志
	TR0 = 1;		//定时器0开始计时
	ET0 = 1;
	EA  = 1;
}
static void Timer0_irt() interrupt 1
{
    
    
	timer0Count ++;
	if(timer0Count >= 200)
	{
    
    
		timer0Count =0;
        flagTimer0_1S = TRUE;
	}
}
#define RCREADTIME 1000
uchar rc522Read(void)
{
    
    
	unsigned char i=0;
	uchar rcID = NONEClient; //先清空,再判断卡有没有匹配到存储的人
	static uint rcCountTime=0;
	static char status=0;
	if(rcCountTime == 0)
		status = PcdRequest(PICC_REQALL, g_ucTempbuf);//寻卡
	rcCountTime ++;
	if(rcCountTime == RCREADTIME)
	{
    
    
		rcCountTime =0;
		for(i=0;i<4;i++)		 //卡序列号
		{
    
    
			Xuhao_Panduan[i]=0;
		}
		if(status == MI_OK )	//若得到卡,则进行判断卡序号
		{
    
    
			status = PcdAnticoll(g_ucTempbuf);//防冲撞
			if (status != MI_OK)
			{
    
            }
			for(i=0;i<4;i++)		 //卡序列号  显示
			{
    
    
				Xuhao_Panduan[i]=g_ucTempbuf[i];
//				write_BCD(2,4+i,Xuhao_Panduan[i]);		
			}
			flag_ReceiveCard = TRUE;
			delay_ms(800);  //防抖动--稳定下来后再判断
			rcID=Xuhao_Check();			
		}
		else	 //如果没有得到卡,则重启PCD
		{
    
        
			PcdReset();
			PcdAntennaOff(); 
			delay_ms(2);
			PcdAntennaOn();		
		}
	}
	return rcID;
}	
uchar Xuhao_Check()
{
    
    
	uchar i=0;
	for(i=0;i<4;i++)
	{
    
    
		if(Xuhao_Panduan[i]==Xuhao_SQL[i])
			continue;
		else
			break;
	}
	if(i==4)
	{
    
    
		return 1; //识别出为客户1 :绿色卡1	
	}	
	for(i=0;i<4;i++)
	{
    
    
		if(Xuhao_Panduan[i]==Xuhao_SQL[i+4])
			continue;
		else
			break;
	}
	if(i==4)
	{
    
    
		return 2; //识别出为客户2 :绿色卡2	
	}
	for(i=0;i<4;i++)
	{
    
    
		if(Xuhao_Panduan[i]==Xuhao_SQL[i+8])
			continue;
		else
			break;
	}
	if(i==4)
	{
    
    
		return 3; //识别出为客户3 :白色卡1	
	}
	for(i=0;i<4;i++)
	{
    
    
		if(Xuhao_Panduan[i]==Xuhao_SQL[i+12])
			continue;
		else
			break;
	}
	if(i==4)
	{
    
    
		return 4; //识别出为客户4 :白色卡2	
	}
	else
	{
    
    
		return NONEClient; //不在数据库内
	}
}
//按键响应程序,参数是键值
//返回键值:
//         1    2    3    10	   //10: 
//         4    5    6    11	   //11: 修改密码
//         7    8    9    12	   //12: 手动关闭锁 
//         14   0    15   13	   //14:显示/隐藏输入的密码    15:删除    13:确认
void KeyPress_InputMenu(uchar keycode)
{
    
    
	uchar i=0;
	switch (keycode)
	{
    
    
		case 0:
		case 1:
		case 2:
		case 3:
		case 4:
		case 5:
		case 6:
		case 7:
		case 8:
		case 9:	
            break;
        case 15:  	 	/*---------功能(删除1位密码)-----------*/
			if(in_password_mun != 255)
			{
    
    
				password_bj[in_password_mun] = 20;
                if(in_password_mun%2 != 0)  //偶数个,因序号从0开始:0,1,2,3,4,5
                {
    
    
                    SendCMD(0x90+3+in_password_mun/2);
                    if(password_dis == FALSE)
					{
    
    
						SendDat(muntochar[password_bj[in_password_mun-1]]);
					}	
                    else{
    
    
						SendDat('*');
					}                      
                    SendDat(' ');
                }
                else{
    
    
                    SendCMD(0x90+3+in_password_mun/2);
                    SendDat(' ');
                }
				if(in_password_mun > 0)        //0-1 = 255
					in_password_mun--;
				else
					in_password_mun = 255;									//记录密码输入位数还原.255+1=0
			}
			break;    
        case 13:	  /*---------功能(确定密码是否正确)-----------*/
				for(i = 0;i < 6;i++)										//先比较输入密码
				{
    
    
					if(password[i] != password_bj[i])						//如果密码不匹配.
						break;												//跳出for循环.								
				}
				if(i == 6)												//如果循环6次没有跳出for循环,密码输入正确.
				{
    
    
					LED_R = LED_STATE(OFF);	
					LED_G = LED_STATE(ON);
					password_ok_open = TRUE;								//密码正确致1,表示输入成功.
					password_err_mun = 0;								//密码错误次数清0.					
				}
				else
				{
    
    
					write_string(2,0,"密码:输入错误!");//清空显示
					LED_R = LED_STATE(ON);	
					LED_G = LED_STATE(OFF);										
					delay_ms(2000);
					LED_R = LED_STATE(OFF);		
					
					write_string(2,0,"密码:          ");//清空显示
					SendCMD(0x90+3);						//液晶AC控制到第2行的第3位置.
					
					password_err_mun ++;
					if(password_err_mun >= 3)
					{
    
    
						password_err_mun = 0;
						flag_inputError = TRUE;
					}
				}
				for(i = 0;i < 6;i++)								//循环6次
					password_bj[i] = 20;							//置密码比较数组里的数还原到20.
				in_password_mun = 255;								//记录密码输入位数还原.
            break;    
        case 14:          /*---------功能(显示输入密码)-----------*/	   
			password_dis = !password_dis;	
			if(password_dis == FALSE)
			{
    
    
				SendCMD(0x90+3);						//液晶AC控制到第2行的第3位置.									
				for(i = 0;i < 6;i++)
				{
    
    
					if(password_bj[i] != 20)
						SendDat(muntochar[password_bj[i]]);
				}
			}
			else
			{
    
    
				SendCMD(0x90+3);						//液晶AC控制到第2行的第3位置.							
				for(i = 0;i < 6;i++)
				{
    
    
					if(password_bj[i] != 20)
						SendDat('*');
				}
			}				
			break;
        default:break;    
    }
}
/*******************************************************************/

Fingerprint Identification Module

#ifndef __FPMXX_H__
#define __FPMXX_H__

#include "config.h"

sbit  Finger_Touch=P0^0;

#include "Uart4_Timer4.h"
#define Uart_Send_Byte            UART4_Send_Byte
#define Uart_Receive_Byte         UART4_Receive_Byte  

extern unsigned char FPM10A_RECEICE_BUFFER[32];

void FPM10A_Cmd_Get_Img(void);
void FPM10A_Cmd_Check(void);
void Device_Check(void);
void FPM10A_Receive_Data(unsigned char ucLength);
void FPM10A_Delete_All_Fingerprint();


#define NONESTORE 0xffff
uchar  FPM10A_Find_Fingerprint_Touch(uint *IdNumber);


void FPM10A_Find_Fingerprint();
void FPM10A_Cmd_Search_Finger(void);
void FPM10A_Add_Fingerprint();
void FPM10A_Cmd_Reg_Model();
void FPM10A_Cmd_Save_Finger( unsigned int storeID );
void FINGERPRINT_Cmd_Delete_All_Finger(void);



#endif
#include "FPM10A.h"
#include "beep.h"
#include "keyBoard.h"
#include "12864_serial.h"     

volatile unsigned char FPM10A_RECEICE_BUFFER[32];
int finger_id = 0;

#define DISMAXBUFF_ZW 30
char disBuff_ZW[DISMAXBUFF_ZW];  //LCD12864显示

//FINGERPRINT通信协议定义

code unsigned char FPM10A_Get_Device[10] ={
    
    0x01,0x00,0x07,0x13,0x00,0x00,0x00,0x00,0x00,0x1b};//口令验证
code unsigned char FPM10A_Pack_Head[6] = {
    
    0xEF,0x01,0xFF,0xFF,0xFF,0xFF};  //协议包头
code unsigned char FPM10A_Get_Img[6] = {
    
    0x01,0x00,0x03,0x01,0x00,0x05};    //获得指纹图像
code unsigned char FPM10A_Get_Templete_Count[6] ={
    
    0x01,0x00,0x03,0x1D,0x00,0x21 }; //获得模版总数
code unsigned char FPM10A_Search[11]={
    
    0x01,0x00,0x08,0x04,0x01,0x00,0x00,0x03,0xE7,0x00,0xF8}; //搜索指纹搜索范围0 - 999,使用BUFFER1中的特征码搜索
code unsigned char FPM10A_Search_0_9[11]={
    
    0x01,0x00,0x08,0x04,0x01,0x00,0x00,0x00,0x13,0x00,0x21}; //搜索0-9号指纹
code unsigned char FPM10A_Img_To_Buffer1[7]={
    
    0x01,0x00,0x04,0x02,0x01,0x00,0x08}; //将图像放入到BUFFER1
code unsigned char FPM10A_Img_To_Buffer2[7]={
    
    0x01,0x00,0x04,0x02,0x02,0x00,0x09}; //将图像放入到BUFFER2
code unsigned char FPM10A_Reg_Model[6]={
    
    0x01,0x00,0x03,0x05,0x00,0x09}; //将BUFFER1跟BUFFER2合成特征模版
code unsigned char FPM10A_Delete_All_Model[6]={
    
    0x01,0x00,0x03,0x0d,0x00,0x11};//删除指纹模块里所有的模版
volatile unsigned char  FPM10A_Save_Finger[9]={
    
    0x01,0x00,0x06,0x06,0x01,0x00,0x0B,0x00,0x19};//将BUFFER1中的特征码存放到指定的位置
//volatile:系统总是重新从它所在的内存读取数据,即使它前面的指令刚刚从该处读取过数据
/*------------------ FINGERPRINT命令字 --------------------------*/
 //发送包头
void FPM10A_Cmd_Send_Pack_Head(void)
{
    
    
	int i;	
	for(i=0;i<6;i++) //包头
   {
    
    
     Uart_Send_Byte(FPM10A_Pack_Head[i]);   
    }		
}
//发送指令
void FPM10A_Cmd_Check(void)
{
    
    
	int i=0;
	FPM10A_Cmd_Send_Pack_Head(); //发送通信协议包头
	for(i=0;i<10;i++)
	 {
    
    		
		Uart_Send_Byte(FPM10A_Get_Device[i]);
	  }
}
//接收反馈数据缓冲
void FPM10A_Receive_Data(unsigned char ucLength)
{
    
    
  unsigned char i;

  for (i=0;i<ucLength;i++)
     FPM10A_RECEICE_BUFFER[i] = Uart_Receive_Byte();

}

//FINGERPRINT_获得指纹图像命令
void FPM10A_Cmd_Get_Img(void)
{
    
    
    unsigned char i;
    FPM10A_Cmd_Send_Pack_Head(); //发送通信协议包头
    for(i=0;i<6;i++) //发送命令 0x1d
	{
    
    
       Uart_Send_Byte(FPM10A_Get_Img[i]);
	}
}
//讲图像转换成特征码存放在Buffer1中
void FINGERPRINT_Cmd_Img_To_Buffer1(void)
{
    
    
 	unsigned char i;
	FPM10A_Cmd_Send_Pack_Head(); //发送通信协议包头      
   	for(i=0;i<7;i++)   //发送命令 将图像转换成 特征码 存放在 CHAR_buffer1
     {
    
    
      Uart_Send_Byte(FPM10A_Img_To_Buffer1[i]);
   	  }
}
//将图像转换成特征码存放在Buffer2中
void FINGERPRINT_Cmd_Img_To_Buffer2(void)
{
    
    
     unsigned char i;
     for(i=0;i<6;i++)    //发送包头
	 {
    
    
    	Uart_Send_Byte(FPM10A_Pack_Head[i]);   
   	 }
     for(i=0;i<7;i++)   //发送命令 将图像转换成 特征码 存放在 CHAR_buffer1
      {
    
    
      	Uart_Send_Byte(FPM10A_Img_To_Buffer2[i]);
   	  }
}
//搜索全部用户999枚
void FPM10A_Cmd_Search_Finger(void)
{
    
    
       unsigned char i;	   	    
			 FPM10A_Cmd_Send_Pack_Head(); //发送通信协议包头
       for(i=0;i<11;i++)
           {
    
    
    	      Uart_Send_Byte(FPM10A_Search[i]);   
   		   }
}

void FPM10A_Cmd_Reg_Model(void)
{
    
    
       unsigned char i;	   
	    
			 FPM10A_Cmd_Send_Pack_Head(); //发送通信协议包头

       for(i=0;i<6;i++)
           {
    
    
    	      Uart_Send_Byte(FPM10A_Reg_Model[i]);   
   		   }


}
//删除指纹模块里的所有指纹模版
void FINGERPRINT_Cmd_Delete_All_Model(void)
{
    
    
     unsigned char i;    
    for(i=0;i<6;i++) //包头
      Uart_Send_Byte(FPM10A_Pack_Head[i]);   
    for(i=0;i<6;i++) //命令合并指纹模版
	   {
    
    
      Uart_Send_Byte(FPM10A_Delete_All_Model[i]);   
		 }	
}
//保存指纹
void FPM10A_Cmd_Save_Finger( unsigned int storeID )
{
    
    
       unsigned long temp = 0;
		   unsigned char i;
       FPM10A_Save_Finger[5] =(storeID&0xFF00)>>8;
       FPM10A_Save_Finger[6] = (storeID&0x00FF);
		   for(i=0;i<7;i++)   //计算校验和
		   	   temp = temp + FPM10A_Save_Finger[i]; 
		   FPM10A_Save_Finger[7]=(temp & 0x00FF00) >> 8; //存放校验数据
		   FPM10A_Save_Finger[8]= temp & 0x0000FF;		   
       FPM10A_Cmd_Send_Pack_Head(); //发送通信协议包头	
       for(i=0;i<9;i++)  
      		Uart_Send_Byte(FPM10A_Save_Finger[i]);      //发送命令 将图像转换成 特征码 存放在 CHAR_buffer1
}
bit Flag_KEY_CANCEL=1;
//添加指纹
void FPM10A_Add_Fingerprint()
{
    
    
	unsigned char id_show[]={
    
    0,0,0};	
	unsigned char keycode;
	SendCMD(0x01);//清除显示LCD12864
	finger_id=0;  
	while(1)
	{
    
    
//	write_string(1,0,"   Add  finger  ");
//	write_string(2,0,"    ID is       ");
	write_string(1,0,"    添加指纹    ");	
	//指纹iD值显示处理  
//	 write_com(0xc0+10);
//	 write_date(finger_id/100+48);
//	 write_date(finger_id%100/10+48);
//	 write_date(finger_id%100%10+48);
	memset(disBuff_ZW,0,DISMAXBUFF_ZW);
	sprintf(disBuff_ZW,"指纹ID:%d    ",(int)finger_id);
	write_string(2,0,disBuff_ZW);	
	write_string(3,0,"B:ID加    C:ID减");	
	write_string(4,0,"D:确认    #:返回");				
	 keycode = Getkeyboard();	
		//有效键值0-15
		if (keycode<16)
		{
    
    
			Buzz_Times(1);
			if(keycode==15)	   //按返回键直接回到主菜单
			{
    
    
				break;
			}
			if(keycode==11)	  //按切换键指纹iD值加1
			{
    
    
				if(finger_id == 1000)
				{
    
    
					finger_id = 0;
				}
				else
					finger_id = finger_id + 1;
			}
			if(keycode==12)	  //按切换键指纹iD值减1
			{
    
    
				if(finger_id <= 0)
				{
    
    
					finger_id = 0;
				}
				else
					finger_id = finger_id - 1;
			}
			if(keycode==13)	   //按确认键开始录入指纹信息 
			{
    
    
				Flag_KEY_CANCEL=1;
//				write_string(1,0," Please  finger ");
//			    write_string(2,0,"                ");
				write_string(1,0,"    添加指纹    ");	
				memset(disBuff_ZW,0,DISMAXBUFF_ZW);
				sprintf(disBuff_ZW,"指纹ID:%d    ",(int)finger_id);
				write_string(2,0,disBuff_ZW);	
				write_string(3,0,"    请放置手指  ");	
				write_string(4,0,"                ");	
				while(Flag_KEY_CANCEL == 1)
			    {
    
    
					keycode = Getkeyboard();
					if (keycode<16)
					{
    
    
						Buzz_Times(1);
						if(keycode==15)	    //按下返回键退出录入返回fingerID调整状态   
						{
    
    
							Flag_KEY_CANCEL=0;
							break;
						}
					}
					FPM10A_Cmd_Get_Img(); //获得指纹图像
					FPM10A_Receive_Data(12);
					//判断接收到的确认码,等于0指纹获取成功
					if(FPM10A_RECEICE_BUFFER[9]==0)
					 {
    
    
						delay_ms(100);
						FINGERPRINT_Cmd_Img_To_Buffer1();
					    FPM10A_Receive_Data(12);
						 
//						write_string(1,0,"Successful entry");
						write_string(3,0,"第一次采集成功!");	 
						Buzz_Times(1);
						delay_ms(1000);
//						write_string(1,0," Please  finger ");
//				  		write_string(2,0,"                ");
						write_string(4,0,"请再次放置手指  ");	 
						while(1)
						{
    
    
							keycode = Getkeyboard();
							if (keycode<16)
							{
    
    
								Buzz_Times(1);
								if(keycode==15)	    //按下返回键退出录入返回fingerID调整状态   
								{
    
    
									break;
								}
							}
						 FPM10A_Cmd_Get_Img(); //获得指纹图像
						 FPM10A_Receive_Data(12);
						//判断接收到的确认码,等于0指纹获取成功
						if(FPM10A_RECEICE_BUFFER[9]==0)
						{
    
    
							delay_ms(200);
//							write_string(1,0,"Successful entry");
//							write_string(2,0,"    ID is       ");
							write_string(4,0,"第二次采集成功!");	
							
							write_string(2,0,"指纹ID:        ");	
							memset(disBuff_ZW,0,DISMAXBUFF_ZW);
							sprintf(disBuff_ZW,"指纹ID:%d    ",(int)finger_id);
							write_string(2,0,disBuff_ZW);	
							 //指纹iD值显示处理 
//							 write_com(0xc0+10);
//							 write_date(finger_id/100+48);
//							 write_date(finger_id%100/10+48);
//							 write_date(finger_id%100%10+48);
							
							FINGERPRINT_Cmd_Img_To_Buffer2();
					  		FPM10A_Receive_Data(12);
							FPM10A_Cmd_Reg_Model();//转换成特征码
		         			FPM10A_Receive_Data(12); 
						  	FPM10A_Cmd_Save_Finger(finger_id);                		         
		          			FPM10A_Receive_Data(12);
							Buzz_Times(1);
							delay_ms(1000);
							finger_id=finger_id+1;
					    	break;
					  	}
					   }
					   
		        		break;
						}
					}
			}
		}
		//	delay_ms(500);
	}
}
uchar  FPM10A_Find_Fingerprint_Touch(uint *IdNumber) //检测到指纹:1   未检测到指纹:0  --因为有界面变化
{
    
    
	unsigned int find_fingerid = 0;
	unsigned char id_show[]={
    
    0,0,0};
	FPM10A_Cmd_Get_Img(); //获得指纹图像
	FPM10A_Receive_Data(12);		
	//判断接收到的确认码,等于0指纹获取成功
	if(FPM10A_RECEICE_BUFFER[9]==0)
	{
    
    			
		delay_ms(100);
		FINGERPRINT_Cmd_Img_To_Buffer1();
		FPM10A_Receive_Data(12);		
		FPM10A_Cmd_Search_Finger();
		FPM10A_Receive_Data(16);			
		if(FPM10A_RECEICE_BUFFER[9] == 0) //搜索到  
		{
    
    
//			SendCMD(0x01);//清除显示
//			write_string(1,0,"  指纹检测成功  ");
				
			//拼接指纹ID数
			find_fingerid = FPM10A_RECEICE_BUFFER[10]*256 + FPM10A_RECEICE_BUFFER[11];					
			 //指纹iD值显示处理 
//			 write_com(0xc0+10);
//			 write_date(find_fingerid/100+48);
//			 write_date(find_fingerid%100/10+48);
//			 write_date(find_fingerid%100%10+48);
			
//			memset(disBuff_ZW,0,DISMAXBUFF_ZW);
//			sprintf(disBuff_ZW,"指纹ID:%d    ",(int)find_fingerid);
//			write_string(2,0,disBuff_ZW);		

			*IdNumber = find_fingerid;
		   }
			else //没有找到
			{
    
    
//				write_string(1,0," Search  failed ");
//				write_string(2,0,"                ");
				
//				SendCMD(0x01);//清除显示
//				write_string(1,0,"  指纹检测失败! ");
//				
//			 	Buzz_Times(5);
				*IdNumber = NONESTORE;
			}
//			delay_ms(5000);		
			/**************回到主功能界面****************/
			return 1;
			//	write_com(0x01);   //清屏	
			//	write_string(1,0,"  search finger ");	 //第一排显示搜索指纹
			//	write_string(2,0,"  Add     delete");	 //添加和删除指纹 
		} 
	return 0;
}
//搜索指纹
void FPM10A_Find_Fingerprint()
{
    
    
	unsigned int find_fingerid = 0,keycode;
	unsigned char id_show[]={
    
    0,0,0};
	Flag_KEY_CANCEL=1;
	SendCMD(0x01);//清除显示
	do
	{
    
    	
		write_string(1,0,"    搜索指纹    ");
		write_string(4,0,"按下# 键返回主页");	
		FPM10A_Cmd_Get_Img(); //获得指纹图像
		FPM10A_Receive_Data(12);		
		//判断接收到的确认码,等于0指纹获取成功
		if(FPM10A_RECEICE_BUFFER[9]==0)
		{
    
    			
			delay_ms(100);
			FINGERPRINT_Cmd_Img_To_Buffer1();
			FPM10A_Receive_Data(12);		
			FPM10A_Cmd_Search_Finger();
			FPM10A_Receive_Data(16);			
			if(FPM10A_RECEICE_BUFFER[9] == 0) //搜索到  
			{
    
    
//				write_string(1,0," Search success ");
//				write_string(2,0,"    ID is       ");
				
				write_string(2,0,"指纹搜索成功!  ");
				Buzz_Times(1);					
				//拼接指纹ID数
				find_fingerid = FPM10A_RECEICE_BUFFER[10]*256 + FPM10A_RECEICE_BUFFER[11];					
				 //指纹iD值显示处理 
//				 write_com(0xc0+10);
//				 write_date(find_fingerid/100+48);
//				 write_date(find_fingerid%100/10+48);
//				 write_date(find_fingerid%100%10+48);	
				memset(disBuff_ZW,0,DISMAXBUFF_ZW);
				sprintf(disBuff_ZW,"指纹ID:%d    ",(int)find_fingerid);
				write_string(3,0,disBuff_ZW);	
				
				delay_ms(2000);				
			   }
				else //没有找到
				{
    
    
//					write_string(1,0," Search  failed ");
//					write_string(2,0,"                ");
					
					write_string(2,0,"指纹搜索失败!  ");
					write_string(3,0,"                ");
					
				 	Buzz_Times(3);
				}
			}
			keycode = Getkeyboard();	
				//有效键值0-15
			if (keycode<16)
			{
    
    
				 Buzz_Times(1);
				 if(keycode==15)//返回键
				 {
    
    
				 	Flag_KEY_CANCEL=0;
					break;
				}
			}		
		}while(Flag_KEY_CANCEL == 1);
}
//删除所有存贮的指纹库
void FPM10A_Delete_All_Fingerprint()
{
    
    
		unsigned char i=0,keycode;
//				write_string(1,0,"   empty all    ");
//				write_string(2,0,"   Yes or no ?  "); 
		SendCMD(0x01);//清除显示
		write_string(1,0,"    指纹删除    ");
		write_string(2,0,"删除所有指纹?  ");
	    write_string(3,0,"  是  或  否?  ");
		write_string(4,0,"D:确认    #:返回");	
		Flag_KEY_CANCEL=1;
		do
		 {
    
    
		 	keycode = Getkeyboard();	
				//有效键值0-15
			if (keycode<16)
			{
    
    
				 Buzz_Times(1);
				 if(keycode==13)//确认键
				 {
    
    
				 	Flag_KEY_CANCEL=0;
					write_string(3,0,"正在删除指纹....");
					delay_ms(300);
					SendCMD(0x98);  //设定光标位置
					for(i=0;i<16;i++)      //进度条式更新,看起来美观
					 {
    
    
						SendDat(42);   //42对应ASIC码的 *
						delay_ms(200);     //控制进度条速度
					 }
						FINGERPRINT_Cmd_Delete_All_Model();
					    FPM10A_Receive_Data(12); 
						write_string(4,0,"  指纹删除成功!");
						Buzz_Times(3);
						break;
				 }	
				 if(keycode==15)//返回键
				 {
    
    
					 break;
				 }
			}
		 }while(Flag_KEY_CANCEL==1);
}

void Device_Check(void)
{
    
    
		unsigned char i=0;
		P3M1 &= ~(1<<5);	//Finger_Touch接口设置成准双向IO
		P3M0 &= ~(1<<5);
	
		
		FPM10A_RECEICE_BUFFER[9]=1;				           //串口数组第九位可判断是否通信正常
	
		SendCMD(0x01);//清除显示
		write_string(1,0,"    指纹模块    ");
		write_string(2,0,"正在加载        ");
		SendCMD(0x90+4);
		for(i=0;i<8;i++)						   //进度条式更新,看起来美观
		{
    
    
			SendDat(42);	                       //42对应ASIC码的 *
			delay_ms(300);						           //控制进度条速度
		}	
		FPM10A_Cmd_Check();									//单片机向指纹模块发送校对命令
		FPM10A_Receive_Data(12);							//将串口接收到的数据转存
 		if(FPM10A_RECEICE_BUFFER[9] == 0)					//判断数据低第9位是否接收到0
		{
    
    
			write_string(2,0,"    加载成功!  ");   //符合成功条件则显示对接成功
		}
		else
		{
    
    
			write_string(2,0,"    加载失败!  ");               //液晶先显示对接失败  		
		}
		delay_ms(2000);
}






DS1302 clock module

#ifndef  __DS1302_H__
#define  __DS1302_H__
//注意:使用时注意 BCD码问题
#include "config.h"
/********************************************************************/ 
sbit SCK=P2^0;		
sbit SD=P2^1;		
sbit RST=P2^2;
/********************************************************************/ 
/*复位脚*/
#define RST_CLR	RST=0	/*电平置低*/
#define RST_SET	RST=1	/*电平置高*/
/*双向数据*/
#define SDA_CLR	SD=0	/*电平置低*/
#define SDA_SET	SD=1	/*电平置高*/
#define SDA_R	SD	/*电平读取*/	
/*时钟信号*/
#define SCK_CLR	SCK=0	/*时钟信号*/
#define SCK_SET	SCK=1	/*电平置高*/
/********************************************************************/ 
#define ds1302_sec_addr_write			0x80		//秒数据地址	   //写地址
#define ds1302_min_addr_write			0x82		//分数据地址
#define ds1302_hr_addr_write			0x84		//时数据地址
#define ds1302_date_addr_write		0x86		//日数据地址
#define ds1302_month_addr_write		0x88		//月数据地址
#define ds1302_day_addr_write			0x8A		//星期数据地址
#define ds1302_year_addr_write		0x8C		//年数据地址


//#define ds1302_sec_addr_read		0x81		//秒数据地址	 //读地址
//#define ds1302_min_addr_read		0x83		//分数据地址
//#define ds1302_hr_addr_read			0x85		//时数据地址
//#define ds1302_date_addr_read		0x87		//日数据地址
//#define ds1302_month_addr_read		0x89		//月数据地址
//#define ds1302_day_addr_read		0x8B		//星期数据地址
//#define ds1302_year_addr_read		0x8D		//年数据地址


#define ds1302_control_addr		0x8E		//写保护命令字单元地址
#define ds1302_charger_addr		0x90 		//涓电流充电命令字地址			 
#define ds1302_clkburst_addr	0xBE		//日历、时钟突发模式命令字地址
/********************************************************************/ 
/********************************************************************/ 

/*初始化DS1302*/
extern void Init_Ds1302(uchar *p);		//初始化时间
/*读取DS1302*/
extern void Read_NowTime_Ds1302(uchar *p);	  
/*设置DS1302*/
void Set_Ds1302(uchar *p);

#endif	 
/********************************************************************/
//		     	END FILE
/********************************************************************/

#include "ds1302.h"
//注意:使用时注意 BCD码问题
/********************************************************************/ 
/*单字节写入一字节数据*/
void Write_Ds1302_Byte(unsigned char dat) 
{
    
    
	unsigned char i;
	SCK = 0;
	for (i=0;i<8;i++) 
	{
    
     
		if (dat & 0x01) 	// 等价于if((addr & 0x01) ==1) 
		{
    
    
			SDA_SET;		//#define SDA_SET SDA=1 /*电平置高*/
		}
		else 
		{
    
    
			SDA_CLR;		//#define SDA_CLR SDA=0 /*电平置低*/
		}		 
		SCK_SET;
		_nop_();
		SCK_CLR;
		_nop_();		
		dat = dat >> 1; 
	} 
}
/********************************************************************/ 
/*单字节读出一字节数据*/
unsigned char Read_Ds1302_Byte(void) 
{
    
    
	unsigned char i, dat=0;	
	for (i=0;i<8;i++)
	{
    
    	
		dat = dat >> 1;
		if (SDA_R) 	  //等价于if(SDA_R==1)    #define SDA_R SDA /*电平读取*/	
		{
    
    
			dat |= 0x80;
		}
		else 
		{
    
    
			dat &= 0x7F;
		}
		SCK_SET;
		_nop_();
		SCK_CLR;
		_nop_();
	}
	return dat;
}

/********************************************************************/ 
/*向DS1302 单字节写入一字节数据*/
void Ds1302_Single_Byte_Write(unsigned char addr, unsigned char dat)
{
    
     

	RST_CLR;			/*RST脚置低,实现DS1302的初始化*/
	_nop_();
	SCK_CLR;			/*SCK脚置低,实现DS1302的初始化*/
	_nop_();
	RST_SET;			/*启动DS1302总线,RST=1电平置高 */
	_nop_();

	addr = addr & 0xFE;	 
	Write_Ds1302_Byte(addr); /*写入目标地址:addr,保证是写操作,写之前将最低位置零*/	
	Write_Ds1302_Byte(dat);	 /*写入数据:dat*/
	RST_CLR;				 /*停止DS1302总线*/
	_nop_();				//  注意驱动上没有!!!!!!!!
}

/********************************************************************/ 
/*从DS1302单字节读出一字节数据*/
unsigned char Ds1302_Single_Byte_Read(unsigned char addr) 
{
    
     
	unsigned char temp;
	RST_CLR;			/*RST脚置低,实现DS1302的初始化*/
	_nop_();
	SCK_CLR;			/*SCK脚置低,实现DS1302的初始化*/
	_nop_();
	RST_SET;	/*启动DS1302总线,RST=1电平置高 */	
	_nop_();

	addr = addr | 0x01;	   //最低位置位1,则是读地址  ,写之前将最低位置高
	Write_Ds1302_Byte(addr); /*写入目标地址:addr,保证是读操作*/
	temp=Read_Ds1302_Byte(); /*从DS1302中读出一个字节的数据*/	
		
	RST_CLR;	/*停止DS1302总线*/
	_nop_();	 //  注意驱动上没有!!!!!!!!
	SCK_SET;
	_nop_();
	SDA_CLR;	//  注意驱动上没有!!!!!!!!
	_nop_();
	SDA_SET	;
	_nop_();  //  注意驱动上没有!!!!!!!!
	return temp;
}
/********************************8421BCD码到十进制转换*****************************/
uchar BCD_DEC_conv(uchar x)
{
    
    
	uchar dec;
	dec =  0x0f & x;
	x = x >> 4;
	dec	= dec + x * 10;
	return(dec);
}
/********************************十进制到8421BCD码转换*****************************/	
uchar DEC_BCD_conv(uchar x)
{
    
    
	uchar bcd;
	bcd =  x % 10;
	x = x / 10;
	x = x << 4;
	bcd	= bcd | x ;
	return(bcd);
}
void DS1302_IOInit(void)
{
    
    
	P2M1 &= ~(1<<0);	//设置成准双向IO
	P2M0 &= ~(1<<0);

	P2M1 &= ~(1<<1);	//设置成准双向IO
	P2M0 &= ~(1<<1);
	
	P2M1 &= ~(1<<2);	//设置成准双向IO
	P2M0 &= ~(1<<2);
}
void Init_Ds1302(uchar *p)
{
    
    
	DS1302_IOInit();
	if((Ds1302_Single_Byte_Read(ds1302_sec_addr_write) & 0x80))  //  秒寄存器最高位:1的时候 时钟停止,0的时候时钟运行
	{
    
    
		Ds1302_Single_Byte_Write(ds1302_control_addr,0x00);	   //关写保护
		Ds1302_Single_Byte_Write(ds1302_year_addr_write,DEC_BCD_conv(*(p)));
		Ds1302_Single_Byte_Write(ds1302_month_addr_write,DEC_BCD_conv(*(p+1)));
		Ds1302_Single_Byte_Write(ds1302_date_addr_write,DEC_BCD_conv(*(p+2)));
		Ds1302_Single_Byte_Write(ds1302_hr_addr_write,DEC_BCD_conv(*(p+3)));
		Ds1302_Single_Byte_Write(ds1302_min_addr_write,DEC_BCD_conv(*(p+4)));
		Ds1302_Single_Byte_Write(ds1302_sec_addr_write,DEC_BCD_conv(*(p+5)));
		Ds1302_Single_Byte_Write(ds1302_control_addr,0x80);					 //开写保护
	}
	else   //时钟运行的话就不初始化了
	{
    
    
//		Ds1302_Single_Byte_Write(ds1302_control_addr,0x00);	   //关写保护
//		Ds1302_Single_Byte_Write(ds1302_year_addr_write,DEC_BCD_conv(*(p)));
//		Ds1302_Single_Byte_Write(ds1302_month_addr_write,DEC_BCD_conv(*(p+1)));
//		Ds1302_Single_Byte_Write(ds1302_date_addr_write,DEC_BCD_conv(*(p+2)));
//		Ds1302_Single_Byte_Write(ds1302_hr_addr_write,DEC_BCD_conv(*(p+3)));
//		Ds1302_Single_Byte_Write(ds1302_min_addr_write,DEC_BCD_conv(*(p+4)));
//		Ds1302_Single_Byte_Write(ds1302_sec_addr_write,DEC_BCD_conv(*(p+5)));
//		Ds1302_Single_Byte_Write(ds1302_control_addr,0x80);					 //开写保护
	}
}
void Read_NowTime_Ds1302(uchar *p)
{
    
    
	*(p) =   BCD_DEC_conv(Ds1302_Single_Byte_Read(ds1302_year_addr_write));
	*(p+1) = BCD_DEC_conv(Ds1302_Single_Byte_Read(ds1302_month_addr_write));
	*(p+2) = BCD_DEC_conv(Ds1302_Single_Byte_Read(ds1302_date_addr_write));
	*(p+3) = BCD_DEC_conv(Ds1302_Single_Byte_Read(ds1302_hr_addr_write));
	*(p+4) = BCD_DEC_conv(Ds1302_Single_Byte_Read(ds1302_min_addr_write));
	*(p+5) = BCD_DEC_conv(Ds1302_Single_Byte_Read(ds1302_sec_addr_write));
}
void Set_Ds1302(uchar *p)
{
    
    
	Ds1302_Single_Byte_Write(ds1302_control_addr,0x00);	   //关写保护
	Ds1302_Single_Byte_Write(ds1302_year_addr_write,DEC_BCD_conv(*(p)));
	Ds1302_Single_Byte_Write(ds1302_month_addr_write,DEC_BCD_conv(*(p+1)));
	Ds1302_Single_Byte_Write(ds1302_date_addr_write,DEC_BCD_conv(*(p+2)));
	Ds1302_Single_Byte_Write(ds1302_hr_addr_write,DEC_BCD_conv(*(p+3)));
	Ds1302_Single_Byte_Write(ds1302_min_addr_write,DEC_BCD_conv(*(p+4)));
	Ds1302_Single_Byte_Write(ds1302_sec_addr_write,DEC_BCD_conv(*(p+5)));
	Ds1302_Single_Byte_Write(ds1302_control_addr,0x80);					 //开写保护
}

Built-in EEPROM read and write program of STC series


#ifndef	__EEPROM_H
#define	__EEPROM_H

#include "config.h"

/************************** ISP/IAP *****************************

用户可用根据自己的需要在整个FLASH空间中规划出任意不超过FLASH大小的EEPROM空间,但需要注意:EEPROM总是从后向前进行规划的。
例如:STC8A8K64S4A12这个型号的FLASH为64K,
此时若用户想分出其中的8K作为EEPROM使用,则EEPROM的物理地址则为64K的最后8K,物理地址为E000h-FFFFh,
当然,用户若使用IAP的方式进行访问,目标地址仍然从0000h开始,到1FFFh结束,当使用MOVC读取则需要从EO00h开始,到FFFFh结束。
0x0000 - 0x01ff
0x0200 - 0x03ff
0x0400 - 0x05ff
*/
#define   EEROM_USEADDR 0x0200
#define   EEROM_CHECK_VALUE 0xf1


#define WT_30M          0x80
#define WT_24M          0x81
#define WT_20M          0x82
#define WT_12M          0x83
#define WT_6M           0x84
#define WT_3M           0x85
#define WT_2M           0x86
#define WT_1M           0x87

uchar IapRead(uint addr);
void IapErase(uint addr);
void IapProgram(uint addr, uchar dat);

void 	EEPROM_read_n(uint EE_address,uchar *DataAddress,uint number);
void 	EEPROM_write_n(uint EE_address,uchar *DataAddress,uint number);


#endif

//	本程序是STC系列的内置EEPROM读写程序。
#include "eeprom.h"

void IapIdle()
{
    
    
    IAP_CONTR = 0;                              //关闭IAP功能
    IAP_CMD = 0;                                //清除命令寄存器
    IAP_TRIG = 0;                               //清除触发寄存器
    IAP_ADDRH = 0x80;                           //将地址设置到非IAP区域
    IAP_ADDRL = 0;
}
uchar IapRead(uint addr)
{
    
    
    uchar dat;

    IAP_CONTR = WT_12M;                         //使能IAP
    IAP_CMD = 1;                                //设置IAP读命令
    IAP_ADDRL = addr;                           //设置IAP低地址
    IAP_ADDRH = addr >> 8;                      //设置IAP高地址
    IAP_TRIG = 0x5a;                            //写触发命令(0x5a)
    IAP_TRIG = 0xa5;                            //写触发命令(0xa5)
    _nop_();
    dat = IAP_DATA;                             //读IAP数据
    IapIdle();                                  //关闭IAP功能

    return dat;
}
void IapProgram(uint addr, uchar dat)
{
    
    
    IAP_CONTR = WT_12M;                         //使能IAP
    IAP_CMD = 2;                                //设置IAP写命令
    IAP_ADDRL = addr;                           //设置IAP低地址
    IAP_ADDRH = addr >> 8;                      //设置IAP高地址
    IAP_DATA = dat;                             //写IAP数据
    IAP_TRIG = 0x5a;                            //写触发命令(0x5a)
    IAP_TRIG = 0xa5;                            //写触发命令(0xa5)
    _nop_();
    IapIdle();                                  //关闭IAP功能
}
void IapErase(uint addr)
{
    
    
    IAP_CONTR = WT_12M;                         //使能IAP
    IAP_CMD = 3;                                //设置IAP擦除命令
    IAP_ADDRL = addr;                           //设置IAP低地址
    IAP_ADDRH = addr >> 8;                      //设置IAP高地址
    IAP_TRIG = 0x5a;                            //写触发命令(0x5a)
    IAP_TRIG = 0xa5;                            //写触发命令(0xa5)
    _nop_();                                    //
    IapIdle();                                  //关闭IAP功能
}
//========================================================================
// 函数: void EEPROM_read_n(uint EE_address,uchar *DataAddress,uint number)
// 描述: 从指定EEPROM首地址读出n个字节放指定的缓冲.
// 参数: EE_address:  读出EEPROM的首地址.
//       DataAddress: 读出数据放缓冲的首地址.
//       number:      读出的字节长度.
// 返回: non.
// 版本: V2.0, 2021-12-27
//========================================================================
void EEPROM_read_n(uint EE_address,uchar *DataAddress,uint number)
{
    
    
	EA = 0;		//禁止中断
	do
	{
    
    
		*DataAddress = IapRead(EE_address);			//读出数据
		EE_address++;
		DataAddress++;
	}while(--number);
	EA = 1;		//重新允许中断
}
//========================================================================
// 函数: void EEPROM_write_n(uint EE_address,uchar *DataAddress,uint number)
// 描述: 把缓冲的n个字节写入指定首地址的EEPROM.
// 参数: EE_address:  写入EEPROM的首地址.
//       DataAddress: 写入源数据的缓冲的首地址.
//       number:      写入的字节长度.
// 返回: non.
// 版本: V2.0, 2021-12-27
//========================================================================
void EEPROM_write_n(uint EE_address,uchar *DataAddress,uint number)
{
    
    
	EA = 0;		//禁止中断	
	//-----------------------------------------	
    IapErase(EE_address);
	do
	{
    
    
        IapProgram(EE_address, *DataAddress);
		EE_address++;
		DataAddress++;
	}while(--number);
	EA = 1;		//重新允许中断
}

LCD12864 serial drive

#ifndef __12864_SERIAL_H__
#define __12864_SERIAL_H__

#include "config.h"

sbit RS_CS =P0^7;//chip select 
sbit RW_SID=P0^6;//data input/output         
sbit E_CLK =P0^5;//clock input 

//sbit psb=P3^2;//串并行选择端  L串行  可直接接到L  	 可接地

#define cursor_on  0x0f 		  //开光标
#define cursor_off 0x0c 	      //关光标	 

void lcd_12864_delay(uint n);
//串行发送一字节数据
void SendByte(uchar dat);     
//写控制命令
void SendCMD(unsigned char dat);
//写显示数据或单字节字符
void SendDat(unsigned char dat);
void write_string(uchar hang,uchar add,uchar *p);
void write_BCD(uchar hang,uchar add,uchar dat);
//初始化 LCM
void LCD_Init(void);


#endif
#include "12864_serial.h"     
void lcd_12864_delay(uint n) 
{
    
      
	unsigned int i;
	 do{
    
    
	      i = 10;
		  while(--i);   
     }while(--n);
}
//串行发送一字节数据
void SendByte(uchar dat)
{
    
        
	uchar i;
	for(i=0;i<8;i++)
	{
    
    
		E_CLK=0;
		if(dat&0x80)
		RW_SID=1;
		else RW_SID=0;
		E_CLK=1;

		dat<<=1;
	}
}
      
//写控制命令
void SendCMD(unsigned char dat)
{
    
        lcd_12864_delay(30);
	 RS_CS=1;
     SendByte(0xF8);//11111,00,0 RW=0,RS=0   同步标志
     SendByte(dat&0xF0);//高四位
     SendByte((dat&0x0F)<<4);//低四位
     RS_CS=0;
	if(dat == 0x01) delay_ms(100);  //清屏指令需要延时!
}

//写显示数据或单字节字符
void SendDat(unsigned char dat)
{
    
    	lcd_12864_delay(30);
 	RS_CS=1;
 	SendByte(0xFA);//11111,01,0 RW=0,RS=1
 	SendByte(dat&0xF0);//高四位
 	SendByte((dat&0x0F)<<4);//低四位
    RS_CS=0;
}  

//void SendStr(uchar x_add,uchar code *ptr)
//{   if(x_add)
//       SendCMD(x_add);
//    //1xxx,xxxx 设定DDRAM 7位地址xxx,xxxx到地址计数器AC
//	    while(*ptr != '\0')
//             {  		SendDat(*ptr++);
//	      }
//}    
/***********************lcd12864上显示字符函数************************/
//地址:  128/16=8,一行只有8个汉字,可显示16个字符	  add<8(汉字)

void write_string(uchar hang,uchar add,uchar *p)
{
    
    
	uchar number=0;
	if(hang==1)   
		SendCMD(0x80+add);
	else if(hang==2)
		SendCMD(0x90+add);
	else if(hang==3)
		SendCMD(0x88+add);
	else 
		SendCMD(0x98+add);

	while(*p != '\0' && number<16)
	{
    
      		
		SendDat(*p++);
		number++;
	}	
}
void write_BCD(uchar hang,uchar add,uchar dat)
{
    
    
	uchar a=0,b=0;
	a=dat/16;
	b=dat%16;
	if(hang==1)   
		SendCMD(0x80+add);
	else if(hang==2)
		SendCMD(0x90+add);
	else if(hang==3)
		SendCMD(0x88+add);
	else 
		SendCMD(0x98+add);
	if(a<10)
	{
    
    
		SendDat(0x30+a);			
	}
	else if(a==10)
	{
    
    
		SendDat('A');	
	}
	else if(a==11)
	{
    
    
		SendDat('B');	
	}
	
	else if(a==12)
	{
    
    
		SendDat('C');	
	}
	else if(a==13)
	{
    
    
		SendDat('D');	
	}
	else if(a==14)
	{
    
    
		SendDat('E');	
	}
	else if(a==15)
	{
    
    
		SendDat('F');	
	}
	else{
    
    }	
	if(b<10)
	{
    
    
		SendDat(0x30+b);			
	}
	else if(b==10)
	{
    
    
		SendDat('A');	
	}
	else if(b==11)
	{
    
    
		SendDat('B');	
	}
	
	else if(b==12)
	{
    
    
		SendDat('C');	
	}
	else if(b==13)
	{
    
    
		SendDat('D');	
	}
	else if(b==14)
	{
    
    
		SendDat('E');	
	}
	else if(b==15)
	{
    
    
		SendDat('F');	
	}
	else{
    
    }	
}
//初始化 LCM
void LCD_Init(void)
{
    
      
	P0M1 &= ~(1<<5);	//设置成准双向IO
	P0M0 &= ~(1<<5);
	
	P0M1 &= ~(1<<6);	//设置成准双向IO
	P0M0 &= ~(1<<6);

	P0M1 &= ~(1<<7);	//设置成准双向IO
	P0M0 &= ~(1<<7);
	
	
//	psb=0;			//可接地
    RS_CS=0;
    lcd_12864_delay(100);
	SendCMD(0x30);//功能设定
	SendCMD(0x0C);//0000,1100 整体显示,游标off,游标位置	    
	SendCMD(0x01);//清除显示
	write_string(1,0,"    欢迎使用    ");
	write_string(2,0,"  ****学院  ");
	write_string(3,0,"学生门禁管理系统");
	write_string(4,0,"设计人:    **");	
	delay_ms(3000);	   
//	SendCMD(0x01);//清除显示
}

PS: Since the previous article has an RFID code, it will not be posted here. If you are interested, you can read the previous article.

Guess you like

Origin blog.csdn.net/qq_20467929/article/details/126141011