基于51单片机的可改位数的记忆密码锁,有警报声和门铃(包含免费下载工程代码压缩包,持续更新)

本文主要是介绍基于51单片机的可改位数的记忆密码锁,有警报声和门铃(包含免费下载工程代码压缩包,持续更新),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

51单片机增强版密码锁

  • 视频演示
  • 密码锁功能
  • 提要
  • 文章部分代码解释
  • ********下载代码工程压缩包********
  • 密码锁介绍
    • 按键说明
    • 使用方法
    • 运行逻辑
  • 工程代码压缩包
  • 代码实现(下面为用到的模块)
  • PassWord.c讲解
    • PassWord.c文件
    • **Timer0.c** 定时器和中断
    • Timer0.h文件
    • **LCD1602.c文件**
    • PassWord .h文件
    • LCD1602.h文件
    • Beep.c文件
    • Beep.h文件
    • Delay.c文件
    • Delay.h文件
    • AT24C02.h包含I2C 文件
    • AT24C02.h文件
    • MatriKey.c
    • MatriKey.h文件
    • main主函数
  • 总结

视频演示

开机和门铃

修改密码

警报

密码锁功能

1.具备密码存储功能,即使断电也能保持密码不丢失。
2.配有各种按键音效,如普通按键提示音、正确输入提示音、错误输入提示音;并在连续输入错误时触发警报声;3.还具备门铃声与关闭按键音效功能。
4.支持修改密码、恢复原密码及清除密码等操作。
5.提供可调整的密码长度设置,以满足不同需求。
6.可设计一个开发者密码,防止密码忘记(输入对应位数的开发者密码也可以成功开锁),开发者密码只可在程序修改

提要

本人小白,刚接触51单片机不久,这是我第一次将自己的课程设计上传到博客,有诸多地方尚不了解,如果有哪里写法不对或者代码哪里出问题,欢迎各位指出!

文章部分代码解释

虽然文中我也有写注释,但是是思路的注释,如需了解原理请点击下面链接
AT24C02代码解释
点击link或
http://t.csdn.cn/TZihH
定时器消抖解释
点击link或
https://www.bilibili.com/video/BV1Mb411e7re?t=3197.8&p=28

下载代码工程压缩包

如要下载代码文件,即可在文章最上方点击下载,免费下载
或者 如下分享
百度网盘链接:
link
链接:https://pan.baidu.com/s/1c88CGpzYGu7_CdxwCmLH3Q?pwd=f5bp
提取码:f5bp
51单片机密码锁
link
https://www.aliyundrive.com/s/WLoKq5f9vH2
点击链接保存,或者复制本段内容,打开「阿里云盘」APP ,无需下载极速在线查看,视频原画倍速播放。

密码锁介绍

通过矩阵键盘,定时器,蜂鸣器,AT24C02,等等模块来实现密码锁功能
在这里插入图片描述

按键说明

在这里插入图片描述
密码按键一一对应上面的图片

使用方法

独立按键K1:门铃
独立按键K4:开关按键提示音
1~9和 * #:输入密码
Del::回退键,清除一位密码
Clear::清除键,清除已输入的密码
Mod::设置密码,在成功开锁后,按下此键修改密码并保持在单片机里面(断电不会擦除)
Deter::确认键,输入完密码,按下此键进行检验开锁或保存密码

可调密码位数
调节方式:

更改Length的大小即可
Administrator则是你自己设计的开发者密码

#define Length 3 							//长度
#define Administrator "2869902214"			//开发者密码设置(建议10位以内)

运行逻辑

extern 是类似在别的文件定义了共享使用,数据互通

开机后读取存放在AT24C02的密码
接着就输入Length位密码按下Deter,如果密码错误,则发出错误提示音,并且按下Clear清除后才可再次输入密码,但是连续输错三次则发出警报声
如果忘记了密码,则输入开发者密码进行重置密码

如果输入的密码正确会发出正确提示音则可以按下Mod进行更改密码,要输入两次更改后的密码,如果两次密码一致才会写入AT24C02,如果不一致则按下Clear重新进行更改

