基于51单片机的密码锁数码管显示仿真

仿真图:

在这里插入图片描述

芯片/模块的特点:

AT89C52简介:
AT89C52是一款经典的8位单片机,是意法半导体(STMicroelectronics)公司生产的一系列单片机之一。它基于8051内核,并具有许多与其兼容的特性。

AT89C52的主要特点如下:

内部存储器:AT89C52具有8KB的闪存(Flash)存储器,可用于存储用户程序和数据。这些存储器的内容可以通过编程器进行编程和擦除。

RAM存储器:AT89C52配备了256字节的随机存取存储器(RAM),用于暂存数据和程序的变量。

外部扩展性:AT89C52支持多种外部扩展设备的连接,包括外部存储器(如RAM、EEPROM)和外设(如ADC、LCD、UART等),通过外部硬件连接,可以扩展单片机的功能和应用。

通用I/O引脚:AT89C52拥有32个可编程的通用输入/输出引脚,可用于连接外部设备和与其他芯片进行通信。

定时器/计数器:AT89C52内置了3个16位定时器/计数器和一个可编程的串行定时器/计数器。这些计时器/计数器可用于实现定时功能、生成脉冲信号、测量时间间隔等。0

串行通信:AT89C52支持串行通信接口,包括UART(串行异步通信)和SPI(串行外设接口),便于与其他设备进行数据通信和交互。

低功耗模式:AT89C52具有多种低功耗模式,如空闲模式和电源下模式,在不需要执行任务的时候可以将CPU进入低功耗状态以节省能量。

宽电源电压范围:AT89C52的工作电压范围通常为4.0V至5.5V,可以满足大多数应用需求。

主程序:


#include<reg52.h>

#define uchar unsigned char
#define uint unsigned int

uchar old1,old2,old3,old4,old5,old6; //原始密码123456
unsigned char PassWord[6];
uchar new1,new2,new3,new4,new5,new6;  //每次MCU采集到的密码输入
uchar a=16,b=16,c=16,d=16,e=16,f=16; //送入数码管显示的变量
uchar wei,key,temp;
unsigned char st=0;

bit allow,genggai,ok,wanbi,retry,close;	 //各个状态位


sbit beep=P3^6;
sbit Lock=P3^7;

sbit GLED=P3^4;
sbit RLED=P3^5;

sbit SCL = P3^3;		  //引脚定义
sbit SDA = P3^2;

unsigned char code table[]=
{0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,
0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71,0x00,0x40};



void InitI2C();
void I2CStart();
void I2CStop();
void I2CSend(uchar byte);
uchar I2CRead();
uchar read_eeprom(uchar addr);
void write_eeprom(uchar addr, uchar databyte); 

/*****************************************************************************
** 函数名称:delay
** 功能描述:延时
******************************************************************************/
void delay(unsigned int i)
{
	uint j,k;
  for(j=i;j>0;j--)
    for(k=125;k>0;k--);
}


/*****************************************************************************
** 函数名称:InitI2C
** 功能描述:配置模拟I2C的IO端口
******************************************************************************/
void InitI2C()
{
	 SDA = 1;
	 SCL = 1;
}

/*****************************************************************************
** 函数名称:I2CStart
** 功能描述:发送I2C总线起始状态
** 输    入:无
** 输    出:无
** 全局变量:无
** 调用模块:delay()
** 可移植性:直接移植
******************************************************************************/
void I2CStart()
{
	SDA = 1;    
	delay(1);      // 延时子程序
	SCL = 1;
	delay(1);
	SDA = 0;
	delay(1);
	SCL = 0;

}
/*****************************************************************************
** 函数名称:I2CStop
** 功能描述:发送I2C总线停止起始状态
** 输    入:无
** 输    出:无
** 全局变量:无
** 调用模块:delay()
** 可移植性:直接移植
******************************************************************************/
void I2CStop()
{
	SCL = 0;
    delay(1);
	SDA = 0;
	delay(1);
	SCL = 1;
	delay(1);
	SDA = 1;
	delay(1);

}
/*****************************************************************************
** 函数名称:I2CSend
** 功能描述:向I2C总线发送一个字节数据,并检测应答
** 输    入:待发送字节byte
** 输    出:无
** 全局变量:无
** 调用模块:delay()
** 可移植性:直接移植
******************************************************************************/
void I2CSend(uchar byte)
{
	uchar mask;
	uchar i;

	mask = 0x80;
	for(i = 0; i < 8; i++)
	{
		SCL = 0;
		delay(1);
		if((mask & byte) == 0)
		{
			SDA = 0;
		}
		else
		{
			SDA = 1;
		}
		mask >>= 1;
		delay(1);
		SCL = 1;
		delay(1);
	}
	
	SCL = 0;
	SDA = 1;
	delay(1);
	SCL = 1;
	delay(1);
	SCL = 0;


	
}

