精华内容
下载资源
问答
  • 51单片机C语言的密码锁程序.doc
    2021-05-19 16:19:10

    51单片机C语言的密码锁程序,单片机密码锁程序,单片机电子密码锁程序,单片机c语言延时程序,单片机c语言程序设计,c语言写单片机程序,单片机c语言查表程序,单片机c语言程序,单片机时钟程序c语言,stm8单片机c语言程序

    求51单片机C语言编的密码锁程序

    悬赏分:100 - 解决时间:2008-6-22 10:16

    要求:

    能输入密码与制定密码箱同时亮起一个灯表示密码正确,否则蜂鸣器报警表示密码错误,能设定新的密码,可扩展将密码写入flash,掉电不丢失

    提问者: 匿名

    最佳答案

    #include

    #define uint unsigned int

    #define uchar unsigned char

    #define BIN(a,b,c,d,e,f,g,h) ((a<<7)+(b<<6)+(c<<5)+(d<<4)+(e<<3)+(f<<2)+(g<<1)+(h<<0))

    //下面的code表示数组存放在ROM中,因为这个数组的值不需要改写

    uchar code KeyCode[16]={15,14,12,8,30,28,24,16,60,56,48,32,120,112,96,64};//值为m*(n+1)的乘积,用于Key()

    uchar dis[6];

    msdelay(uint x)//延时子函数

    {uchar j;

    while(x--)

    {for(j=0;j<125;j++){;}

    }

    }

    //键盘子程序一,键盘值与数组值对比得到

    uchar Key(void)

    {uchar temp,m,n,i,j,matrix,k;

    P1=0xF0; /*行线电平为高,列线为低*/

    temp=P1&0xf0;

    if (temp==0xf0) return(16); /*行仍为高,无按健,退出*/

    else msdelay(10);

    for(i=1;i<16;i=i*2)

    {m=i;

    for(j=1;j<16;j=j*2)

    {n=(~j)&0x0f;

    P1=(m<<4)|n; /*m为P1的行值由i循环得到,n为列值,由j循环并取反得到*/

    temp=P1&0xf0;

    if (!temp)

    {do{temp=P1&0xf0;}while(!temp);

    matrix=m*(n+1);/*为避免乘积重复,n+1*/

    for(k=0;k<16;k++){if (matrix==KeyCode[k]) return(k);} //KeyCode:见前

    return(16);

    } //if loop

    }//j loop

    }//i loop

    }//Key end

    //用Switch...case语句得到键盘值*/

    uchar Key1(void)

    {uchar temp,m,n,i,j,matrix;

    P1=0xF0; /*行线电平为高,列线为低*/

    temp=P1&0xf0;

    if (temp==0xf0) return(16); /*行仍为高,无按健,退出*/

    else msdelay(10);

    for(i=1;i<16;i=i*2)

    {m=i;

    for(j=1;j<16;j=j*2)

    {n=(~j)&0x0f;

    P1=(m<<4)|n;/*m为P1的行值由i循环得到,n为列值,由j循环并取反得到*/

    temp=P1&0xf0;

    if (!temp)

    {do{temp=P1&0xf0;}while(!temp);

    matrix=m*(n+1);

    switch(matrix) //此方法的基本思路:

    {case 15:return(1); break; //由循环得到的m,n值赋于P1端口实现逐个键扫描

    case 14:return(2); break; //同时由m,n+1的值相乘得到对应键点de的积

    更多相关内容
  • 电子密码锁程序

    2018-12-21 21:43:45
    基于单片机的电子密码锁程序,文件只有c源代码,需要其他东西记得问我。
  • 电子密码锁程序.zip

    2021-05-07 16:32:30
    1)6位密码,通过键盘可修改初始密码; 2)采用液晶模块LCD1602显示当前输入密码; 3)具有输入正确和错误警告; 4)具有输错次数锁定功能;
  • 基于51单片机+LCD1602显示的电子密码锁程序源代码及仿真 基于51单片机的电子密码锁c程序,可保护密码,三次报警,基于51单片机的电子密码锁程序及仿真,支持报警,密码修改,密码保存,管理员密码等功能! /*密码...
  • 基于51单片机的电子密码锁程序

    千次阅读 2021-05-19 16:20:08
    结果图:4.png (839.58 KB, 下载次数: 5)2020-10-17 20:57 上传一、目的概述(收集相关资料、选设计方案、电路设计):本设计是以STC89C52单片机为控制核心的电子密码锁,属于单片机的应用。做本设计有助于对单片机...

    结果图:

    3f829e29e76caa8c3b1f630a6b27d58d.gif

    4.png (839.58 KB, 下载次数: 5)

    2020-10-17 20:57 上传

    一、目的概述(收集相关资料、选设计方案、电路设计):

    本设计是以STC89C52单片机为控制核心的电子密码锁,属于单片机的应用。做本设计有助于对单片机矩阵键盘,数码管以及串行通信原理的深入了解。电子锁由于其保密性高,使用灵活性好,安全系数高,受到了广大用户的青睐。

    系统设计方案为:

    (1)系统设置6位密码,密码通过键盘输入,若密码正确,则将锁打开。

    (2)密码可由用户自己设定,在开锁状态下,用户可自行修改密码。

    (3)具有自动报警功能,密码输入错误时,报警由扬声器发出“滴滴”报警声。而密码输入正确则是“叮咚”声。

    系统设计结构图:3f829e29e76caa8c3b1f630a6b27d58d.gif

    屏幕截图 2020-10-17 205131.png (26.31 KB, 下载次数: 4)

    2020-10-17 20:52 上传

    本设计由主控芯片51单片机,单片机时钟电路,键盘,数码管组成。单片负责控制整个系统的控制执行过程。开锁成功由数码管显示OPEN,以及蜂鸣器“叮咚”表示,开锁失败由数码管显示Err,以及蜂鸣器“滴滴”表示。

    二、实验原理图

    电路设计:

    3f829e29e76caa8c3b1f630a6b27d58d.gif

    2.png (180.44 KB, 下载次数: 1)

    2020-10-17 20:54 上传

    3f829e29e76caa8c3b1f630a6b27d58d.gif

    1.png (96.78 KB, 下载次数: 3)

    2020-10-17 20:54 上传

    程序设计:(只展示核心部分)

    主程序

    1.  //4×4 键盘及8 位数码管显示构成的电子密码锁

    2.  void main() //主程序

    3.  {

    4.      uchar key;

    5.      Timer0_Init();

    6.      while(1)

    7.      {

    8.          key = KeyScan();

    9.          password(key);

    10.     }

    11. }

    核心程序:数码管的动态扫描显示

    12. void Display()

    13. {

    14.     uchar i;

    15.     Segment_sel=0x00;//消隐

    16.     switch(i)    //位选,选择点亮的数码管,

    17.     {

    18.         case(0):

    19.             LSA=0;LSB=0;LSC=0; break;

    20.         case(1):

    21.             LSA=1;LSB=0;LSC=0; break;

    22.         case(2):

    23.             LSA=0;LSB=1;LSC=0; break;

    24.         case(3):

    25.             LSA=1;LSB=1;LSC=0; break;

    26.         case(4):

    27.             LSA=0;LSB=0;LSC=1; break;

    28.         case(5):

    29.             LSA=1;LSB=0;LSC=1; break;

    30.     }

    31. }

    核心程序:矩阵键盘的扫描输入

    32. uchar KeyScan()

    33. {

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

    35.     {

    36.         P1 = P1Pin[ i];

    37.         Button = P1;

    38.         if(Button != P1Pin[ i])

    39.         {

    40.             Delayms(5);

    41.             Button = P1;

    42.             if(Button != P1Pin[ i])

    43.             {

    44.                 KeyState=1;

    45.                 key8 = Button;

    46.             }

    47.             while(Button != P1Pin[ i])

    48.             { Button = P1; }

    49.         }

    50.     }

    51.     switch(key8)

    52.     {

    53.         case 0x77:{key = 1;break;}

    54.         case 0x7b:{key = 2;break;}

    55.         case 0x7d:{key = 3;break;}

    56.         case 0xb7:{key = 4;break;}

    57.         case 0xbb:{key = 5;break;}

    58.         case 0xbd:{key = 6;break;}

    59.         case 0xd7:{key = 7;break;}

    60.         case 0xdb:{key = 8;break;}

    61.         case 0xdd:{key = 9;break;}

    62.         case 0xeb:{key = 0;break;}  //0

    63.         case 0x7e:{key = 10;break;}  //÷

    64.         case 0xbe:{key = 11;break;}  //×

    65.         case 0xde:{key = 12;break;}  //+

    66.         case 0xee:{key = 13;break;}  //-

    67.         case 0xed:{key = 14;break;}  //=

    68.         case 0xe7:{key = 15;break;}  //ENTER

    69.         default:{key = 0xff;break;}

    70.     }

    71.     return key;

    72. }

    核心程序:输入密码以及校对和处理

    73. void password(uchar key)//0~9 数字键,10 输入密码,11 设置密码,12 删除上一个数,13 重新输入 15 确定

    74. {

    75.     uchar i=0;

    76.     if(KeyState==1)

    77.     {

    78.         switch(state)

    79.         {

    80.             case 0:

    81.             {

    82.                 if(key == 10)

    83.                 {

    84.                     state = 1;

    85.                     LSA=1;LSB=1;LSC=1;

    86.                     Segment_sel=0xff;  //显示8

    87.                 }

    88.                 else if(key == 11)

    89.                 {

    90.                     state = 2;

    91.                     LSA=1;LSB=1;LSC=1;

    92.                     Segment_sel=0xfd;  //显示P

    93.                 }

    94.                 break;

    95.             }

    96.             case 1:

    97.             {

    98.                 if(key>=0 && key <= 9)  //输入

    99.                 {

    100.                     InPassword[5]=InPassword[4];

    101.                     InPassword[4]=InPassword[3];

    102.                     InPassword[3]=InPassword[2];

    103.                     InPassword[2]=InPassword[1];

    104.                     InPassword[1]=InPassword[0];

    105.                     InPassword[0]=smgduan[key];

    106.                     KeyState=0;

    107.                 }

    108.                 else if(key == 15)  //确定

    109.                 {

    110.                     if(Compare(InPassword))

    111.                     {

    112.                         for(i=17;i<23;i++)

    113.                             InPassword[ i]=smgduan;

    114.                         Delayms(1000);

    115.                     }//open

    116.                     else

    117.                     {

    118.                         for(i=23;i<27;i++)

    119.                             InPassword[ i]=smgduan;

    120.                         Delayms(1000);

    121.                     }//err

    122.                 state = 0;

    123.                 }

    124.                 else if(key == 13)  //重新输入

    125.                 {

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

    127.                         InPassword[ i] = 0xff;  // 全亮

    128.                     Delayms(1000);

    129.                     state = 0;

    130.                 }

    131.                 break;

    132.             }

    133.     else//如果没有按键按下

    134.     {

    135.         if(state == 0)

    136.         {

    137.             Segment_sel= 0x00;// 不显示

    138.         }

    139.     }

    140. }

    C语言代码51hei下载地址:

    08888e3a94b1d4845f47f7539b112be4.gif

    电子密码锁程序.zip

    (1.79 KB, 下载次数: 52)

    2020-10-17 20:59 上传

    点击文件名下载附件

    下载积分: 黑币 -5

    展开全文
  • 通过Verilog编程,可实现电子密码锁的功能,分为设置密码,密码清零,验证密码,重置显示4个部分
  • 红外控电子密码锁程序代码 程序 , 密码锁 红外控电子密码锁程序代码 程序 , 密码锁
  • 本系统由单片机系统、矩阵键盘、LED显示和报警系统组成。系统能完成开锁、超时 ;报警、超次锁定、管理员解密、修改用户密码基本的密码锁的功能。
  • 单片机电子密码锁程序-汇编 初始化密码830620
  • 汇编电子密码锁程序.docx
  • (1)设计4位密码电子锁。 (2)在数码管上显示密码,并且密码可删除。 (3)当密码正确时,LED灯亮,密码错误,蜂鸣器报警三声。 (4)矩阵键盘包括0-9输入密码键以及删除密码键、关闭键。 (5)4个独立按键...
  • 基于单片机的电子密码锁程序.doc
  • 8279应用于电子密码锁程序设计[借鉴].pdf
  • 电子密码锁程序设计

    2012-06-09 12:37:37
    实现密码判断(15分) 实现密码更改(15分) 实现程序正常结束(5分) 实现非软件的准确延时(5分) 输入错误3次后自动结束程序(20分)
  • 基于51的单片机的电子密码锁的C语言程序(含详细注释)以及ptoteus仿真(含使用说明),除了基本的断电储存密码的电子锁功能外,还集成了以下功能 1)利用DS18B20采集温度显示,在开锁后显示; 2)利用DS1302记录...
  • 基于51单片机的带记忆功能的电子密码锁设计。 设计要求:1、利用51系列单片机为核心,矩阵键盘与LCD1602液晶显示屏组成硬件系统,设计一款电子密码锁; 2、该密码锁具有设置、修改六位用户密码、超次报警、超次锁定...
  • 基于单片机的电子密码锁,通过密码输入来控制芯片工作,完成开锁、闭锁、修改密码等任务的电子产品。它具有保密性高、成本低、功耗低、操作简单,使用灵活性好等特点。 附件包含源代码
  • Arduino密码锁

    2019-04-26 16:52:15
    基于Arduino的密码锁,可以实现密码存储等等功能,同时还具有密码修改功能。
  • 基于单片机的电子密码锁设计程序: 设计要求:1、4*3阵键盘0—9数字输入及2个功能键:用于密码输入和功能选择; 2、根据设定好的密码,当密码输入正确之后,锁就打开,绿色发光二极管亮; 3、当输入密码错误时,...
  • 电子密码锁主要功能: 1.实现按键中断功能,中断处给予警报提示; 2.实现对AT24C02的通讯,存储密码,掉电不丢失; 3.实现对PCF8563为RTC时钟的控制,给系统提供准确的时间; 4.实现AD按键的检测,通过定时器0的通道0...
  • 基于单片机的电子密码锁设计程序及电路图.pdf
  • 密码为6位,只有在开锁时密码可更改,更改时要输入两遍确认; 2.采用矩阵按键输入、1602液晶显示、继电器模拟开锁,有开锁指示灯。继电器有常开常闭触点可外接电磁等负载; 3.输入密码错误会提示错误次数,当次数...
  • 《基于单片机的电子密码锁程序》由会员分享,可在线阅读,更多相关《基于单片机的电子密码锁程序(17页珍藏版)》请在人人文库网上搜索。1、基于单片机的电子密码锁设计摘要随着科技和人们的生活水平的提高,如何...

    《基于单片机的电子密码锁及程序》由会员分享,可在线阅读,更多相关《基于单片机的电子密码锁及程序(17页珍藏版)》请在人人文库网上搜索。

    1、基于单片机的电子密码锁设计摘要随着科技和人们的生活水平的提高,如何实现家庭防盗这一问题也变的尤为突出,传统的机械锁由于构造简单,被撬事件屡见不鲜。电子密码锁保密性好,使用灵活性高,收到广大用户的青睐。本设计是以单片机AT89C52作为密码锁的主控芯片与数据存储单元,结合外围的矩阵键盘输入、LCD显示、开锁、报警等,用C语言编写程序,并用Keil uVision4软件进行编译设计了一款可以更改密码,具有报警功能的电子密码控制系统。本设计采用矩阵键盘对密码进行输入,具有较高的优势,减少了I/O口的占用数目。密码的显示采用LCD显示屏实现,为确保安全性统一使用“*”显示密码,当重新设置密码时按下“修。

    2、改”键,LCD显示屏显示数字。采用蜂鸣器模拟报警系统,增加了密码锁的安全能力。软件使用C语言编程,运用自上而下的模块化设计思想,使系统朝着分布式、小型化方向发展,增强系统的可扩展性和运行的稳定性。测试结果表明,设计达到电子密码锁的功能。关键字:密码锁、AT89C52、矩阵键盘、报警一、设计背景随着社会科技的进步,锁已经发展到了密码锁、磁性锁、电子锁、激光锁、声控锁等等。在传统钥匙的基础上,加了一组或多组密码,不同声音,不同磁场,不同声波,不同光束光波,不同图像来控制锁的开启,从而大大提高了锁的安全性。当今安全信息系统应用越来越广泛,特别在机密保护、维护隐私和财产保护方面起到重大作用,而基于电子。

    3、密码锁的安全系统是其中的一部分,运用非常广泛,研究它具有重大的现实意义。电子密码锁可以在日常生活和现代办公中,住宅与办公室的安全防范、单位的文件档案、财务报表以及一些个人资料的保存等多种场合使用。大大提高了主人物资的安全性。目前使用的密码锁种类繁多,各具特色。本文从经济实用的角度出发,采用AT89C52单机,研制了一款具有防盗自动报警功能的电子密码锁。该密码锁设计方法合理,简单易行,成本低,符合住宅、办公室用锁要求,具有一定的推广价值。2、 设计目的1. 了解单片机开发系统的组成及结构;2. 掌握I/O口的操作方法;3. 能够熟练使用protues和keil软件进行连线和编程,并熟练掌握仿真方。

    4、法;4. 掌握LCD显示屏的显示原理;5. 掌握C语言编程方法;6. 培养查找错误和改正错误的能力。3、 设计要求本设计采用单片机为主控芯片,结合外围电路组成电子密码控制系统。设计主要功能有:1. 设置6位密码,密码通过键盘输入,若密码正确,则锁打开,LCD显示“Password Right Lock Opened!”。原始密码在首次开锁时为“000000”。2. 重新设置密码时,LCD显示“*”,按下“修改”键显示数值。3. 密码只能输入6位数字,无法输入多余数字。4. 具有自动报警功能:当密码输入错误三次,报警,蜂鸣器响3秒。5. LED数码管显示密码,为确保安全性所有密码均用“*”表示。。

    5、4、 设计原理和硬件仿真方案1. 矩阵键盘密码的输入用矩阵键盘实现,包括数字键和功能键。具体功能设计如表一:表一 键盘具体功能设计表按键键名功能09数字键输入密码新建新建键设定新密码确认确认键比较密码修改修改键显示密码进入进入键允许输入密码取消取消键取消输入密码如图一所示,矩阵键盘的每一条水平(行线)与垂直线(列线)的交叉处不相通,而是通过一个按键来连通,利用这种行列式矩阵结构只需要N条行线和M条列线即可组成有个按键的键盘。图一 矩阵键盘本次设计需要09十个数字按键、一个新建键、一个确认键、一个修改键、一个进入键和一个取消键共15个按键,所以选用4X4的矩阵按键。在这种行列式矩阵键盘编码的单片。

    6、机系统中,键盘处理程序首先执行等待按键并确认有无按键按下的程序段,还要对按键进行消抖处理。当确认有按键按下后,就要识别是哪一个按键被按下。本次设计使用的是线反转法。给行线置为0x0f,给列线置为0xf0,再将行列进行逻辑或结果为0xff,当有按键按下时相应的按键位行列均为0,行列逻辑或不为0xff,由此可利用行列逻辑或后的值是否为0xff来判断是否有按键按下。再根据扫描结果判断按下键的位置。给相应的按键赋值即可实现数字键和功能键。对功能键进行相应的软件编程即可实现按键功能。使用矩阵键盘能减少键盘和单片机接口所占用的I/O线数目,当按键较多的时候通常采用这种方法。2. 开锁电路在本次设计中用发光。

    7、二极管代替电磁锁,二极管D1亮表示锁开,二极管灭表示没有开锁。如图二所示,当输入密码与内置密码相配合时将P2.1置0,二极管亮,否则二极管不亮。图二 发光二级管电路3. 报警电路报警电路由单片机和蜂鸣器组成,如图三所示,当P2.0为低电平时蜂鸣器发出声音报警。每次输入的密码与正确密码进行比较,如果相同,锁开灯亮。如果输入错误则用一个变量来记录输入错误的次数,当输入密码错误达到三次时,蜂鸣器工作发出报警声音,本次设计使用的是声音持续3秒蜂鸣器报警,即可听到“嘟”3秒的响声。图三 报警电路4. LCD显示电路密码显示电路由单片机、排阻和LCD显示屏组成。显示电路如图四所示。为保证密码的保密性,本设。

    8、计采用“*”显示所有输入密码,如图四所示。当重设密码时,按下“修改”键显示数字,如图五所示。本设计只允许输入数字密码6次,超过6次以后的数字无法输入。图四 LCD显示电路图五 重设密码LCD显示数字5、 软件程序设计本系统软件设计由主程序、初始化程序、键盘扫描程序、密码输入程序、功能键定义程序、重置密码程序、LCD显示程序、中断延时程序、报警程序、延时程序组成。如图六所示为主程序流程图,开始接上电源,程序进行初始化设置,然后在键盘上输入密码,此系统进行键盘扫描,判断密码是否正确,密码正确开锁,密码不正确统计错误密码次数加1。在开锁情况下进行修改密码,点击确认密码修改成功,否则结束返回。若密码修。

    9、改成功则再执行之前的操作。开始初始化键盘扫描子程序结束调用密码重置子程序调用报警子程序密码错误次数q+1重设密码?密码正确?输入密码个数N=6?LCD显示子程序输入密码子程序Nq=3?调用延时子程序开锁Y N N Y Y Y N 图六 主程序流程图六、系统调试本次调试采用的是protues和keil软件进行仿真。首先运用keil软件编写电子密码锁的源程序,本设计主要运用C语言编写。源程序编写后运行生成目标文件供protues仿真调试。图七为LED显示六位密码的情况图七 LCD显示密码图当密码正确按下确认键发光二极管亮,锁开。如图八图八 密码正确锁开灯亮当密码输入错误三次蜂鸣器发出声音报警,如图。

    10、九所示图九 蜂鸣器报警由图九可以看到蜂鸣器接地端为蓝色,即此时为低电平,所以蜂鸣器正在发出报警声音。Protues仿真电路图如图十所示图十 protues仿真电路图七、设计总结与展望课程设计是培养学生综合运用所学知识发现、提出、分析和解决实际问题,锻炼实践能力的重要环节,是对学生实际工作能力的具体训练和考察过程。随着科学技术发展的日新月异,单片机已经成为当今计算机应用中空前活跃的领域,在生活中可以说是无处不在。因此作为二十一世纪的大学生来说掌握单片机的开发技术是十分重要的。本设计经过多次修改和整理,可以满足基本的要求。密码正确,锁开;密码输入错误三次,报警;输入密码超过6位之后的数无效;LCD。

    11、显示屏显示密码为“*”。在设计的过程中遇到了各种各样的问题,譬如说断电密码保护的设计,由于电路和编程都过于复杂,本设计并未加入。在编程的过程中问题也是很多,由于程序较长,当实现了这个功能另外一个功能有不能很好的实现,所以要做到模块与模块之间的衔接。遇到的一些问题也经过努力一一克服。回顾此次单片机课程设计,至今我仍感触颇多。在设计过程中从理论到实践我们可以到很多很多东西,巩固了以前学过的知识,还懂得了如何将理论联系实际。只有理论知识是远远不够的,只有将理论运用到实际中对我们来说才是有意义的,这样才能真正的为社会服务。七、附录源程序清单:#include#include#define uchar 。

    12、unsigned charstatic unsigned char table6=0,0,0,0,0,0;/Declare functionsuchar Busy_Check();void Initialize_LCD();void Write_LCD_Data(uchar dat);void Write_LCD_Command(uchar cmd);void Display_String(uchar x,uchar y,uchar *str);void Display_char(uchar hang,uchar lie,char sign);/void write_add(uchar add。

    13、ress,uchar date);/向AT24Cxx中的指定地址写入数据uchar read_add(uchar address);/ 从AT24Cxx中的指定地址读取数据void init();uchar h=20; sbit touch=P21;sbit touch1=P22;sbit speaker=P20;void delay(unsigned char ms) / 延时*msunsigned char i;while(ms-)for(i=250;i0;i-)_nop_();_nop_();_nop_();_nop_();unsigned char keyscan() / 扫描键盘un。

    14、signed char temp,y,j;unsigned char anjian=0xfe,0xfd,0xfb,0xf7; for(y=0;y4;y+)P1 = anjiany;temp = 0x10;for(j=0;j4;j+)if(!(P1&temp)return(j+y*4);temp = _crol_(temp,1);void judge()P1 = 0xf0;if(P1!=0xf0) / 判断是否有按键delay(50);delay(50); / 消抖if(P1!=0xf0)h=keyscan();void main() unsigned char a=1,i=0,k=0,l=1,。

    15、m=1,n,f=0,s=0;int q;Initialize_LCD();init();Display_String(1,1,Welcome To Use );Display_String(2,1, );touch1=0;/第一个while循环 while(1) judge();if(h10)if(h=tablei)k+;Display_String(2,a,*);a+;i+;if(a=7)a=1;if(i=6)i=0;h=16;if(h=14) Display_String(1,1,Input Password);Display_String(2,1, );h=16;touch=1;touc。

    16、h1=0;k=0;l=1;q=0;if(h=12)if(k=6)Display_String(1,1,Password Right);Display_String(2,1,Lock Opened!);touch=touch;else Display_String(1,1,Password Error);Display_String(2,1, );l=0;q+;while(q=3)speaker=0;delay(200);delay(200);delay(200);speaker=1 ;q=0;h=14;delay(255);k=0;h=16;while(l)judge();if(h=11) D。

    17、isplay_String(1,1,New Code);Display_String(2,1, );while(m=1) judge();touch1=touch1; if(h10)tablen=h;write_add(s,h);s+;Display_String(2,a,*);a+;n+;h=16;if(n=6) n=0;s=0; if(h=15)if(n=0)n=6;s=6;a-;s-;Display_String(2,a, );n-;h=16;if(h=13)m=0;if(h=13)h=13;f=1;if(h=14) l=0; if(h=13) Display_String(2,1, )。

    18、; for(n=0;n6;n+)Display_char(2,n+1,(uchar)(tablen+48) );h=13;l=0;f=1; k=0;if(h=15)a-;Display_String(2,a, );k-;i-;h=16;if(h=13) if(f=1) for(n=0;n6;n+)Display_char(2,n+1,(uchar)(tablen+48) );f=0; elseDisplay_String(2,1, * );delay(255);delay(255);Display_String(1,1, Welcome To Use );Display_String(2,1, );l=1;a=1;k=0;n=0;m=1;h=16;for(s=0;s6;s+) tables=read_add(s);delay(50);。

    展开全文
  • 该资料包含原理图、源程序和仿真等 功能介绍: 1.采用AT24C02芯片可以实现存储的密码掉电保存。密码为4位,只有在开锁时密码可更改,更改时要输入两遍确认; 2.采用矩阵按键输入、1602液晶显示、LED灯模拟开锁,...
  • 基于金沙滩51单片机的电子密码锁程序 很久之前做的一个课设,在B站发了效果视频,发现忘记分享代码了,现在整理分享一下。 零、设计报告 1.设计要求 这部分是讲的整个系统实现了什么功能。 1.1、密码的设定,此密码...

    基于金沙滩51单片机的电子密码锁程序

    很久之前做的一个课设,在B站发了效果视频,发现忘记分享代码了,现在整理分享一下。

    零、设计报告

    1.设计要求

    这部分是讲的整个系统实现了什么功能。
    1.1、密码的设定,此密码是固定在程序存储器ROM中,假设预设的密码为“123456”共6位密码。
    1.2、密码的输入: 用4*4矩阵键盘中的10个按键分别表示0~9的数字,完成6位密码的输入。
    1.3、密码的修改:能够修改密码,修改以后的密码掉电不丢失,即下一次上电以后用新设定密码进入系统。
    1.4、密码错误蜂鸣器发出报警音。

    2.系统硬件电路设计

    这部分其实就是金沙滩开发板上的电路图,再对其作一些讲解,懂的可以略过这部分,但是设计报告上要写明的。
    2.1 主控芯片STC89C52RC模块

    单片机电路原理图

    STC89C52RC是STC公司生产的一种低功耗、高性能CMOS8位微控制器,具有8K字节系统可编程Flash存储器。STC89C52使用经典的MCS-51内核,但是做了很多的改进使得芯片具有传统的51单片机不具备的功能。在单芯片上,拥有灵巧的8 位CPU 和在系统可编程Flash,使得STC89C52为众多嵌入式控制应用系统提供高灵活、超有效的解决方案。
    STC89C52RC有40个引脚,8k字节Flash,512字节RAM, 32 位I/O 口线,看门狗定时器,内置4KB EEPROM,MAX810复位电路,3个16 位定时器/计数器,4个外部中断,一个7向量4级中断结构(兼容传统51的5向量2级中断结构),全双工串行口。另外 STC89C52 可降至0Hz 静态逻辑操作,支持2种软件可选择节电模式。空闲模式下,CPU 停止工作,允许RAM、定时器/计数器、串口、中断继续工作。掉电保护方式下,RAM内容被保存,振荡器被冻结,单片机一切工作停止,直到下一个中断或硬件复位为止。最高运作频率35MHz,6T/12T可选。

    2.1.1 STC89C52RC主要功能特性

    • 8K字节程序存储空间;
    • 512字节数据存储空间;
    • 内带4K字节EEPROM存储空间;
    • 可直接使用串口下载;

    2.2 按键电路模块
    电路采用4x4的矩阵按键,节省IO口,效率高。矩阵键盘又称行列键盘,它是用四条I/O线作为行线,四条I/O线作为列线组成的键盘。
    在行线和列线的每个交叉点上设置一个按键。这样键盘上按键的个数就为4x4个。

    按键电路原理图

    2.3 LCD1602显示模块
    LCD1602液晶显示器是广泛使用的一种字符型液晶显示模块。它是由字符型液晶显示屏(LCD)、控制驱动主电路HD44780及其扩展驱动电路HD44100,以及少量电阻、电容元件和结构件等装配在PCB板上而组成。项目使用LCD1602模块与用户交互。

    LCD1602显示电路原理图

    2.4 蜂鸣器模块
    本项目使用的是无源蜂鸣器,无源蜂鸣器利用电磁感应现象,为音圈接入交变电流后形成的电磁铁与永磁铁相吸或相斥而推动振膜发声,接入直流电只能持续推动振膜而无法产生声音,只能在接通或断开时产生声音。因此需要给一定的脉冲才能发出声音。

    蜂鸣器电路原理图

    2.5 EEPROM存储模块
    EEPROM模块采用的是24C01芯片,EEPROM (Electrically Erasable Programmable read only memory)是指带电可擦可编程只读存储器。是一种掉电后数据不丢失的存储芯片。每块24C01有256字节,使用I2C进行通信,页写缓冲区最高可达8字节,数据保存时间大于二百年,是很方便的存数据的芯片,本项目的密码就保存于此。

    EEPROM存储电路原理图

    3、系统程序设计

    这部分是讲的整个系统的程序是怎么实现的,以及通过程序流程图对程序的解读。
    3.1 程序流程图
    设备开机后,读取EEPROM上对应地址的密码,没有密码使用默认密码123456,然后请输入密码。用户输入密码后,对比用户输入的跟存在EEPROM的密码是否一样,一样的话就显示密码正确,密码不对就报警并重新让用户输入密码。输入成功之后可以让用户输入新密码或者退出。输入新密码之后保存到EEPROM上。

    3.1.1程序 按键输入部分
    按键输入负责监听按键事件,然后把对应的按键转换成按键值存入输入密码数组,并显示“*”。按键扫描使用定时器进行定时判断按键是否按下。

    3.1.2 保存密码和读取密码部分
    密码是保存在EEPROM上的,这里我们用的EEPROM为AT24C01要实现单片机通过模拟I2C总线对AT24C01的读或写,在发送起始条件之后,必须是器件的控制字节,其中高四位为器件类型识别码,EEPROM芯片一般应为1010,接着三位为片选,最后一位为读写位,当读写为1时为读操作,即主器件从从器件读数据,为0时为写操作,即主器件把信息写到所选的从器件中[1]。接着是发送读或写的地址。无论是读还是写,在I2C总线上传送的每一字节都是8个bit 串行数据的传送总是从最高位开始的,每一数据帧后面都有一个确认为,也叫应答位[1]。因此,在读数据的时候,需要先将变量x中的各二进位向左移一位,再与SDA上的数据通过按位“或“运算存入变量x中。而数据则刚好相反,先将待写的数据通过和数0x80按位“与”运算将最高位数据送到SDA,再将该数据中的各二进位向左移一位。上述两个过程重复8次,即可完成一个字节的读或写。按照此流程,把一串密码读写完成。

    3.2 I2C通信协议简介
    I2C总线是由Philips公司开发的一种简单、双向二线制同步串行总线。它只需要两根线即可在连接于总线上的器件之间传送信息。
    主器件用于启动总线传送数据,并产生时钟以开放传送的器件,此时任何被寻址的器件均被认为是从器件.在总线上主和从、发和收的关系不是恒定的,而取决于此时数据传送方向。如果主机要发送数据给从器件,则主机首先寻址从器件,然后主动发送数据至从器件,最后由主机终止数据传送;如果主机要接收从器件的数据,首先由主器件寻址从器件.然后主机接收从器件发送的数据,最后由主机终止接收过程。在这种情况下.主机负责产生定时时钟和终止数据传送。

    4、调试及性能分析

    这部分是对整个系统的测试方案,这边当时写得比较随便,凑合能用,其实大致也就这样。
    4.1 软件调试
    把程序下载到单片机里,通过按键和单片机交互,看是否达到要求,不能达到要求的话,调整程序,重复下载,直到满足要求为止。

    5、总结与致谢

    这部分是讲的…………你懂的,哈哈。
    通过本次项目,我们深入了解了单片机的硬件,软件的各种知识,知道了单片机在实际应用中的作用很大,也许我家楼下的密码锁就是这么设计的。了解了单片机的一些扩展功能,更深入的了解了单片机的原理。
    在此感谢指导老师对我们的精心指导,通过这次课程设计,我们知道了理论和实际的距离,也知道了理论和实际想结合的重要性,也从中得知了很多书本上无法得知的知识。自己今后将会更加的把理论知识和实际应用结合起来,提高自己的能力。最后再次感谢指导老师对我们的帮助。

    一、程序代码

    新建Keil项目,单片机选Intel的8051,在工程的.c文件内写入如下代码:

    #include <reg52.h>
    /* 全局运行参数定义 */
    #define SYS_MCLK   (11059200/12)  //系统主时钟频率,即振荡器频率÷12
    
    /*蜂鸣器相关*/
    bit staBuzzer = 0; //蜂鸣器状态控制位,1-鸣叫、0-关闭
    sbit BUZZER = P1^6;  //蜂鸣器控制引脚
    void Waring();
    
    /*--------------------------------LCD1602函数声明---------------------------*/
    //LCD1602函数声明
    void InitLcd1602();									//初始化
    void LcdWriteCmd(unsigned char cmd);					//写命令
    void LcdSetCursor(unsigned char x, unsigned char y);	//写指针
    void LcdShowStr(unsigned char x, unsigned char y,unsigned char *str, unsigned char len);
    
    /*--------------------------------EEPROM读写函数----------------------------*/
    void E2Read(unsigned char *buf, unsigned char addr, unsigned char len);
    void E2Write(unsigned char *buf, unsigned char addr, unsigned char len);
    
    /*--------------------------------按键驱动函数声明---------------------------*/
    void KeyDriver();		//按键变化检测
    
    /*--------------------------------密码输入函数声明---------------------------*/
    void inputpassword();	//密码输入特效支持(智能隐藏)
    
    /*--------------------------------系统控制函数声明---------------------------*/
    void control();
    
    #define PWN 16										/*密码位数*/
    unsigned char code PassWordAddr = 0x17;				//密码储存地址
    /*密码存储格式:前两个固定字符:PW,P为0x17,PW后紧接密码(字符)*/
    unsigned char InputStr[PWN] =							//输入的密码
    {' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' '};
    unsigned char PassWord[PWN];							//正确的密码
    unsigned char system = 0;								//流程控制变量
    /*0:开始,1设置密码,2输入密码,3显示密文*/
    bit PWRight  = 0;		//密码是否对
    bit EnterSta = 0;		//回车状态
    
    void main()
    {
    	TMOD = 0x01;
    	TH0 = 0xFC;
    	TL0 = 0x66;
    	EA = 1;
    	ET0 = 1;
    	TR0 = 1;
    
    	
        T2CON = 0x00;  //配置T2工作在16位自动重载定时器模式
    	RCAP2H = ((65536-SYS_MCLK/1500)>>8);  //配置重载值,每秒产生1500次中断,
        RCAP2L = (65536-SYS_MCLK/1500);       //以使刷新率达到100Hz无闪烁的效果
        TH2 = RCAP2H;  //设置初值等于重载值
        TL2 = RCAP2L;
        ET2 = 1;       //使能T2中断
        PT2 = 1;       //设置T2中断为高优先级
        TR2 = 1;       //启动T2
    	
    	InitLcd1602();
    	
    	//E2Write(PWhead,PassWordAddr,2);		//去掉密码头
    	
    	while(1)
    	{
    		control();
    	}
    }
    /*--------------------------------系统控制函数声明---------------------------*/
    void control()
    {
    	static unsigned char systemb = 0;
    	if(system == 0)						//系统刚启动
    	{
    		unsigned char PWhead[2] = {0,0};
    		if(system != systemb)
    		{
    			systemb = system;
    			LcdWriteCmd(0x01);	//清屏
    			system = systemb;
    			LcdShowStr(0,0,"Loading......   ", 16);
    		}
    		
    		E2Read(PWhead,PassWordAddr,2);	//读密码头
    		if((PWhead[0] == 'P')&&(PWhead[1] == 'W'))	//存在密码头
    		{
    			E2Read(PassWord,PassWordAddr+2,sizeof(PassWord));//读密码
    			system = 2;				//输入密码
    		}else{										//不存在密码头
    			system = 1;				//设置密码
    		}
    	}
    	
    	if(system == 1)	//如果是设置密码
    	{
    		if(system != systemb)
    		{
    			systemb = system;
    			LcdWriteCmd(0x01);	//清屏
    			system = systemb;
    			LcdShowStr(0,1,"Set Password!   ", 16);
    		}
    		
    		inputpassword();	//运行密码特效
    		KeyDriver();		//运行按键驱动
    		if((PWRight == 1)&&(EnterSta == 1))
    		{
    			PWRight = 0;
    			EnterSta = 0;
    			if((InputStr[0] == ' ')||((InputStr[0]<('9'+1))&&(InputStr[0]>('0'-1))))
    			//如果是合法的密码
    			{
    				//写密码头
    				E2Write("PW",PassWordAddr,2);
    				
    				//跳过密码头写密码
    				E2Write(InputStr,(PassWordAddr+2),sizeof(InputStr));
    				
    				system = 0;	//重新开始系统
    			}
    		}
    	}
    	
    	if(system == 2)	//如果是输入密码
    	{
    		if(system != systemb)
    		{
    			systemb = system;
    			LcdWriteCmd(0x01);	//清屏
    			system = systemb;
    			LcdShowStr(0,1,"Enter Password! ", 16);
    			//LcdShowStr(0,0,PassWord, PWN);//直接显示密码
    		}
    		inputpassword();	//运行密码特效
    		KeyDriver();		//运行按键驱动			
    		if((PWRight == 1)&&(EnterSta == 1))	//如果密码正确
    		{
    			PWRight = 0;
    			EnterSta = 0;
    			system = 3;			//显示密文
    		}
    	}
    	
    	if(system == 3)		//显示密文
    	{
    		if(system != systemb)
    		{
    			systemb = system;
    			LcdShowStr(0,0,"Pwd is correct! ", 16);
    		}
    		KeyDriver();		//运行按键驱动
    	}
    	
    	Waring();//报警
    }
    
    /*-------------------------密码输入控制部分----------------------------------*/
    unsigned char inputI = 0;								//输入指针
    bit clear = 1;				//变*标志位,0为到1s
    bit time1 = 0;				//密码延时定时器
    unsigned int cnt = 0;			//延时计数器
    unsigned char code staR = '*';
    unsigned char code blank = ' ';
    unsigned char AinputI;		//打印inputI 
    
    void esc()		//按下清除键
    {
    	switch(system)
    	{
    		case 1:			//输入密码的时候
    		case 2:	
    			if(inputI != 0)
    			{
    				time1 = 0;	//停止变*
    				inputI--;
    				LcdShowStr(inputI,0,&blank,1);
    				InputStr[inputI] = blank;
    			}
    			break;
    		
    		case 3:
    			system = 2;
    			break;
    		
    		default: break;
    	}
    }
    
    //可以和按键一起放到1ms定时器中调用
    void pwtime()
    {
    	if(time1 == 1)		//如果在运行
    	{
    		cnt++;
    		if(cnt>1000)	//1s到了
    		{
    			cnt = 0;
    			clear = 0;	//超时变成*
    			time1 = 0;	//关闭密码延时定时器	
    		}
    	}
    }
    
    void inputpassword()
    {
    	static unsigned char inputIb = 1;		//输入指针备份
    	
    	if(clear == 0)
    	{
    		clear = 1;	//取消标志	
    		if(inputI > 0 )
    				LcdShowStr(inputI-1,0,&staR,1);
    	}
    	
    	if(inputIb != inputI)	//如果有新输入
    	{
    		inputIb = inputI;	//备份
    		
    		AinputI = (inputI + '0');
    		
    		if(inputI>1)		//上一个字符马上变成*
    		{
    			LcdShowStr(inputI-2,0,&staR,1);
    		}
    				
    		time1 = 1;			//打开延时定时器
    		cnt = 0;				//清零计数
    		
    		if(inputIb == 0)		//清空了输入
    		{
    			time1 = 0;	//停止变*
    		}
    		
    		LcdShowStr(15,1,&AinputI,1);	//打印inputI 
    		
    		LcdSetCursor(inputI, 0);			//光标控制
    		//LcdWriteCmd(0x0E);			//光标模式,这里在初始化里写了					
    	}
    }
    
    //字符串清空函数,*p字符串,n清空的个数
    void empty(unsigned char *p,unsigned char n)	
    {
    	unsigned char i;
    	for(i = 0;i<n;i++)
    	{
    		(*p++) = blank;		//依次清空
    	}
    }
    
    //密码核对函数,直接对比InputStr[i],PassWord[i]的内容
    void isright()		
    {
    	unsigned char i;		//循环对比
    	
    	EnterSta = 1;
    	
    	switch(system)
    	{
    		case 1:
    			PWRight = 1;		
    			inputI = 0;									//输入指针归零
    		break;
    		
    		case 2:
    			for(i = 0;i<PWN;i++)
    			{
    				if(InputStr[i] != PassWord[i])	//如有不同
    					break;				//退出
    			}
    			
    			if(i == PWN)									//如果有PWN个相同
    			{
    				LcdShowStr(0,1,"True!           ",16);		//提示密码正确
    				PWRight = 1;
    			}else{
    				LcdShowStr(0,1,"False!          ",16);		//提示密码错误
    				PWRight = 0;
    				staBuzzer = 1;//报警!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
    			}
    			inputI = 0;									//输入指针归零
    			
    			empty(InputStr,sizeof(InputStr));			//清空输入
    			LcdShowStr(0,0,InputStr,sizeof(InputStr));	//显示清空后的输入
    		break;
    			
    		case 3:
    			system = 1;
    		break;
    		
    		default:break;
    	}
    	
    //	
    //	if(system == 3)		//查看密文时,按enter键修改密码
    //	{
    //		system = 1;
    //	}
    //	
    //	if(system == 2)		//输入密码状态
    //	{
    //		for(i = 0;i<PWN;i++)
    //		{
    //			if(InputStr[i] != PassWord[i])	//如有不同
    //				break;				//退出
    //		}
    //		
    //		if(i == PWN)									//如果有PWN个相同
    //		{
    //			LcdShowStr(0,1,"Right!          ",16);		//提示密码正确
    //			PWRight = 1;
    //		}else{
    //			LcdShowStr(0,1,"Try again!      ",16);		//提示密码错误
    //			PWRight = 0;
    //		}
    //		inputI = 0;									//输入指针归零
    //		
    //		empty(InputStr,sizeof(InputStr));			//清空输入
    //		LcdShowStr(0,0,InputStr,sizeof(InputStr));	//显示清空后的输入
    //	}
    //	
    //	if(system == 1)		//如果是设置密码
    //	{
    //		PWRight = 1;		
    //		inputI = 0;									//输入指针归零
    //	}
    }
    #undef PWN				//结束宏定义
    
    //密码输入控制函数
    void InputSetNumber(unsigned char ccode)
    {
    	if(inputI<16)
    	{
    		if  ((ccode>='0') && (ccode<='9'))  	//数字键输入当前位设定值
    		{	
    			InputStr[inputI] = ccode;		//保存
    			LcdShowStr(inputI,0,&ccode,1);	//显示输入
    			
    			inputI++;						//输入指针+1
    		}
    	}
    }
    void SetLeftShift()
    {
    	
    }
    void SetRightShift()
    {
    	
    }
    /*--------------------------以下是蜂鸣器报警部分-------------------------------*/
    bit buti = 0;//蜂鸣器定时器状态
    bit buSta = 0;//蜂鸣器状态
    unsigned char bucnout = 0;//蜂鸣器计数器
    unsigned char butimes = 0;//响声计次
    void Waring()
    {
    	if(staBuzzer == 1)
    	{
    		butimes = 6;//警报响的次数
    		staBuzzer = 0;
    		buti = 1;//开始计数		
    	}	
    	if(butimes)
    	{
    		if(bucnout>127)
    		{
    			buSta = 0;
    		}else{
    			buSta = 1;
    		}
    	}
    }
    
    void buzzTime()
    {
    	if(buti == 1)
    	{
    		bucnout++;
    		if(bucnout>254)
    		{
    			bucnout = 0;
    
    			if(butimes == 0)
    			{
    				buti = 0;	
    			}else{
    				butimes--;
    			}
    		}	
    	}
    }
    
    /*--------------------------以下是矩阵按键驱动-------------------------------*/
    sbit KEY_IN_1  = P2^4;
    sbit KEY_IN_2  = P2^5;
    sbit KEY_IN_3  = P2^6;
    sbit KEY_IN_4  = P2^7;
    sbit KEY_OUT_1 = P2^3;
    sbit KEY_OUT_2 = P2^2;
    sbit KEY_OUT_3 = P2^1;
    sbit KEY_OUT_4 = P2^0;
    
    unsigned char code KeyCodeMap[4][4] = {  //矩阵按键到标准键码的映射表
        { '1',  '2',  '3', 0x26 },  //数字键1、数字键2、数字键3、向上键
        { '4',  '5',  '6', 0x25 },  //数字键4、数字键5、数字键6、向左键
        { '7',  '8',  '9', 0x28 },  //数字键7、数字键8、数字键9、向下键
        { '0', 0x1B, 0x0D, 0x27 }   //数字键0、ESC键、  回车键、 向右键
    };
    unsigned char KeySta[4][4] = {  //全部矩阵按键的当前状态
        {1, 1, 1, 1},  {1, 1, 1, 1},  {1, 1, 1, 1},  {1, 1, 1, 1}
    };
    
    void KeyAction(unsigned char keycode)
    {
    	if  ((keycode>='0') && (keycode<='9'))  //数字键输入当前位设定值
    	{
    		InputSetNumber(keycode);//调用字符串储存函数,用于存输入的密码
    	}
    	else if (keycode == 0x25)  //向左键,向左切换设置位
    	{
    		SetLeftShift();
    	}
    	else if (keycode == 0x27)  //向右键,向右切换设置位
    	{
    		SetRightShift();
    	}
    	else if (keycode == 0x0D)  //回车键,切换运行状态/保存设置
    	{
    		isright();		//调用密码核对
    	}
    	else if (keycode == 0x1B)  //Esc键,静音/取消当前设置
    	{
    		esc();
    	}
    }
    
    //按键驱动函数,检测按键动作,调度相应动作函数,需在主循环中调用 
    void KeyDriver()
    {
    	unsigned char i, j;
    	static unsigned char backup[4][4] = {  //按键值备份,保存前一次的值
    		{1, 1, 1, 1},  {1, 1, 1, 1},  {1, 1, 1, 1},  {1, 1, 1, 1}
    	};
    
    	for (i=0; i<4; i++)  //循环检测4*4的矩阵按键
    	{
    		for (j=0; j<4; j++)
    		{
    			if (backup[i][j] != KeySta[i][j])    //检测按键动作
    			{
    				if (backup[i][j] != 0)           //按键按下时执行动作
    				{
    					KeyAction(KeyCodeMap[i][j]); //调用按键动作函数
    				}
    				backup[i][j] = KeySta[i][j];     //刷新前一次的备份值
    			}
    		}
    	}
    }
    
    // 按键扫描函数,需在定时中断中调用,推荐调用间隔1ms 
    void KeyScan()
    {
    	unsigned char i;
    	static unsigned char keyout = 0;   //矩阵按键扫描输出索引
    	static unsigned char keybuf[4][4] = {  //矩阵按键扫描缓冲区
    		{0xFF, 0xFF, 0xFF, 0xFF},  {0xFF, 0xFF, 0xFF, 0xFF},
    		{0xFF, 0xFF, 0xFF, 0xFF},  {0xFF, 0xFF, 0xFF, 0xFF}
    	};
    
        //将一行的4个按键值移入缓冲区
    	keybuf[keyout][0] = (keybuf[keyout][0] << 1) | KEY_IN_1;
    	keybuf[keyout][1] = (keybuf[keyout][1] << 1) | KEY_IN_2;
    	keybuf[keyout][2] = (keybuf[keyout][2] << 1) | KEY_IN_3;
    	keybuf[keyout][3] = (keybuf[keyout][3] << 1) | KEY_IN_4;
        //消抖后更新按键状态
    	for (i=0; i<4; i++)  //每行4个按键,所以循环4次
    	{
    		if ((keybuf[keyout][i] & 0x0F) == 0x00)
    		{   //连续4次扫描值为0,即4*4ms内都是按下状态时,可认为按键已稳定的按下
    			KeySta[keyout][i] = 0;
    		}
    		else if ((keybuf[keyout][i] & 0x0F) == 0x0F)
    		{   //连续4次扫描值为1,即4*4ms内都是弹起状态时,可认为按键已稳定的弹起
    			KeySta[keyout][i] = 1;
    		}
    	}
    	//执行下一次的扫描输出
    	keyout++;        //输出索引递增
    	keyout &= 0x03;  //索引值加到4即归零
    	switch (keyout)  //根据索引值,释放当前输出引脚,拉低下次的输出引脚
    	{
    		case 0: KEY_OUT_4 = 1; KEY_OUT_1 = 0; break;
    		case 1: KEY_OUT_1 = 1; KEY_OUT_2 = 0; break;
    		case 2: KEY_OUT_2 = 1; KEY_OUT_3 = 0; break;
    		case 3: KEY_OUT_3 = 1; KEY_OUT_4 = 0; break;
    		default: break;
    	}
    }
    
    /*-----------------------以下是LCD1602显示驱动-------------------------------*/
    //定义LCD1602显示相关的IO接口
    #define LCD1602_DB  P0
    sbit LCD1602_RS = P1^0;
    sbit LCD1602_RW = P1^1;
    sbit LCD1602_E  = P1^5;
    
    //等待液晶准备好
    void LcdWaitReady()
    {
        unsigned char sta;
         
        LCD1602_DB = 0xFF;
        LCD1602_RS = 0;
        LCD1602_RW = 1;
        do {
            LCD1602_E = 1;      //使能LCD1602
            sta = LCD1602_DB;   //读取状态字
            LCD1602_E = 0;      //避免干扰其他器件
        } while (sta & 0x80);   //第七位等于1表示液晶正忙,重复检测直到第七位等于0为止
    }
    //向LCD1602液晶写入一字节命令,cmd为待写入命令值
    void LcdWriteCmd(unsigned char cmd)
    {
        LcdWaitReady();
        LCD1602_RS = 0;
        LCD1602_RW = 0;
        LCD1602_DB = cmd;
        LCD1602_E  = 1;
        LCD1602_E  = 0;
    }
    //向LCD1602液晶写入一字节数据,dat为待写入数据值
    void LcdWriteDat(unsigned char dat)
    {
        LcdWaitReady();
        LCD1602_RS = 1;
        LCD1602_RW = 0;
        LCD1602_DB = dat;
        LCD1602_E  = 1;
        LCD1602_E  = 0;
    }
    //设置显示RAM起始地址,亦即光标位置,(x,y)对应屏幕上的字符的坐标
    void LcdSetCursor(unsigned char x, unsigned char y)
    {
        unsigned char addr;
         
        if (y == 0)  			//由输入的屏幕坐标计算显示RAM的地址
            addr = 0x00 + x;	//第一行字符地址从0x00起始
        else
            addr = 0x40 + x;	//第二行字符地址从0x40起始
        LcdWriteCmd(addr | 0x80);	//设置RAM地址
    }
    //在液晶上显示字符串,(x,y)-对应屏幕上的起始坐标,
    //str-字符串指针,len-需显示的字符长度
    void LcdShowStr(unsigned char x, unsigned char y,unsigned char *str, unsigned char len)
    {
    	LcdSetCursor(x, y);   //设置起始地址
    	while (len--)         //连续写入len个字符数据
    	{
    		LcdWriteDat(*str++);  //先取str指向的数据,然后str自加1
    	}
    }
    
    void InitLcd1602()//初始化1602液晶
    {
        LcdWriteCmd(0x38);  //16*2显示,5*7点阵,8位数据接口
        LcdWriteCmd(0x0E);  //显示器开,光标打开
        LcdWriteCmd(0x06);  //文字不动,地址自动+1
        LcdWriteCmd(0x01);  //清屏
    }
    
    /*--------------------------------以下是I2C总线协议--------------------------*/
    #include <intrins.h>
    sbit I2C_SDA = P3^6;
    sbit I2C_SCL = P3^7;
    
    //I2C延时函数
    void I2CDelay()
    {
    	_nop_();	//1us
    	_nop_();
    	_nop_();
    	_nop_();
    }
    
    //I2C起始信号
    void I2CStart()
    {
    	I2C_SDA = 1;	//确保SDA,SCL为高电平
    	I2C_SCL = 1;
    	I2CDelay();	//延时,让其他器件识别
    	I2C_SDA = 0;	//先拉低SDA
    	I2CDelay();
    	I2C_SCL = 0;	//再拉低SCL
    }
    
    //I2C写函数,dat:要写入的字节,返回为应答值:1应答、0非应答
    bit I2CWrite(unsigned char dat)
    {
    	unsigned char mask;		//临时变量
    	bit ack;					//应答值变量
    	for(mask = 0x80;mask != 0;mask>>=1)	//从高位到低位依次取值
    	{
    		if((mask&dat) == 0)		//如果是0
    			I2C_SDA = 0;	//写0
    		else
    			I2C_SDA = 1;	//写1
    		I2CDelay();		//等其他器件反应
    		I2C_SCL = 1;		//让其他器件读取
    		I2CDelay();		//其他器件读取要时间,等
    		I2C_SCL = 0;		//准备发送下一位
    	}
    	I2C_SDA = 1;		//发送完后释放总线,以检测从机应答
    	I2CDelay();		//等其他器件反应
    	I2C_SCL = 1;		//让其他器件发送应答位
    	ack = I2C_SDA;	//读取应答位
    	I2CDelay();		//等待
    	I2C_SCL = 0;		//保持住总线,以进行其他操作
    	
    	return (~ack);	//返回应答位,1成功,0失败
    }
    
    //I2C停止信号
    void I2CStop()
    {
    	I2C_SDA = 0;	//确保SDA,SCL为低电平
    	I2C_SCL = 0;
    	I2CDelay();	//等待其他器件反应
    	I2C_SCL = 1;	//先拉高SCL
    	I2CDelay();
    	I2C_SDA = 1;	//再拉高SDA
    	I2CDelay();
    }
    
    //I2C读并发送非应答信号函数,返回读到的字节
    unsigned char I2CReadNAK()
    {
    	unsigned char dat,mask;	//临时变量,dat存数据,mask循环辅助
    	
    	I2C_SDA = 1;				//释放总线,读操作,读IO口置1
    	for(mask = 0x80;mask != 0;mask >>= 1)	//从高位依次读取
    	{
    		I2CDelay();			//等待SDA被其他器件送入要读取的数据
    		I2C_SCL = 1;			//表示要读了
    		if(I2C_SDA == 0)		//读数据
    			dat &= ~mask;	//读到0,当前位置零
    		else
    			dat |= mask;		//读到1,当前位置壹
    		I2CDelay();			//等其他器件反应
    		I2C_SCL = 0;			//让从机准备发送下一位
    	}
    	I2C_SDA = 1;		//准备发送非应答信号
    	I2CDelay();
    	I2C_SCL = 1;		//让从机接收应答位
    	I2CDelay();
    	I2C_SCL = 0;		//保持住总线,准备下一个操作
    	
    	return dat;			//返回收到的数据
    }
    
    //I2C读并发送应答信号函数,返回读到的字节
    unsigned char I2CReadACK()
    {
    	unsigned char dat,mask;	//临时变量,dat存数据,mask循环辅助
    	
    	I2C_SDA = 1;			//释放总线,读操作,读IO口置1
    	for(mask = 0x80;mask != 0;mask >>= 1)	//从高位依次读取
    	{
    		I2CDelay();		//等待SDA被其他器件送入要读取的数据
    		I2C_SCL = 1;	//表示要读了
    		if(I2C_SDA == 0)	//读数据
    			dat &= ~mask;	//读到0,当前位置零
    		else
    			dat |= mask;	//读到1,当前位置壹
    		I2CDelay();		//等其他器件反应
    		I2C_SCL = 0;	//让从机准备发送下一位
    	}
    	I2C_SDA = 0;		//准备发送应答信号(与NAK就这不同)
    	I2CDelay();
    	I2C_SCL = 1;		//让从机接收应答位
    	I2CDelay();
    	I2C_SCL = 0;		//保持住总线,准备下一个操作
    	
    	return dat;		//返回收到的数据
    }
    
    /*---------------------------以下是EEPROM驱动-------------------------------*/
    //EEPROM读取函数,buf:读取出的数据储存指针,
    //addr:EEPROM中读数据的起始地址,len:读取数据的长度
    void E2Read(unsigned char *buf, unsigned char addr, unsigned char len)
    {
    	do {						//用寻址检查当前是否可进行读操作
    		I2CStart();
    		if (I2CWrite(0x50<<1))	//如果应答(表示不忙)
    		{
    			break;				//跳出循环
    		}
    		I2CStop();
    	} while(1);
    	I2CWrite(addr);				//写入起始地址
    
    	I2CStart();					//重复发送启动信号
    	I2CWrite((0x50<<1)|0x01);	//寻址,读操作
    	while (len > 1)				//连续读取len-1个字节
    	{
    		*buf++ = I2CReadACK();	//还没到最后一个字节,发送应答信号
    		len--;
    	}
    	*buf = I2CReadNAK();			//最后一个字节,发送非应答
    	I2CStop();					//发送停止信号
    }
    
    //EEPROM写入数据函数,buf:源数据指针,addr:EEPROM中的起始地址,len:写入长度
    void E2Write(unsigned char *buf, unsigned char addr, unsigned char len)
    {
    	while (len > 0)
    	{
    		//等待上次写入操作完成
    		do {							//用寻址操作查询当前是否可进行读写操作
    			I2CStart();
    			if (I2CWrite(0x50<<1))	//应答则跳出循环,非应答则进行下一次查询
    			{
    				break;
    			}
    			I2CStop();
    		} while(1);
    
    		//按页写模式连续写入字节
    		I2CWrite(addr);				//写入起始地址
    		while (len > 0)
    		{
    			I2CWrite(*buf++);		//写入一个字节数据
    			len--;					//待写入长度计数递减
    			addr++;					//EEPROM存储地址递增
    			if ((addr&0x07) == 0)		//检查地址是否到达页边界,24C02每页8字节,检测低3位是否为零即可
    			{
    				break;				//到达页边界时,跳出循环,结束本次写操作
    			}
    		}
    		I2CStop();
    	}
    }
    
    /*------------------------------中断函数------------------------------------*/
    /* T0中断服务函数,按键扫描、计时器、蜂鸣器控制 */
    void InterruptTimer0() interrupt 1
    {
    	TH0 = 0xfc;
    	TL0 = 0x66;
    	KeyScan();
    	pwtime();
    	buzzTime();
    }
    
    /* T2中断服务函数,LED动态扫描、蜂鸣器控制 */
    void InterruptTimer2() interrupt 5
    {
        TF2 = 0;  //清零T2中断标志
        
        //由蜂鸣器状态位控制蜂鸣器
        if (buSta == 1)
            BUZZER = ~BUZZER;  //蜂鸣器鸣叫
        else
            BUZZER = 1;        //蜂鸣器静音
    }
    

    不知道怎么回事,在Keil里缩进是正确的,上传到这里有点小错误,也暂时没时间来得及调整了,哈哈。
    这是刚学51不久写的代码,很多不规范的地方,目前也没时间整理了,不过上面的注释是比较详细的,就不再多解释了,不懂的可以在下方留言讨论,哈哈。

    二、效果演示

    B站视频链接:51单片机电子密码锁设计_哔哩哔哩 (゜-゜)つロ 干杯~-bilibili

    三、总结

    这个似乎是用到了状态机,当时不知道,就想切换模式。
    这里我比较满意的是密码的效果,不是按一下就是*号,而是等一会儿才变,灵感来自安卓手机,如果不想要密码效果,直接注释那个函数的调用就可以了,很方便,可能这就是解耦的意义所在吧。
    兴趣是最好的老师,希望这个能给你带来学习的兴趣,欢迎交流哦,哈哈

    展开全文
  • 单片机c51电子密码锁程序 用到AT24C02 分为两个程序:main.c和AT24C02.c
  • 本文简单介绍了电子密码锁设计的方法和他的程序代码。
  • 合肥工业大学,单片机课程设计,电子密码锁,汇编程序
  • 基于STM32的智能电子密码锁系统设计.pdf

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 17,317
精华内容 6,926
关键字:

电子密码锁程序