门锁密码为Length位(自己设置)初始密码开发者密码(自己设置需长度和Length一样),包含开发者密码(防止密码忘记)输入密码(在LCD1602屏幕上的密码都显示为*) 成功开锁将在屏幕上提示Success并发出开锁成功的音效,在开锁后按下Mod按键将进入密码设置模式,重新输入Length位密码,(需要输入两次修改后的密码,如果一致则修改成功,否则重新修改)按下Deter保存到单片机的AT24C02当中,此后的密码将以AT24C02的密码为准,输入错误将在屏幕上显示ERROR,并发出密码错误的音效,错误三次以上发出警报声。

大致的流程图(不是很会写,见谅)

在这里插入图片描述

工程代码压缩包

如果感觉看的内容过多,混乱,则可以下载这个工程压缩包,下载解压即用

代码实现(下面为用到的模块)

由于运用了多个模块,那么我将每个模块分别放出
用了LCD1602.c和.h文件 显示屏
MatriKey.c和.h文件 矩阵键盘
Timer0.c和.h文件 定时器
PassWord.c和.h文件 工程核心部分
Beep.c和.h文件蜂鸣器
Delay.c和.h文件1ms延时函数
AT24C02.c和.h文件

PassWord.c讲解

PassWord.c文件

#include <REGX52.H>
#include "MatriKey.h"
#include "LCD1602.h"
#include "String.h"
#include "Delay.h"
#include "AT24C02.h"
#include "PassWord.h"
#include "Beep.h"
#define Length 3 							//长度
#define Administrator "2869902214"			//开发者密码设置(建议10位以内)extern unsigned char Number;						//键值
unsigned char Count_Input,Count_ERROR;				//目前输入的位数,错误次数
unsigned char Write_LCD_PassWord[Length + 1];		//输入的密码	
unsigned char Temp_Read_AT[Length + 1];				//读取过渡字符串
unsigned char First_PassWord[Length + 1];			//改密码第一次的字符串
unsigned char Second_PassWord[Length + 1];			//第二次的字符串
unsigned char Administrator_PassWorld[Length + 1];	//忘记密码(Length为目前设置的密码长度)
unsigned char Write_Count;							//写入的次数
bit ERROR,Wirte_Flag,Success,Success_Flag;			//密码错误、写入的标志、密码正确、蜂鸣器正确音效标志void Set_PassWord()		  	//设置密码
{Count_Input = 0;Wirte_Flag = 1;		//进入写入模式LCD_Init();LCD_ShowString(1,1,"Write:");}
void Init_PassWord()		//初始化密码
{	LCD_Init();if(Wirte_Flag == 0)			//如果不为写入状态则LCD_ShowString(1,1,"PassWord:");else if(Wirte_Flag == 1)	//写入状态{if(Write_Count == 0)LCD_ShowString(1,1,"Write:");else  LCD_ShowString(1,1,"Again:");}strcpy(Write_LCD_PassWord," ");			//清空密码Count_Input = 0;						//回到密码输入最初位置Success = 0;							//返回后不可修改密码
}
void Back_PassWord()		//回退密码
{Count_Input = Count_Input - 1;		//输入回退一个Write_LCD_PassWord[Count_Input] = ' ';			//赋值空格LCD_ShowChar(2,Count_Input+1,Write_LCD_PassWord[Count_Input]);		//空格覆盖	
}
void Judge_PassWord()		//输入密码的判断结果
{if (strcmp(Write_LCD_PassWord, Temp_Read_AT) == 0 || strcmp(Write_LCD_PassWord, Administrator_PassWorld) == 0)			{LCD_ShowString(1,10,"Success");Success = 1;				//正确则赋值1Success_Flag = 1;		 	//蜂鸣器的赋值strcpy(Write_LCD_PassWord," ");Count_Input = Length + 1;			//确认后不再输入,不再回退Count_ERROR = 0;			//清除}else 								//错误{LCD_ShowString(1,10,"ERROR!!");ERROR = 1;Count_Input = Length + 1;			//确认后不再输入,不再回退,因为i=Length 是最后一位Count_ERROR++;				//如果确认后i=Length 或者0都可以再输入密码}
}
void Read_PassWord()		//读取正确密码
{unsigned char a;for(a = 0;a<Length ;a++){Temp_Read_AT[a] = AT24C02_ReadByte(a);}for(a = 0;a<Length ;a++){Administrator_PassWorld[a] = Administrator[a];}}void Write_PassWord()		//写入正确密码
{unsigned char a;for(a = 0;a<Length ;a++){AT24C02_WriteByte(a,Write_LCD_PassWord[a]);Delay(5);}
}
void Change_PassWord()		//更改密码
{unsigned char i;if(Write_Count == 0){for(i=0;i<Length;i++){First_PassWord[i] = Write_LCD_PassWord[i];   遍历length次传递第一次密码}LCD_Init();LCD_ShowString(1,1,"Again:");Count_Input = 0;Write_Count++;}else if(Write_Count == 1){for(i=0;i<Length;i++)  Second_PassWord[i] = Write_LCD_PassWord[i];   //遍历length次传递第二次密码if(strcmp(Second_PassWord, First_PassWord) == 0)		//如果一样{LCD_Init();LCD_ShowString(1,1,"Success!");Success = 0;//改完密码后置0,必须再输入正确密码才可以改Wirte_Flag = 0;				//存入后退出修改密码模式Write_PassWord();			//存入AT24C02Count_Input = Length + 1;			//防误操作Success_Flag = 1;Write_Count = 0;}else {LCD_Init();LCD_ShowString(1,1,"Start Again!");Write_Count = 0;Count_Input = 0;			//防误操作ERROR = 1;}	}							
}
void LCD_PassWord()			//LCD显示
{if(Count_Input!=0 && Count_Input <= Length )		//按键之后开始输入密码{//LCD_ShowChar(2,Count_Input,Write_LCD_PassWord[Count_Input-1]);LCD_ShowChar(2,Count_Input,'*');	}
}void Key_Number()			//数字和 * # 按键
{if(Count_Input < Length ){switch(Number){case 16: Write_LCD_PassWord[Count_Input] = '0';Count_Input++;break;case 10:Write_LCD_PassWord[Count_Input] = '*';Count_Input++;break;case 11:Write_LCD_PassWord[Count_Input] = '#';Count_Input++;break;case 9:Write_LCD_PassWord[Count_Input] = '9';Count_Input++;break;case 8:Write_LCD_PassWord[Count_Input] = '8';Count_Input++;break;case 7:Write_LCD_PassWord[Count_Input] = '7';Count_Input++;break;case 6:Write_LCD_PassWord[Count_Input] = '6';Count_Input++;break;case 5:Write_LCD_PassWord[Count_Input] = '5';Count_Input++;break;case 4:Write_LCD_PassWord[Count_Input] = '4';Count_Input++;break;case 3:Write_LCD_PassWord[Count_Input] = '3';Count_Input++;break;case 2:Write_LCD_PassWord[Count_Input] = '2';Count_Input++;break;case 1:Write_LCD_PassWord[Count_Input] = '1';Count_Input++;break;default :break;}}
}
void Function_Key()			//功能按键
{	if(Count_Input == Length  && Number == 15 && Wirte_Flag == 0)		//确认密码,和确认设置密码{Judge_PassWord();		//判断密码	}else if(Count_Input == Length  && Number == 15 && Wirte_Flag == 1)	//确认修改密码{Change_PassWord();	//修改密码}if(Count_Input != 0 && Number == 12 && Count_Input != Length + 1) 		//回退一个密码{	Back_PassWord();		}if(Number == 13)		//初始化密码{Init_PassWord();}if((Count_Input == Length + 1 || Count_Input == 0) && Number == 14 && Success == 1 )			//设置密码{Set_PassWord();}Number = 99;//如果为0,那么0不会进入Key_Flag();
}
void PassWord()				//执行
{if(Key() != 0)			//调用密码键{		if(Number == 101)	//如果是101门铃,则不进行下面的操作,防止蜂鸣器再次发声DoorBell(1);else{			if(Wirte_Flag == 0)	//输入密码{Key_Number();}if(Wirte_Flag == 1)	//改写密码{Key_Number();}	Function_Key();		//调用功能键Buzzer();			//按键蜂鸣器	}}	
}

Timer0.c 定时器和中断

#include <REGX52.H>  //头文件
#include "PassWord.h"	
unsigned int T0Count,T0Count_LCD,T0Count_Read;//分别定义了定时器中断变量
extern bit Success;		//extern 是类似在别的文件定义了共享使用,数据互通,
void Timer0_Init(void)		//1毫秒@11.0592MHz
{TMOD &= 0xF0;TMOD |= 0x01;		TL0 = 0x66;		TH0 = 0xFC;		EA = 1;PT0 = 0;TF0 = 0;		TR0 = 1;		ET0 = 1;}void Timer0_Routine() interrupt 1
{TL0 = 0x66;TH0 = 0xFC;		//定时器T0Count++;			//频率T0Count_LCD++;T0Count_Read++;if(T0Count_Read == 1000)	//每1000ms读取一次保存的密码{Read_PassWord();T0Count_Read = 0;}//下面是按键定时器消抖if(T0Count >= 20) //20s断一次{T0Count = 0;	//断一次后重置MatriKey();	//20ms调用一次按键驱动函数}//下面是每100ms更新一次显示屏显示的内容,防止太快出错,则选择100ms一次if(T0Count_LCD >= 100) //100ms断一次{T0Count_LCD = 0;	//断一次后重置LCD_PassWord();}PassWord();
}

Timer0.h文件

#ifndef __Timer0_H_
#define __Timer0_H_void Timer0_Init(void);#endif

LCD1602.c文件

#include <REGX52.H>//引脚配置:
sbit LCD_RS=P2^6;
sbit LCD_RW=P2^5;
sbit LCD_EN=P2^7;
#define LCD_DataPort P0//函数定义:
/*** @brief  LCD1602延时函数,12MHz调用可延时1ms* @param  无* @retval 无*/
void LCD_Delay()
{unsigned char i, j;i = 2;j = 239;do{while (--j);} while (--i);
}/*** @brief  LCD1602写命令* @param  Command 要写入的命令* @retval 无*/
void LCD_WriteCommand(unsigned char Command)
{LCD_RS=0;LCD_RW=0;LCD_DataPort=Command;LCD_EN=1;LCD_Delay();LCD_EN=0;LCD_Delay();
}/*** @brief  LCD1602写数据* @param  Data 要写入的数据* @retval 无*/
void LCD_WriteData(unsigned char Data)
{LCD_RS=1;LCD_RW=0;LCD_DataPort=Data;LCD_EN=1;LCD_Delay();LCD_EN=0;LCD_Delay();
}/*** @brief  LCD1602设置光标位置* @param  Line 行位置,范围:1~2* @param  Column 列位置,范围:1~16* @retval 无*/
void LCD_SetCursor(unsigned char Line,unsigned char Column)
{if(Line==1){LCD_WriteCommand(0x80|(Column-1));}else if(Line==2){LCD_WriteCommand(0x80|(Column-1+0x40));}
}/*** @brief  LCD1602初始化函数* @param  无* @retval 无*/
void LCD_Init()
{LCD_WriteCommand(0x38);//八位数据接口,两行显示,5*7点阵LCD_WriteCommand(0x0c);//显示开,光标关,闪烁关LCD_WriteCommand(0x06);//数据读写操作后,光标自动加一,画面不动LCD_WriteCommand(0x01);//光标复位,清屏
}/*** @brief  在LCD1602指定位置上显示一个字符* @param  Line 行位置,范围:1~2* @param  Column 列位置,范围:1~16* @param  Char 要显示的字符* @retval 无*/
void LCD_ShowChar(unsigned char Line,unsigned char Column,char Char)
{LCD_SetCursor(Line,Column);LCD_WriteData(Char);
}/*** @brief  在LCD1602指定位置开始显示所给字符串* @param  Line 起始行位置,范围:1~2* @param  Column 起始列位置,范围:1~16* @param  String 要显示的字符串* @retval 无*/
void LCD_ShowString(unsigned char Line,unsigned char Column,char *String)
{unsigned char i;LCD_SetCursor(Line,Column);for(i=0;String[i]!='\0';i++){LCD_WriteData(String[i]);}
}/*** @brief  返回值=X的Y次方*/
int LCD_Pow(int X,int Y)
{unsigned char i;int Result=1;for(i=0;i<Y;i++){Result*=X;}return Result;
}/*** @brief  在LCD1602指定位置开始显示所给数字* @param  Line 起始行位置,范围:1~2* @param  Column 起始列位置,范围:1~16* @param  Number 要显示的数字,范围:0~65535* @param  Length 要显示数字的长度,范围:1~5* @retval 无*/
void LCD_ShowNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length)
{unsigned char i;LCD_SetCursor(Line,Column);for(i=Length;i>0;i--){LCD_WriteData(Number/LCD_Pow(10,i-1)%10+'0');}
}/*** @brief  在LCD1602指定位置开始以有符号十进制显示所给数字* @param  Line 起始行位置,范围:1~2* @param  Column 起始列位置,范围:1~16* @param  Number 要显示的数字,范围:-32768~32767* @param  Length 要显示数字的长度,范围:1~5* @retval 无*/
void LCD_ShowSignedNum(unsigned char Line,unsigned char Column,int Number,unsigned char Length)
{unsigned char i;unsigned int Number1;LCD_SetCursor(Line,Column);if(Number>=0){LCD_WriteData('+');Number1=Number;}else{LCD_WriteData('-');Number1=-Number;}for(i=Length;i>0;i--){LCD_WriteData(Number1/LCD_Pow(10,i-1)%10+'0');}
}/*** @brief  在LCD1602指定位置开始以十六进制显示所给数字* @param  Line 起始行位置,范围:1~2* @param  Column 起始列位置,范围:1~16* @param  Number 要显示的数字,范围:0~0xFFFF* @param  Length 要显示数字的长度,范围:1~4* @retval 无*/
void LCD_ShowHexNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length)
{unsigned char i,SingleNumber;LCD_SetCursor(Line,Column);for(i=Length;i>0;i--){SingleNumber=Number/LCD_Pow(16,i-1)%16;if(SingleNumber<10){LCD_WriteData(SingleNumber+'0');}else{LCD_WriteData(SingleNumber-10+'A');}}
}/*** @brief  在LCD1602指定位置开始以二进制显示所给数字* @param  Line 起始行位置,范围:1~2* @param  Column 起始列位置,范围:1~16* @param  Number 要显示的数字,范围:0~1111 1111 1111 1111* @param  Length 要显示数字的长度,范围:1~16* @retval 无*/
void LCD_ShowBinNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length)
{unsigned char i;LCD_SetCursor(Line,Column);for(i=Length;i>0;i--){LCD_WriteData(Number/LCD_Pow(2,i-1)%2+'0');}
}

