要求:

1、在锁开的状态下输入密码,设置的密码共6位,用数据开关K1∼K10分别代表数字1、2、…、9、0,输入的密码用1602显示,可删除输入的数字,删除的是最后输入的数字,每删除一位。


2、可以修改密码,断电不掉数据。


3、三次密码输入错误,开始警报,需要按下复位才能重新输入。


一、Protues仿真图:

二、程序源码:

因为注释非常的全,这里就不再进行讲解了。

/*******************************************************************************

================================================================================

【平    台】STC89C51_sumjess平台

【编    写】sumjess

【E-mail  】1371129880@qq.com

【软件版本】V2.0

【最后更新】2019年06月10日

【相关信息参考下列地址】

【网    站】

           https://blog.csdn.net/qq_38351824

           http://www.51hei.com/bbs/mcu-2-1.html

---------------------------------------------------------------------------------

【dev.env.】MDK4.02及以上版本

【Target  】STC89C51

第一次修订:2019/05/09

第二次修订:2019/05/21

第三次修订:2019/06/10

【problem 】

    (1)库内补充的不全面;

    (2)库内解释部分不全面;

    (3)库内还存在一定的bug;

【direction】

      下一步的目标就是把库继续集成!

【explain 】

      为了方便使用,我也自己写了很多的库,和优化了算法和表示方式!

【warning】

      目前程序中暂无错误 !   

---------------------------------------------------------------------------------

没有完美的代码,只有不断的奉献,大家一起努力;

赠人玫瑰手留余香,欢迎大家反馈bug!

================================================================================

********************************************************************************/

#include

#include

 

#define uchar unsigned char 

#define uint  unsigned int

 

sbit beep=P2^4;//蜂鸣器接口

sbit D1=P2^2;  //开锁信号

sbit k1=P3^2;  //恢复初始密码按键

sbit RS=P2^7;  //数据命令选择 

sbit RW=P2^6;  //读写控制

sbit E=P2^5;   //液晶使能 

sbit SDA=P2^1; //数据线接口

sbit SCL=P2^0; //时钟线接口 

 

uchar idata table1[6]={1,2,3,4,5,6}; //初始密码

uchar dd; 

uchar aa;//存放密码错误的次数,够三次报警

uchar bb;

uchar cc;

//延时子函数

void delay1(uint z)

