51单片机增强版密码锁
视频演示
开机和门铃
修改密码
警报
密码锁功能
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; //正确则赋值1
Success_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(); //存入AT24C02
Count_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 0xA1
void I2C_Start(void) //I2C开始
{
//初始化全部置为高电平
I2C_SDA = 1;
I2C_SCL = 1;
//先SDA,再SCL
I2C_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;//释放SDA
for(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;//释放SDA
I2C_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" == 13
P1 = 0xFF;
P1_2 = 0;
if(P1_7 == 0) {KeyNumber = 2;}
if(P1_6 == 0) {KeyNumber = 6;}
if(P1_5 == 0) {KeyNumber = 10;}//"*" == 10
if(P1_4 == 0) {KeyNumber = 14;}//"Mod" == 14
P1 = 0xFF;
P1_1 = 0;
if(P1_7 == 0) {KeyNumber = 3;}
if(P1_6 == 0) {KeyNumber = 7;}
if(P1_5 == 0) {KeyNumber = 11;}//"#" == 11
if(P1_4 == 0) {KeyNumber = 15;}//"Deter" == 15
P1 = 0xFF;
P1_0 = 0;
if(P1_7 == 0) {KeyNumber = 4;}
if(P1_6 == 0) {KeyNumber = 8;}
if(P1_5 == 0) {KeyNumber = 12;}//"DEL" == 12
if(P1_4 == 0) {KeyNumber = 16;}
if(P3_3 == 0) {KeyNumber = 104;}//K4
if(P3_1 == 0) {KeyNumber = 101;}//K1
return 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复制进去再引用头文件即可