首页 > 代码库 > 【51项目】电子密码锁设计

【51项目】电子密码锁设计

  • 设计采用AT89S52单片机作为核心控制单元,配以相应的硬件电路,完成开锁密码的设置、存储、校对、提醒和报警功能。
  • 硬件结构

技术分享

  • 整体电路

技术分享

  • 软件结构

技术分享

  • 液晶驱动12864.c
  1 /*  ****************************************************                  2                     程序参考地址  3       http://blog.chinaunix.net/uid-21658993-id-1819849.html  4                       图片显示  5        http://www.51hei.com/mcu/4161.html  6 ********************************************************/  7 #ifndef _12864_H_  8 #define _12864_H_  9 #define LCD_DATA P0  10 sbit RS = P2^4;         //并行的指令/数据选择信号: 1数据, 0命令 11 sbit RW = P2^5;         //并行读写选择信号:1读, 0写 12 sbit E = P2^6;          //并行使能端:1有效 13 sbit PSB = P2^1;        //并/串接口选择:1并,0串 14 sbit RET = P2^3;        //复位:0有效 15  16 bit checkBusy() 17 {   bit busy; 18     RS = 0; 19     RW = 1; 20     E = 1; 21     delayUs(); 22     busy = (bit)(LCD_DATA&0x80); 23     E = 0; 24     return busy; 25 } 26 void wait() 27 { 28     while(checkBusy()); 29 } 30 void writeCmd(uchar cmd) 31 { 32     wait(); 33     RS = 0; 34     RW = 0; 35     E = 0; 36     delayUs(); 37     LCD_DATA =http://www.mamicode.com/ cmd; 38     delayUs(); 39     E = 1; 40     delayUs(); 41     E = 0; 42 } 43 void writeData(uchar dat) 44 { 45     wait(); 46     RS = 1; 47     RW = 0; 48     E = 0; 49     delayUs(); 50     LCD_DATA =http://www.mamicode.com/ dat; 51     delayUs(); 52     E = 1; 53     delayUs(); 54     E = 0; 55 } 56  57 void setPosition(uchar x, uchar y)             //4*8 58 {   uchar p; 59     switch(x%4) 60     { 61         case 0: p = 0x80; break; //第0行 62         case 1: p = 0x90; break; //第1行 63         case 2: p = 0x88; break; //第2行 64         case 3: p = 0x98; break; //第3行 65     } 66     p += y; 67     writeCmd(p); 68 } 69 void lcd_mesg(uchar * str) 70 {   uchar n = 0; 71     while(str[n] != \0) 72     { 73         writeData(str[n++]); 74     } 75 } 76 void lcd_draw(unsigned char code *pic) 77 { 78     unsigned i,j,k; 79     writeCmd(0x34);//扩充指令集      80     for(i=0;i<2;i++)//上半屏和下半屏 81     { 82         for(j=0;j<32;j++)//上下半屏各32行 83         { 84             writeCmd(0x80+j);//写行地址(y地址) 85             if(i==0) 86             { 87                 writeCmd(0x80);//写列地址(x地址),上半屏列地址为0x80,下半屏列地址为0x88 88             } 89             else 90             { 91                 writeCmd(0x88); 92             } 93             for(k=0;k<16;k++)//写入列数据 94             { 95                 writeData(*pic++); 96             } 97         } 98     } 99     writeCmd(0x36);//显示图形100     writeCmd(0x30);//基本指令集101 }102 void init_lcd()                                                                                                                                                                                                                                                                             103 {104     PSB = 1;            //并口方式105     writeCmd(0x30);     //基本指令, 扩充指令为34H106     delayMs(10);107     writeCmd(0x0c);     //显示开, 关光标108     delayMs(10);109     writeCmd(0x01);     //清屏110     delayMs(10);   111 }112 113 #endif
  • 存储驱动24c02.c
