课程设计题十二:电子密码锁

要求:

1、在锁开的状态下输入密码,设置的密码共6位,用数据开关K1K10分别代表数字1、2、、9、0,输入的密码用1602显示,可删除输入的数字,删除的是最后输入的数字,每删除一位。

2、可以修改密码,断电不掉数据。

3、三次密码输入错误,开始警报,需要按下复位才能重新输入。

获取该程序的方式:

1、优快云下载:

https://download.youkuaiyun.com/download/qq_38351824/11418941

2、关注微信公众号下载:

     ① 关注微信公众号:Tech云  

     ②

3、可以关注点赞并在下方评论,我给你邮箱发过去。

一、Protues仿真图:

二、程序源码:

因为注释非常的全,这里就不再进行讲解了。

/*******************************************************************************
================================================================================
【平    台】STC89C51_sumjess平台
【编    写】sumjess
【E-mail  】1371129880@qq.com
【软件版本】V2.0
【最后更新】2019年06月10日
【相关信息参考下列地址】
【网    站】
           https://blog.youkuaiyun.com/qq_38351824
           http://www.51hei.com/bbs/mcu-2-1.html
---------------------------------------------------------------------------------
【dev.env.】MDK4.02及以上版本
【Target  】STC89C51
第一次修订:2019/05/09
第二次修订:2019/05/21
第三次修订:2019/06/10
【problem 】
    (1)库内补充的不全面;
    (2)库内解释部分不全面;
    (3)库内还存在一定的bug;
【direction】
      下一步的目标就是把库继续集成!
【explain 】
      为了方便使用,我也自己写了很多的库,和优化了算法和表示方式!
【warning】
      目前程序中暂无错误 !   
---------------------------------------------------------------------------------
没有完美的代码,只有不断的奉献,大家一起努力;
赠人玫瑰手留余香,欢迎大家反馈bug!
================================================================================
********************************************************************************/	
#include<reg51.h>
#include<intrins.h>

#define uchar unsigned char 
#define uint  unsigned int
 
sbit beep=P2^4;//蜂鸣器接口
sbit D1=P2^2;  //开锁信号
sbit k1=P3^2;  //恢复初始密码按键
sbit RS=P2^7;  //数据命令选择 
sbit RW=P2^6;  //读写控制
sbit E=P2^5;   //液晶使能 
sbit SDA=P2^1; //数据线接口
sbit SCL=P2^0; //时钟线接口 
 