/*****************************************************************************
** 函数名称:I2CRead
** 功能描述:从I2C总线读取最后一个字节数据,并发送非应答位
** 输    入:无
** 输    出:接收到的字节byte
** 全局变量:无
** 调用模块:delay()
** 可移植性:直接移植
******************************************************************************/
uchar I2CRead()
{
	uchar byte;
	uchar i;

	byte = 0;
	for(i = 0; i < 8; i++)
	{
		SCL = 0;
		SDA = 1;
		delay(1);
		SCL = 1;
		delay(1);
		byte <<= 1;	 
		if(SDA == 1)
		{
			byte |= 0x01;
		}
		delay(1);
	} 
	SCL = 0;
	SDA = 1;
	delay(1);
	SCL = 1;
	delay(1);
	SCL = 0;
	
	return byte;

}
/*****************************************************************************
** 函数名称:read_eeprom
** 功能描述:读取EEPROM数据函数
** 输    入:EEPROM中目的地址addr
** 输    出:读取的数据
******************************************************************************/
uchar read_eeprom(uchar addr)
{
	uchar databyte;

	I2CStart();
	I2CSend(0xa0);
	I2CSend(addr);
	I2CStart();
	I2CSend(0xa1);
	databyte = I2CRead();
	I2CStop();

	return databyte;
	
}
/*****************************************************************************
** 函数名称:write_eeprom
** 功能描述:向EEPROM写入数据函数
** 输    入:EEPROM中目的地址addr及写入的数据
** 输    出:无
******************************************************************************/
void write_eeprom(uchar addr, uchar databyte)
{
	I2CStart();
	I2CSend(0xa0);	    
	I2CSend(addr);
	I2CSend(databyte);
	I2CStop();

}

void display(void)
{
	
   switch(st)
	{
		case 0: st=1;P0=0xff;P2=table[a];P0=0xfe;break;
		case 1: st=2;P0=0xff;P2=table[b];P0=0xfd;break;
		case 2: st=3;P0=0xff;P2=table[c];P0=0xfb;break;
		case 3: st=4;P0=0xff;P2=table[d];P0=0xf7;break;
		case 4: st=5;P0=0xff;P2=table[e];P0=0xef;break;
		case 5: st=0;P0=0xff;P2=table[f];P0=0xdf;break;
	}
}

void Timer0() interrupt 1
{
	TR0=0;
 	TH0  = (65535-2000)/256;
	TL0  = (65535-2000)%256;
	display();
	TR0=1;
}


void keyscan(void)
{
	P1=0xfe;
   temp=P1;
   temp=temp&0xf0;
   if(temp!=0xf0)
   {
		delay(10);
      if(temp!=0xf0)
      {	
			temp=P1;
			switch(temp)
			{
				case 0xee:	key=0;wei++;break;
				case 0xde:	key=1;wei++;break;
				case 0xbe:	key=2;wei++;break;
				case 0x7e:	key=3;wei++;break;
         }
			beep=0;delay(50);beep=1;
         while(temp!=0xf0) 
			{
				temp=P1;
				temp=temp&0xf0;				
         }		
		}
	}
	P1=0xfd;
	temp=P1;
	temp=temp&0xf0;
	if(temp!=0xf0)
	{
		delay(10);
		if(temp!=0xf0)
      {
			temp=P1;
			switch(temp)
			{
				case 0xed: 	key=4;wei++;break;
				case 0xdd:	key=5;wei++;break;
				case 0xbd:	key=6;wei++;break;
				case 0x7d:	key=7;wei++;break;
         }
			beep=0;delay(50);beep=1;
         while(temp!=0xf0)
         {
           temp=P1;
           temp=temp&0xf0;
         }
      }
	}
	temp=temp&0xf0;
	if(temp!=0xf0)
	{
		delay(10);
      if(temp!=0xf0)
      {
			temp=P1;
			switch(temp)
			{
				case 0xeb:	key=8;wei++;break;
				case 0xdb:	key=9;wei++;break;
				case 0xbb:	genggai=1;wei=0;break;
				case 0x7b:	if(allow) ok=1;break;
         }
			beep=0;delay(50);beep=1;
			while(temp!=0xf0)
         {
				temp=P1;
				temp=temp&0xf0;
         }
      }
   }
	P1=0xf7;
   temp=P1;
   temp=temp&0xf0;
   if(temp!=0xf0)
   {
      delay(10);
      if(temp!=0xf0)
      {
			temp=P1;
			switch(temp)
			{
				case 0xe7:	retry=1;break;
				case 0xd7:	close=1;break;
         }
			beep=0;delay(50);beep=1;
			while(temp!=0xf0)
         {
				temp=P1;
				temp=temp&0xf0;
         }
      }
	}
}

