找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 1689|回复: 2
收起左侧

我的51单片机密码锁程序与原理图,可更改密码

[复制链接]
ID:284522 发表于 2023-5-19 14:42 | 显示全部楼层 |阅读模式
51hei.png

51hei.png

单片机源程序如下:
  1. /*****************************************************************
  2.                                                               
  3. 名称:51单片机密码锁              
  4. 说明:1、开锁:输入6位密码加#号,密码正确报警“滴......”显示OK并开锁,
  5.       不正确声音提示“滴...滴”显示ERROR,重新输入密码,五次输入不正确,
  6.           报警滴...滴滴、锁机10分钟。
  7.           2、更改密码:输入管理员密码090564加#号,报警“滴....”,显示
  8.           NEW Password,输入6位新密码加#号,报警“滴......”,已修改开锁密码。
  9.           密码存储于单片机内部EEPROM中,可有3459.4560万种密码。
  10. 器件:使用STC90C58R单片机,利用P2口、4x4键盘做键盘扫描口,12M晶体
  11. 晶振:12MHZ
  12. 时间:2020.12.18                                                                              
  13. ******************************************************************/
  14. #include<stc90c.h>
  15. #include<intrins.h>
  16. #include "string.h"
  17. #define uchar unsigned char
  18. #define uint unsigned int
  19. #define WaitTime 0x01
  20. #define RdCommand 0x01
  21. #define PrgCommand 0x02
  22. #define EraseCommand 0x03
  23. #define open 0        
  24. #define clok 1

  25. /*
  26. sfr ISP_DATA = 0xe2;   //声明特殊功能寄存器//stc90c.h中已声明过,这里不需在声明
  27. sfr ISP_ADDRH = 0xe3;
  28. sfr ISP_ADDRL = 0xe4;
  29. sfr ISP_CMD = 0xe5;
  30. sfr ISP_TRIG = 0xe6;
  31. sfr ISP_CONTR = 0xe7;*/
  32. sfr MDT_CONTR=0xe1;

  33. sbit lcdrw=P3^6;
  34. sbit lcdrs=P3^5;
  35. sbit lcden=P3^4;
  36. sbit dula=P2^6;
  37. sbit wela=P2^7;
  38. sbit scl=P2^1;
  39. sbit sda=P2^0;
  40. sbit FM=P2^3;
  41. sbit lock=P1^0;                                                           //开关锁
  42. sbit lcd_led=P1^1;                                                  //开关LCD背景灯
  43. sbit P_25=P2^5;

  44. void read_busy();
  45. void lcdrw_dat(unsigned char dat);                  //写数据
  46. void check_k();                                                            //检测确认键(k12)是否按下

  47. void lcdrw_com(unsigned char com);

  48. uchar code table[]="0123456789 *#ABCD";


  49. uchar code table1[]="    Password";


  50. uchar code table3[]=" OK";

  51. uchar code table6[]="  New Password";


  52. uchar code error[]="     ERROR";

  53. uchar table4[6];   

  54. uchar table_open_password[6]={0x01,0x02,0x03,0x04,0x05,0x06};//开锁密码
  55. uchar table_update_password[6]={0x0,0x9,0x0,0x05,0x06,0x04};//改密码密码
  56.                                                 //                0    9   0   5    6    4
  57. uchar num,numl,i,a,b=0;//
  58. uint t=0,t1=0;
  59. uchar key_num;
  60. bit flag=0,flag1=0,flag2=0,flag3=0;         
  61. void delayms(uint xms)
  62. {
  63.         uint i,j;
  64.         for(i=xms;i>0;i--)
  65.                 for(j=110;j>0;j--);
  66. }

  67. void yanshi500us(uint x)
  68. {
  69.         uchar y;
  70.         
  71.         for(x;x>0;x--)
  72.                 for(y=240;y>0;y--);        
  73. }


  74. void FM_3()
  75. {
  76.         FM=0;
  77.         delayms(100);
  78.         FM=1;
  79.         delayms(100);
  80.         FM=0;
  81.         delayms(100);
  82.         FM=1;
  83.         delayms(100);
  84.         FM=0;
  85.         delayms(100);
  86.         FM=1;         
  87. }

  88. void FM_2()
  89. {
  90.         FM=0;
  91.         delayms(100);
  92.         FM=1;
  93.         delayms(100);
  94.         FM=0;
  95.         delayms(100);
  96.         FM=1;
  97. }

  98. void FM_1()                         //        按键时短响一声
  99. {
  100.         FM=0;
  101.         delayms(100);
  102.         FM=1;        
  103. }

  104. void FM_11()                 //        ok时长响一声
  105. {
  106.         FM=0;
  107.         delayms(500);
  108.         FM=1;        
  109. }


  110. void xianshi_password()
  111. {
  112.         for(i=0;i<12;i++)
  113.         {
  114.                 lcdrw_dat(table1[i]);        
  115.         }        
  116. }

  117. void xianshi_ok()
  118. {
  119.         for(i=0;i<3;i++)
  120.         {
  121.                 lcdrw_dat(table3[i]);        
  122.         }        
  123. }

  124. void xianshi_New_Password()
  125. {
  126.         for(i=0;i<14;i++)
  127.         {
  128.                 lcdrw_dat(table6[i]);        
  129.         }        
  130. }

  131. void xiansh_error()
  132. {
  133.         for(i=0;i<10;i++)
  134.         {
  135.                 lcdrw_dat(error[i]);        
  136.         }        
  137. }

  138. //==================以下是内部EEPROM操作================
  139. /*******************打开ISP/ISA功能*********************/

  140. void ISP_IAP_enable()         
  141. {
  142.         EA=0;
  143.         ISP_CONTR=ISP_CONTR & 0x18;            //ISP_CONTR复位
  144.         ISP_CONTR=ISP_CONTR | WaitTime;        //设置等待时间
  145.         ISP_CONTR=ISP_CONTR | 0x80;                //允许读/写/擦除
  146. }

  147. /*********************关闭ISP/ISA功能*******************/

  148. void ISP_IAP_disable()           
  149. {
  150.         ISP_CONTR=ISP_CONTR & 0x7f;          //禁止读/写/擦除
  151. //        ISP_TRIG=0x00;
  152.         EA=1;
  153. }

  154. /*******************读/写/擦除的触发代码*****************/

  155. void ISPgoon()                          
  156. {
  157.         ISP_IAP_enable();  //打开ISP/ISA功能
  158.         ISP_TRIG=0x46;           //写入0x46;0xb9;使命令生效
  159.         ISP_TRIG=0xb9;
  160.         _nop_ ();
  161. }

  162. /***********************读字节***************************/

  163. uchar byte_read(uint byte_addr)         
  164. {
  165.         ISP_ADDRH=(uchar)(byte_addr>>8);                    //设置读字节地址
  166.         ISP_ADDRL=(uchar)(byte_addr & 0x00ff);
  167.         ISP_CMD=ISP_CMD & 0xf8;                                            //清除低三位
  168.         ISP_CMD=ISP_CMD | RdCommand;                           //读命令0x01
  169.         ISPgoon();                                                                   //开始读
  170.         ISP_IAP_disable();                                                   //关闭IAP功能
  171.         return(ISP_DATA);                                                    //返回读出的数据
  172. }

  173. /*********************扇区擦除***********************/

  174. void SectorErase(uint Sector_addr)         
  175. {

  176.         ISP_ADDRH=(uchar)(Sector_addr>>8); //设置要擦除扇区地址
  177.         ISP_ADDRL=0x00;        

  178.         ISP_CMD=ISP_CMD & 0xf8;                           //清除低三位
  179.         ISP_CMD=ISP_CMD | EraseCommand;           //删除命令0x03
  180.         ISPgoon();                                                   //开始删除
  181.         ISP_IAP_disable();                                   //关闭IAP功能
  182. }

  183. /************************字节写*************************/

  184. void byte_write(uint byte_addr,uchar original_data)         
  185. {        
  186.         ISP_ADDRH=(uchar)(byte_addr>>8);        //取地址高八位
  187.         ISP_ADDRL=(uchar)(byte_addr&0x00ff);//取地址低八位
  188.         ISP_CMD=ISP_CMD & 0xf8;                                //清零低三位
  189.         ISP_CMD=ISP_CMD | PrgCommand;                //写命令0x02
  190.         ISP_DATA=original_data;                                //数据放入ISP_DATA
  191.         ISPgoon();                                                        //开始写入
  192.         ISP_IAP_disable();                                        //关闭IAP功能
  193. }

  194. //================以下是LCD操作=========================

  195. void read_busy() //LCD1602 忙等待
  196. {
  197.     lcdrs = 0;
  198.     lcdrw = 1;
  199.     lcden = 1;
  200.     P0 = 0xff;
  201.     while (P0&0x80);
  202.     lcden = 0;

  203. }
  204.                                                   
  205. void lcdrw_com(unsigned char com) //写命令
  206. {
  207.         read_busy();
  208.         lcdrw=0;
  209.         lcdrs=0;
  210.         P0=com;
  211.         yanshi500us(1);
  212.         lcden=1;
  213.         yanshi500us(1);
  214.         lcden=0;
  215. //        lcdrs=1;
  216.         yanshi500us(10);        
  217. }

  218. void lcdrw_dat(unsigned char dat) //写数据
  219. {
  220.         read_busy();
  221.         lcdrw=0;
  222.         lcdrs=1;
  223.         P0=dat;
  224.         yanshi500us(1);
  225.         lcden=1;   
  226.         yanshi500us(1);
  227.         lcden=0;
  228. //        lcdrs=1;
  229.         yanshi500us(10);        
  230. }

  231.                                          
  232. void lcdinit()
  233. {
  234.         P0=0x0;
  235.         dula=1;
  236.         dula=0;         
  237.         P0=0xff;
  238.         wela=1;        
  239.         wela=0;                 
  240.                                          

  241.         yanshi500us(30);
  242.         lcdrw_com(0x38);   //设置16*2屏显,5*7点阵,8位数据接口
  243.         yanshi500us(10);
  244.         lcdrw_com(0x38);
  245.         yanshi500us(10);
  246.         lcdrw_com(0x38);
  247.         yanshi500us(10);
  248.         lcdrw_com(0x08);   //关闭显示
  249.         lcdrw_com(0x01);   //清屏
  250.         lcdrw_com(0x06);   //读写一个字符后指针加一光标加一
  251.         lcdrw_com(0x0c);   //开显示,显示光标,光标闪烁
  252.         xianshi_password();                  
  253. }                                                            
  254.                                                                                                          
  255. //==================键盘扫描=========================
  256.                                  
  257. void keyscan()
  258. {
  259.         uchar num1,num2,a1;
  260.         if(flag==0)
  261.         {
  262.         P2=0x0f;
  263.         delayms(1);                                                        //延时一下使IO口稳定        
  264.                 {
  265.                         if(P2!=0x0f)
  266.                         {  
  267.                                 delayms(50);
  268.                                 if(P2!=0x0f)
  269.                                 {        
  270.                                         num1=P2;
  271.                                         P2=0xf0;                        //反转P2口                                
  272.                                         delayms(1);                        //延时一下使IO口稳定
  273.                                         num2=P2;
  274.                                         delayms(50);
  275.                                         while((P2!=0xf0));
  276.                                         a1=num1 | num2;        
  277.                                         lcd_led=0;                        //开LCD背景灯
  278.                                         EA=0;
  279.                                         t1=200;                                //设置定时器定时10秒
  280.                                         t=0;
  281.                                         EA=1;                 
  282.                                         TR0 = 1;                         //开定时器        
  283.                                         switch(a1)
  284.                                         {
  285.                                                 case 0xee:  key_num =1;  break;  //1               
  286.                                                 case 0xde:  key_num =2;  break;  //2                                                
  287.                                                 case 0xbe:  key_num =3;  break;  //3                                                
  288.                                                 case 0x7e:  key_num =13; break;  //A                                                  
  289.                                                 case 0xed:  key_num =4;  break;  //4                                                
  290.                                                 case 0xdd:  key_num =5;  break;  //5                                                  
  291.                                                 case 0xbd:  key_num =6;  break;  //6                                                  
  292.                                                 case 0x7d:  key_num =14; break;  //B                                                   
  293.                                                 case 0xeb:  key_num =7;  break;  //7                                                  
  294.                                                 case 0xdb:  key_num =8;  break;  //8                                                  
  295.                                                 case 0xbb:  key_num =9;  break;  //9                                                   
  296.                                                 case 0x7b:  key_num =15; break;  //C                                                   
  297.                                                 case 0xe7:  key_num =11; break;  //*                                                         
  298.                                                 case 0xd7:  key_num =0;  break;  //0                                                   
  299.                                                 case 0xb7:  key_num =12; break;  //#                                                   
  300.                                                 case 0x77:  key_num =16; break;  //D                                                   
  301.                                         }
  302.                                        
  303.                                         if(b==0)   
  304.                                         {
  305.                                                 lcdrw_com(0x01);                                //lcd清零

  306.                                         }
  307.                                         if(key_num!=12)
  308.                                         {                                                        
  309.                                                 table4[b]=key_num;  
  310.                                                 FM_1();
  311.                                                 if(flag2==1)                                          //标识位为1,可写入新密码
  312.                                                 {
  313.                                                         lcdrw_dat(table[key_num]);        //显示输入密码
  314.                                                         if(b==5)
  315.                                                         {
  316.                                                                 flag3=1;                                 //flag3=1写新密码结束
  317.                                                                 flag2=0;        
  318.                                                         }
  319.                                                 }
  320.                                                 else
  321.                                                         lcdrw_dat('*');                                //显示*号                                                                        
  322.                                         }                                       
  323.                                         b++;                                                                //按键次数                                          
  324.                                         if(b==6)
  325.                                         {                                       
  326.                                                 b=0;
  327.                                         }                                                                                                                                                                                                                     
  328.                                 }                                                
  329.                         }                        
  330.                 }
  331.         }
  332. }

  333. /*================判断确认键是否按下=========================
  334. 如果确认键(#)按下,再判断密码是否正确(是开锁密码还是
  335. 修改密码的密)若正确即开锁或修改密码,不正确返回 。

  336. //==========================================================*/
  337. void check_k()                                                   //检测是否#键按下
  338. {        
  339.         if(key_num==12)
  340.         {                        
  341.                 if(flag3==1)                                 //标识flag3为1,新密码更新完毕
  342.                  {                                         
  343.                          delayms(100);
  344.                         lcdrw_com(0x01);                   //清屏
  345.                         FM_11();
  346.                         xianshi_ok();                          //显示ok                                                                                                        
  347.                         delayms(1000);
  348.                         lcdrw_com(0x01);                   //清屏
  349.                         xianshi_password();                //显示password
  350.                         SectorErase(0x8000);        //擦除EEPROM扇区
  351.                         for(i=0;i<6;i++)
  352.                         {
  353.                                 table_open_password[i]=table4[i];        //向 table_open_password[]写入新密
  354.                                 
  355.                                 byte_write((0x8000+i),table4[i]);        //向 EEPROM 写入新密码        
  356.                         }
  357.                         b=0;
  358.                         flag3=0;                                //新密码更新完毕,标识flag3复位
  359.                         key_num=0;                                //封锁check_k函数
  360.                         table4[5]=0xff;                        //更改密码后将输入的密码打乱
  361.                  }        
  362.                  else if((memcmp(table4, table_open_password, 6))==0)//开锁密码正确(本句是数组比较语句)
  363.                 {
  364.                         flag=1;                                        //屏蔽键盘,不允许输入        
  365.                         xianshi_ok();                    //显示ok
  366.                         lock=open;                                 //开锁                        
  367.                         FM_11();                                                                                                                                   
  368.                         lock=clok;                                 //关锁
  369.                         table4[5]=0xff;                        //开完锁后将输入的密码打乱
  370.                         delayms(1500);
  371.                         lcdrw_com(0x01);                 //清屏
  372.                         xianshi_password();                //显示password
  373.                                 
  374.                         a=0;
  375.                         flag=0;                                        //打开键盘,允许输入
  376.                         key_num=0;                                //封锁check_k函数
  377.                         b=0;         
  378.                 }
  379.                 else if((memcmp(table4, table_update_password, 6))==0)//修改密码的密码正确(本句是数组比较语句)                                                        
  380.                 {
  381.                            flag=1;                                //屏蔽键盘,不允许输入

  382.                               xianshi_New_Password();         //显示New Password
  383.                            FM_11();                          
  384.                            flag2=1;                                           //标识位置1,可以输入新密码
  385.                         //   SectorErase(0x8000);        //擦除EEPROM扇区
  386.                            key_num=0;                                //封锁check_k函数        
  387.                            b=0;
  388.                            table4[5]=0xff;                        //将输入密码打乱
  389.                            flag=0;                                        //打开键盘,允许输入
  390.                 }                                   
  391.                 else                                                        //如果密码错误
  392.                 {        
  393.                         flag=1;               
  394.                         lcdrw_com(0x01);                           //清屏
  395.                         xiansh_error();                                //显示错误                                                                                                
  396.                         if(a==4)                                        //密码输错5次
  397.                         {
  398.                             FM_3();
  399. //                                flag=1;
  400.                                 TR0=0;
  401.                                 EA=0;
  402.                                 t1=12000;                                //设置定时器定时10分钟
  403.                                 t=0;
  404.                                 EA=1;
  405.                                 TR0=1;                                                               
  406.                         }                                 
  407.                         else         
  408.                         {                                       
  409.                                 FM_2();
  410.                                 delayms(500);                                    
  411.                             lcdrw_com(0x01);                   //清屏
  412.                                 xianshi_password();                //显示password
  413.                                 delayms(10);
  414.                                 flag=0;
  415.                         }                                       
  416.                         key_num=0;                                        //封锁check_k函数
  417.                         b=0;
  418.                         a++;                                                //密码错误次数                                                                                
  419.                  }                                

  420. //                 P3=0xff;                                                   //进入掉电模式前让p3口为高电位
  421. //                PCON |=0x02;                                           //进入掉电模式                                 
  422.         }                                                                          
  423. }

  424. //================定时器T0设置===================

  425. void Timer0Init(void)                                        //5ms@12.000MHz
  426. {
  427.         TMOD = 0x01;
  428. //        TL0 = 0xB0;                                                        //设置定时初值 12MHZ
  429. //        TH0 = 0x3C;                                                        //设置定时初值
  430.         TL0 = (65536-50000)%256;
  431.         TH0 = (65536-50000)/256;
  432.         ET0 = 1;                                                        //清除TF0标志
  433.         TR0 = 0;
  434.         EA=1;                                                                //定时器0开始计时
  435. }

  436. //================定时器T0=====================

  437. void T0_time() interrupt 1
  438. {
  439.         TL0 = (65536-50000)%256;
  440.         TH0 = (65536-50000)/256;
  441.         t++;
  442.         if(t>=200) //定时10秒
  443.         {
  444.                 P_25=1;                        //因为键盘扫描程序等待时P2口为0x0f关闭了U3,这里打开U3
  445.                 lcd_led=1;                 //关LCD背景灯
  446.                 P_25=0;                        //关闭U3,如果键盘单独一个P口在不需要
  447.         }         
  448.                 if(t>=t1)
  449.                 {               
  450.                         b=0;
  451.                         lcdrw_com(0x01);                    //清屏
  452.                         xianshi_password();                        //显示password

  453.                         t=0;
  454.                         a=0;
  455.                         flag=0;  
  456.                         flag2=0;
  457.                         flag3=0;
  458.                         table4[5]=0xff;                         //将上次输入的密码打乱
  459.                         TR0=0;        
  460.                 }        
  461. }
  462. /************外部中断1函数****************
  463.                                                                                         *
  464.                                                                                         *
  465. void EX1_int()                //外部中断1初始化                *
  466. {                                                                                        *
  467.         IT1=1;                                                                        *
  468.         EA=1;                                                                        *
  469.         EX1=1;                                                                        *
  470. }                                                                                        *
  471.                                                                                         *
  472. void exint() interrupt 2   //外部中断                *
  473. {                                                                                        *
  474.         PCON &=0xfd;                //进入掉电模式                *
  475. }                                                                                        *
  476. *********************************************/                  
  477. //===============主函数===================

  478. void main()
  479. {
  480.      MDT_CONTR=0x35;                                           //启动看门狗
  481.          a=b=flag=flag1=flag2=flag3=0;
  482.          lcdinit();
  483.             Timer0Init();
  484. //         EX1_int();                                                           //掉电模式

  485.          for(i=0;i<6;i++)
  486.          {
  487.                   table_open_password[i]=byte_read(0x8000+i);
  488.                  //上电时将EEPROM中的密码取出放入table_open_password[]

  489.          }         
  490.                                    
  491.          while(1)
  492.          {                        
  493.                  keyscan();
  494.                  check_k();
  495.                  MDT_CONTR=0x35;                                //        喂狗
  496.          }         
  497. }
复制代码

回复

使用道具 举报

ID:641483 发表于 2023-5-22 11:42 | 显示全部楼层
谢谢楼主无私分享 先收藏 慢慢学习
回复

使用道具 举报

ID:76027 发表于 2024-4-30 13:19 | 显示全部楼层
这个能编译通过吗?table4[b],这个b是什么地方来的?        if(key_num!=12)
                                        {                                                        
                                                table4[b]=key_num;  
                                                FM_1();
                                                if(flag2==1)                                          //
回复

使用道具 举报

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

本版积分规则

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

Powered by 单片机教程网

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