HYLOVEYOURSELF

小洋宝的进步史

导航

矩阵式键盘数字密码锁

矩阵式键盘数字密码锁设计

一、实验目的

  1. 掌握微机系统总线与各芯片管脚连接方法,提高接口扩展硬件电路的连接能力。
  2. 初步掌握键盘扫描,密码修改和计时报警程序的编写方法。
  3. 掌握通过矩阵式键盘扫描实现密码锁功能的设计思路和实现方法。

二、实验内容

根据设定好的密码,采用 4x4 矩阵键盘实现密码的输入功能。当密码输入正确之后,锁就打开(绿灯亮),10 秒之后,锁自动关闭(红灯亮);如果连续输入三次密码不正确,就锁定按键 5 秒钟,同时发出报警(黄灯闪),5 秒后,解除按键锁定,恢复密码输入。

三、系统功能与设计要求

1.基本功能要求

  1. 具有开锁、修改用户密码等基本的密码锁功能。
  2. 对于超过 3 次密码密码错误,锁定键盘 5 秒,系统报警。5 秒后解除锁定。
  3. 通过 LCD 字符液晶和 LED 指示灯(红,绿,黄)实时显示相关信息。
  4. 用户密码为 6 位数字,显示采用 “*” 号表示。
  5. 密码锁键盘设计合理,功能完善,方便用户使用。

2.相关提示

数字密码锁操作键盘自行设计。用户初始密码为“123456”,系统加电运行后,密码锁初始状态为常闭(红灯亮),用户可以选择开锁或修改密码:

如果选择开锁就按“Open”键,系统提示输入密码,输入用户密码+“#”键后,如果密码正确,就打开锁(绿灯亮),系统等待 10 秒,然后重新关闭密码锁,若密码错,提示重新输入,连续三次错误,提示警告词同时报警(黄灯闪),锁定键盘 5 秒,然后重新进入初始状态;

如果选择修改密码就按”Modify Secret”键,系统提示输入旧密码,输入旧密码+“#”键后,如果正确,系统提示输入新密码,输入新密码+“#”后,新密码起效,重新进入初始状态;如果旧密码错,不能修改密码,密码锁直接进入初始状态。

3.我们的附加实现

(1)增加管理员(Admin)功能

如果用户忘记密码可向管理员求助。管理员密码为 8 位数字(系统内预先已设定,我们默认为“12345678”),管理员按“Admin”键后,系统提示输入管理员密码,输入管理员密码+“#”键后,如果正确,系统自动恢复用户初始密码为“123456”;如果错误,程序停止运行,系统退出。

(2)增加组合键(Shift)功能

使系统的密码选择范围除数字外,另外增加a,b,c,d,e,f,g,h,i,j 等 10 个字母。数字直接输入,字母“Shift”+“字母”。

(3)增加输入清除功能(Delete)

在输入密码过程中,如果中途按下“Del”键,则清除前面的输入,开始重新输入密码。

*用户的密码输入部分可以实现“退格”,管理员的密码输入部分可以实现“清空”。

(4)增加密码输入错误提示功能

用户第一次输入密码错误会提醒“还有两次机会”,第二次输入密码错误会提醒“还有一次机会”。

(5)增加密码输入阈值

管理员输入密码错误次数大于三次,就会转回到最初的模式选择页面。

四、实验环境

1.硬件配置:

微机一台 (Pentium 4)

微机接口技术实验箱 一个

ISA – PCI 转接卡 一块

连接电缆 一条

万用表 一块

微机接口技术实验讲义 一本

连接导线

2.软件环境:

Windows XP/2000/Win 7 平台

Visual C++ 6.0 编译器

五、设计思路

  1. 延时时间通过计数/定时器(8253)来控制。8253的时钟源采用时钟信号发生器与分频电路提供,通过计算获得计数初值,按照设定的工作方式获得精确的延时时间。
  2. 密码锁键盘采用4x4矩阵键盘,液晶显示LCD和LED灯可以采用系统提供的相应模块。
  3. 控制通过8255可编程并行接口,如:PA口控制LCD液晶显示,PB口和PC口低四位控制键盘扫描,PC口高四位控制LED灯。
  4. 编程通过键盘扫描实时处理键盘输入数据,完成密码锁相关操作。