void shumima(void)		//对按键采集来的数据进行分配
{
	if(!wanbi)
	{
		switch(wei)
		{
			case 1:	new1=key;if(!allow)a=17;else a=key;	break;
			case 2:	new2=key;if(a==17) b=17;else b=key;	break;
			case 3:	new3=key;if(a==17) c=17;else c=key;	break;
			case 4:	new4=key;if(a==17) d=17;else d=key;	break;
			case 5:	new5=key;if(a==17) e=17;else e=key;	break;
			case 6:	new6=key;if(a==17) f=17;else f=key;wanbi=1;break;
		}
	}
}

void yanzheng(void)	  //验证密码是否正确
{
	if(wanbi)	 //只有当六位密码均输入完毕后方进行验证
	{
		if((new1==PassWord[0])&(new2==PassWord[1])&(new3==PassWord[2])&(new4==PassWord[3])&(new5==PassWord[4])&(new6==PassWord[5]))
		allow=1;	//当输入的密码正确,会得到allow置一
	}
}


void WritePassWord(void)
{
	unsigned char j=0;
	for(j=0;j<6;j++)   		     //从02地址开始写初始密码数据
	{
		write_eeprom(j,PassWord[j]);	 //初始密码123456
		delay(10);				
	}
}

void ReadPassWord(void)
{
	unsigned char j=0;
	for(j=0;j<6;j++)				 //将24C02中的密码读取出来保存在dumima_tab1[]数组中
	{
 		PassWord[j] = read_eeprom(j);
		delay(10);		
	}	
}

void WritePassWord_Ini(void)
{
	unsigned char j=0;
	for(j=0;j<6;j++)   		     //从02地址开始写初始密码数据
	{
		write_eeprom(j,j+1);	 //初始密码123456
		delay(10);				
	}
}

void main(void)
{
	InitI2C();			   //初始化
	TMOD = 0x01;
	TH0  = (65535-2000)/256;
	TL0  = (65535-2000)%256; 
	EA=1;
	ET0=1;
	TR0=1;
	//WritePassWord_Ini();
	ReadPassWord();
	if(PassWord[0]==0xff) WritePassWord_Ini();
		
	while(1)
	{
		keyscan();
		shumima();
		yanzheng();
		if(allow)	 //验证完后,若allow为1,则开锁
		{
			Lock=0;GLED=0;RLED=1;
			if(!genggai)	wanbi=0;
		}
		else 
		{
			Lock=1;GLED=1;RLED=0;
			if(wanbi)
			{
				delay(500);
				beep=0;delay(500);beep=1;delay(500);
				beep=0;delay(100);beep=1;delay(200);
				beep=0;delay(100);beep=1;delay(200);
				beep=0;delay(100);beep=1;delay(200);
				beep=0;delay(100);beep=1;delay(200);
				beep=0;delay(100);beep=1;delay(200);
				beep=0;delay(100);beep=1;
				wei=0;wanbi=0;allow=0;
				a=16;b=16;c=16;d=16;e=16;f=16;
				new1=0;new2=0;new3=0;new4=0;new5=0;new6=0;
			}
			
		}
		if(genggai)	  //当S16更改密码键被按下,genggai会被置一
		{
			if(allow)	 //若已经把锁打开,才有更改密码的权限
			{
				while(!wanbi)	//当新的六位密码没有设定完,则一直在这里循环
				{
					delay(20);
				 	keyscan();
					shumima();
					if(retry|close)	 //而当探测到重试键S18或者关闭密码锁键S19被按下时,则跳出
					{	
						wanbi=1;
						break;
					}
				}
			}
		}
		if(ok)	  //更改密码时,当所有六位新密码均被按下时,可以按下此键,结束密码更改
		{		  //其他时间按下此键无效
			ok=0; wei=0;Lock=1;GLED=1;RLED=0;
			genggai=0;
			PassWord[0]=new1;PassWord[1]=new2;PassWord[2]=new3; //此时,旧的密码将被代替
			PassWord[3]=new4;PassWord[4]=new5;PassWord[5]=new6;
			WritePassWord();
			wei=0;wanbi=0;allow=0;
			a=16;b=16;c=16;d=16;e=16;f=16;
			new1=0;new2=0;new3=0;new4=0;new5=0;new6=0;
		}
		if(retry)	//当重试按键S18被按下,retry会被置位
		{
			retry=0; wei=0;wanbi=0;
			a=16;b=16;c=16;d=16;e=16;f=16;
			new1=0;new2=0;new3=0;new4=0;new5=0;new6=0;		
		}
		if(close)  //当关闭密码锁按键被按下,close会被置位
		{
			close=0;genggai=0;//所有变量均被清零。
			wei=0;	wanbi=0;
			allow=0;
			Lock=1;GLED=1;RLED=0;
			a=16;b=16;c=16;d=16;e=16;f=16;
			new1=0;new2=0;new3=0;new4=0;new5=0;new6=0;
		}
	}
}

设计文件:

链接:https://pan.baidu.com/s/1slBzaoujiIUUStdT6tq0gQ?pwd=13tf

  • 4
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值