一、基本组成:
单片机小系统+4*4矩阵键盘+1602显示+DC电机
基本电路:
键盘和和显示
键盘接P1口,液晶的电源的开、关通过P2.7口控制
电机(控制口P2.4)
小系统就不贴上来了吧。。。
二、基本功能描述:
1.验证密码、修改密码
a)锁的初始密码是123456(密码最长为10位,最短为1位)。
2.恢复初始密码
a)系统可以恢复初始密码,否则一旦忘记密码而又不能恢复初始密码,该锁就永远打不开。但是又不能让用户自行修改密码,否则其他人也可以恢复该初始密码,使得锁的安全性大大下降。
3.使系统进入低功耗状态
a)在实际使用中,锁只有在开门时才被使用。因而在大多数的时间里,应该让锁进入休眠状态、以降低功耗,这使系统进入掉电状态,可以大大降低系统功耗。
b)同时将LCD背光灯关闭
4.DC电机模拟开锁动作。
a)DC电机启动时解除开锁把手的锁定,允许通过把手开锁。DC电机不直接开锁,使得DC电机的功率不用太大,系统的组成和维护将变得简单,功耗也降了下来。
三、密码锁特点说明:
1.0 输入将被以字符形式输入,最长为10位。
超过10位时系统将自动截取前10位、但不作密码长度溢出提示。
2.0 开锁10秒后不允许更改密码、并提示修改超时_进入初始态,需要重新输入密码方可再次修改密码。
3.0 系统未使用存储器存储密码故掉电后密码自动恢复为初始密码。
4.0 若2分钟内无任何操作,系统自动进入省电模式运行,同时关闭液晶显示,以节省电力。
5.0 输入密码正确后、电机允许开锁时间为5秒, 5秒后需要再次输入密码才可以再次开锁。
6.0 修改密码键和恢复初始密码键最好置于室内。
这是Proteus仿真结果:
输入密码123456:
显示结果:
密码正确时电机启动、电机将持续5秒:
这是键盘:
开锁键是接INT0引脚接的一个独立按键,用于唤醒CPU工作、进而开启整个系统
密码正确时可以修改密码:
再次输入新密码,两次输入相同时、更改有效
当然你可以随时放弃修改密码
改进:
1.0 密码锁的秘密没有存储,因而在掉电时最新的密码将丢失,重新上电后密码将恢复成为初始密码。这使得每次换电池或停电后密码都得恢复一次,给使用带来不便,但是为了要存储一个最多只有十几字节的密码就增加一个存储器、似乎不是很值,最好是所选的单片机自带这样的存储器(容量很小、如32B)。当然如果电源来自市电的话,就不会经常掉电了。
2.0 系统的最好再增加电源监测的设计,在电池电力不够时发出提示。这时还可以增加备用电池,这样就可以保证系统不会掉电。但是这些都要依赖于成本。
3.0 液晶的显示最好采用中文。通过对1602的CGRAM的操作可以实现中文显示,使得用户界面更好。
主函数:
确认键操作:
确认函数_ confirm()操作:
0_将 '\0' 置于输入table_input[]结尾
(table_input[]的长度返回值在length里面)
根据操作标识选择任务:
1_确认密码:判定输入密码正确与否
2_修改密码:确认第一次输入并保存
要求第二次输入
比较两次输入是否相同
根据比较结果选择任务:
修改失败,进入输入密码态
修改成功,将输入复制到table_password[]
确认函数_confirm()相关标识位目录:
flag_display;//根据其值可以确定显示信息
flag_confirm;//确认键根据此标识判定任务,默认为0_即为确定密码状态
flag_allow;//允许修改密码标识,在密码比较正确时置1
flag_amend;//第一/二次输入新密码标识
flag_M;//允许电机开锁标识
相关变量
sbit M=P3^6;//电机控制口
flag_confirm;//操作任务标识位
flag_compare;//比较输入与密码|相等时返回1,否则返回0
static flag_amend;//修改密码时的标识
第一次输入前=1,输入后置2
第二次输入前=2,输入后置0
flag_display=0;//确认键操作的返回值根据返回值可以确定显示信息
flag_allow;//允许改密码标识,在密码比较正确时置1,不正确时置0
process_char()函数::_M;//DC电机控制口
process_char()函数::_length;//跟踪记录输入table_input[11]的字符长度(
lcd_display()函数中标识位flag_display的值与意义:
=0:不显示|不刷新显示
=1:密码错误
=2:密码正确
=3:请输入新密码
=4:请再次输入新密码
=5:密码修改成功
=6:密码修改失败
=7:显示输入密码状态_The password!
=8:放弃修改密码
=9:已开锁
流图不怎么清晰、不过下一篇就是程序了,可以从程序推出流图。
程序比较多,所以写成了几个文件,同时应用了相当多的标识位来进行信号传递。
我觉得边看程序边画它的流程图会更好地帮助我们读程序。
1.0 main.c文件
#include
#include
#includemydefine_2.h
static void delay(unsigned int N)//N ms延时_12MHz/准确性高
{
unsigned int i=0,j=0;
for(i=1;i
for(j=1;j
}
void clock()
{
key_clock=0;
delay(15);
key_clock=1;
}
void init()
{
key_LCD=0;
init_1602();
TMOD=0x01;
TH0=0x3C;//=(65535-5000)/256
TL0=0xAF;//(65535-5000)%256
EA=1;
ET0=1;
TR0=0;
EA=1;//外部中断0唤醒CPU(空闲方式)
EX0=1;
IT0=1;
command(0x80);
lcd_display(7);
}
void main()
{
init();
while(1)
{
temp=keyboard_matrix();//扫描输入
if(temp)//有按键输入信息
{
clock();//按键声
TR0=0;//关闭计时
timer=0;
receive(temp);//输入的字符串长度为length(
if(i!=length)//输入时显示*
{
command(0xC0+length);//为显示密码输入设定位置
display('*');
i=length;
}
switch(temp)//根据按键号调用任务
{
//修改密码
case 12: if((flag_allow) && (flag_amend==0))//输入密码正确的条件下可以更改
{
table_input[0]='\0';
flag_display=3;//请输入新密码
flag_confirm=1;//确认键进入确认修改密码功能
flag_amend=1;//每次按下修改键时都是第一次输入新密码
length=0; //重按修改键时也是第一次输入新密码
i=0;
}
else
{
flag_confirm=0;//恢复初始态
flag_amend=0;
lcd_display(1);//密码不正确
delay(500);
flag_display=7;
length=0;
i=0;
}
break;
case 11: //取消
command(0xC0+length);//擦出显示
display(' ');//显示后光标_显示地址又加了1
command(0xC0+length);//重置光标_显示地址|实为将光标拉回来
i=0;
if(length > 0)
{
length--;//input[]位置后退一位
}
break;
case 10: confirm();//确定
i=0;
break;
case 13: //修改密码的过程中取消修改密码|将系统置于初始态即可
if((flag_amend==1) || (flag_amend==2))
{
flag_amend=0;
flag_confirm=0;
lcd_display(8);
delay(500);
flag_display=7;
length=0;
i=0;
}
break;
}
lcd_display(flag_display);
}
else
{
TR0=1;//开始计时等待
}
DC_Moter();
resume_password();
if(flag_clear)//恢复密码和开锁键_外部中断有效时重新计时
{
flag_clear=0;
timer=0;
}
if(timer==100)//10秒后不允许更改密码
{
flag_allow=0;
flag_amend=0;
flag_confirm=0;
length=0;
i=0;
lcd_display(7);//显示初始态,以提示修改超时
}
if(timer==1200)//≈2分钟后休眠|空闲方式
{
TR0=0;
timer=0;
clear_system();//恢复初始态
i=0;
key_clock=0;
delay(250);
key_clock=1;
PCON|=0x01;
lcd_display(7);//唤醒CPU后显示初始态
}
}
}
void int0() interrupt 0
{
key_LCD=0;//开液晶电源
key_clock=0;
delay(250);
key_clock=1;
flag_clear=1;
}
void Timer0() interrupt 1 //50ms
{
TH0=0x3C;//(65535-50000)/256
TL0=0xAF;//(65535-50000)%256
timer++;
}
2.0 负责实现具体操作的 process_char.c 文件
#include
#include
#includemydefine.h
sbit key_self=P2^1;//独立按键,用于恢复初始密码
sbit key_LED=P2^0;
sbit key_M=P2^4;//DC电机控制口
sbit key_LCD=P2^7;//液晶电源控制口
extern bit flag_clear;//恢复密码和开锁键_外部中断的有效标识
extern unsigned int timer;//定时器0计数时段标记_50ms一次定时中断
extern unsigned char length=0;//跟踪记录输入table_input[11]的字符长度(
extern unsigned char flag_display=0;//根据其值可以确定显示信息
extern unsigned char flag_confirm=0;//确认键根据此标识判定任务,默认为0_即为确定密码状态
extern unsigned char flag_allow=0;//允许修改密码标识,在密码比较正确时置1
extern unsigned char flag_amend=0;//第一/二次输入新密码标识
unsigned char flag_M=0;//允许电机开锁标识
extern void command(unsigned char command);
extern void display(unsigned char date);
//向I2C地址为address处写入数据date
extern void write_I2C(unsigned char address,unsigned char date);
//读出I2C地址为address处的数据
extern unsigned char read_I2C(unsigned char address);
static void delay(unsigned int N)//N ms延时/准确性高
{
unsigned int i=0,j=0;
for(i=1;i
for(j=1;j
}
//休眠前清除table_input中的值
extern void clear_system()
{
table_input[0]='\0';//恢复初始态
length=0;
flag_allow=0;
flag_confirm=0;
flag_amend=0;
flag_clear=0;
key_LCD=1;//关液晶电源
}
//接收键盘输入|以字符形式存入table_input[11]
extern void receive(unsigned char temp)
{
//按键在松手时读取按键号,故不会重复读取按键值
if(temp && length
{
switch(temp)
{
case 1:
case 2:
case 3:
case 4:
case 5:
case 6:
case 7:
case 8:
case 9: table_input[length++]=temp+48;//以字符形式存入table_input[11]
break;
case 14: table_input[length++]=48;//字符0
}
}
}
//根据任务选择显示信息
extern void lcd_display(unsigned char temp)
{
unsigned char i=0,*p=NULL;
if(temp)
{
switch(temp)//选择显示信息
{
case 1: p=table_error;//密码不正确
break;
case 2: p=table_pass;//密码正确
break;
case 3: p=table_new;//请输入新密码
break;
case 4: p=table_again;//请再次输入新密码
break;
case 5: p=table_changed;//密码修改成功
break;
case 6: p=table_fail;//密码修改失败
break;
case 7: p=table_enter;//显示输入密码:The password!
break;
case 8: p=table_abandon;//放弃修改密码
break;
case 9: p=table_close;//锁闭
break;
case 10: p=table_resume;//锁闭
break;
}
command(0x01);
delay(1);
command(0x80);
while(*p!='\0')
{
display(*(p++));
}
flag_display=0;//显示后清0,避免重复显示
}
}
//确认
extern void confirm(void)
{
unsigned char flag_compare=0;//用于记录比较输入与密码的结果|相等时返回1,否则返回0
unsigned char flag_compare_2=0;//用于记录对两次输入的新密码的比较结果|相等时返回1,否则返回0
unsigned char i=0;
if(length > 0)//输入不为空
{
table_input[length]='\0';
length=0;//输入字符串长度清0
if(flag_confirm)//修改密码
{
switch(flag_amend)
{
case 1: strcpy(table_newpassword,table_input);//第一次输入新密码
table_input[1]='\0';//避免第一次输入的内容在放弃修改时再次被利用
flag_amend=2;
flag_display=4;//请再次输入密码
break;
case 2: flag_compare_2=strcmp(table_input,table_newpassword);//第二次输入新密码
flag_amend=0;//清0,允许再次修改
flag_confirm=0;//进入初始之确认密码状态
if(!flag_compare_2)//两次输入相同==0
{
strcpy(table_password,table_input);
table_input[1]='\0';//避免修改完成后再次被利用,造成重复修改,同时避免刚修改了就是pass状态
lcd_display(5);//修改成功
delay(500);
flag_display=7;
}
else
{
lcd_display(6);//修改失败
delay(500);
flag_display=7;
}
break;
}
}
else//验证密码
{
flag_compare=strcmp(table_input,table_password);
if(!flag_compare)//密码正确==0
{
flag_allow=1;//允许修改密码
flag_M=1;//允许开锁
flag_display=2;//密码正确信息:Pass!
table_input[1]='\0';//改变输入,使不致出乱
}
else//密码错误
{
flag_allow=0;//不允许修改密码
lcd_display(1);//密码错误信息:Error!
delay(500);
flag_display=7;
}
}
}
}
//电机控制
extern void DC_Moter()
{
if(flag_M)//允许开锁
{
flag_M=0;
key_M=0;//开锁
key_LED=0;
delay(1250);
key_M=1;
key_LED=1;
timer=0;
lcd_display(7);//进入初始态
}
}
//恢复初始密码
extern void resume_password()
{
if(!key_self)//==0
{
delay(3);
if(!key_self)//==0
{
while(!key_self) ;//==0
strcpy(table_password,table_original);
flag_clear=1;
lcd_display(10);
delay(500);
lcd_display(7);
}
}
}
确认函数_ confirm()操作:
0_将 '\0' 置于输入table_input[]结尾
(table_input[]的长度返回值在length里面)
根据操作标识选择任务:
1_确认密码:判定输入密码正确与否
2_修改密码:确认第一次输入并保存
要求第二次输入
比较两次输入是否相同
根据比较结果选择任务:
修改失败,进入输入密码态
修改成功,将输入复制到table_password[]
确认函数_confirm()相关标识位目录:
flag_display;//根据其值可以确定显示信息
flag_confirm;//确认键根据此标识判定任务,默认为0_即为确定密码状态
flag_allow;//允许修改密码标识,在密码比较正确时置1
flag_amend;//第一/二次输入新密码标识
flag_M;//允许电机开锁标识
相关变量
sbit M=P3^6;//电机控制口
flag_confirm;//操作任务标识位
flag_compare;//比较输入与密码|相等时返回1,否则返回0
static flag_amend;//修改密码时的标识
第一次输入前=1,输入后置2
第二次输入前=2,输入后置0
flag_display=0;//确认键操作的返回值根据返回值可以确定显示信息
flag_allow;//允许改密码标识,在密码比较正确时置1,不正确时置0
process_char()函数::_M;//DC电机控制口
process_char()函数::_length;//跟踪记录输入table_input[11]的字符长度(
lcd_display()函数中标识位flag_display的值与意义:
=0:不显示|不刷新显示
=1:密码错误
=2:密码正确
=3:请输入新密码
=4:请再次输入新密码
=5:密码修改成功
=6:密码修改失败
=7:显示输入密码状态_The password!
=8:放弃修改密码
=9:已开锁
3.0 定义各个数组的头文件mydefine.h
extern unsigned char table_input[11]={0}; //接收键盘输入
unsigned char table_password[11]=123456; //密文
unsigned char table_newpassword[11]=456; //接收新密码
unsigned char code table_original[11]=123456; //初始密码
//显示信息
unsigned char code table_pass[]=Pass!; //成功进入
unsigned char code table_error[]=Operate Error!; //密码错误信息
unsigned char code table_enter[]=The password:; //输入密码
unsigned char code table_new[]=New password:; //输入新密码
unsigned char code table_again[]=Enter again:; //再次输入新密码
unsigned char code table_changed[]=Changed!; //密码修改成功
unsigned char code table_fail[]=Fail changce!; //密码修改失败
unsigned char code table_abandon[]=Abandon changce!;//放弃修改密码
unsigned char code table_close[]=Locked!;//锁闭
unsigned char code table_resume[]=Resumed!;//恢复初始密码
4.0 头文件mydefine_2.h
定义了各个外部文件向主函数用到的操作函数和外部变量
#ifndef _mydefine_2_h_
#define _mydefine_2_h_
sbit key_LED=P2^0;
sbit key_clock=P3^3;//蜂鸣器
sbit key_LCD=P2^7;//液晶电源控制口
extern bit flag_clear=0;//恢复密码和开锁键_外部中断的有效标识
extern unsigned int timer=0;//定时器0计数时段标记_50ms一次定时中断
static unsigned char i=0;//显示*用变量
unsigned char temp=0;//用于接收键盘输入(按键在松手时读取按键号)
extern unsigned int table_input[11];//接收输入
extern unsigned char flag_allow;//允许改密码标识,在密码比较正确时置1
extern unsigned char flag_confirm;//确认键根据此标识判定任务,默认为0_即为确定密码状态
extern unsigned char flag_display;//确认键操作的返回值,根据返回值可以确定显示信息
extern unsigned char flag_amend;//第一/二次输入新密码标识
extern unsigned char length;//输入input的字符长度(length
//1602液晶:extern_1602.c *****************************************************************
extern void init_1602();
extern void command(unsigned char command);
extern void display(unsigned char date);
//键盘:extern_keyboard_no_T0_2.c *********************************************************
//矩阵键盘.无按键动作时其返回值num_key=0,否则返回按键号num_key
extern unsigned char keyboard_matrix();//(在松手时读取按键号****检测高四位)
//密码处理:process_char.c ****************************************************************
//电机控制
extern void DC_Moter();
//接收键盘输入|以bit形式存入input__返回值为输入的字符串长度length(length
extern void receive(unsigned char temp);//涉及文件间变量length
//确认按键操作
extern void confirm(void);//涉及跨文件调用的变量flag_confirm,flag_allow,flag_amend
//根据任务选择显示信息
extern void lcd_display(unsigned char flag_display);//涉及跨文件调用的变量flag_display
extern void clear_system();//恢复初始态
extern void resume_password();//恢复初始密码
//****************************************************************************************
#endif
键盘和1602显示的程序见其他文章。