#ifndef _24C02_H_#define _24C02_H_uchar flag_lock;          //键盘锁定标识,1有效uchar userpsw[6]; uchar adminpsw[6];/*24C02读写驱程序*/sbit scl=P1^1;sbit sda=P1^2;sbit  wp=P1^0;    //写保护//应答函数:在SCL保持高电平期间,拉低SDA,且保持4us以上,再拉高void iic_ack()        {    scl=0;        //默认初值为0    scl=1;        //SCL保持高电平    delay_5us();    sda=1;            delay_5us();    sda=0;    delay_5us();    scl=0;        //SCL结束保持高    sda=1;        //SDA返回原值}void iic_start()        //开始信号,上升沿{    sda=1;    //发送起始条件的数据信号    scl=1;     //发送起始条件的时钟信号    delay_5us();     sda=0;    //发送起始信号    delay_5us();     scl=0;    //钳住IIC总线,准备发送或接收数据     delay_5us(); }void iic_stop()         //结束信号,下降沿{    sda=0;    //发送结束条件的数据信号     scl=1;    //发送结束条件的时钟信号     delay_5us();     sda=1;    //发送结束信号     delay_5us();}void writex(unsigned char x)  //写一个字节{    unsigned char i;    for(i=0;i<8;i++)        //循环8次,由高到低赋给SDA    {        scl=0;                //允许更改SDA        delay_5us();        //存在边沿时间,需等5us        sda=x&0x80;     //SDA = 数据和10000000按位与; 串口SDA只送最高位        x=x<<1;        delay_5us();        scl=1;        delay_5us();        scl=0;            }}unsigned char readx()   //读一个字节{    unsigned char i,value;        for(i=0;i<8;i++)    //8次读取1个字节    {        scl=0;        delay_5us();        scl=1;            //保持着SDA的值,以便读出从机数据        delay_5us();        if(sda==1)        {            value=(value<<1)|1;            }        if(sda==0)        {            value=(value<<1)|0;            }        delay_5us();    }    return value;}//向24C02的地址address中写入一个字节的数据infovoid write_24c02(unsigned char address,unsigned char info){    iic_start();     writex(0xae);       //24c02芯片地址为111,写方向位0:1010 1110    iic_ack();    writex(address);    iic_ack();     writex(info);    iic_ack();     iic_stop();}//从24C02的地址address中读取一个字节的数据unsigned char read_24c02(unsigned char address){    unsigned char value;    iic_start();     writex(0xae);    iic_ack();    writex(address);    iic_ack();    iic_start();    writex(0xaf);        //24c02芯片地址为111,读方向位1:1010 1111    iic_ack();    value=readx();     iic_stop();    return(value);}void initset_read()            {    uchar tmp;    flag_lock=read_24c02(20);       //读出键盘锁定标识并显示,地址20,出厂状态为0    delay_ms(50);    for(tmp=0;tmp<6;tmp++)    {        adminpsw[tmp]=read_24c02(10+tmp);       }    delay_ms(50);     for(tmp=0;tmp<6;tmp++)    {        userpsw[tmp]=read_24c02(tmp);    }    delay_ms(50);   }void init_24c02()  //总线初始化,拉高释放总线,并读出错误计数和密码{    wp=1;    scl=1;     delay_5us();     sda=1;     delay_5us();     initset_read();                      //将外部存储器中的密码读入缓存区    }#endif
  • 日历/时钟驱动ds1302.c
/*  ****************************************************                                    程序参考地址            http://www.51hei.com/mcu/1730.html********************************************************/#ifndef _DS1302_H_#define _DS1302_H_sbit CLK=P3^6;        //DS1302引脚定义sbit IO=P3^4;sbit CE=P3^5;         //RSTsbit ACC0=ACC^0;sbit ACC7=ACC^7;extern uchar timer_cnt;void Input_1byte(uchar TD)        //DS1302输入一字节数据{    uchar i;    ACC=TD;    for(i=8;i>0;i--)    {        IO=ACC0;        CLK=1;        CLK=0;        ACC=ACC>>1;    }}uchar Output_1byte(void)       //DS1302输出一字节数据{    uchar i;    for(i=8;i>0;i--)    {        ACC=ACC>>1;        ACC7=IO;        CLK=1;        CLK=0;    }    return(ACC);}void Write_DS1302(uchar add,uchar dat)//向DS1302写{    CE=0;    CLK=0;    CE=1;    Input_1byte(add);    Input_1byte(dat);    CE=0;}uchar Read_DS1302(uchar add)    //从DS1302读{    uchar inf;      //信息临时存储变量    CE=0;    CLK=0;    CE=1;    Input_1byte(add);    inf=Output_1byte();    CE=0;    return(inf);}/**********************DS1302初始化*****************************/void init_1302(){    if(Read_DS1302(0xd1)==0x55)               //判断内存单元的内容,是否进行初始化               return;          else     {        Write_DS1302(0x8e,0x00); //关闭写保护        Write_DS1302(0x90,0x00); //电池充电设置        Write_DS1302(0x80,0x00); //        Write_DS1302(0x82,0x51); //        Write_DS1302(0x84,0x17); //        Write_DS1302(0x86,0x17); //        Write_DS1302(0x88,0x04); //        Write_DS1302(0x8c,0x16); //        Write_DS1302(0xd0,0x55); //写RAM        Write_DS1302(0x8e,0x80); //打开写保护      }}/**********************************************************                      DS1302显示                        ***********************************************************/void disp_ds1302(){    uchar min,min1,min2;    uchar hour,hour1,hour2;    uchar date,date1,date2;    uchar mon,mon1,mon2;    uchar year,year1,year2;//******读出1302的日期******/    min=Read_DS1302(0x83);      //读分:min1=十位,min2=个位    min2=min&0x0f;        min1=min>>4;        hour=Read_DS1302(0x85);     //读时:hour1=十位,hour2=个位    hour2=hour&0x0f;    hour1=hour>>4;        date=Read_DS1302(0x87);     //读日期:date1=十位,date2=个位    date2=date&0x0f;    date1=date>>4;        mon=Read_DS1302(0x89);      //读月份:mon1=十位,mon2=个位    mon2=mon&0x0f;    mon1=mon>>4;    year=Read_DS1302(0x8d);     //读年份:year1=十位,year2=个位    year2=year&0x0f;        year1=year>>4;    //******显示1302的日期******/               setPosition(0,0);    writeData(2+0x30);    writeData(0+0x30);    writeData(year1+0x30);          //    writeData(year2+0x30);     writeData(-);                 //-    writeData(mon1+0x30);           //    writeData(mon2+0x30);    writeData(-);                 //-    writeData(date1+0x30);          //    writeData(date2+0x30);    writeData( );                 //空格    writeData(hour1+0x30);          //    writeData(hour2+0x30);     if(timer_cnt<18)   writeData(:);         else    writeData( );    writeData(min1+0x30);           //    writeData(min2+0x30);           }#endif
  • 键盘扫描keyscan.c
#ifndef _KEYSCAN_H_#define _KEYSCAN_H_#define keyport P3uchar key=0; //按键值/*------------------------------------------------按键扫描函数,返回扫描键值------------------------------------------------*/unsigned char key_scan(void)//键盘扫描函数,使用行列反转扫描法{    uchar cord_h,cord_l;            //行列值中间变量    keyport=0xf0;                   //行线输出全为0,P3=1111 0000    cord_h=keyport&0xf0;            //读入列线值    if(cord_h!=0xf0)                //有键按下    {        delay_ms(5);                //去抖        if(cord_h!=0xf0)        {            cord_h=keyport&0xf0;    //读入列线值            keyport=cord_h|0x0f;    //输出当前列线值            delay_ms(5);            cord_l=keyport&0x0f;    //读入行线值                        while((keyport&0x0f)!=0x0f);//等待松开并输出                        return(cord_h+cord_l);  //键盘最后组合码值        }    }    return(0xff);                   //返回"无键按下",键盘不起作用}/*------------------------------------------------键值处理函数,返回扫键值------------------------------------------------*/unsigned char key_value(void) //按下相应的键显示相对应的码值{    switch(key_scan())    {        case 0xee:return  0;break;      //0    1110 1110        case 0xde:return  1;break;      //1        case 0xbe:return  2;break;      //2        case 0x7e:return  3;break;      //3        case 0xed:return  4;break;      //4        case 0xdd:return  5;break;      //5        case 0xbd:return  6;break;      //6        case 0x7d:return  7;break;      //7        case 0xeb:return  8;break;      //8        case 0xdb:return  9;break;      //9        case 0xbb:return 10;break;      //a    * 键        case 0x7b:return 11;break;      //b    # 键        case 0xe7:return 12;break;      //c  管理/退出键        case 0xd7:return 13;break;      //d  删除键        case 0xb7:return 14;break;      //e  清空键        case 0x77:return 15;break;      //f  确认键        default:return 0xff;break;    }}#endif
  • 软件仿真

技术分享

 

【51项目】电子密码锁设计