找回密码
 立即注册

QQ登录

只需一步,快速开始

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

兴向荣电子密码锁配套资料 1602显示屏,矩阵键盘实现4组密码锁

[复制链接]
跳转到指定楼层
楼主
基于51单片机密码锁,1602显示屏,矩阵键盘以及继电器





10、读写存储并显示\
11最终程序-按键修改完密码后进行存储\
1、液晶显示\
2、读取矩阵键盘键码\
3、六个按键码的显示\
4、将程序3输入的6个键码显示改为隐藏\
5、判断输入的6位数和系统默认密码是否一样\
6、再程序5的基础上加入定时器\
7、在程序6的基础上加入声音和计数器\
8、加入修改开锁密码的功能\
9、读存储器并显示\


  1. //编译环境: KEIL UVISION2
  2. //单片机晶振:12M  单片机型号AT89S52
  3. //单片机晶振: 无特殊要求
  4. //作者:兴向荣电子元件店
  5. //功能:实现4组密码锁,4组密码均可以修改,修改后掉电可以保持
  6. #include <reg52.h>
  7. #include <intrins.h>

  8. #define uchar unsigned char
  9. #define uint  unsigned int

  10. //==============LCD1602接口连接方法=====================
  11. /*-----------------------------------------------------
  12.        |DB0-----P0.0 | DB4-----P0.4 | RW-------P2.3    |
  13.        |DB1-----P0.1 | DB5-----P0.5 | RS-------P2.4    |
  14.        |DB2-----P0.2 | DB6-----P0.6 | E--------P2.2    |
  15.        |DB3-----P0.3 | DB7-----P0.7 |
  16.     ---------------------------------------------------*/
  17. //===============================AT24C16控制引脚定义===================
  18. sbit    sda_24c16=P2^0;//定义24C16串行数据线 第5脚
  19. sbit    scl_24c16=P2^1;//定义24C16串行时钟线 第6脚
  20. //================================================*/              
  21. #define LCM_Data     P0    //LCD1602数据接口
  22. #define Busy         0x80   //用于检测LCM状态字中的Busy标识
  23. sbit    LCM_RW     = P2^6;  //读写控制输入端,LCD1602的第五脚
  24. sbit    LCM_RS     = P2^5;  //寄存器选择输入端,LCD1602的第四脚
  25. sbit    LCM_E      = P2^7;  //使能信号输入端,LCD1602的第6脚
  26. #define key_port   P3//用KEY_PORT代替P3
  27. sbit    beek_c  =P2^2;//定义蜂鸣器控制口
  28. sbit    lock_c  =P2^3;//定义锁信号输出口
  29. //**************函数声明***************************************
  30. void    delay_3us();//3US的延时程序
  31. void    nack_24c16();//24C16非应答信号   
  32. void    stop_24c16();//停止通讯信号
  33. void    star_24c16();//启动信号
  34. void    cack_24c16();//检测应答信号
  35. void    mack_24c16();//发送应答信号
  36. void    w1byte_24c16(uchar byte1);//向24C16写入一字节的数据
  37. uchar   rd1byte_24c16(void);
  38. void    read_24c16();//读数据操作
  39. void    write_24c16();//写入16字节的数据操作
  40. void    init_t0();//定时器0初始化函数
  41. void    WriteDataLCM                (uchar WDLCM);//LCD模块写数据
  42. void    WriteCommandLCM        (uchar WCLCM,BuysC); //LCD模块写指令
  43. uchar   ReadStatusLCM(void);//读LCD模块的忙标
  44. void    DisplayOneChar(uchar X,uchar Y,uchar ASCII);//在第X+1行的第Y+1位置显示一个字符
  45. void    LCMInit(void);//LCD初始
  46. void    delayms(uint ms);//1MS基准延时程序
  47. void    delay_50us(unsigned int t);// 延时50*t(us)
  48. void    DisplayListChar(uchar X,uchar Y,uchar delayms, uchar code *DData);
  49. void    judge_xianshi(void);//显示处理程序
  50. void    read_key(void);//按键键码读取子函数,返回相应的键码
  51. uchar   keybord_value;//全局变量,存储最终的键码,其值为0-F
  52. void    read_password(void);//6位数据的读取,也就是密码的读取
  53. uchar        deal_password(void);//输入密码和系统码对比,看是否符合开锁条件
  54.                             //返回值为1就开锁,返回值为0为密码错误
  55. void    makesurekeydeal();//确认键处理程序
  56. void    cancelkeydeal();//取消键处理程序
  57. //***********矩阵键盘键码****************************************
  58. const uchar tabl2[16]={0xee,0xed,0xeb,0xe7,0xde,0xdd,0xdb,0xd7,0xbe,
  59.                           //    s1   s2   s3   s4   s5   s6   s7   s8   s9
  60.                                0xbd,0xbb,0xb7,0x7e,0x7d,0x7b,0x77};
  61.                           //    s10  s11  s12  s13  s14  s15  s16
  62. uchar system[4][6];//定义 4*6个数据作为系统的密码 也就是4组6位数
  63. uchar passin[6];//定义全局变量,储存输入的6个按键数据
  64. uchar temppassin[6];//输入的数据暂存
  65. uchar flag1;//按键键入是否成功的标准,为1成功  为0失败
  66. uchar  passcount;//键入次数的统计
  67. uchar  flag2;//密码是否对的标志单位 ,为1成功  ,为0失败
  68. uchar  flag3,flag4,flag5,flag6,flag7,flag12;
  69. uchar t0_crycle;
  70. uchar error_count;//密码输入次数
  71. //***********************主程序******************************
  72. main()   
  73. {   
  74.    passcount=0;
  75.    flag5=0;
  76.    flag7=0;
  77.    flag6=0;
  78.    flag4=0;
  79.    flag3=0;
  80.    flag1=0;
  81.    beek_c=1;//关闭蜂鸣器
  82.    lock_c=0;//关闭锁
  83.    LCMInit();//液晶初始化设置
  84.    init_t0();
  85.    TR0=0;//关闭定时器T0
  86.    error_count=0;
  87.    read_24c16();//单片机上电的时候先读取4组密码
  88.    while(1)
  89.    {
  90.        read_key();//读取键码
  91.        read_password();//把键码转为密码
  92.        judge_xianshi();//显示
  93.    }
  94. }
  95. //****************************************************
  96. //写入数据操作
  97. void write_24c16()
  98. {
  99.    uchar i,j;
  100. write1:
  101.    star_24c16();//发送启动脉冲
  102.    w1byte_24c16(0xa0);//写24C16的芯片地址,高四位固定为1010,选择第一区,写操作
  103.    cack_24c16();// 读取应答或非应答信号
  104.    if(flag12)goto write1;//判断
  105.    w1byte_24c16(01);//写入24C16的内部地址
  106.    cack_24c16();
  107.    if(flag12)goto write1;
  108.    for(j=0;j<2;j++)//先写入12个字节的数据
  109.    {
  110.      for(i=0;i<6;i++)
  111.      {
  112.        w1byte_24c16(system[j][i]);
  113.        cack_24c16();
  114.        if(flag12)goto write1;
  115.      }
  116.     }
  117.     stop_24c16();//写数据完毕,发送停止脉冲      
  118. write2:
  119.     star_24c16();//发送启动脉冲
  120.     w1byte_24c16(0xa0);//写24C16的芯片地址,高四位固定为1010,选择第一区,写操作
  121.     cack_24c16();// 读取应答或非应答信号
  122.     if(flag12)goto write2;//判断
  123.     w1byte_24c16(17);//写入24C16的内部地址
  124.     cack_24c16();
  125.     if(flag12)goto write2;
  126.     for(j=2;j<4;j++)//写入后面24字节的数据
  127.     {
  128.         for(i=0;i<6;i++)
  129.         {
  130.              w1byte_24c16(system[j][i]);
  131.              cack_24c16();
  132.              if(flag12)goto write2;
  133.         }
  134.      }
  135.      stop_24c16();//写数据完毕,发送停止脉冲              
  136. }  
  137. //***************************************************
  138. //读数据操作
  139. void read_24c16()
  140. { uchar  i,j;
  141. read1:  
  142.   for(j=0;j<2;j++)//读取前面12字节的数据
  143.   {
  144.      for(i=0;i<6;i++)
  145.      {
  146.         nack_24c16();
  147.         star_24c16();//发送启动脉冲
  148.         w1byte_24c16(0xa0);//24C16的芯片地址,高四位固定为1010,选择第一区,写操作
  149.         cack_24c16();
  150.         if(flag12)goto read1;
  151.         w1byte_24c16(j*6+i+1);//写入24C16的内部地址,选择第二页
  152.         cack_24c16();
  153.         if(flag12)goto read1;
  154.         nack_24c16();
  155.         stop_24c16();//重新开始   
  156.         star_24c16();//
  157.         w1byte_24c16(0xa1);// 24C16的芯片地址,高四位固定为1010,选择第一区,读操作
  158.         cack_24c16();
  159.         if(flag12)goto read1;
  160.         system[j][i]=rd1byte_24c16();
  161.       }
  162.    }
  163.    mack_24c16();
  164.    nack_24c16();
  165.    stop_24c16();
  166. read2:  
  167.    for(j=2;j<4;j++)
  168.    {
  169.      for(i=0;i<6;i++)
  170.      {
  171.         nack_24c16();
  172.         star_24c16();//发送启动脉冲
  173.         w1byte_24c16(0xa0);//24C16的芯片地址,高四位固定为1010,选择第一区,写操作
  174.         cack_24c16();
  175.         if(flag12)goto read2;
  176.         w1byte_24c16(j*6+i+5);//写入24C16的内部地址,选择第二页
  177.         cack_24c16();
  178.         if(flag12)goto read2;
  179.         nack_24c16();
  180.         stop_24c16();//重新开始   
  181.         star_24c16();//
  182.         w1byte_24c16(0xa1);// 24C16的芯片地址,高四位固定为1010,选择第一区,读操作
  183.         cack_24c16();
  184.         if(flag12)goto read2;
  185.        system[j][i]=rd1byte_24c16();
  186.      }
  187.   }
  188.   mack_24c16();
  189.   nack_24c16();
  190.   stop_24c16();
  191.   for(j=0;j<4;j++)//
  192.   {
  193.      for(i=0;i<6;i++)
  194.      {
  195.          if(system[j][i]>15)system[j][i]=1;//出厂芯片读出的是FF,这样就没有密码可以输入了,防止防止这种任何密码都无效的情况,我们设置出厂4组密码都是111 111
  196.      }
  197.   }
  198. }
  199. //****************************************************
  200. //显示处理程序
  201. void   judge_xianshi()
  202. {
  203.   uchar i;
  204.   _nop_();
  205.   if(flag2==0)//开关初始显示
  206.   {
  207.      DisplayListChar(0,0,0, "Electronics Lock");//
  208.      DisplayListChar(1,0,0, "Password:");
  209.      for(i=0;i<passcount&&i<6;i++)//显示输入的6个数据
  210.      {
  211.         DisplayOneChar( 1, 9+i, '*'); //第一行改为隐藏
  212. //    //第二行改为真实显示,可以把这句删除就隐藏密码了
  213.      }
  214.   }
  215.   else if(flag2==5)
  216.   {
  217.      DisplayListChar(0,0,0, "Change passwor ");
  218.      DisplayOneChar( 0,15,flag5+0x30);
  219.      DisplayListChar(1,0,0, "0:      n:      ");
  220.      
  221.      for(i=0;i<6;i++)
  222.      {
  223.         DisplayOneChar( 1,i+2,system[flag5-1][i]+0x30);
  224.      }
  225.      for(i=0;i<6;i++)DisplayOneChar( 1,i+10,temppassin[i]+0x30);
  226.   }
  227. }
  228. //6位数据的读取,也就是密码的读取
  229. void  read_password()
  230. {
  231.    _nop_();
  232.    if(flag1==1 )//判断键入是否成功
  233.    {
  234.       flag1=0;
  235.       if(passcount<6 && flag5==0)
  236.       {
  237.               passin[passcount]=keybord_value;
  238.               passcount++;
  239.       }

  240.       if(passcount<6 && flag5!=0)
  241.       {
  242.               if(keybord_value!=15 && keybord_value!=14 )
  243.               {
  244.                 flag7=1;
  245.                 temppassin[passcount]=keybord_value;
  246.                 passcount++;
  247.               }
  248.       }
  249.       cancelkeydeal();//取消键处理程序
  250.       makesurekeydeal();//确认键处理程序
  251.       if(keybord_value==15 && flag7==0)//判断是否为设置键
  252.       {
  253.          flag5++;
  254.          if(flag5>=5)flag5=1;
  255.        }
  256.    }
  257. }
  258. //************************************************
  259. //确认键处理程序
  260. void    makesurekeydeal()
  261. {
  262.    uchar i;
  263.    _nop_();
  264.    if(keybord_value==12 && flag7==0 )//判断时候为确认键
  265.       {
  266.            flag2=deal_password();// 判断输入的密码是否正确
  267.            passcount=0;
  268.            if(flag3==0)//按第一次确认
  269.            {
  270.               flag3=1;
  271.               if(flag2==1)//输入的密码正确
  272.               {
  273.                  beek_c=0;//开蜂鸣器
  274.                  lock_c=1;//开锁
  275.                  flag6=1;
  276.                  DisplayListChar(1,0,0, "Opening........");//在液晶的第二行显示字符"OPERING
  277.                  TR0=1;
  278.                  flag4=0;
  279.                  error_count=0;
  280.                  while(flag4<=20);//密码正确开锁信号闭合2秒 蜂鸣器响2秒
  281.                  flag4=0;
  282.                  flag2=0;
  283.                  flag3=0;
  284.                  TR0=0;
  285.                  WriteCommandLCM(0x01,1); //清除显示一下
  286.                  beek_c=1;//关闭蜂鸣器
  287.                  lock_c=0;//断开锁信号输出
  288.                
  289.               }
  290.               else if(flag2==2)//输入的密码错误
  291.               {
  292.                   beek_c=0;
  293.                   TR0=1;
  294.                   flag6=0;
  295.                   error_count++;//密码输入错误后,计数器+1
  296.                   DisplayListChar(1,0,0, "Input Error  TIS");
  297.                   DisplayOneChar( 1,12,error_count+0x30);//显示输入多少次错误
  298.                   while(flag4<=5);//密码输入错误蜂鸣器响0.5秒,关0.5秒的频率响2次
  299.                   beek_c=1;
  300.                   flag4=0;
  301.                   while(flag4<=5);
  302.                   beek_c=0;
  303.                   flag4=0;
  304.                   while(flag4<=5);
  305.                   beek_c=1;
  306.                   flag4=0;
  307.                   flag2=0;
  308.                   flag3=0;
  309.                   TR0=0;
  310.                   if(error_count>=3)//如果密码输入3次错误经锁定2.54分钟或需要重新断电
  311.                   {
  312.                      DisplayListChar(0,0,0, "Input Error 3 Ts");
  313.                      DisplayListChar(1,0,0, "locked 3 minutes");
  314.                      TR0=1;
  315.                      while(flag4<=254);//锁定时间过后系统恢复
  316.                      DisplayListChar(0,0,0, "Electronics Lock");
  317.                      TR0=0;
  318.                      error_count=0;
  319.                      flag4=0;
  320.                   }
  321.               }
  322.            }
  323.        /*    else if(flag3==1)//第二次按确认
  324.            {
  325.               flag2=0;
  326.               flag3=0;
  327.            }*/
  328.             WriteCommandLCM(0x01,1); //清除显示一下
  329.       }
  330.     if(keybord_value==12 && flag7==1 )//确认修改密码
  331.     {
  332.            for(i=0;i<6;i++)
  333.            {
  334.                   system[flag5-1][i]=temppassin[i];//把暂存单元的数据传给对应的开始密码
  335.                   temppassin[i]=0;//暂存单元清零,下次修改密码可以再次利用
  336.            }
  337.            write_24c16();
  338.            flag7=0;//各种标志单元清零
  339.            flag2=0;
  340.            flag3=0;
  341.            flag5=0;
  342.            flag6=0;
  343.            passcount=0; //按键次数计数清零
  344.            WriteCommandLCM(0x01,1); //清除显示一下
  345.     }
  346. }
  347. //************************************************
  348. //取消键处理程序
  349. void    cancelkeydeal()
  350. {
  351.     uchar i;
  352.     _nop_();
  353.     if(keybord_value==13 )//判断是否为取消键
  354.     {
  355.        if(flag7==0)
  356.        {
  357.            for(i=0;i<passcount;i++)
  358.            {
  359.                passin[i]=0;
  360.            }//清零
  361.            passcount=0;//按取消键后,键入按键次数的计数单元清零
  362.            if(flag3==1)//取消显示密码错误
  363.            {
  364.               flag2=0;
  365.               flag3=0;
  366.             }
  367.        }
  368.        else if(flag7==1)
  369.        {
  370.            flag7=0;
  371.            flag2=0;
  372.            flag3=0;
  373.            flag5=0;
  374.            flag6=0;
  375.            passcount=0;
  376.            
  377.        }
  378.        WriteCommandLCM(0x01,1); //清除显示一下
  379.     }
  380. }
  381. uchar  deal_password()//输入密码和系统码对比,看是否符合开锁条件
  382. {
  383.    uchar i,j,temp2,temp;
  384.    temp2=0;
  385.    _nop_();
  386.    for(j=0;j<4;j++)//依次判断4组
  387.    {
  388.      temp=0;
  389.      for(i=0;i<6;i++)
  390.      {
  391.       if(system[j][i]==passin[i])temp++;//如果系统密码和键入的密码对应的位一样,则暂存单元自加1
  392.      }
  393.      if(temp==6)
  394.      {
  395.        temp2=1;
  396.        return(1);//如果TEMP为6,证明键入的密码和4组系统密码中的一组一样;
  397.        break;//退出判断
  398.      }
  399.    }
  400.    if(temp2==0)return(2);
  401. }
  402. void read_key(void)
  403. {
  404.    uchar  key_value,i=1;
  405.    uchar key_high_value,key_low_value;//定义变量暂存高四位和低四位按键的键码
  406.    _nop_();
  407.    key_port=0xf0;//置按键控制口为1,准备读入数据
  408.    key_value=key_port & 0xf0;
  409.    if(key_value!=0xf0)//如果没有按键按下,则相等
  410.    {
  411.       delay_50us(200);//延时10ms去除抖动
  412.       key_port=0xf0;//再次讲IO置1,准备读入去除抖动后的数据
  413.       key_value=key_port & 0xf0;
  414.       switch (key_value)
  415.       { case 0xf0:break;//经软件延时后,判断为误判,则退出函数,返回
  416.         case 0x70:key_high_value=0x70;break;
  417.         case 0xb0:key_high_value=0xb0;break;
  418.         case 0xd0:key_high_value=0xd0;break;
  419.         case 0xe0:key_high_value=0xe0;break;
  420.         default:key_high_value=0x00;break;//多个按键同时按下,显示0,然后退出
  421.       }
  422.       key_port=0x0f;//交换高四位和低四位的状态,再次读取键码
  423.       key_value=key_port & 0x0f;
  424.       switch(key_value)
  425.       {
  426.          case 0x07:key_low_value=0x07;break;
  427.          case 0x0b:key_low_value=0x0b;break;
  428.          case 0x0d:key_low_value=0x0d;break;
  429.          case 0x0e:key_low_value=0x0e;break;
  430.          default:key_low_value=0x00;break;
  431.       }
  432.      key_value=key_high_value | key_low_value;
  433.      for(i=0;i<16;i++)
  434.      {
  435.        if(key_value==tabl2[i])
  436.        {
  437.           keybord_value=i;
  438.           flag1=1;//置按键码读取成功标志位1;
  439.           if(flag6==1 && keybord_value==14)
  440.           {
  441.                 flag1=0;
  442.           }
  443.           break;
  444.        }
  445.      }
  446.      beek_c=0;//开蜂鸣器
  447.      TR0=1;
  448.      while(flag4<=1);//按按键的时候蜂鸣器响0.1秒
  449.      flag4=0;
  450.      TR0=0;//关闭定时器
  451.      beek_c=1;//关闭蜂鸣器
  452.      if(flag6!=0)
  453.      {
  454.      if(keybord_value==14)
  455.      {
  456.          TR0=1;
  457.          key_port=0xf0;//置按键控制口为1,准备读入数据
  458.          while((key_port & 0xf0 )!=0xf0 && flag5==0)
  459.          {
  460.             
  461.              if(flag4>=30)
  462.              {
  463.                 TR0=0;
  464.                 flag4=0;
  465.                 flag2=5;
  466.                 flag5=1;
  467.                 flag7=0;
  468.              }
  469.          }

  470.        }
  471.      }
  472.      key_port=0xf0;//置按键控制口为1,准备读入数据
  473.      while((key_port & 0xf0 )!=0xf0 && keybord_value!=14 );    //等待按键释放,按键释放后才往下执行程序
  474.    }
  475. }
  476. //定时器0中断服务程序
  477. void timer0() interrupt 1
  478. {
  479.         TH0=(65536-50000)/256;
  480.         TL0=(65536-50000)%256;//定时器设置为定时50MS
  481.         t0_crycle++;
  482.         if(t0_crycle==2)// 0.1秒
  483.         {
  484.           t0_crycle=0;
  485.           flag4++; //定时器开启后,FLAG4每0.1秒自加1
  486.       if(flag6!=0 && flag4>=40)//输入密码正确开锁后超过2分钟后不能进入修改开锁密码的界面
  487.       {
  488.          flag6=0;
  489.          flag4=0;
  490.          TR0=0;
  491.       }
  492.         }
  493. }
  494. //********************************************************************************************
  495. void init_t0()
  496. {
  497.     _nop_();
  498.            TMOD=0x01;//设定定时器工作方式1,定时器定时50毫秒
  499.         TH0=(65536-50000)/256;
  500.         TL0=(65536-50000)%256;
  501.         EA=1;//开总中断
  502.         ET0=1;//允许定时器0中断
  503.         t0_crycle=0;//定时器中断次数计数单元
  504. }
  505. /*====================================================================  
  506.   按指定位置显示一串字符:第 X 行,第 y列
  507.   注意:字符串不能长于16个字符
  508. ======================================================================*/
  509. void DisplayListChar(uchar X,uchar Y,uchar ms, uchar code *DData)
  510. {
  511.     uchar ListLength;
  512.     _nop_();
  513.     ListLength = 0;
  514.     X &= 0x1;
  515.     Y &= 0xF; //限制X不能大于15,Y不能大于1
  516.     while (DData[ListLength]!='\0') //若到达字串尾则退出
  517.     {
  518.         if (Y <= 0xF) //X坐标应小于0xF
  519.         {
  520.              DisplayOneChar(X, Y, DData[ListLength]); //显示单个字符
  521.              ListLength++;
  522.              Y++;
  523.                  delayms(ms);//延时显示字符串
  524.         }
  525.         else
  526.             break;//跳出循环体
  527.      }
  528. }
  529. /*======================================================================
  530. LCM初始化
  531. ======================================================================*/
  532. void LCMInit(void)
  533. {
  534. LCM_Data = 0;
  535. _nop_();
  536. WriteCommandLCM(0x38,0); //三次显示模式设置,不检测忙信号
  537. delayms(5);
  538. WriteCommandLCM(0x38,0);
  539. delayms(5);
  540. WriteCommandLCM(0x38,0);
  541. delayms(5);
  542. WriteCommandLCM(0x38,1); //显示模式设置,开始要求每次检测忙信号
  543. WriteCommandLCM(0x08,1); //关闭显示
  544. WriteCommandLCM(0x01,1); //显示清屏
  545. WriteCommandLCM(0x06,1); // 显示光标移动设置
  546. WriteCommandLCM(0x0C,1); // 显示开及光标设置
  547. delayms(100);
  548. }
  549. //==============================LCD1602显示子程序================================================
  550. // 写数据函数: E =高脉冲 RS=1 RW=0
  551. //======================================================================*/
  552. void WriteDataLCM(uchar WDLCM)
  553. {
  554. ReadStatusLCM(); //检测忙
  555. _nop_();
  556. LCM_Data = WDLCM;
  557. LCM_RS = 1;
  558. LCM_RW = 0;
  559. LCM_E = 0; //若晶振速度太高可以在这后加小的延时
  560. LCM_E = 0; //延时
  561. LCM_E = 1;
  562. }
  563. /*====================================================================
  564.   写指令函数: E=高脉冲 RS=0 RW=0
  565. ======================================================================*/
  566. void WriteCommandLCM(uchar WCLCM,BuysC) //BuysC为0时忽略忙检测
  567. {
  568. if (BuysC) ReadStatusLCM(); //根据需要检测忙
  569. LCM_Data = WCLCM;
  570. LCM_RS = 0;
  571. LCM_RW = 0;
  572. LCM_E = 0;
  573. LCM_E = 0;
  574. LCM_E = 1;
  575. }
  576. /*====================================================================
  577.   正常读写操作之前必须检测LCD控制器状态:E=1 RS=0 RW=1;
  578.   DB7: 0 LCD控制器空闲,1 LCD控制器忙。
  579.   读状态
  580. ======================================================================*/
  581. uchar ReadStatusLCM(void)
  582. {
  583. LCM_Data = 0xFF;
  584. LCM_RS = 0;
  585. LCM_RW = 1;
  586. LCM_E = 0;
  587. LCM_E = 0;
  588. LCM_E = 1;
  589. while (LCM_Data & Busy); //检测忙信号  
  590. return(LCM_Data);
  591. }
  592. /*======================================================================
  593. 功 能:     在1602 指定位置显示一个字符:第一行位置0~15,第二行16~31
  594. 说 明:     第 X 行,第 y 列  注意:字符串不能长于16个字符
  595. ======================================================================*/
  596. void DisplayOneChar( uchar X, uchar Y, uchar ASCII)
  597. {
  598.   X &= 0x1;
  599.   Y &= 0xF; //限制Y不能大于15,X不能大于1
  600.   if (X) Y |= 0x40; //当要显示第二行时地址码+0x40;
  601.   Y |= 0x80; // 算出指令码
  602.   WriteCommandLCM(Y, 0); //这里不检测忙信号,发送地址码
  603.   WriteDataLCM(ASCII);
  604. }
  605. /*====================================================================
  606.   设定延时时间:x*1ms
  607. ====================================================================*/
  608. void delayms(uint Ms)
  609. {
  610.   uint i,TempCyc;
  611.   for(i=0;i<Ms;i++)
  612.   {
  613.     TempCyc =70;
  614.     while(TempCyc--);
  615.   }
  616. }
  617. //***********************************************************************
  618. //函数名称:void delay_50US(unsigned int t)
  619. //功能: 延时50*t(us)
  620. void delay_50us(unsigned int t)
  621. {
  622.   unsigned char j;
  623.   for(;t>0;t--)
  624.   {
  625.     for(j=19;j>0;j--);
  626.   }
  627. }
  628. //******************************************************************************************
  629. //***********************************************
  630. //3微秒延时程序
  631. void delay_3us()
  632. {
  633.   ;
  634.   ;
  635. }   
  636. //*************************************************
  637. //功能:发送非应答信号
  638. void nack_24c16()
  639. {
  640. sda_24c16=1;   
  641. delay_3us();
  642. delay_3us();
  643. scl_24c16=1;
  644. delay_3us();
  645. delay_3us();
  646. scl_24c16=0;
  647. sda_24c16=0;
  648. }
  649. //*************************************************
  650. //功能:发送IIC停止信号
  651. void stop_24c16()
  652. {  
  653.    sda_24c16=0;
  654.    scl_24c16=1;                              
  655.    delay_3us();
  656.    delay_3us();                        
  657.    sda_24c16=1;
  658.    delay_3us();
  659.    delay_3us();                                 
  660.    scl_24c16=0;
  661. }
  662. //*************************************************
  663. //功能:发送启动通讯的信号
  664. void star_24c16()
  665. {
  666.   sda_24c16=1;
  667.   scl_24c16=1;
  668.   delay_3us();
  669.   delay_3us();
  670.   sda_24c16=0;
  671.   delay_3us();
  672.   delay_3us();
  673.   scl_24c16=0;
  674. }  
  675. //****************************************************
  676. //功能:判断应答或非应答
  677. //说明:通讯出错时标志为1,否则为0
  678. void cack_24c16()
  679. {  
  680.    scl_24c16=0;
  681.    sda_24c16=1;
  682.    delay_3us();         
  683.    scl_24c16=1;              
  684.    flag12=0;//清除错误标志   
  685.    if(sda_24c16)flag12=1;
  686.    scl_24c16=0;
  687. }      
  688. //****************************************************
  689. //功能:发送应答信号
  690. void mack_24c16()  
  691. {
  692.   sda_24c16=0;
  693.   scl_24c16=1;
  694.   delay_3us();
  695.   delay_3us();
  696.   scl_24c16=0;
  697.   sda_24c16=1;
  698. }
  699. //*************************************************
  700. //功能:向24C16写入一字节的数据
  701. void w1byte_24c16(uchar byte1)
  702. {
  703.   uchar i=8;
  704.   while(i--)   
  705.   {            
  706.     delay_3us();
  707.     delay_3us();
  708.     delay_3us();
  709.     if(byte1 & 0x80)
  710.     {sda_24c16=1;}
  711.     else
  712.     {sda_24c16=0;}
  713.     delay_3us();
  714.     delay_3us();
  715.     delay_3us();
  716.     scl_24c16=1;
  717.     delay_3us();
  718.     delay_3us();
  719.     delay_3us();
  720.     scl_24c16=0;
  721.     byte1<<=1;  
  722.   }
  723. }
  724. //*******************************
  725. …………限于本文篇幅 余下代码请从51黑下载附件…………
复制代码




下载:
rar (1)rr.rar (1.95 MB, 下载次数: 46)


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

使用道具 举报

沙发
ID:139236 发表于 2017-5-8 07:54 | 只看该作者
很好的例程感谢分享
回复

使用道具 举报

板凳
ID:257877 发表于 2017-12-6 15:55 | 只看该作者
我想请问下楼主你的这个程序里是怎么按下才算是修改密码的
回复

使用道具 举报

地板
ID:795427 发表于 2022-12-5 22:33 | 只看该作者
修改密码存在问题
回复

使用道具 举报

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

本版积分规则

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

Powered by 单片机教程网

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