找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 7609|回复: 8
打印 上一主题 下一主题
收起左侧

51单片机+LCD12864实现密码锁Proteus仿真和代码

  [复制链接]
跳转到指定楼层
楼主
51单片机-密码锁仿真原理图如下(proteus仿真工程文件可到本帖附件中下载)


单片机源程序如下:
  1. #include <reg51.h>      //  包含51单片机寄存器定义的头文件
  2. #include <intrins.h>    //包含_nop_()函数定义的头文件
  3. #include<string.h>
  4. #include <12864.h>
  5. #include<KEYPAD4_3.h>
  6. #define N 8
  7. #define        NOP5() {_nop_();_nop_();_nop_();_nop_();_nop_();}        // 执行5个空操作,延时5微秒
  8. unsigned char readerror=0;  //读取成功为0,否则为1
  9. unsigned char writeerror=0; //写入成功为0,否则为1
  10. unsigned char Rbuff[10]={0};
  11. unsigned char Wbuff[10]="0000";
  12. sbit SDA=P2^7;          //将串行数据总线SDA位定义在为P3.4引脚
  13. sbit SCL=P2^6;          //将串行时钟总线SDA位定义在为P3.3引脚
  14. sbit led = P2^0;
  15. u8 str[]="123456789*0#";
  16. u8 s[10]={0};
  17. /*****************************************************
  18. 函数功能:延时若干毫秒
  19. 入口参数:n
  20. *****************************************************/
  21. void delay_ms(unsigned int n)
  22. {
  23.    unsigned int i,j;       
  24.          for(i=0;i<n;i++)
  25.           for(j=0;j<110;j++);                 
  26. }
  27. /***************************************************
  28. 函数功能:开始数据传送
  29. ***************************************************/
  30. void start()
  31. // 开始位
  32. {
  33.         SDA = 1;    //SDA初始化为高电平“1”
  34.     SCL = 1;    //开始数据传送时,要求SCL为高电平“1”
  35.         NOP5();
  36.         SDA = 0;    //SDA的下降沿被认为是开始信号
  37.         NOP5();
  38.         SCL = 0;    //SCL为低电平时,SDA上数据才允许变化(即允许以后的数据传递)  
  39. }
  40. /***************************************************
  41. 函数功能:结束数据传送
  42. ***************************************************/
  43. void stop()
  44. // 停止位
  45. {
  46.         SDA = 0;     //SDA初始化为低电平“0”        _n
  47.         SCL = 1;     //结束数据传送时,要求SCL为高电平“1”
  48.         NOP5();
  49.         SDA = 1;    //SDA的上升沿被认为是结束信号
  50.         NOP5();       
  51. }
  52. /***************************************************
  53. 函数功能:发送应答/非应答信号
  54. ***************************************************/
  55. void Send_Ack(bit ack)
  56. //ack=0表示应答;ack=1表示非应答
  57. {
  58.         SCL = 0; //拉低SCL为输出数据到SDA做准备
  59.         SDA = ack; //输出ack到SDA,表示应答/不应答
  60.         SCL = 1;
  61.         NOP5();   //NOP5()>4us
  62.     SCL = 0;    //SCL从0-1-0为一个完整的时钟周期
  63.     SDA=1;//释放总线
  64. }
  65. /***************************************************
  66. 函数功能:查询/接收应答信号
  67. ***************************************************/
  68. unsigned char Rec_Ack(void)   
  69. //返回值为0表示应答,为1表示非应答
  70. {unsigned char i,ack;
  71. SCL=0;  //拉低SCL为输出数据到SDA做准备
  72. SDA = 1; //释放总线,让从设备能输出数据到SDA
  73. SCL=1;
  74. while((SDA==1)&&(i<250)) i++;
  75. /*等待从设备发送应答信号,若为0,表示应答,循环结束;若为1,可能是从机还未将信号送上来,循环延时到i>250,若仍为1,此时才认为是未应答*/
  76. ack=SDA;
  77. SCL = 0;//SCL从0-1-0为一个完整的时钟周期
  78. SDA=1; //释放总线
  79. return(ack);
  80. }
  81. /***************************************************
  82. 函数功能:从AT24Cxx读取数据
  83. 出口参数:recbyte
  84. ***************************************************/
  85. unsigned char ReadData()
  86. // 从AT24Cxx中读取一个字节数据到MCU
  87. {
  88.         unsigned char i;
  89.         unsigned char recbyte;   //储存从AT24Cxx中读出的数据
  90.         SCL=0;         //拉低SCL为从设备输出数据到SDA做准备
  91.     SDA=1; //释放总线
  92.     for(i = 0; i < 8; i++)
  93.         {
  94.                 SCL = 1;                //SCL置为高电平
  95.                 NOP5();
  96.         recbyte=(recbyte<<1)|SDA;       //读SDA
  97.         SCL=0;                       //SCL从0-1-0为一个完整的时钟周期
  98.     }
  99.     SDA=1;
  100.         return(recbyte);         //返回所读数据
  101. }
  102. /***************************************************
  103. 函数功能:向AT24Cxx的当前地址写入数据
  104. 入口参数:sendbyte (储存待写入的数据)
  105. ***************************************************/
  106. //在调用此数据写入函数前需首先调用开始函数start(),所以SCL=0
  107. void WriteData(unsigned char sendbyte)
  108. {
  109.         unsigned char i;
  110.         for(i = 0; i < 8; i++)                // 循环移入8个位
  111.         {
  112.             sendbyte<<=1; //左移时最低位补0,最高位移入PSW的CY位
  113.         SDA=CY;        //输出数据到SDA
  114.         SCL = 1;            //在SCL的上升沿将数据写入AT24Cxx      
  115.                NOP5();                 
  116.             SCL = 0;            //将SCL重新置为低电平,以在SCL线形成传送数据所需的8个脉冲
  117.          }
  118.         SDA = 1;  // 发送设备(主机)应在时钟脉冲的高电平期间(SCL=1)释放SDA线,
  119. }
  120. /***************************************************
  121. 函数功能:向AT24Cxx中的指定地址写入数据
  122. 入口参数:add (储存指定的地址);dat(储存待写入的数据)
  123. ***************************************************/
  124. void WriteRom(unsigned char add, unsigned char dat[],unsigned char j)
  125. // 将数组里的j个字节的数据写入到起始地址为addr处的连续区域中
  126. {  unsigned char flag=0,k=0,i=3;//i为允许最大重写次数,若出现i次操作失效后,则函数中止操作,并返回
  127.    while(i--)
  128.    {start();             //开始数据传递
  129.         WriteData(0xa0);  //选择要操作的AT24Cxx芯片,并告知要对其写入数据,器件地址以及写入操作为1010 0000B(0xa0)
  130.         if(Rec_Ack()) continue;
  131.     WriteData(add);   //写入器件内部地址
  132.         if(Rec_Ack()) continue;
  133.     while(j--)
  134.         {WriteData(dat[k++]);   //向当前地址(上面指定的地址)写入数据
  135.          if(!Rec_Ack()) continue;
  136.      flag=1;
  137.          break;
  138.         }
  139.         if(flag)  continue;/*能不能改成:if(j>=0)  continue? (j>=0意味着数据未写完,即出现了未应答,要重写)*/
  140.         break;
  141.    }
  142.    stop();                //停止数据传递         
  143.    if(i<0) writeerror=1;     
  144. }
  145. /***************************************************
  146. 函数功能:从AT24Cxx中的指定地址读取数据
  147. 入口参数:set_addr
  148. 出口参数:x
  149. ***************************************************/
  150. void ReadRom(unsigned char set_addr,unsigned char dat[],unsigned char j)
  151. // 在指定地址开始连续读取j个字节,并将数据存放到数组中
  152. { unsigned char i=3,k=0;//i为允许最大重读次数,若出现i次操作失效后,则函数中止操作,并返回
  153.   while(i--)
  154.   {        start();             //开始数据传递
  155.         WriteData(0xa0);     //选择要操作的AT24Cxx芯片,并告知要对其写入数据,器件地址以及写入操作为1010 0000B(0xa0)
  156.         if(Rec_Ack()) continue;
  157.     WriteData(set_addr);       //写入指定地址
  158.         if(Rec_Ack()) continue;
  159.     start();//调启动总线函数
  160.     WriteData(0xa1);    //选择器件要操作的AT24Cxx芯片,并告知要对其读取数据,器件地址以及读取操作为1010 0001B(0xa1)
  161.     if(Rec_Ack()) continue;//如果操作失败,就退出
  162.     while(--j)
  163.         { dat[k++]=ReadData();
  164.           Send_Ack(0);          
  165.         }//接收前j-1个字节,并应答
  166.         dat[k++]=ReadData();//接收最后一个字节
  167.         Send_Ack(1);//向从设备发出非应答信号,结束数据传输
  168.     break;
  169.   }
  170.   stop();
  171.   if(i<0) readerror=1;  
  172. }


  173. //密码错误时
  174. void mimacuowu(){
  175.         lcd_wcmd(0x01);
  176.         lcd12864_pos(0,0);
  177.         LCD12864disp("密码错误!");
  178.         lcd12864_pos(1,0);
  179.         LCD12864disp("请重新输入!");
  180.         delay_ms(1000);
  181.         lcd_wcmd(0x01);
  182.         lcd12864_pos(0,0);
  183.         LCD12864disp("请输入密码:");
  184.         lcd12864_pos(1,0);
  185. }


  186. //密码正确时
  187. u8 zhengque(){
  188.                   u8 key;
  189.                 lcd_wcmd(0x01);
  190.                 lcd12864_pos(0,0);
  191.                 LCD12864disp("开锁成功!");
  192.                 lcd12864_pos(1,0);
  193.                 LCD12864disp("是否修改密码?");
  194.                 lcd12864_pos(2,0);
  195.                 LCD12864disp("1:是,2:否");
  196.                 lcd12864_pos(3,0);
  197.                 while(1){
  198.                         key=keypad4_3();
  199.                         if(key==0 || key==1){
  200.                                 if(key==0)  LCD12864disp("1");
  201.                                 else        LCD12864disp("2");
  202.                                 delay_ms(1000);
  203.                                 return key;
  204.                                 }
  205.                 }
  206. }

  207. //改密码
  208. void gai(){
  209.         u8 key,a=0;
  210.         u8 s1[10]={0};
  211.         u8 s2[10]={0};
  212.         lcd_wcmd(0x01);
  213.         lcd12864_pos(0,0);
  214.         LCD12864disp("请输入密码:");
  215.         lcd12864_pos(1,0);
  216.         while(1){
  217.                 key=keypad4_3();
  218.                 if(key<12)
  219.                 {
  220.                         if(key==9)         LCD12864_backspace();
  221.                         if(key==11)  break;
  222.                         if(key!=9 && key!=11){s1[a++]=str[key]; LCD12864disp("*");}
  223.                 }
  224.         }
  225.         lcd12864_pos(2,0);
  226.         LCD12864disp("再次输入密码:");
  227.         lcd12864_pos(3,0);
  228.         a=0;
  229.         while(1){
  230.         key=keypad4_3();       
  231.         if(key<12)
  232.         {
  233.                 if(key==9)         LCD12864_backspace();
  234.                 if(key==11)  break;
  235.                 if(key!=9 && key!=11){s2[a++]=str[key]; LCD12864disp("*");}
  236.                 }
  237.         }
  238.         if(strcmp(s1,s2)==0){
  239.                 SDA = 1;           //I2C初始化:SDA=1,SCL=1,使主从设备处于空闲状态
  240.                    SCL = 1;
  241.                 memset(Rbuff,0,sizeof(s));   //再次初始化数组
  242.                 strcpy(Rbuff,s2);
  243.                 //WriteRom(0x32,s2,10);   //向起始地址为“0x32”的连续区域中写入数组Wbuff中的5个数据
  244.                    //ReadRom(0x32,Rbuff,10);    //从起始地址为“0x32”的连续区域中读取5个数据到数组Rbuff中
  245.                   
  246.                 lcd_wcmd(0x01);
  247.                 lcd12864_pos(0,0);
  248.                 LCD12864disp("密码修改成功");
  249.                 delay_ms(2000);

  250.                    lcd_wcmd(0x01);
  251.                 lcd12864_pos(0,0);
  252.                 LCD12864disp("请输入密码:");
  253.                 lcd12864_pos(1,0);
  254.         }
  255.         else
  256.         {
  257.                 lcd_wcmd(0x01);
  258.                 lcd12864_pos(0,0);
  259.                 LCD12864disp("两次输入不一致");
  260.                 lcd12864_pos(1,0);
  261.                 LCD12864disp("密码修改失败");
  262.                 delay_ms(2000);

  263.                 lcd_wcmd(0x01);
  264.                 lcd12864_pos(0,0);
  265.                 LCD12864disp("请输入密码:");
  266.                 lcd12864_pos(1,0);       
  267.         }
  268. }

  269. /***************************************************
  270. 函数功能:主函数
  271. ***************************************************/
  272. void main()
  273. {  
  274.    int a=0,flage=1;
  275.    unsigned char i=0;
  276.    u8 key,f;
  277.    SDA = 1;           //I2C初始化:SDA=1,SCL=1,使主从设备处于空闲状态
  278.    SCL = 1;  
  279.    //led = 1;               
  280.    WriteRom(0x32,Wbuff,10);   //向起始地址为“0x32”的连续区域中写入数组Wbuff中的5个数据
  281.    ReadRom(0x32,Rbuff,10);    //从起始地址为“0x32”的连续区域中读取5个数据到数组Rbuff中
  282.           
  283.     //初始化

  284.    /*while(i<N)
  285.      { P1=Rbuff[i];
  286.            delaynms(1000);
  287.            i++;        //将读出的数据送P1口显示
  288.          }*/
  289.        
  290.         lcd12864_init();
  291.           lcd12864_pos(0,0);
  292.         //lcd_wcmd(0x01);
  293.         LCD12864disp("请输入密码:");
  294.         lcd12864_pos(1,0);
  295.           while(1)
  296.           {

  297.           key=keypad4_3();

  298.         if(key<12){ if(key==9) {LCD12864_backspace();}  //删除
  299.                            if(key==11) //密码确认
  300.                            {
  301.                                   
  302.                                      if(strcmp(Rbuff,s)==0) flage=0;  //正确
  303.                                   else flage=1;                                           //错误
  304.                                   if(flage==0)
  305.                                   {
  306.                                              led=0;   //灯亮
  307.                                             f=zhengque();
  308.                                           if(f==0){
  309.                                              
  310.                                                     gai();
  311.                                           }
  312.                                           if(f==1){
  313.                                                           lcd_wcmd(0x01);
  314.                                                           lcd12864_pos(0,0);
  315.                                                         LCD12864disp("请输入密码:");
  316.                                                         lcd12864_pos(1,0);       
  317.                                           }
  318.                                           led = 1;   //灯灭
  319.                                           a=0;
  320.                                           memset(s,0,sizeof(s));   //再次初始化数组
  321.                                   }
  322.                                   else
  323.                                   {
  324.                                             mimacuowu();
  325.                                           a=0;
  326.                                           memset(s,0,sizeof(s));   //再次初始化数组
  327.                                   }
  328.                            }
  329.                           if(key!=9 && key!=11) {s[a++]=str[key]; LCD12864disp("*");}
  330.                           }          
  331.   }                 
  332. }
