码迷,mamicode.com
首页 > 其他好文 > 详细

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

时间:2016-09-23 12:48:15      阅读:313      评论:0      收藏:0      [点我收藏+]

标签:

  • 设计采用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项目】电子密码锁设计

标签:

原文地址:http://www.cnblogs.com/Afterwork/p/5899344.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!