1.硬件设计连接图

F5区:键盘LED

D3区:8255

A3区:与总线的接口部分

F8区:蜂鸣器

F4区 :发光管

A1区:液晶屏

image-20240323153554543

2.密码锁键盘设计图

image-20240323154351273

3.运行流程图

image-20240323155608253

4.硬件连线图

image-20240323155739621

六、代码分析

实验过程中,我们参考了PC中的很多实验例程,如

image-20240323160110316

先后完成了液晶显示器功能,并且借助字模转换器实现了符号点阵图的提取,接着完成了左右半屏的基本控制模块,实现了左右半屏文字分布的控制以及清屏功能,实现了字符串的显示;接着我们通过各端口号配置了8255,实现了延时子程序、判断是否有键被按下、读取键盘输入、shift键获取字母、灯的闪烁以及蜂鸣器发出警报声等功能。

image-20240323160649140

下面是我们原创性较高的功能函数部分:

1.密码比较模块

u16 checkPwd()
{
	int i = 0;
	u8 buf[7];
	
	//	u16 inputPassword = 0;
	// 重复扫描6次键盘输入
	//for(i = 0;i < 6;)
	while(i < 6)
	{	
		
	flag1:	buf[i] = key();
		if(buf[i] == 0x0f)    // 若按下了我们设定的微机键盘del键,则清屏后重新输入密码
		{
			i--;		
			if(i<0) i = 0; 
			LCD_INIT();       // 液晶初始化
			showStars(i-1);
			continue;         // 进入下一循环
		}
		if(i < 6)
		{
			if(buf[i] == 0x0e)
				buf[i] = shift();	
			else
				buf[i] += (u8)'0';
		
			LCD_INIT();       // 清屏,液晶初始化
			if(i == 0)
				show1Star();  // 按下1个键,显示1个*
			else if(i == 1)
				show2Stars();  // 按下2个键,显示2个*
			else if(i == 2)
				show3Stars();  // 按下3个键,显示3个*
			else if(i == 3)
				show4Stars();  // 按下4个键,显示4个*
			else if(i == 4)
				show5Stars();  // 按下5个键,显示5个*
			else if(i == 5)
				show6Stars();  // 按下6个键,显示6个*
			
		}
		i++;

                
	}
	
	while(1)
	{
        //依位比较输入密码和保存的密码,如果中间有一位不匹配,则返回0,完全匹配说明密码正确
		u8 temp = key();
		if(temp == 0x0f)
		{	
			i--;			  
			if(i<0) i = 0; 
			LCD_INIT();       // 液晶初始化
			showStars(i-1);
			goto flag1;
		} 
		if(temp == 0x0a) { 
			for(i = 0; i < 6; i++)
			{
				if(buf[i] != pwd[i])
					return 0;
			}
			return 1;
		}	
	}	
	
}

输入密码并与原密码进行比较,如果正确则返回1,否则返回0。这段代码的巧妙之处在于,我们实现了按位删除,扩大了对应的数组进行最后一位是删除还是#或者是其他字符的判断;另外巧妙使用了无条件跳转”goto“。

2.更改密码模块