PassWord .h文件

#ifndef __PassWord_H_
#define __PassWord_H_void PassWord(void);	//执行
void LCD_PassWord(void);//LCD显示密码
void Function_Key(void);//功能按键
void Write_PassWord(void);//写入密码
void Read_PassWord(void);//读取密码
void Key_Number(void);//输入的密码
void Judge_PassWord(void);//判断密码
void Change_PassWord(void);//更改密码
void Back_PassWord(void);//回退密码
void Init_PassWord(void);//初始化清除密码
void Set_PassWord(void);//进入设置密码#endif

LCD1602.h文件

#ifndef __LCD1602_H__
#define __LCD1602_H__//用户调用函数:
void LCD_Init();
void LCD_ShowChar(unsigned char Line,unsigned char Column,char Char);
void LCD_ShowString(unsigned char Line,unsigned char Column,char *String);
void LCD_ShowNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length);
void LCD_ShowSignedNum(unsigned char Line,unsigned char Column,int Number,unsigned char Length);
void LCD_ShowHexNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length);
void LCD_ShowBinNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length);#endif

Beep.c文件

#include <REGX52.H>
#include "Delay.h"
#include "Beep.h"
#include "MatriKey.h"
#define LED P2
extern unsigned char Count_ERROR,Number;
extern bit ERROR,Success,Success_Flag;
bit Buzzer_Flag;
sbit Beep = P2^5;void Key_Buzzer(unsigned char k)				//按键
{while(k--){Beep = 0;Delay(1);			Beep = 1;Delay(1);}
}
void ERROR_Buzzer(unsigned char k,unsigned char Count)
{while(--k){Beep = 0;Delay(1);				//音效Beep = 1;Delay(1);if(Count  && k%20 == 0 ){Delay(100);Count--;}}
}
void Success_Buzzer(unsigned char k,unsigned char Count)
{while(k--){Beep = 0;Delay(1);				//音效Beep = 1;Delay(1);			if(Count == 2 && k == 20 ){Delay(300);Count--;}if(Count == 1 && k == 10 ){Delay(100);Count--;}	}	
}				void Warning(unsigned char Count)
{unsigned int  i, j;while(Count--){for(i = 0; i < 300; i++){for(j = 0; j < 150; j++); Beep=~Beep; }LED=0xAA;for(i = 0; i < 300; i++){for(j = 0; j < 300; j++);Beep = ~Beep;}LED=0x55;}
}
void DoorBell(unsigned char Count)
{unsigned int  i, j;while(Count--){for(i = 0; i < 500; i++){for(j = 0; j < 130; j++); Beep=~Beep; }LED=0xAA;for(i = 0; i < 200; i++){for(j = 0; j < 300; j++);Beep = ~Beep;}LED=0x55;}
}
void Buzzer() //蜂鸣器提示音
{Key_Flag();if(Buzzer_Flag == 1){	Key_Buzzer(20);Buzzer_Flag = 0;}if(ERROR == 1){if(Count_ERROR != 3){ERROR_Buzzer(40,1);}if(Count_ERROR == 3){Warning(5);			LED = 0xFF;Count_ERROR = 0;}	ERROR = 0;}if(Success_Flag == 1){Success_Buzzer(40,2);Success_Flag = 0;}
}

Beep.h文件

#ifndef __Beep_H_
#define __Beep_H_void Buzzer(void);
void Key_Buzzer(unsigned char k);
void ERROR_Buzzer(unsigned char k,unsigned char Count);
void Warning(unsigned char Count);
void DoorBell(unsigned char Count);
#endif

Delay.c文件

void Delay(unsigned int xms)
{unsigned char i ,j;while(xms--){i = 2;j = 239;do{while(--j);}	while(--i);}
}

Delay.h文件

#ifndef __DELAY_H__
#define __DELAY_H__ void Delay(unsigned int xms);#endif

AT24C02.h包含I2C 文件

#include <REGX52.H>
sbit I2C_SCL=P2^1;
sbit I2C_SDA=P2^0;
// SLAVE ADDRESS+W为0xA0,SLAVE ADDRESS+R为0xA1
#define AT24C02_ADDRESS_READ		0xA0
#define AT24C02_ADDRESS_WRITE		0xA1void I2C_Start(void)	//I2C开始
{//初始化全部置为高电平I2C_SDA = 1;I2C_SCL = 1;//先SDA,再SCLI2C_SDA = 0;I2C_SCL = 0;
}void I2C_Stop(void)		//I2C停止
{	//SDA从低电平开始,所以=0,终止条件先SCL置高电平,SDA再高电平I2C_SDA = 0;I2C_SCL = 1;I2C_SDA = 1;
}void I2C_SendByte(unsigned char Byte) //发送一个bite
{unsigned char i;for(i=0;i<8;i++)	//八次{I2C_SDA = Byte & (0x80 >> i);//寻位I2C_SCL = 1;	//切换I2C_SCL = 0;}
}unsigned char I2C_ReceiveByte()	//接受Byte
{unsigned char i,Byte = 0x00;I2C_SDA = 1;//释放SDAfor(i=0;i<8;i++){I2C_SCL = 1;if(I2C_SDA){Byte |= (0x80 >> i);}I2C_SCL = 0;}return Byte;
}void I2C_SendAck(unsigned char AckBit) //发送答应
{I2C_SDA = AckBit;I2C_SCL = 1;I2C_SCL = 0;
}unsigned char I2C_ReceiveAck(void)//接受答应
{unsigned char AckBit;I2C_SDA = 1;//释放SDAI2C_SCL = 1;AckBit = I2C_SDA;I2C_SCL = 0;return AckBit;
}/*** @brief  AT24C02写入一个字节* @param  WordAddress 要写入字节的地址* @param  Data 要写入的数据* @retval 无*/
void AT24C02_WriteByte(unsigned char WordAddress,Data)
{I2C_Start();I2C_SendByte(AT24C02_ADDRESS_READ);I2C_ReceiveAck();I2C_SendByte(WordAddress);I2C_ReceiveAck();I2C_SendByte(Data);I2C_ReceiveAck();I2C_Stop();
}/*** @brief  AT24C02读取一个字节* @param  WordAddress 要读出字节的地址* @retval 读出的数据*/
unsigned char AT24C02_ReadByte(unsigned char WordAddress)
{unsigned char Data;I2C_Start();I2C_SendByte(AT24C02_ADDRESS_READ);I2C_ReceiveAck();I2C_SendByte(WordAddress);I2C_ReceiveAck();I2C_Start();// 读地址I2C_SendByte(AT24C02_ADDRESS_WRITE);I2C_ReceiveAck();Data=I2C_ReceiveByte();I2C_SendAck(1);I2C_Stop();return Data;
}

AT24C02.h文件

#ifndef __AT24C02_H_
#define __AT24C02_H_void I2C_Start(void);
void I2C_Stop(void);
void I2C_SendByte(unsigned char Byte);
unsigned char I2C_ReceiveByte(void);
void I2C_SendAck(unsigned char AckBit);
unsigned char I2C_ReceiveAck(void);void AT24C02_WriteByte(unsigned char WordAddress,Data);
unsigned char AT24C02_ReadByte(unsigned char WordAddress);#endif

MatriKey.c

#include <REGX52.H>
#include "Beep.h"
unsigned char Button,Number;
extern bit Buzzer_Flag;
bit Sound_Switch;
unsigned char Key(void)
{unsigned char Temp=0;Temp=Button;Number = Button;if(Number == 104){Sound_Switch = ~Sound_Switch;}Button=0;return Temp;
}
bit Key_Flag(void)
{if(Sound_Switch == 0)//控制按键音效Buzzer_Flag = 1;return Buzzer_Flag;
}
unsigned char Key_GetState()
{unsigned char KeyNumber=0;P1 = 0xFF;P1_3 = 0;if(P1_7 == 0) {KeyNumber = 1;}if(P1_6 == 0) {KeyNumber = 5;}if(P1_5 == 0) {KeyNumber = 9;}if(P1_4 == 0) {KeyNumber = 13;}//"Clear" == 13P1 = 0xFF;P1_2 = 0;if(P1_7 == 0) {KeyNumber = 2;}if(P1_6 == 0) {KeyNumber = 6;}if(P1_5 == 0) {KeyNumber = 10;}//"*" == 10if(P1_4 == 0) {KeyNumber = 14;}//"Mod" == 14P1 = 0xFF;P1_1 = 0;if(P1_7 == 0) {KeyNumber = 3;}if(P1_6 == 0) {KeyNumber = 7;}if(P1_5 == 0) {KeyNumber = 11;}//"#" == 11if(P1_4 == 0) {KeyNumber = 15;}//"Deter" == 15P1 = 0xFF;P1_0 = 0;if(P1_7 == 0) {KeyNumber = 4;}if(P1_6 == 0) {KeyNumber = 8;}	if(P1_5 == 0) {KeyNumber = 12;}//"DEL" == 12if(P1_4 == 0) {KeyNumber = 16;}	if(P3_3 == 0) {KeyNumber = 104;}//K4if(P3_1 == 0) {KeyNumber = 101;}//K1return KeyNumber;
}unsigned char MatriKey()
{static unsigned char NowState,LastState;LastState=NowState;				//按键状态更新NowState=Key_GetState();		//获取当前按键状态//如果上个时间点按键按下,这个时间点未按下,则是松手瞬间,以此避免消抖和松手检测if(NowState == 0){switch(LastState){case 1 	: Button=7; 	break;case 2 	: Button=8; 	break;case 3 	: Button=9; 	break;case 4 	: Button=12; 	break;case 5 	: Button=4; 	break;case 6 	: Button=5; 	break;case 7 	: Button=6; 	break;case 8 	: Button=13;	break;case 9 	: Button=1; 	break;case 10 : Button=2; 	break;case 11 : Button=3; 	break;case 12 : Button=14;	break;case 13 : Button=10;	break;case 14 : Button=16; 	break;case 15 : Button=11; 	break;case 16 : Button=15; 	break;case 104: Button=104;	break;case 101: Button=101;	break;}}return Button;
}}

MatriKey.h文件

#ifndef __MatriKey_H_
#define	__MatriKey_H_unsigned char MatriKey(void);
unsigned char Key(void);
unsigned char Key_GetState(void);
bit Key_Flag(void);#endif

main主函数

#include <REGX52.H>
#include "Timer0.h"
#include "LCD1602.h"
void main()
{Timer0_Init();LCD_Init();LCD_ShowString(1,1,"PassWord:");while(1){}
}

总结

这是我第一次写比较长的代码,变量命名或者函数命名可能不太规范或者不明了,希望各位见谅,慢慢提升自己,包括博客写作内容。大家如果需要参考个别代码,则可以在K5上创建两个文件,一个.c一个.h复制进去再引用头文件即可

这篇关于基于51单片机的可改位数的记忆密码锁,有警报声和门铃(包含免费下载工程代码压缩包,持续更新)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/830860

相关文章

Ilya-AI分享的他在OpenAI学习到的15个提示工程技巧

Ilya(不是本人,claude AI)在社交媒体上分享了他在OpenAI学习到的15个Prompt撰写技巧。 以下是详细的内容: 提示精确化:在编写提示时,力求表达清晰准确。清楚地阐述任务需求和概念定义至关重要。例:不用"分析文本",而用"判断这段话的情感倾向:积极、消极还是中性"。 快速迭代:善于快速连续调整提示。熟练的提示工程师能够灵活地进行多轮优化。例:从"总结文章"到"用

poj3468(线段树成段更新模板题)

题意:包括两个操作:1、将[a.b]上的数字加上v;2、查询区间[a,b]上的和 下面的介绍是下解题思路: 首先介绍  lazy-tag思想:用一个变量记录每一个线段树节点的变化值,当这部分线段的一致性被破坏我们就将这个变化值传递给子区间,大大增加了线段树的效率。 比如现在需要对[a,b]区间值进行加c操作,那么就从根节点[1,n]开始调用update函数进行操作,如果刚好执行到一个子节点,

hdu1394(线段树点更新的应用)

题意:求一个序列经过一定的操作得到的序列的最小逆序数 这题会用到逆序数的一个性质,在0到n-1这些数字组成的乱序排列,将第一个数字A移到最后一位,得到的逆序数为res-a+(n-a-1) 知道上面的知识点后,可以用暴力来解 代码如下: #include<iostream>#include<algorithm>#include<cstring>#include<stack>#in

hdu1689(线段树成段更新)

两种操作:1、set区间[a,b]上数字为v;2、查询[ 1 , n ]上的sum 代码如下: #include<iostream>#include<algorithm>#include<cstring>#include<stack>#include<queue>#include<set>#include<map>#include<stdio.h>#include<stdl

常用的jdk下载地址

jdk下载地址 安装方式可以看之前的博客: mac安装jdk oracle 版本:https://www.oracle.com/java/technologies/downloads/ Eclipse Temurin版本:https://adoptium.net/zh-CN/temurin/releases/ 阿里版本: github:https://github.com/

活用c4d官方开发文档查询代码

当你问AI助手比如豆包,如何用python禁止掉xpresso标签时候,它会提示到 这时候要用到两个东西。https://developers.maxon.net/论坛搜索和开发文档 比如这里我就在官方找到正确的id描述 然后我就把参数标签换过来

poj 1258 Agri-Net(最小生成树模板代码)

感觉用这题来当模板更适合。 题意就是给你邻接矩阵求最小生成树啦。~ prim代码:效率很高。172k...0ms。 #include<stdio.h>#include<algorithm>using namespace std;const int MaxN = 101;const int INF = 0x3f3f3f3f;int g[MaxN][MaxN];int n

hdu 1754 I Hate It(线段树,单点更新,区间最值)

题意是求一个线段中的最大数。 线段树的模板题,试用了一下交大的模板。效率有点略低。 代码: #include <stdio.h>#include <string.h>#define TREE_SIZE (1 << (20))//const int TREE_SIZE = 200000 + 10;int max(int a, int b){return a > b ? a :

day-51 合并零之间的节点

思路 直接遍历链表即可,遇到val=0跳过,val非零则加在一起,最后返回即可 解题过程 返回链表可以有头结点,方便插入,返回head.next Code /*** Definition for singly-linked list.* public class ListNode {* int val;* ListNode next;* ListNode() {}*

AI行业应用(不定期更新)

ChatPDF 可以让你上传一个 PDF 文件,然后针对这个 PDF 进行小结和提问。你可以把各种各样你要研究的分析报告交给它,快速获取到想要知道的信息。https://www.chatpdf.com/