AT89C51单片机制作密码锁,真的很详细了

  • Post author:
  • Post category:其他




前言

设计一个基本实现密码锁功能的程序开发,作者实测实物有效,且在后来添加了红外功能,其再次可开发性是很好的。采用模块式编程,易懂易理解,作者大二写的,所以可以用作课程设计。



所需基础

1、C语言基础

2、有一点单片机编程语法基础

3、了解AT89C51芯片的管脚分布以及其电平驱动逻辑



工具准备

1、Keil uVision4

2、如果是刚开始学习单片机的伙伴对于89的管脚不是很熟悉的话,建议这个项目还是安装一下Protel99se,这个工具的使用阐述了,网上有很多基础教程,一看就懂。老手跳过。



代码截图

代码截图



模块使用介绍

项目由几个模块组成,如截图所示:LCD1602+24C02+MODIFYKEY+MAIN,1602用于信息的显示,是一块显示屏;24c02是一块小芯片,用于保存密码;modifykey是密码修改模块,将他单独放出也是为了避免一下不必要的错误,main函数主要是键值判断和存储密码。设计不涉及中断,当然你要去加别的模块,当然是需要中断的,不介绍了。

电路图

由于找不到原来的电路图了,只有这个带红外的了,网上找了一张,参考一下,如果代码看懂了,那你也知道哪个线在哪。键盘矩阵的话当时要求自己焊接,但是自己焊接的真的太丑了,不如买一个薄膜的又好看又好用。



必学几部分

接下来就开始讲主要的函数,主要分为:1、键值判断 2、密码修改 3、1602显示屏显示函数 4、24c02存储



键值判断

全局变量定义

#include "reg52.h"			 //此文件中定义了单片机的一些特殊功能寄存器
#include "i2c.h"
#include "1602.h"	
#include "modifykey.h"

typedef unsigned int u16;	  //对数据类型进行声明定义
typedef unsigned char u8;
sbit led=P2^2;
sbit Beep_P=P2^4;

u8 p[]={"  pass  "}	;
u8 l[]={"  loss  "}	;  
u8 start[]={"input   password: "} ;
u16 num=0;
u8 keybord,s=0;
u16  passkey=12345;
int adminkey=199607;

键值判断函数Getch

void Getch ( )        //取键值函数
{char a=0,b=0,c=0;
u8 X,Y,Z;
GPIO_KEY=0x0f; //先对P3 置数 行扫描
if(GPIO_KEY!=0x0f) //判断是否有键按下
        {
        delay1(1000); //延时,软件去干扰
        if(GPIO_KEY!=0x0f) //确认按键按下
                {
                X=GPIO_KEY; //保存行扫描时有键按下时状态
                GPIO_KEY=0xf0; //列扫描
                Y=GPIO_KEY;    //保存列扫描时有键按下时状态
                Z=X|Y; //取出键值
/*********************************************************************/
switch ( Z ) //判断键值(那一个键按下)
                        {
                                case 0xeb: keybord=0;num=num*10+keybord;LcdWriteData('*');delay1(1000); break; //对键值赋值
                                case 0x77: keybord=1;num=num*10+keybord;LcdWriteData('*');delay1(1000); break;
                                case 0x7b: keybord=2;num=num*10+keybord;LcdWriteData('*');delay1(1000); break;
                                case 0x7d: keybord=3;num=num*10+keybord;LcdWriteData('*');delay1(1000); break;
                                case 0xb7: keybord=4;num=num*10+keybord;LcdWriteData('*');delay1(1000); break;
                                case 0xbb: keybord=5;num=num*10+keybord;LcdWriteData('*');delay1(1000); break;
                                case 0xbd: keybord=6;num=num*10+keybord;LcdWriteData('*');delay1(1000); break;
                                case 0xd7: keybord=7;num=num*10+keybord;LcdWriteData('*');delay1(1000); break;
                                case 0xdb: keybord=8;num=num*10+keybord;LcdWriteData('*');delay1(1000); break;
                                case 0xdd: keybord=9;num=num*10+keybord;LcdWriteData('*');delay1(1000);break;
								case 0xde: num=num/10;b=0;c=num;LcdWriteCom(0x01);while(c!=0){c=c/10;b++;}for(;b>0;b--){LcdWriteData('*');delay1(1000);}b=0;c=0;break;  //除位
                                case 0x7e: if(num==passkey||num==adminkey){led=1;
								while(p[b]!='\0'){LcdWriteData(p[b]);b++;};delay1(40000);delay1(40000);b=0;delay1(40000);LcdWriteCom(0x01);
								delay1(1000);passkey=modifypassword();storageInit(passkey);delay1(10000);delay1(20000);delay1(20000);delay1(20000);led=0;}
								else {while(l[b]!='\0'){LcdWriteData(l[b]);b++;};MingJiao();delay1(40000);delay1(40000);b=0;delay1(40000);LcdWriteCom(0x01);delay1(1000);}
								num=0;LcdWriteCom(0x01);break; //密码确认
								default : num=num;break;              
                        }
		 while((a<50)&&(GPIO_KEY!=0xf0))	 //检测按键松手检测
			{
				delay1(1000);
				a++;
			}
         } 		
    }
} 		   



