标题: 51单片机1602显示按键密码锁 [打印本页]
作者: weiwei315 时间: 2018-6-22 14:31
标题: 51单片机1602显示按键密码锁
我按照这个程序做出来的,总是输入密码错误,不知道是啥问题,麻烦大神帮看看是啥问题。
#include <reg52.h>
#include <intrins.h>
#define uchar unsigned char // 以后unsigned char就可以用uchar代替
#define uint unsigned int // 以后unsigned int 就可以用uint 代
sbit SDA_P = P2^1; // 定义了AT24C02的SCL引脚
sbit SCL_P = P2^0; // 定义了AT24C02的SDA引脚
sbit LcdEn_P = P2^5; // 1602液晶的EN管脚
sbit LcdRw_P = P2^6; // 1602液晶的RW管脚
sbit LcdRs_P = P2^7; // 1602液晶的RS管脚
sbit Beep_P = P3^3; // 蜂鸣器引脚
sbit Relay_P = P3^2; // 继电器引脚
uchar ArrCodeBuff[6]; // 密码输入缓冲区
uchar ArrCodeUnlock[6]; // 解锁密码
uchar ArrCodeTemp[6]; // 临时数组(修改密码时会用到)
uchar ArrCodeAdmin[6]={1,2,3,1,2,3}; // 管理员密码
uchar row,column; // 液晶的当前行列坐标
uchar inputNum=0; // 输入的密码位数
uchar inputMode=1; // =1输入解锁密码,=2输入修改密码1,=3输入解锁密码2
uchar errTime=0; // 密码输入错误的次数
/*********************************************************/
// 毫秒级的延时函数,time是要延时的毫秒数
/*********************************************************/
void DelayMs(uint time)
{
uint i,j;
for(i=0;i<time;i++)
for(j=0;j<112;j++);
}
/*********************************************************/
// 延时6微秒
/*********************************************************/
void Delay6us()
{
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
}
/*********************************************************/
// 1602液晶写命令函数,cmd就是要写入的命令
/*********************************************************/
void LcdWriteCmd(uchar cmd)
{
LcdRs_P = 0;
LcdRw_P = 0;
LcdEn_P = 0;
P0=cmd;
DelayMs(2);
LcdEn_P = 1;
DelayMs(2);
LcdEn_P = 0;
}
/*********************************************************/
// 1602液晶写数据函数,dat就是要写入的数据
/*********************************************************/
void LcdWriteData(uchar dat)
{
LcdRs_P = 1;
LcdRw_P = 0;
LcdEn_P = 0;
P0=dat;
DelayMs(2);
LcdEn_P = 1;
DelayMs(2);
LcdEn_P = 0;
}
/*********************************************************/
// 1602液晶初始化函数
/*********************************************************/
void LcdInit()
{
LcdWriteCmd(0x38); // 16*2显示,5*7点阵,8位数据口
LcdWriteCmd(0x0C); // 开显示,不显示光标
LcdWriteCmd(0x06); // 地址加1,当写入数据后光标右移
LcdWriteCmd(0x01); // 清屏
}
/*********************************************************/
// 液晶光标定位函数
/*********************************************************/
void LcdGotoXY(uchar y, uchar x)
{
// 第一行
if(y==0)
LcdWriteCmd(0x80+x);
// 第二行
if(y==1)
LcdWriteCmd(0x80+0x40+x);
row=y;
column=x;
}
/*********************************************************/
// 液晶输出字符串函数
/*********************************************************/
void LcdPrintStr(uchar *str)
{
while(*str!='\0')
LcdWriteData(*str++);
}
/*********************************************************/
// IIC起始函数
/*********************************************************/
void IIcStart()
{
SDA_P=1;
Delay6us();
SCL_P=1;
Delay6us();
SDA_P=0;
Delay6us();
}
/*********************************************************/
// IIC终止函数
/*********************************************************/
void IIcStop()
{
SDA_P=0;
Delay6us();
SCL_P=1;
Delay6us();
SDA_P=1;
Delay6us();
}
/*********************************************************/
// IIC写一个字节
/*********************************************************/
void IIcWriteByte(uchar dat)
{
uchar i;
for(i=0;i<8;i++)
{
dat=dat<<1;
SCL_P=0;
Delay6us();
SDA_P=CY;
Delay6us();
SCL_P=1;
Delay6us();
}
SCL_P=0;
Delay6us();
SDA_P=1;
Delay6us();
}
/*********************************************************/
// IIC读一个字节
/*********************************************************/
uchar IIcReadByte()
{
uchar i,temp,dat=0;
SCL_P=0;
Delay6us();
SDA_P=1;
Delay6us();
for (i=0;i<8;i++)
{
SCL_P=1;
Delay6us();
temp=SDA_P;
Delay6us();
dat=(dat<<1)|temp;
SCL_P=0;
Delay6us();
}
return(dat);
}
/*********************************************************/
// IIC总线响应
/*********************************************************/
void IIcRespons()
{
uchar i=0;
SCL_P=1;
Delay6us();
while((SDA_P==1)&&(i<250))
{
i++;
}
SCL_P=0;
Delay6us();
}
/*********************************************************/
// IIC读出数据
/*********************************************************/
uchar IIcReadDat(uchar addr)
{
uchar dat;
IIcStart(); // 开始信号
IIcWriteByte(0xa0); // 写芯片地址(写)
IIcRespons(); // 等待应答
IIcWriteByte(addr); // 写内存地址(0-255)
IIcRespons(); // 等待应答
IIcStart(); // 开始信号
IIcWriteByte(0xa1); // 写芯片地址(读)
IIcRespons(); // 等待应答
dat=IIcReadByte(); // 读取一个字节数据
IIcRespons(); // 等待应答
IIcStop(); // 结束信号
DelayMs(2); // 简短延时
return dat; // 返回读取到的数据
}
/*********************************************************/
// IIC写入数据
/*********************************************************/
void IIcWriteDat(uchar addr,uchar dat)
{
IIcStart(); // 开始信号
IIcWriteByte(0xa0); // 写芯片地址(写)
IIcRespons(); // 等待应答
IIcWriteByte(addr); // 写内存地址(0-255)
IIcRespons(); // 等待应答
IIcWriteByte(dat); // 写入数据
IIcRespons(); // 等待应答
IIcStop(); // 结束信号
DelayMs(2); // 简短延时
}
/**********************************************************
矩阵键盘扫描程序.
如果扫描到有按键按下,则返回按键值,返回值情况如下所示:
-------------------------------------------------------------
| 第1列 第2列 第3列 第4列 |
|第1行 1 2 3 12 |
|第2行 4 5 6 13 |
|第3行 7 8 9 14 |
|第4行 10 0 11 15 |
------------------------------------------------------------
如果扫描不到有按键按下,则返回99
**********************************************************/
uchar KeyScanf()
{
uchar ret,temp1,temp2;
P1=0x0f;
if(P1!=0x0f)
{
DelayMs(15);
if(P1!=0x0f)
{
temp1=P1; // 判断出是哪一行按键按下
P1=0xf0;
DelayMs(5);
temp2=P1; // 判断出是哪一列按键被按下
ret=temp1|temp2; // 通过行和列的值,确定是哪个按键被按下
switch(ret)
{
case 0xe7: return 1;
case 0xd7: return 2;
case 0xb7: return 3;
case 0x77: return 12;
case 0xeb: return 4;
case 0xdb: return 5;
case 0xbb: return 6;
case 0x7b: return 13;
case 0xed: return 7;
case 0xdd: return 8;
case 0xbd: return 9;
case 0x7d: return 14;
case 0xee: return 10;
case 0xde: return 0;
case 0xbe: return 11;
case 0x7e: return 15;
}
return ret;
}
}
return 99;
}
/*********************************************************/
// 液晶显示密码
/*********************************************************/
void LcdPrintCode(uchar num)
{
LcdGotoXY(row,column); // 液晶显示定位
LcdWriteData(num+0x30); // 显示输入的密码
DelayMs(150); // 等待150毫秒
LcdGotoXY(row,column); // 重新回到刚刚的显示位置
LcdWriteData('*'); // 显示“*”替换刚刚显示的数字
column++; // 液晶显示光标的纵坐标加1
}
/********************************************************/
// 蜂鸣器鸣叫
/*********************************************************/
void MingJiao(uint time)
{
Beep_P=0; // 蜂鸣器开始鸣叫
DelayMs(time); // 延时
Beep_P=1; // 蜂鸣器停止鸣叫
}
/*********************************************************/
// 清除密码输入缓冲区的内容
/*********************************************************/
void ClearCodeBuff()
{
uchar i;
for(i=0;i<6;i++) // 循环执行6次
{
ArrCodeBuff=' '; // 每次清除一位密码缓冲区
}
inputNum=0; // 输入的密码位数为0
}
/*********************************************************/
// 密码输入初始化
/*********************************************************/
void inputInit()
{
LcdGotoXY(0,0); // 光标定位
LcdPrintStr(" State:lock "); // 液晶第0行显示" State:lock "
LcdGotoXY(1,0); // 光标定位
LcdPrintStr("Password: ");
LcdGotoXY(1,9); // 液晶第1行显示"Password: "
ClearCodeBuff(); // 清除密码缓冲区
}
/*********************************************************/
// 密码初始化
/*********************************************************/
void CodeInit()
{
uchar dat,i;
dat=IIcReadDat(10);
if(dat!=88) // 如果是第一次使用AT24C02芯片
{
IIcWriteDat(0,1); // 给AT24C02第0个内存写入第一个密码“1”
IIcWriteDat(1,2); // 给AT24C02第1个内存写入第二个密码“2”
IIcWriteDat(2,3); // 给AT24C02第2个内存写入第三个密码“3”
IIcWriteDat(3,4); // 给AT24C02第3个内存写入第四个密码“4”
IIcWriteDat(4,5); // 给AT24C02第4个内存写入第五个密码“5”
IIcWriteDat(5,6); // 给AT24C02第5个内存写入第六个密码“6”
IIcWriteDat(10,88); // 第10个内存写入数字“88”,代表密码初始化好了
}
for(i=0;i<6;i++) // 从AT24C02读取6个密码,赋值给密码数组ArrCode
{
ArrCodeUnlock=IIcReadDat(i);
}
}
/*********************************************************/
// 主函数,程序从这里开始执行
/*********************************************************/
void main()
{
uchar i; // 临时变量
uchar keyVal; // 按键扫描的返回值
uchar ArrCodeTemp[6]; // 临时数组
LcdInit(); // 液晶初始化
inputInit(); // 密码输入初始化
CodeInit(); // 密码初始化
while(1)
{
if(inputNum==6) // 如果输入了6位密码了
LcdWriteCmd(0x0c); // 关闭光标闪烁
else // 如果输入不够6位密码
LcdWriteCmd(0x0f); // 开启光标闪烁
keyVal=KeyScanf(); // 扫描按键是否有按键
if(keyVal!=99) // 如果有按键被按下了
{
MingJiao(50); // 那么蜂鸣器鸣叫50毫秒
}
/* 0-9 数字 */
if(keyVal<10) // 如果数字键被按下
{
if(inputNum<6) // 如果输入的密码不到6位
{
ArrCodeBuff[inputNum]=keyVal; // 给缓冲区加入一个新的密码记录
inputNum++; // inputNum加1,代表当前的密码输入多了一位
LcdPrintCode(keyVal); // 将输入的密码显示出来
}
while(KeyScanf()!=99); // 等待按键释放
}
/* 删除一个密码 */
if(keyVal==10) // 如果删除键被按下
{
if(inputNum>0) // 如果当前已经有输入密码了
{
column--; // 光标退回上一个位置
LcdGotoXY(row,column);
LcdWriteData(' '); // 显示空格
LcdGotoXY(row,column); // 光标退回上一个位置
inputNum--; // inputNum减1,代表当前的密码删掉了一位
ArrCodeBuff[inputNum]=' '; // 清除一位密码缓冲区
}
while(KeyScanf()!=99); // 等待按键释放
}
/* 清除全部密码 */
if(keyVal==11) // 如果取消键被按下
{
ClearCodeBuff(); // 清除密码缓冲区
if(inputMode==1) // 如果当前正在输入解锁密码
{
LcdGotoXY(1,0); // 光标定位
LcdPrintStr("Password: "); // 液晶第1行显示“Password: ”
LcdGotoXY(1,9); // 光标定位
}
if(inputMode==2) // 如果当前正在输入修改密码1
{
LcdGotoXY(0,0); // 光标定位
LcdPrintStr(" input1: "); // 液晶第0行显示“input1: ”
LcdGotoXY(0,8); // 光标定位
}
if(inputMode==3) // 如果当前正在输入修改密码2
{
LcdGotoXY(1,0); // 光标定位
LcdPrintStr(" input2: "); // 液晶第1行显示“input1: ”
LcdGotoXY(1,8); // 光标定位
}
while(KeyScanf()!=99); // 等待按键释放
}
/* 手动关锁 */
if(keyVal==12)
{
while(KeyScanf()!=99); // 等待按键释放
}
/* 取消密码修改 */
if(keyVal==13) // 如果修改密码按键被按下
{
if((inputMode==2)||(inputMode==3)) // 如果当前正在输入修改密码
{
inputInit(); // 输入初始化(退出修改)
Relay_P=1; // 继电器闭合
inputMode=1; // 改为输入解锁密码模式
}
while(KeyScanf()!=99);
}
/* 管理员密码 */
if(keyVal==14)
{
for(i=0;i<6;i++)
{
if(ArrCodeBuff!=ArrCodeAdmin)
break;
}
if(i<6)
{
LcdGotoXY(1,0);
LcdPrintStr(" ERROR ");
MingJiao(5000);
}
else
{
LcdGotoXY(1,0);
LcdPrintStr("Password Init OK");
MingJiao(3000);
IIcWriteDat(10,' ');
CodeInit();
}
inputInit();
}
/* 确认按键 */
if(keyVal==15) // 如果确定键被按下
{
/*解锁密码*/
if(inputMode==1) // 如果当前正在输入解锁密码
{
for(i=0;i<6;i++) // 把密码缓冲区的内容和解锁密码进行6次比较
{
if(ArrCodeBuff!=ArrCodeUnlock)
break;
}
if(i<6) // 如果密码错误
{
errTime++; // 错误次数加1
LcdGotoXY(1,0); // 光标定位
LcdPrintStr(" ERROR "); // 第1行显示" ERROR "
LcdGotoXY(1,11); // 光标定位
LcdWriteData(errTime+0x30); // 显示错误的次数
LcdWriteCmd(0x0c); // 关闭光标闪烁
MingJiao(3000); // 蜂鸣器鸣叫3秒
if(errTime==3) // 如果错误了3次
{
LcdGotoXY(1,0); // 光标定位
LcdPrintStr("Password:lock "); // 第1行显示"Password:locd
errTime=0; // 密码错误次数清零
DelayMs(60000); // 延时60秒
}
}
else // 如果密码正确
{
errTime=0; // 密码错误次数清零
Relay_P=0; // 打开继电器
LcdGotoXY(0,0); // 光标定位
LcdPrintStr(" State:open "); // 第0行显示" State:open "
LcdGotoXY(1,0); // 光标定位
LcdPrintStr(" "); // 第1行显示" "
for(i=0;i<100;i++) // 进行10秒等待,执行100次循环
{
keyVal=KeyScanf(); // 扫描按键
DelayMs(100); // 等待100毫秒
if(keyVal==12) // 如果手动关锁按键被按下
break; // 退出for循环,结束开始等待
if(keyVal==13) // 如果按下修改密码键
{
LcdGotoXY(0,0); // 光标定位
LcdPrintStr(" input1: ");// 第0行显示" input1: "
LcdGotoXY(1,0); // 光标定位
LcdPrintStr(" input2: ");// 第1行显示" input2: "
LcdGotoXY(0,8); // 光标定位
inputMode=2; // 切换密码输入模式
ClearCodeBuff(); // 清除密码缓冲区
while(KeyScanf()!=99); // 等待按键释放
break; // 退出for循环,进入密码修改
}
}
}
if(inputMode==1) // 如果当前处于输入解锁密码状态
{
Relay_P=1; // 闭合继电器
inputInit(); // 密码输入初始化
}
}
/*修改密码1*/
else if(inputMode==2) // 如果当前正在输入修改密码1
{
for(i=0;i<6;i++) // 将输入的密码暂时存入ArrCodeTemp数组
{
ArrCodeTemp=ArrCodeBuff;
}
LcdGotoXY(1,8); // 光标定位
inputMode=3; // 改为输入 修改密码2
ClearCodeBuff(); // 清除密码缓冲区
while(KeyScanf()!=99); // 等待按键释放
}
/*修改密码2*/
else
{
for(i=0;i<6;i++) // 将2次输入的密码进行比较
{
if(ArrCodeBuff!=ArrCodeTemp)
break;
}
if(i<6) // 密码修改错误
{
LcdGotoXY(0,0); // 光标定位
LcdPrintStr("Password Modify "); // 第0行显示"Password Modify "
LcdGotoXY(1,0); // 光标定位
LcdPrintStr("-----failed-----"); // 第1行显示"-----failed-----"
MingJiao(3000); // 蜂鸣器鸣叫3秒
}
else // 密码修改成功
{
LcdGotoXY(0,0); // 光标定位
LcdPrintStr("Password Modify "); // 第0行显示"Password Modify "
LcdGotoXY(1,0); // 光标定位
LcdPrintStr("---Successful---"); // 第1行显示"---Successful---"
MingJiao(2000); // 蜂鸣器鸣叫2秒
for(i=0;i<6;i++)
{
IIcWriteDat(i,ArrCodeTemp);// 将新的密码存入EEPROM芯片
ArrCodeUnlock=ArrCodeTemp;// 将新的密码存入密码数组
}
}
Relay_P=1; // 继电器闭合
inputMode=1; // 改为输入解锁密码模式
for(i=0;i<6;i++) // 清空修改密码缓冲区
{
ArrCodeTemp=' ';
}
inputInit(); // 输入初始化
while(KeyScanf()!=99); // 等待按键释放
}
}
}
}
-
01、未上电.jpg
(211.09 KB, 下载次数: 35)
-
2、输入密码状态.jpg
(214.99 KB, 下载次数: 32)
-
03、密码输入错误.jpg
(215.74 KB, 下载次数: 30)
-
04、修改密码.jpg
(215.47 KB, 下载次数: 39)
-
-
1602显示的密码锁.rar
1.27 MB, 阅读权限: 10, 下载次数: 55
作者: 110101 时间: 2019-6-14 11:35
请问问题解决了吗?
欢迎光临 (http://www.51hei.com/bbs/) |
Powered by Discuz! X3.1 |