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