复制代码

所有资料51hei提供下载:
密码锁.zip (295.89 KB, 下载次数: 233)


评分

参与人数 1黑币 +50 收起 理由
admin + 50 共享资料的黑币奖励!

查看全部评分

分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏6 分享淘帖 顶 踩
回复

使用道具 举报

沙发
ID:393984 发表于 2019-1-15 15:54 | 只看该作者
这个可以成功的吗?
回复

使用道具 举报

板凳
ID:454000 发表于 2019-1-16 01:24 | 只看该作者
yangqun1998 发表于 2019-1-15 15:54
这个可以成功的吗?

我空间有16位的,仿真绝对没任何问题

评分

参与人数 2黑币 +30 收起 理由
还有谁? + 15
钻牛尖滴刘尖尖 + 15

查看全部评分

回复

使用道具 举报

地板
ID:524025 发表于 2019-5-6 16:53 | 只看该作者
这个初始密码是什么啊
回复

使用道具 举报

5#
ID:473704 发表于 2019-6-21 17:35 | 只看该作者
带中文字库的12864怎么做出来的
回复

使用道具 举报

6#
ID:432151 发表于 2019-9-8 15:07 | 只看该作者
非常感谢,很有用
回复

使用道具 举报

7#
ID:247623 发表于 2021-4-10 23:16 | 只看该作者
shuisheng 发表于 2019-1-16 01:24
我空间有16位的,仿真绝对没任何问题

你好,你空间我看了,没有找到16按键的密码锁啊
回复

使用道具 举报

8#
ID:895926 发表于 2021-4-12 23:09 | 只看该作者
你这个是做了一个中文字库吗?
回复

使用道具 举报

9#
ID:895926 发表于 2021-4-13 13:35 | 只看该作者
1145483334 发表于 2019-6-21 17:35
带中文字库的12864怎么做出来的

你会做字库了吗
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

手机版|小黑屋|51黑电子论坛 |51黑电子论坛6群 QQ 管理员QQ:125739409;技术交流QQ群281945664

Powered by 单片机教程网

快速回复 返回顶部 返回列表