void changePwd()
{
	int i = 0;
	u8 buf[7];
	//u16 inputPassword = 0;
	// 重复6次读取键盘输入
	//for(i = 0;i < 6;)
	while(i < 6)
	{
	flag2:	buf[i] = key();
		if(buf[i] == 0x0f)    // 若按下了我们设定的微机键盘del键,则清屏后重新输入密码
		{
			i--;		  
			if(i<0) i = 0;
			LCD_INIT();       // 液晶初始化
			showStars(i-1);
			continue;         // 进入下一循环
		}
		if(i < 6)
		{
			if(buf[i] == 0x0e) //如果按下shift键
				buf[i] = shift();	//获取字母型变量,原先0-9的数字键现在变为a-j字母键
			else //如果未按下shift键
				buf[i] += (u8)'0'; //数字变量要转成unsigned char类型,即转成ASCII码型数字,方便显示
			LCD_INIT();
        	
		
			switch(i)
			{
				case 0:
					show1Star();
					break;
				case 1:
					show2Stars();
					break;
				case 2:
					show3Stars();
					break;
				case 3:
					show4Stars();
					break;
				case 4:
					show5Stars();
					break;
				case 5:
					show6Stars();
					break;
			}
			
		}
		i++;
		
	}
	while(1)
	{	u8 temp = key();
		if(temp == 0x0f)
		{	
			i--;			
			if(i<0) i = 0; 
			LCD_INIT();       // 液晶初始化
			showStars(i-1);
			goto flag2;
		} 
		if(temp == 0x0a) { //依位次替换原先密码为新密码
			for(i = 0; i < 6; i++)
				pwd[i] = buf[i];
			break;
		}		
	}
	
}

//修改密码,如果修改密码成功,返回1,否则返回0
u16 modify()
{
	if(checkPwd())   // 首先让用户重新输入密码并与原密码进行比较,如果正确则返回1,否则返回0
	{   // 原密码输入正确
		LCD_INIT();       // 清屏,液晶初始化
		showNewPwd();      // 显示"新的密码"汉字
		changePwd(); // 让用户输入新密码,实现更改密码
		return 1;
	}
	else
		return 0;
}

这段代码比较好的地方在于实现了对输入字母还是数字的分开处理。液晶初始化也完成了对应的刷新功能。

3.管理员功能

//管理员功能:如果管理员密码输入正确,则将开锁密码重置为123456,并返回1,管理员密码只允许数字出现。
u16 adminOption()
{
	u8 i;
	u16 buf[8];
	u16 errornumber=0;
	while(1)
	{
		u16 inputPassword = 0;   // !!!!!!!!!初始化!!!!!!!!!
		for(i = 0;i < 8;i++)     // 管理员输入密码(扫描8次键盘)
		{
			buf[i] = key();
			if(buf[i] == 0x0f)    // 若按下了我们设定的微机键盘del键,则清屏后重新输入密码
			{
				i = -1;			  // 先置i=-1,以使continue之后i=0,可以继续按键盘6次
				LCD_INIT();       // 液晶初始化
				showReEnter();     // 显示"重新输入"汉字
				delayTime();      // 延时一段时间
				LCD_INIT();       // 液晶初始化
				continue;         // 进入下一循环
			}
			LCD_INIT();
			switch(i)
			{
				case 0:
					show1Star();
					break;
				case 1:
					show2Stars();
					break;
				case 2:
					show3Stars();
					break;
				case 3:
					show4Stars();
					break;
				case 4:
					show5Stars();
					break;
				case 5:
					show6Stars();
					break;
				case 6:
					show7Stars();
					break;
				case 7:
					show8Stars();
					break;
			}
		}
	
		for(i = 0; i < 8; i++)   // 计算管理员密码对应的十进制值
		{
			inputPassword = inputPassword*10 + buf[i];
		}
		while(1)
		{
			if(key() == 0x0a)
				break;
		}
		if(inputPassword == adminPassword)
		{
			//password = 123456; // 重置密码为123456
			for(i = 0; i < 6; i++)
			{
				pwd[i] = i + (u8)'1';
			}
			LCD_INIT();        // 液晶初始化
			showCorrectPwd();        // 显示密码正确
			delayTime();
			break;
		}
		else
		{
		    errornumber++;
		    if(errornumber==3)
		        return 0;
			LCD_INIT();    // 液晶初始化
			showReEnter();  // 显示重新输入
			
			delayTime();
		}
	}
	return 1;
}

这段代码比较巧妙的部分在于errornumber的设置,让管理员不再一直循环在”输入密码-输入错误-重新输入-输入错误“的循环中。另外,管理员密码是按照整数进行比较的,每位*10的循环也是一个亮点。

4.错误密码处理