头文件意义

#include "reg52.h"			 //此文件中定义了单片机的一些特殊功能寄存器
#include "i2c.h"
#include "1602.h"	
#include "modifykey.h"

为什么引入头文件,单片机中引入模块,引入函数,就一定引入头文件,因为有哪些函数,用什么格式,针对哪种单片机都是在头文件中定义的,24c02举例,I2C.H

#ifndef __I2C_H_
#define __I2C_H_

#include <reg52.h>

sbit SCL=P2^1;
sbit SDA=P2^0;

void I2cStart();
void I2cStop();
unsigned char I2cSendByte(unsigned char dat);
unsigned char I2cReadByte();
void At24c02Write(unsigned char addr,unsigned char dat);
unsigned char At24c02Read(unsigned char addr);

#endif

声明名称

引入reg52头文件,带入管脚

定义24c02芯片连接管脚,SCL时钟管脚连接2.1,SDA数据管脚连接2.0

定义相关函数

结束定义 endif



typedef 和 sbit方法

typedef用于简化变量的定义,typedef unsigned int u16; 那么 u16 a 等同于 unsigned int a

sbit 定义管脚名称

当然模块头文件也可以声明如此定义,但是不建议,避免不必要的麻烦,建议使用全名,仅仅在main函数去定义,但是这种头文件定义是可以的

//---重定义关键词---//
//#ifndef uchar
//#define uchar unsigned char
//#endif

//#ifndef uint 
//#define uint unsigned int
//#endif



键值判断case 0xeb

那么0xeb怎么来的呢,我们看到电路图,

矩阵键盘

现在我把P17置高电平,也就是置1,当我按下s14的时候,p17和p10之间导通,p10接收到来自于p17的高电平,这时候单片机可以进行判断,if p10 = 1:XXX;而现实中,我们一般将P14到P17置1,P10到P13置0,也就是P1为0x0f,oxfo是转化为2进制也就是:0000 1111;很显然了就,同样电平由于按键更改P1的值也就发生了短暂的变化。



modifykey

一个修改密码的函数为什么要单独拿出来呢,首先是逻辑,先修改临时密码变量,然后再进行判断。其次,加强可读性,最后也是最重要的,当你按键的时候,是两个操作在进行,1、在lcd上显示*表示你键入了一个值,2、在密码变量中保存这个值。同时我们知道这两个操作是没有办法同时进行的,所以分解。



LCD1602、24C02

这两个模块建议单独进行练习和学习,也是很独立的两个模块,别人已经单独给你封装好勒读懂直接用。



学习建议

淘宝买一个开发板进行学习,也就60块钱,不打广告,随便推一个吧,反正客服嗯哼大家也知道,产品无质量问题就行了。https://detail.tmall.com/item.htm?spm=a230r.1.14.15.7f3a4a62vSMiOV&id=36522460231&ns=1&abbucket=8

祝各位学习愉快,

代码地址

提取码:f6ax



版权声明:本文为qq_40574123原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。