{

uint x,y;

for(x=0;x for(y=0;y<110;y++);

}

void delay2() 

{

;;

}

//总线初始化子函数

void i2cinit()

{

SDA=1;

delay2();

SCL=1;

delay2();

}

//启动信号子函数

void start()

{

SDA=1;

SCL=1;

delay2();

SDA=0;

delay2();

}

//停止信号子函数

void stop()

{

SDA=0;

delay2();

SCL=1;

delay2();

SDA=1;

delay2();

}

//应答信号子函数

void respons()

{

uchar i=0;

SCL=1;

delay2();

while(SDA==1&&i<255)//等待应答,过一段时间不应答退出循环

i++;

SCL=0;

delay2();

}

//写一个字节子函数

void writebyte(uchar date)

{

uchar i,temp;

temp=date;

for(i=0;i<8;i++)

{

temp<<=1;//temp左移一位后高位进CY

SCL=0;

delay2();

SDA=CY;

delay2();

SCL=1;

delay2();

}

SCL=0;//应答信号中SCL = 1,所以这里要置0

delay2();

SDA=1;//用完要释放数据总线

delay2();

}

//读一个字节子函数

uchar readbyte() 

{

uchar i,k;

SCL=0;

delay2();

SDA=1;

for(i=0;i<8;i++)

{

SCL=1;

delay2();

k=(k<<1)|SDA; //和最低位或,一位位送到K

SCL=0;

delay2();

}

delay2();

return k;

}

//向地址写一个字节数据子函数

void write_add(uchar address,uchar date)

{

start();

writebyte(0xa0);//A0,A1,A2接地,AT24C02芯片地址为1010,送控制字为1010A2A1A0R/~W

respons();

writebyte(address);

respons();

writebyte(date);

respons();

stop();

}

//向地址读一个字节数据子函数

uchar read_add(uchar address)

{

uchar date;

start();

writebyte(0xa0);//A0,A1,A2接地,AT24C02芯片地址为1010,送控制字为1010A2A1A0R/~W

respons();

writebyte(address);

respons();

start();

writebyte(0xa1);//A0,A1,A2接地,AT24C02芯片地址为1010,送控制字为1010A2A1A0R/~W

respons();

date=readbyte();

stop();

return date;

}

//向地址写n个字节数据子函数

void write_n_add(uchar *p,uchar address,uchar n)

{

uchar i;

for(i=0;i {

write_add((address+i),*(p+i));

delay1(20);//一定要适当延时,不然写不进去

}

}

//向地址读n个字节数据子函数

void read_n_add(uchar *p,uchar address,uchar n)

{

uchar i;

for(i=0;i {

*(p+i)=read_add(address+i);

}

}

//LCD1602液晶读忙子函数

bit LCD1602_busy()

{                          

    bit a;

    RS=0;

    RW=1;

    E=1;

    _nop_();

    _nop_();

    a=(bit)(P0&0x80);

    E=0;

    return a; 

}

//LCD1602液晶写命令子函数

void write_com(uchar com) 

{

while(LCD1602_busy());

    RW=0;

RS=0;

    E=0;

P0=com;

delay1(5);

    E=1;

delay1(5);

    E=0;

}

//LCD1602液晶写数据子函数

void write_date(uchar date)

{

while(LCD1602_busy());

    RW=0;

  RS=1;

    E=0;

  P0=date;

delay1(5);

    E=1;

delay1(5);

    E=0;          

}

//写一个字符子函数

void write_1_char(uchar zifu)

{

write_date(zifu);

}

//向液晶写n个字符子函数

void write_n_char(uchar zifu[])

{

uchar i;

for(i=0;;i++)

{

write_1_char(zifu[i]);

if(zifu[i+1]=='')

break;

}

}

//设置液晶显示位置子函数

void LCD1602_pos(uchar x,uchar y) 

{

uchar pos;

if(x==0)

x=0x80;

else if(x==1)

x=0x80+0x40;

pos=x+y;

write_com(pos);

}

//LCD1602液晶初始化子函数

void LCD1602_init()

{

    E=0;

    write_com(0x38);//设置16x2显示,5x7点阵,8位数据口 

    write_com(0x0c);//设置开显示,不显示光标 

    write_com(0x06);//写一个字符后地址指针加1 

write_com(0x01);//显示清0,数据指针清0         

}

//报警子函数

void baojing1()

{

int i=0;

for(i=0;i<5;i++)

{

beep=1;

D1=0;

delay1(5);

beep=0;

D1=1;

delay1(5);

}

}

void baojing2()

{

uchar i;

for(i=0;i<10;i++)

{

baojing1();

}

}

//矩阵按键扫描子函数

uchar keyscan()

{

uchar temp,key;

key=0xff;

P1=0xfe; //将第一行线置低电平

temp=P1;//读JPJK的当前状态到 temp

temp&=0xf0;// temp = temp & 0xf0 按位与 

if(temp!=0xf0)

{

delay1(10);//延时去抖

temp=P1;

temp&=0xf0;

    if(temp!=0xf0)//第一行有键被按下

{

temp=P1;//读被按下的键

baojing1();

switch(temp)

{

case 0xee: key=1;

break;

case 0xde: key=2;

break;

case 0xbe: key=3;

break;

case 0x7e: key=0x0a;

break;

}

while(temp!=0xf0)//等待按键释放

{

temp=P1;

temp&=0xf0;

}

}

}

P1=0xfd; //将第二行线置低电平

temp=P1;//读JPJK的当前状态到 temp

temp&=0xf0;// temp = temp & 0xf0

if(temp!=0xf0)

{

delay1(10);//延时去抖

temp=P1;

temp&=0xf0;

    if(temp!=0xf0)//第二行有键被按下

{

temp=P1;//读被按下的键

baojing1();

switch(temp)

{

case 0xed: key=4;

break;

case 0xdd: key=5;

break;

case 0xbd: key=6;

break;

case 0x7d: key=0x0b;

break;

}

while(temp!=0xf0)//等待按键释放

{

temp=P1;

temp&=0xf0;

}

}

}

P1=0xfb; //将第 三行线置低电平

temp=P1;//读JPJK的当前状态到 temp

temp&=0xf0;// temp = temp & 0xf0

if(temp!=0xf0)

{

delay1(10);//延时去抖

temp=P1;

temp&=0xf0;

    if(temp!=0xf0)//第三行有键被按下

{

temp=P1;//读被按下的键

baojing1();

switch(temp)

{

case 0xeb: key=7;

break;

case 0xdb: key=8;

break;

case 0xbb: key=9;

break;

case 0x7b: key=0x0c;

break;

}

while(temp!=0xf0)//等待按键释放

{

temp=P1;

temp&=0xf0;

}

}

}

P1=0xf7; //将第四行线置低电平

temp=P1;//读JPJK的当前状态到 temp

temp&=0xf0;// temp = temp & 0xf0

if(temp!=0xf0)

{

delay1(10);//延时去抖

temp=P1;

temp&=0xf0;

    if(temp!=0xf0)//第四行有键被按下

{

temp=P1;//读被按下的键

baojing1();

switch(temp)

{

case 0xe7: key=0;

break;

case 0xd7: key=0;

break;

case 0xb7: key=0x0f;

break;

case 0x77: key=0x0d;

break;

}

while(temp!=0xf0)//等待按键释放

{

temp=P1;

temp&=0xf0;

}

}

}

    return key; //返回按下的键 

}

//比较密码子函数

bit sfj1(uchar *string1,uchar *string2)

{

uchar i;

for(i=0;i<6;i++)

{

if(string1[i]!=string2[i])

return 0;

}

return 1;

}

//选择输入密码或修改密码函数

uchar step_choose()

{

uchar key;

key=0xff;

write_com(0x06);//写一个字符后地址指针加 1 

    write_com(0x01);//显示清零,数据指针清零

LCD1602_pos(0,0);

write_n_char(" Input password ");

LCD1602_pos(1,0);

write_n_char("  Press key A  ");

while((key!=0x0a)&&(key!=B))

key=keyscan();

return key;

}

//输入密码子函数

bit input_mima(uchar * mima)

{

uchar i,key;

LCD1602_pos(1,0);

for(i=0;i<7;i++)

{

delay1(100);

if(i<6)

{

do

{

key=keyscan();

}//扫描键盘

while(key==0xff);

if((key!=0x0f)&&(key!=0x0a)&&(key!=0x0c))//不是退格也不是确认键

{

write_date('*');//是数字键显示*

mima[i]=key;

}

if(key==0x0f)//是退格键

{

if(i>0)

{

    LCD1602_pos(1,--i);//光标前移一位

write_date(' ');//清空一位

mima[i]=' ';//写空

LCD1602_pos(1,i);

i--;//密码计数器减一 ,因为循环后会+1,所以在这里要加1

}

}

if(key==0x0c)//没完成密码输入返回错误信息

{

LCD1602_pos(0,0);

return(0);

}

}

if(i==6)

{

do

{

key=keyscan();

}

while((key!=0x0f)&&(key!=0x0c));

if(key==0x0f)

{

LCD1602_pos(1,--i);

write_date(' ');

mima[i]=' ';

LCD1602_pos(1,i);

i--;

}

if(key==0x0c)//密码位数正确

{

return(1);//返回1正确信号

}

}

}

}

//密码处理子函数

void sfj2() 

{

uchar key,i;

uchar idata table2[6]={' ',' ',' ',' ',' ',' '};//存放密码缓冲区

uchar idata table3[6]={' ',' ',' ',' ',' ',' '};

uchar idata table4[6]={' ',' ',' ',' ',' ',' '};

key=step_choose();

if(key==0x0a)//A被按下,接收输入密码,处理

{

read_n_add(table2,0x00,6);

write_com(0x06);//写一个字符后地址指针加 1 

write_com(0x01);//显示清零,数据指针清零

write_com(0x0f);//显示光标

LCD1602_pos(0,0);

write_n_char(" press password ");

if(input_mima(table3)) //处理输入密码

{

if(sfj1(table3,table2)) //密码正确

{

LCD1602_pos(0,0);

write_com(0x0c);

        write_com(0x06);//写一个字符后地址指针加 1 

          write_com(0x01);//显示清零,数据指针清零

write_n_char(" password right ");

aa=0; //清除密码错误次数

D1=0; //开锁

beep=1; //响一下

delay1(1000);

beep=0;

TR0=1;

cc=1;

while(key!=0x0d&&cc) //D没按下一直开

{

key=keyscan();

}

TR0=0;

D1=1;//D按下了关锁

}

else //密码 不正确

{

LCD1602_pos(0,0);

write_com(0x0c); //关光标

write_com(0x06);//写一个字符后地址指针加 1 

write_com(0x01);//显示清零,数据指针清零

write_n_char(" password wrong");

delay1(1000);

aa++;

if(aa==4)

{

aa=0;

    i=20; //密码不正确报警

while(i--)

baojing2();

}

}

}

else //密码没有输入正确或完成

{

LCD1602_pos(0,0);

write_com(0x0c); //关光标

    write_com(0x06);//写一个字符后地址指针加 1 

    write_com(0x01);//显示清零,数据指针清零

write_n_char(" password wrong");

delay1(1000);

aa++;

if(aa==4)

{

aa=0;

    i=20; //密码不正确报警

[1] [2]
关键字:电子密码锁  STC89C51  数据开关 引用地址:课程设计题十二:电子密码锁

上一篇:课程设计题十三:乒乓球比赛
下一篇:课程设计题十一:拔河游戏机设计

推荐阅读

   华为Mate 20的真面目将于10月16日在伦敦揭晓,但此前关于该机已经有大量爆料消息,包括真机等,现在网上又曝光了该机蓝色版的真机。  从图片来看,华为Mate 20蓝色版格外引人注目,后置摄像头和闪光灯组成的正方形让人确定了该机的身份。正面的照片显示,该机似乎采用了双曲面屏,根据之前的爆料,该机将采用刘海全面屏。  配置方面,华为Mate...
折叠手机Galaxy Fold即将在美国开卖,却又出现折叠屏幕瑕疵。美国科技媒体《TechCrunch》报道指出,Galaxy Fold使用27小时就出现瑕疵。27日起,三星电子将通过美国电信AT&T、美国最大家电品牌百思买、三星直营店销售Galaxy Fold,但外媒《TechCrunch》却传出屏幕瑕疵问题。TechCrunch记者布莱恩·希特(Brian Heater)试用的Galaxy Fold屏幕中间出现...
尽管尚未有几款手机得以升级Android 11正式版系统,但谷歌已经迫不及待的地预告Android 12了。官方透露,基于开发者的反馈,在明年的Android 12系统上,将允许更容易地从第三方商店安装APP。谷歌称,统计发现,大多数Android用户会在手机上装至少两个应用商店。关于如何改善体验的细节,谷歌则未予披露。一般而言,使用三方APP商店的问题,一是安全性不...
国内有这么一家公司,名气与关注度远远不及腾讯、字节跳动或者阿里巴巴这些互联网大厂,但却是一家连续8年营收超过100%增长、活跃用户超过2000万人、估值超过3000亿元(相当于Twitter市值)的“隐形王者”。 它就是SheIn,一家主销女装服饰的跨境电商。 不同于国内互联网公司大浪淘沙式的激烈竞争业态,SheIn从一开始便将战场聚焦到了海外市场,依靠强势...

史海拾趣

问答坊 | AI 解惑

ABCO集成NI PAC与Allen Bradley的PLC用于汽车传感器装配与测试 (

开发具有高速、准确、开放式汽车传感器组装线测试器, 可用于获取和分析波形数据, 且可与现有基于PLC(可编程逻辑控制器)的控制系统实现对话。…

查看全部问答∨

arm linux驱动make发生的错误,大家帮忙看看

编的一个驱动,用的是2.6.22内核,交叉编译器是arm-linux-gcc 3.4.1。 下面是我的makefile文件: KERNELDIR :=/home/arm/linux-2.6.22.19 PWD :=$(shell pwd) CFLAGS =-D__KERNEL__ -DMODULE -I$(KERNELDIR)/include/ CROSS_COMPILE =/home/ar ...…

查看全部问答∨

问一个有关消息队列的问题

这几天做相关项目的测试,有个问题不解: 在vxworks环境下有两个任务A和B,B的优先级高 B接收消息并通过驱动函数转发出去,消息队列中最大消息个数为500个,添加了流量控制,每转发3包个则延迟1个tick 而测试任务A我设定每向B发送20个消息(一个 ...…

查看全部问答∨

avr或单片机可以运行wince操作系统吗

如题,如果可以怎么做,不可以请大家帮我推荐可以在那样的单片机里运行的操作系统,谢谢了…

查看全部问答∨

求大侠来给点指点。

  小弟马上要上手一个水文项目,具体就是做一个RTU设备,能够采集雨量水位等的信息,然后通过GPRS或是GSM方式发送到监控中心,监控中心也能发指令从RTU上取数据,RTU上要带键盘输入LCD的置数器,修改参数等。最好能将这个RTU扩展至很多的 ...…

查看全部问答∨

LPC2132 驱动ILI9320 TFT 程序问题

  这是一个TFT显示一幅红色图片的程序,但是在板上运行时,显示完一幅完整的图片要得差不多一个小时,不知道是什么原因, 请各位大侠 挥指知之间 指点指点 ..................不胜感激.     #include<LPC214X.h>//#include\ ...…

查看全部问答∨

STM32 usb 库不能解析USBHID专用请求吗?

目前正在移植以前51的一个产品。在控制端点0要用到专用请求 host->device 第一字节0x02(表示专用的ID可以是小于255,不等与零的任意数) ,第二字节 0x02 表示实际的device设备有几个(在报告描述里有几个就是几个 可以是大于等于1 ,小于等于255 ...…

查看全部问答∨

求个单片机最小系统原理图和PCB图

&nbsp; 为了完成作业,需要设计一个单片机最小系统,想找个作为参考,不知道谁那儿有啊?可以分享一下,感激不尽!…

查看全部问答∨

跪求解释此硬件电路~~~~~

原文:由于轮椅控制器采用的是双极性模式,有四个功率管:T1、T2、T3、T4,其中 T1 和 T4 的 PWM 脉冲信号是相同的,T2 和 T3 的 PWM 脉冲是相同的,T1 与 T2 的 PWM 脉冲是互补的。而从 DSP 出来的只有一对互补的信号,因此利用 CD74ACT157 再复制 ...…

查看全部问答∨

理解模拟电路:有源器件

本帖最后由 dontium 于 2015-1-23 12:42 编辑 这也是TI的,文章中说了几种有源器件:晶体管、JFET、MOSFET、运放、比较器等的特性 …

查看全部问答∨
小广播
设计资源 培训 开发板 精华推荐

最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

更多每日新闻

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

电子工程世界版权所有 京ICP证060456号 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved