51项目电子密码锁设计

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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 = 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 = 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);     //基本指令, 扩充指令为34H
106     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中写入一个字节的数据info
void 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;         //RST
sbit 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 P3
uchar 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项目电子密码锁设计的主要内容,如果未能解决你的问题,请参考以下文章

基于51单片机LCD1602矩阵键盘电子密码锁proteus仿真设计

基于51单片机的公交车安全智能检测系统基于51单片机的金属探测仪控制设计基于单片机的智能电子密码锁系统设计基于51单片机酒精浓度检测仪设计资料转发分享

基于单片机的智能电子密码锁系统设计-电路程序资料

Express实战 - 应用案例- realworld-API - 路由设计 - mongoose - 数据验证 - 密码加密 - 登录接口 - 身份认证 - token - 增删改查API(代码片段

基于单片机矩阵键盘的电子密码锁设计-毕设课设资料

单片机课设-电子时钟设计(仿真图代码全)