历史上的今天
返回首页

历史上的今天

今天是:2024年09月29日(星期日)

正在发生

2019年09月29日 | 课程设计题十二:电子密码锁

2019-09-29 来源:eefocus

要求:

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; //密码不正确报警

推荐阅读

史海拾趣

GE Industrial Solutions公司的发展小趣事
由于光耦的CTR随温度变化而变化,可能导致输出信号的非线性失真。解决方法包括选择温度稳定性好的光耦,或在电路中加入温度补偿电路。
Barkston Plastics Engineering Ltd.公司的发展小趣事

随着电子行业的快速发展,Barkston Plastics Engineering Ltd.意识到单一产品线的局限性,于是开始扩展其产品线,涵盖更多种类的塑料电子元件。同时,公司积极寻求与行业内其他企业的战略合作,通过技术共享和市场资源互补,共同开拓更广阔的市场。这一战略转型不仅提升了Barkston的市场竞争力,也为其后续发展奠定了坚实的基础。

Everett Charles Technologies (ECT)公司的发展小趣事

1965年,Everett Charles Technologies (ECT) 公司正式成立,标志着其在电子测试系统硬件与软件领域的起点。ECT的创始人凭借对电子技术的深刻理解和市场需求的敏锐洞察,成功开发出了一系列符合工业标准的产品,包括POGO探针、ValuGrid测试治具等。这些产品的推出,不仅奠定了ECT在电子测试领域的基础,也为公司的后续发展提供了强大的动力。

芯联(CHIPLINK)公司的发展小趣事

在稳固了车规级IGBT芯片和模组代工市场地位的基础上,芯联集成开始积极拓展新的市场领域。公司凭借其在半导体制造领域的丰富经验和技术优势,成功进军碳化硅芯片和模块市场,并为多家头部新能源车企提供代工服务。此外,公司还计划向AI领域延伸,加强在AI领域的技术布局和市场拓展。这一举措将进一步拓宽芯联集成的业务范围,实现多元化发展。

上海双岭电子(Double-peak)公司的发展小趣事

上海双岭电子自成立以来,一直致力于场效应半导体器件的研发和生产。在成立初期,公司面临着技术瓶颈和市场竞争的双重压力。然而,双岭电子的创始人团队凭借对技术的执着追求和对市场的敏锐洞察,成功研发出具有自主知识产权的结型场效应晶体管,并迅速在航空、通讯等领域打开了市场。这一创新不仅为公司带来了丰厚的利润,也奠定了双岭电子在电子行业中的领先地位。

ALLTHREAD公司的发展小趣事

面对日益激烈的市场竞争,ALLTHREAD意识到必须不断提升生产效率和质量。于是,他们开始引入先进的自动化设备和智能化生产技术,对生产线进行全面升级。通过技术升级,ALLTHREAD的生产效率得到了大幅提升,产品质量也更加稳定可靠。

问答坊 | AI 解惑

关于题C的问题

本帖最后由 paulhyde 于 2014-9-15 09:30 编辑 AD603产生的自激现象严重,当用两级放大时候,第二级放大严重失真,这个是什么原因啊?我们现在在AD603前面加了OPA658做前级跟随器,希望可以减小自激  …

查看全部问答>

发个我用的元件库

这是我平常所用到的元件库…

查看全部问答>

wince 的cab 安装包问题(vs2005)

想做一个cab安装包,安装今日插件,按照网上的说明写了个安装程序setupdll.dll, 但是在模拟器上(pocket pc se 2003 Emulator)安装发现setupdll没有被调用(在函数Install_Exit中加了MessageBox,没有弹出,注册表也没写) cab安装包使用vs2005做的 ...…

查看全部问答>

GPRS连接问题

我用OPEN AT 已经建立完成了GPRS激活部分,但是为什么数据流中什么都收不到,在超级终端里使用ATD*99***1#,可以收到PPP包,如何使用OPEN AT ADL也能收到这些PPP包?请指教一二!我在软件里已经加入了AT命令,但是没有任何反应,到底是什么地方出了 ...…

查看全部问答>

用KernelIoControl获取逻辑中断号失败

我想使用EINTT4作按键中断输入.定义如下: UINT32  g_EINTIrq = IRQ_EINT4; UINT32  g_EINTSysIntr = SYSINTR_UNDEFINED; PUBLIC DWORD CPK_Init(DWORD dwContext) {             &n ...…

查看全部问答>

EVC4.0中窗体最小化问题

想要实现一个最小化功能 使用ShowWindow函数没反应~ 请问各位还有什么其他办法不?…

查看全部问答>

dshow CreateMediaType FreeMediaType 无法解析的外部符号

我在wince6.0上做dshow开发,已经包含的头文件和库 #include #include #include #include #include                                     &n ...…

查看全部问答>

CE6及BSP安装求救!!!!紧急啊

我之前安装开发环境的时候,发现PB中Device Driver中的SD选项没有,后来把Updates全装上了,就出现了SD选项。 前几天系统崩溃了,重新装上所有东西后发现就是SD选项没有,各位有没有遇到过这种情况啊????急 …

查看全部问答>

请教中断问题

我在做关于MPC8260的工作.目前,我想为DMA加入中断处理程序.MPC8260的参考手册中 说,IDMA1的中断号是6,我使用如下函数: intConnect(INUM_TO_IVEC(6),dma_isr,0); 连接中断处理程序与中断源.但是一旦DMA结束,BC中断到来之后,整个EP8260板子就死掉 ...…

查看全部问答>

MCS-51单片机定时器问题

MCS-51单片机中,采用12Mhz时钟,定时器T0采用模式1(16位计数器),请问在下面程序中,p1.0的输出频率 ? MOV TMOD,#01H SETB TR0 LOOP:MOV TH0,#0B1H MOV TL0,#0E0H LOOP1:JNB TF0,LOOP1 CLR TR0 CPL P1.0 SJMP LOOP…

查看全部问答>