uchar idata table1[6]={1,2,3,4,5,6}; //初始密码
uchar dd; 
uchar aa;//存放密码错误的次数,够三次报警
uchar bb;
uchar cc;
//延时子函数
void delay1(uint z)
{
	uint x,y;
	for(x=0;x<z;x++)
		for(y=0;y<110;y++);
}
void delay2() 
{
	;;
}
//总线初始化子函数
void i2cinit()
{
	SDA=1;
	delay2();
	SCL=1;
	delay2();
}
//启动信号子函数
void start()
{
	SDA=1;
	SCL=1;
	delay2();
	SDA=0;
	delay2();
}
//停止信号子函数
void stop()
{
	SDA=0;
	delay2();
	SCL=1;
	delay2();
	SDA=1;
	delay2();
}
//应答信号子函数
void respons()
{
	uchar i=0;
	SCL=1;
	delay2();
	while(SDA==1&&i<255)//等待应答,过一段时间不应答退出循环
		i++;
	SCL=0;
	delay2();
}
//写一个字节子函数
void writebyte(uchar date)
{
	uchar i,temp;
	temp=date;
	for(i=0;i<8;i++)
	{
		temp<<=1;//temp左移一位后高位进CY
		SCL=0;
		delay2();
		SDA=CY;
		delay2();
		SCL=1;
		delay2();
	}	
	SCL=0;//应答信号中SCL = 1,所以这里要置0
	delay2();
	SDA=1;//用完要释放数据总线
	delay2();
}
//读一个字节子函数
uchar readbyte() 
{
	uchar i,k;
	SCL=0;
	delay2();
	SDA=1;
	for(i=0;i<8;i++)
	{
		SCL=1;	
		delay2();
		k=(k<<1)|SDA; //和最低位或,一位位送到K
		SCL=0;
		delay2();
	}
	delay2();
	return k;
}
//向地址写一个字节数据子函数
void write_add(uchar address,uchar date)
{
	start();
	writebyte(0xa0);//A0,A1,A2接地,AT24C02芯片地址为1010,送控制字为1010A2A1A0R/~W
	respons();
	writebyte(address);
	respons();
	writebyte(date);
	respons();
	stop();
}
//向地址读一个字节数据子函数
uchar read_add(uchar address)
{
	uchar date;
	start();
	writebyte(0xa0);//A0,A1,A2接地,AT24C02芯片地址为1010,送控制字为1010A2A1A0R/~W
	respons();
	writebyte(address);
	respons();
	start();
	writebyte(0xa1);//A0,A1,A2接地,AT24C02芯片地址为1010,送控制字为1010A2A1A0R/~W
	respons();
	date=readbyte();
	stop();
	return date;
}
//向地址写n个字节数据子函数
void write_n_add(uchar *p,uchar address,uchar n)
{
	uchar i;
	for(i=0;i<n;i++)
	{
		write_add((address+i),*(p+i));
		delay1(20);//一定要适当延时,不然写不进去
	}
}
//向地址读n个字节数据子函数
void read_n_add(uchar *p,uchar address,uchar n)
{
	uchar i;
	for(i=0;i<n;i++)
	{
		*(p+i)=read_add(address+i);	
	}
}
//LCD1602液晶读忙子函数
bit LCD1602_busy()
{                          
    bit a;
    RS=0;
    RW=1;
    E=1;
    _nop_();
    _nop_();
    a=(bit)(P0&0x80);
    E=0;
    return a; 
}
//LCD1602液晶写命令子函数
void write_com(uchar com) 
{
	while(LCD1602_busy());
    RW=0;
	RS=0;
    E=0;
	P0=com;
	delay1(5);
    E=1;
	delay1(5);
    E=0;
}
//LCD1602液晶写数据子函数
void write_date(uchar date)
{
	while(LCD1602_busy());
    RW=0;
  	RS=1;
    E=0;
  	P0=date;
	delay1(5);
    E=1;
	delay1(5);
    E=0;          
}
//写一个字符子函数
void write_1_char(uchar zifu)
{
	write_date(zifu);	
}
//向液晶写n个字符子函数
void write_n_char(uchar zifu[])
{
	uchar i;
	for(i=0;;i++)
	{
		write_1_char(zifu[i]);
		if(zifu[i+1]=='\0')
			break;
	}
}
//设置液晶显示位置子函数
void LCD1602_pos(uchar x,uchar y) 
{
	uchar pos;
	if(x==0)
		x=0x80;
	else if(x==1)
		x=0x80+0x40;
	pos=x+y;
	write_com(pos);
}
//LCD1602液晶初始化子函数
void LCD1602_init()
{
    E=0;
    write_com(0x38);//设置16x2显示,5x7点阵,8位数据口 
    write_com(0x0c);//设置开显示,不显示光标 
    write_com(0x06);//写一个字符后地址指针加1 
	write_com(0x01);//显示清0,数据指针清0         
}
//报警子函数
void baojing1()
{
	int i=0;
	for(i=0;i<5;i++)
	{
		beep=1;
		D1=0;
		delay1(5);
		beep=0;
		D1=1;
		delay1(5);	
	}
}
void baojing2()
{
	uchar i;
	for(i=0;i<10;i++)
	{
		baojing1();
	}
}
//矩阵按键扫描子函数
uchar keyscan()
{
	uchar temp,key;
	key=0xff;
	P1=0xfe; //将第一行线置低电平
	temp=P1;//读JPJK的当前状态到 temp
	temp&=0xf0;// temp = temp & 0xf0 按位与 
	if(temp!=0xf0)
	{
		delay1(10);//延时去抖
		temp=P1;
		temp&=0xf0;
	   	if(temp!=0xf0)//第一行有键被按下
		{
			temp=P1;//读被按下的键
			baojing1();
			switch(temp)
			{
				case 0xee: 	key=1;
							break;
				case 0xde: 	key=2;
							break;
				case 0xbe: 	key=3;
							break;
				case 0x7e: 	key=0x0a;
							break;
			}
			while(temp!=0xf0)//等待按键释放
			{
				temp=P1;
				temp&=0xf0;
			}
		}
	}
	P1=0xfd; //将第二行线置低电平
	temp=P1;//读JPJK的当前状态到 temp
	temp&=0xf0;// temp = temp & 0xf0
	if(temp!=0xf0)
	{
		delay1(10);//延时去抖
		temp=P1;
		temp&=0xf0;
	   	if(temp!=0xf0)//第二行有键被按下
		{
			temp=P1;//读被按下的键
			baojing1();
			switch(temp)
			{
				case 0xed: 	key=4;
							break;
				case 0xdd: 	key=5;
							break;
				case 0xbd: 	key=6;
							break;
				case 0x7d: 	key=0x0b;
							break;
			}
			while(temp!=0xf0)//等待按键释放
			{
				temp=P1;
				temp&=0xf0;
			}
		}
	}
	P1=0xfb; //将第 三行线置低电平
	temp=P1;//读JPJK的当前状态到 temp
	temp&=0xf0;// temp = temp & 0xf0
	if(temp!=0xf0)
	{
		delay1(10);//延时去抖
		temp=P1;
		temp&=0xf0;
	   	if(temp!=0xf0)//第三行有键被按下
		{
			temp=P1;//读被按下的键
			baojing1();
			switch(temp)
			{
				case 0xeb: 	key=7;
							break;
				case 0xdb: 	key=8;
							break;
				case 0xbb: 	key=9;
							break;
				case 0x7b: 	key=0x0c;
							break;
			}
			while(temp!=0xf0)//等待按键释放
			{
				temp=P1;
				temp&=0xf0;
			}
		}
	}
	P1=0xf7; //将第四行线置低电平
	temp=P1;//读JPJK的当前状态到 temp
	temp&=0xf0;// temp = temp & 0xf0
	if(temp!=0xf0)
	{
		delay1(10);//延时去抖
		temp=P1;
		temp&=0xf0;
	   	if(temp!=0xf0)//第四行有键被按下
		{
			temp=P1;//读被按下的键
			baojing1();
			switch(temp)
			{
				case 0xe7: 	key=0;
							break;
				case 0xd7: 	key=0;
							break;
				case 0xb7: 	key=0x0f;
							break;
				case 0x77: 	key=0x0d;
							break;
			}
			while(temp!=0xf0)//等待按键释放
			{
				temp=P1;
				temp&=0xf0;
			}
		}
	}
   	return key; //返回按下的键 
}
//比较密码子函数
bit sfj1(uchar *string1,uchar *string2)
{
	uchar i;
	for(i=0;i<6;i++)
	{
		if(string1[i]!=string2[i])
			return 0;
	}
	return 1;
}
//选择输入密码或修改密码函数
uchar step_choose()
{
	uchar key;
	key=0xff;
	write_com(0x06);//写一个字符后地址指针加 1 
    write_com(0x01);//显示清零,数据指针清零
	LCD1602_pos(0,0);
	write_n_char(" Input password ");
	LCD1602_pos(1,0);
	write_n_char("  Press key A  ");	
	while((key!=0x0a)&&(key!=B))
		key=keyscan();	
	return key;
}
//输入密码子函数
bit input_mima(uchar * mima)
{
	uchar i,key;
	LCD1602_pos(1,0);
	for(i=0;i<7;i++)
	{
		delay1(100);
		if(i<6)
		{
			do
			{
				key=keyscan();
			}//扫描键盘
			while(key==0xff);
			if((key!=0x0f)&&(key!=0x0a)&&(key!=0x0c))//不是退格也不是确认键
			{
				write_date('*');//是数字键显示*
				mima[i]=key;
			}
			if(key==0x0f)//是退格键
			{
				if(i>0)
				{
				    LCD1602_pos(1,--i);//光标前移一位
					write_date(' ');//清空一位
					mima[i]=' ';//写空
					LCD1602_pos(1,i);
					i--;//密码计数器减一 ,因为循环后会+1,所以在这里要加1
				}
			}
			if(key==0x0c)//没完成密码输入返回错误信息
			{
				LCD1602_pos(0,0);
				return(0);
			}
		}
		if(i==6)
		{
			do
			{
				key=keyscan();
			}
			while((key!=0x0f)&&(key!=0x0c));
			if(key==0x0f)
			{
				LCD1602_pos(1,--i);
				write_date(' ');
				mima[i]=' ';
				LCD1602_pos(1,i);
				i--;
			}
			if(key==0x0c)//密码位数正确
			{
				return(1);//返回1正确信号
			}
		}
	}	
}
//密码处理子函数
void sfj2() 
{
	uchar key,i;
	uchar idata table2[6]={' ',' ',' ',' ',' ',' '};//存放密码缓冲区
	uchar idata table3[6]={' ',' ',' ',' ',' ',' '};
	uchar idata table4[6]={' ',' ',' ',' ',' ',' '};
	key=step_choose();
	if(key==0x0a)//A被按下,接收输入密码,处理
	{
		read_n_add(table2,0x00,6);
		write_com(0x06);//写一个字符后地址指针加 1 
		write_com(0x01);//显示清零,数据指针清零
		write_com(0x0f);//显示光标
		LCD1602_pos(0,0);
		write_n_char(" press password ");		
		if(input_mima(table3)) //处理输入密码
		{
			if(sfj1(table3,table2)) //密码正确
			{
				LCD1602_pos(0,0);
				write_com(0x0c);
	        	write_com(0x06);//写一个字符后地址指针加 1 
	         	write_com(0x01);//显示清零,数据指针清零
				write_n_char(" password right ");
				aa=0; //清除密码错误次数
				D1=0; //开锁
				beep=1; //响一下
				delay1(1000);
				beep=0;
				TR0=1;
				cc=1;
				while(key!=0x0d&&cc) //D没按下一直开
				{			
					key=keyscan();
				}
				TR0=0;
				D1=1;//D按下了关锁
			}
			else //密码 不正确
			{
				LCD1602_pos(0,0);
				write_com(0x0c); //关光标
				write_com(0x06);//写一个字符后地址指针加 1 
				write_com(0x01);//显示清零,数据指针清零
				write_n_char(" password wrong");
				delay1(1000);
				aa++;
				if(aa==4)
				{
					aa=0;
			    	i=20; //密码不正确报警
					while(i--)
					 	baojing2();
				}
			}
		}
		else //密码没有输入正确或完成
		{
			LCD1602_pos(0,0);
			write_com(0x0c); //关光标
	   		write_com(0x06);//写一个字符后地址指针加 1 
		   	write_com(0x01);//显示清零,数据指针清零
			write_n_char(" password wrong");
			delay1(1000);
			aa++;
			if(aa==4)
			{
				aa=0;
		    	i=20; //密码不正确报警
				while(i--)
				 	baojing2();
			}
		}
	}
	if(key==0x0b)//B被按下,修改密码
	{
		read_n_add(table2,0x00,6);
		write_com(0x06);//写一个字符后地址指针加 1 
		write_com(0x01);//显示清零,数据指针清零
		write_com(0x0f);//显示光标
		LCD1602_pos(0,0);
		write_n_char(" input password");		
		write_com(0x0f);//显示光标	
		if(input_mima(table3)) //处理输入密码
		{
			if(sfj1(table3,table2)) //密码正确
			{
				LCD1602_pos(0,0);
				write_com(0x0c);
	      		write_com(0x06);//写一个字符后地址指针加 1 
	      		write_com(0x01);//显示清零,数据指针清零
				write_n_char("password right ");
				aa=0; //清除密码错误次数
				delay1(1500);
				dd=1;
				while(dd) //下面开始修改密码
				{
					write_com(0x06);//写一个字符后地址指针加 1 
					write_com(0x01);//显示清零,数据指针清零
					write_com(0x0f);//显示光标
					LCD1602_pos(0,0);
					write_n_char("In new password");
					delay1(1500);
					if(input_mima(table3)) //处理输入密码
					{
						LCD1602_pos(0,0);
						write_com(0x0c);
			         	write_com(0x06);//写一个字符后地址指针加 1 
			         	write_com(0x01);//显示清零,数据指针清零
						write_n_char("Input new pass"); //确定新密码
						LCD1602_pos(1,0);
						write_n_char("word again");
						delay1(2000);
						LCD1602_pos(0,0);
						write_com(0x0f);//显示光标
			         	write_com(0x06);//写一个字符后地址指针加 1 
			         	write_com(0x01);//显示清零,数据指针清零
						write_n_char("In new password");						
						if(input_mima(table4)) //处理输入密码
						{
							if(sfj1(table3,table4)) //密码正确
							{
								LCD1602_pos(0,0);
								write_com(0x0c);
						      	write_com(0x06);//写一个字符后地址指针加 1 
						      	write_com(0x01);//显示清零,数据指针清零
								write_n_char("password has");
								LCD1602_pos(1,0);
								write_n_char("change already");
								write_n_add(table4,0x00,6); //把修改的密码存进24C02
								delay1(2000);
								dd=0;
							}
							else //密码 不正确
							{
								LCD1602_pos(0,0);
								write_com(0x0c); //关光标
								write_com(0x06);//写一个字符后地址指针加 1 
								write_com(0x01);//显示清零,数据指针清零
								write_n_char("password wrong");
								delay1(1000);
								aa++;
								if(aa==4)
								{
									aa=0;
								   	i=20; //3次输入密码不正确报警
									while(i--)
										baojing2();
								}
								dd=0;
							}
						}
						else //密码没有输入正确或完成
						{
							LCD1602_pos(0,0);
							write_com(0x0c); //关光标
						   	write_com(0x06);//写一个字符后地址指针加 1 
							write_com(0x01);//显示清零,数据指针清零
							write_n_char(" password wrong");
							delay1(1000);
							aa++;
							if(aa==4)
							{
								aa=0;
							    i=20; //3次输入密码不正确报警
								while(i--)
									baojing2();
							}
						}	
					}
					else //密码没有输入正确或完成
					{
						LCD1602_pos(0,0);
						write_com(0x0c); //关光标
				   		write_com(0x06);//写一个字符后地址指针加 1 
					   	write_com(0x01);//显示清零,数据指针清零
						write_n_char("password wrong");
						delay1(1000);
						dd=0;
						aa++;
						if(aa==4)
						{
							aa=0;
					    	i=20; //3次输入密码不正确报警
							while(i--)
							 	baojing2();
						}
					}									
				}
			}
			else //密码 不正确
			{
				LCD1602_pos(0,0);
				write_com(0x0c); //关光标
				write_com(0x06);//写一个字符后地址指针加 1 
				write_com(0x01);//显示清零,数据指针清零
				write_n_char("password wrong");
				delay1(1000);
				aa++;
				if(aa==4)
				{
					aa=0;
			    	i=20; //3次输入密码不正确报警
					while(i--)
					 	baojing2();
				}
			}
		}
		else //密码没有输入正确或完成
		{
			LCD1602_pos(0,0);
			write_com(0x0c); //关光标
	   		write_com(0x06);//写一个字符后地址指针加 1 
		   	write_com(0x01);//显示清零,数据指针清零
			write_n_char("password wrong");
			delay1(1000);
			aa++;
			if(aa==4)
			{
				aa=0;
		    	i=20; //3次输入密码不正确报警
				while(i--)
				 	baojing2();
			}
		}		
	}
}
//主函数
void main()
{
	LCD1602_init();//调用液晶初始化子函数
	i2cinit();//调用24C02总线初始化子函数
	beep=0;
	D1=1; //关锁
	TMOD=0x01;//选择定时器0方式1
	EA=1;//打开总中断
	ET0=1;//打开定时器0中断
	EX0=1; //打开外部中断0
	IT0=1;//下降沿触发
	TR0=0;//关闭定时器
	TH0=0x4c;//50ms装初值
	TL0=0x00;
	while(1)
	{
	  	sfj2();//调用密码处理子函数 
	}
}
//外部中断0子函数
void wb0() interrupt 0
{
	delay1(2000);
	if(!k1)
	{
		LCD1602_pos(0,0);
		write_com(0x0c); //关光标
	   	write_com(0x06);//写一个字符后地址指针加 1 
		write_com(0x01);//显示清零,数据指针清零
		i2cinit();//24C02总线初始化
		write_n_add(table1,0x00,6);
		write_n_char("password renew");
		LCD1602_pos(1,0);
		write_n_char("already");
		delay1(1000);
		LCD1602_pos(0,0);
		write_com(0x0c); //关光标
	   	write_com(0x06);//写一个字符后地址指针加 1 
		write_com(0x01);//显示清零,数据指针清零
		write_n_char("Input password");
		LCD1602_pos(1,0);
		write_n_char("Press key A");
	}
}
//定时器0中断子函数
void t0() interrupt 1 
{
	TH0=0x4c;//50ms定时
	TL0=0x00;
	bb++;
	if(bb==200)//10秒时间到
	{
		bb=0;
		cc=0;
	}
}
				

 

评论 38
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值