u16 openLock()
{
	u16 errorcount = 0;
	u16  t;
	while(1)
	{
		// 若输错3次,返回0
		if(errorcount >= 3)   
			return 0;
		// 若输错没到3次,液晶显示提示信息"再次输入"
		if(errorcount != 0 && errorcount != 3)
		{
			LCD_INIT();					
			delayTime();
			//showEnterAgain();       // 第2行显示"再次输入"
			
			if(errorcount == 1)
	     	{
	 		   showEntertwo();
	        }
	    //若输错2次,液晶显示提示信息“还有一次机会”
	    	if(errorcount == 2)
	     	{
			   showEnterone();
	        }
		}

		t = checkPwd();  // 输入密码并与原密码进行比较,如果正确则返回1,否则返回0
		if(t)
			return 1;
		else 
			errorcount++;     // 输入错误,error数加一
	}
}

a键代表开锁,如果开锁成功则返回1,如果密码错误超过三次则返回0。这里的“还有一次机会”、‘’还有两次机会“是实现的亮点,我认为这与用户间提供了更好的交互功能。

5.主函数部分

void main()
{
	outportb(CON_Addr, 0x81);	// 写控制字1000 0001————A口、B口方式0,输出;C口低4位:输入
	outportb(CON_Addr,0x0f);    // 写控制字0000 1111————C口位操作:将PC7置位,控制蜂鸣器
	blackl();    			    // 一加电应该保持8个LED灯全灭
	while(1)
	{
		//液晶显示 请输入按键
		LCD_INIT();					
		delayTime();
		showInputButton();
		tt = key();
		// 输入a,尝试开锁
		if(tt == 0x0a)   		
		{
			LCD_INIT();
			delayTime();
			showEnterPwd();			// 第2行显示"输入密码"

			// 如果开锁成功则返回1,如果密码错误超过三次则返回0
			if(openLock())
			{
				LCD_INIT();		// 液晶初始化
				delayTime();
				showCorrectPwd();     // 第2行显示"密码正确"
				delayTime();
				greenl();       // 绿灯亮10s
				redl();         // 红灯亮5s
				blackl();       // 全熄灭
				continue;       // 进入下一循环
			}

			// 三次密码错误,锁定系统
			else				
			{
				LCD_INIT();					
				delayTime();
				showSystemLocked();     // 第2行显示"系统锁定"
				yellowl();		// 黄灯闪烁5s
				continue;       // 进入下一循环
			}
		}

		// 输入b,修改密码功能	
		else if(tt == 0x0b)
		{
			// 打印输入原密码
			LCD_INIT();
			showUsedPwd();
			if(modify())   	    // 修改密码,如果修改密码成功,返回1,否则返回0
			{
				LCD_INIT();
				showModifiedSuccess();
				delayTime();
			}
		}

		//输入c,进入管理员功能:将开锁密码重置为123456
		else if(tt == 0x0c)    
		{
			LCD_INIT();
			showEnterPwd();        // 第2行显示"输入密码"
			delayTime();
			if(adminOption())        // adminOption()函数:如果管理员密码输入正确,将开锁密码重置为123456并返回1
			{
				LCD_INIT();
			  	showResetSuccess();   // 显示"重置成功"
			  	delayTime();
			}
		}
	}
}

主函数部分很好地完成了分模块处理。

七、实验测试

1.按”#“键,进入输入用户密码部分;

2.输入”123456“按”#“键,显示”密码正确“,返回”输入按键“页面;

3.按”#“键,进入输入用户密码部分;

4.输入”123454“,密码错误,显示‘’还有两次机会“;

5.输入”12345a“,密码错误,显示 “还有一次机会”;

6.输入”12345b“,密码错误,显示"系统锁定",黄灯闪烁伴有蜂鸣器警告,返回”输入按键“页面;

7.输入”Modify“键,输入正确旧密码后可以修改新密码为”123457“,返回”输入按键“页面;

8.输入”Admin“键,三次以上输入错误密码会返回”输入按键“页面,按”del“可以进行退格操作;

9.输入”Admin“键,输入密码”12345678“,可初始化用户密码为”123456“;

10.按”#“键,进入输入用户密码部分,输入”123456“,显示”密码正确“。

posted on 2024-05-25 11:09  岁月月宝贝  阅读(30)  评论(1编辑  收藏  举报