注:此文原创,欢迎大家一起交流相关知识,如有需要引用需提前告知。
目录
1设计概述..... 2
1.1功能与设计内容... 2
1.2整体设计方案... 2
2功能实现..... 5
2.1硬件部分... 5
2.1.1硬件模块... 5
2.1.2硬件原理图... 10
2.2软件部分... 11
2.2.1软件模块... 11
2.2.2流程图... 11
2.2.3代码... 17
3所遇问题..... 18
3.1设计问题... 18
3.1.1键盘的利用... 18
3.1.2功能完善... 18
3.2调试问题... 19
3.2.1无法debugging. 19
3.2.2出现syntax error. 19
3.2.3函数未定义/函数参数表错误/函数返回值缺漏... 19
3.2.4数码管显示重影... 19
4收获..... 20
附录..... 22
附录A 头文件Initial.H代码... 22
附录B 源文件ElcLock.c代码... 22
1设计概述
1.1功能与设计内容
现在宿舍一般都有规定时间的门禁,比如晚上23:00关门,早上6:00开门,有时候宿舍管理员忘记或者早上起床晚了或者不想走出房间亲自开门,延迟开关门就会对学生的进出造成不便。所以设想制造一种电子密码锁,应用单片机相应资源,能够在满足基本定时开关门的要求之外扩展一些新功能。
所以针对这一想法,我对这样的时钟密码锁设计了如下功能。
总的说来,功能分为四个模式:
(1) 时钟模式
①24小时制时钟,显示实时时间,包括小时,分,秒信息;
②能够校准时间,通过按键控制小时,分,秒分别加一
(2) 设闹钟模式
①设置闹钟为某一个值,通过设置小时和分实现,且这个闹钟时间能够保存和显示;
②定时时间到,发光二极管亮起,蜂鸣器响应,表示门开启。
(3) 修改密码模式
①修改当前密码为一个新密码,可以是1-6位的任意整数。
注:只有当以原密码登陆后才能修改密码,避免任何人都能修改密码。
(4) 登录模式
①输入密码,完成输入后显示密码正确情况,发光二极管和蜂鸣器响应,实现没到定时时间可通过输入密码开锁的功能;
②输入正确密码后,可以选择继续修改原密码,也可以选择直接退出,后者情况下就不能继续修改密码了,避免一次输入正确密码后,其他人可以继续修改密码。
额外的,实现一键关门和管理功能,即查看上次密码开锁时间和历史开锁次数。
1.2整体设计方案
本设计使用用HL-1单片机实验板,结合Keil单片机软件开发系统,完成整个程序设计和仿真调试的过程。考虑到涉及到的功能有四个模式,且按键较多,所以用到HL-1实验板上的4*4矩阵键盘,而且使用其中的两个键作为模式控制字的模式选择位,对应如表1.1。
表1.1 时钟电子锁的四个模式
mode1 | Mode2 | 模式 |
0 | 0 | 时钟模式 |
0 | 1 | 设闹钟模式 |
1 | 0 | 修改密码模式 |
1 | 1 | 登录模式 |
对于24小时制时钟的设计,对于晶振,采用了外部晶振HL-1实验板上的晶振资源,其频率为11.0592MHz。使用单片机的内部中断定时/计数器T0,在工作方式1下,设置计数初始值为4C00H,软件设计20次循环产生1秒信号。软件设置时分秒的变量,初始时刻为12:00:00,按照周期为1秒的时间增长。利用7段共阴极数码管资源显示时间。
由于要实现校准时间,设置闹钟等功能,必须要设计按键模块,则使用HL-1实验板的4*4矩阵键盘,软件实现键盘扫描,按键防抖等,按键按下返回相应返回值,子程序通过不同返回值进行不同的处理。
在时钟模式下,使用矩阵键盘三个按键分别实现时分秒的加一。闹钟模式下共用时分的加一键。利用数码管资源显示闹钟时间。
登录模式下,软件设计密码储存数组,输入数字的验证数组,以及储存输入数字的备用数组,采用矩阵键盘的一个键实现完成输入功能,当输入完成后进行软件设计对比数组进行密码验证,正确时按下确认键即可继续进入修改密码模式下修改密码,按下主模式mode1键直接返回时钟模式,不可修改密码。利用数码管资源显示密码输入界面。
验证密码后,响应模块利用HL-1实验板的LED流水灯资源和蜂鸣器资源对验证结果进行响应。正确时亮绿灯,错误时亮红灯,但是如果绿灯就是亮的(门开),则软件设计了不会亮红灯(关门)。对应的,也通过软件设计定时时间到,绿灯亮,蜂鸣器响5下。
修改密码时,利用按键资源,软件设计进行修改和返回,利用数码管资源显示修改界面。
另外,新增按键一键关门,即软件设计模式控制字为时钟模式下,开门状态为0。
为了实现管理功能,按下某个键查看上次开锁时间和历史开锁次数,主要通过软件设计储存数据的变量和按键响应的函数。历史开锁次数范围为0-99,到达100时清零。
矩阵键盘功能设计如图1.1:
图1.1 矩阵键盘功能设计图
数码管资源利用如图1.2:
图1.2 数码管功能设计图
2功能实现
2.1硬件部分
2.1.1硬件模块
硬件模块图如图2.1所示,51单片机(STC89C52)为主要控制器,与复位电路,晶振电路,电源电路等组成单片机的最小系统,另外通过I/O接口外接外设矩阵键盘,数码管模块和响应模块资源。单片机内部定时器与外部晶振完成时钟功能,其他功能通过I/O口完成控制和数据传送。
图2.1 硬件模块图
(1) 定时/计数器
①定时/计数器的控制
定时/计数器的控制,是通过特殊功能寄存器TMOD和TCON实现的。本设计选用T0计数器来对定时器模块进行设计。
- 工作方式控制寄存器TMOD
TMOD用于选择定时/计数器的工作模式和工作方式,其格式如表2.1所示。
表2.1 工作方式控制寄存器TMOD的格式
GATE | C/ | M1 | M0 | GATE | C/ | M1 | M0 |
T1定时/计数器 | T0定时/计数器 |
GATE是门控位,当GATE0时,仅用运行控制位TR0就能控制T0是否进行加一计数。即只需要TR0=1,T0就能启动计数。而如果GATE=1,还需要才能控制T0进行加一计数。
M1和M0是工作方式选择位,选择T0定时器工作在工作方式1时,M1=0, M0=1。
C/是工作模式选择位,如果该位取0,T0工作模式为定时器工作模式,计数器T0仅对单片机的时钟信号12分频后的脉冲信号进行加一计数。如果该位取1,T0工作在计数器工作模式下,这时T0对加在单片机T0和T1两个引脚上的外部脉冲信号进行加一计数。
在本设计中,晶振信号加在XTAL1和XTAL2引脚上,所以计数器T0是对单片机的时钟信号进行加一计数,所以最后可以确定TMOD=00000001B=01H。
- 定时/计数器控制寄存器TCON
TCON的格式如表2.2所示。
表2.2控制寄存器TCON的格式
TCON | TF1 | TR1 | TF0 | TR0 | IE1 | IT1 | IE0 | IT0 |
位地址 | 8FH | 8EH | 8DH | 8CH | 8BH | 8AH | 89H | 88H |
TCON中TF1和TF0是计数溢出标志位。使用中断方式时,作为中断请求标志位,CPU进入中断服务后,该位由单片机内部硬件电路自动清0。
TR1和TR0是运行控制位,TR=1时,启动T0开始加一计数,可由软件置1和清0。
②定时/计数器定时常数的确定
51单片机内部计数器用作定时器时,对机器周期计数,每个机器周期的长度是12个振荡周期。HL-1实验板上的晶振频率为11.0592MHz,由于T0工作在工作方式1时是16位计数器,最大计数为65536。那么最大定时时间为
为了实现更精准的1s信号,取定时时间为50ms,利用软件循环20次,每循环20次循环计数变量清零,即能实现1s信号。那么计数范围为
则计数初值取为65536-46080=19456D=4C00H,所以进行T0初始赋值时,TH0=4CH, TL0=0。
(2) 矩阵键盘
①矩阵键盘原理
HL-1实验板上已有的4*4矩阵键盘原理图如图所示:
图2.1 矩阵键盘原理图
图2.1中,每条行线和列线的交叉处不直接连通,而是通过一个按键开关连接。当没有键闭合时,行线,列线之间是断开的。当键盘上某个键被按下时,对应的行列线短路,行线输入即为列线输出,且均为低电平。
②键盘扫描
在某一时刻只让一条行线对应P3.x为0,其余行线和列线均为1,那么当该行有按键被按下而闭合时,这一行线和相应列线电平均被拉低,P3口的8位数据高四位和第四位各有一个0。按照相应行列线为0,其余为1得到P3口的8位数据,逐列查找直到找到对应列线,那么说明这一行和找到的这一列交叉处的按键被按下,通过软件设计返回相应的P3口数据。如果这一行没有按键按下时,则按照相同的方法让下一行对应P3.x为0,逐列查找。这里采用的是循环扫描的扫描方式,对于本设计需要不断读取键盘状态比较有利,而且思考简单,设计容易。
如,当图2.1中的键盘进行扫描时:
- 扫描第0行
先置P3口8位数据为11111110B,则P3.0对应的第0行置为0,若此时有键按下,比如S0按下,那么读取P3口数据,P3=11101110B,没有键按下时仍是11111110B。
- 比较两种情况下的8位数据
本设计采用的方法是比较高四位,判断是否有0。其实按键与否的区别就是高四位是否有0,在判断时为了排除第四位的影响可让8位数据与低四位为0000的8位数据进行与操作&,那么低四位与操作之后均为0000。让高四位与1111进行与操作,则有按键按下时,结果中有一位为0,没有按键按下时,结果还为1111。那么总结可知,让读取的8位数据与11110000B进行与操作。
- 返回8位数据
在排除键抖动之后,确定的按键按下后,逐列查找,软件里依照不同的8位数据依次与读取的P3比对,比对正确的返回相应的键值。处理函数通过键值进行后续处理。
某一行(第0行)键盘扫描的流程如式(2.1)(未表现消除键抖动):
式(2.1)
③按键防抖
由于按键是机械弹性触点,在闭合或者是断开的过程中都有抖动过程,电平跳动,电压信号出现毛刺,因此需要消除抖动的影响以免键盘容易受外部干扰而给单片机发出错误信号。抖动时间一般为5~10ms,因此在判断有键按下时,先通过软件延时一段时间(10ms),再判断是否有键按下,如果仍能检测到按键按下,说明确定有一个键被按下;否则,按照键抖动处理。
(3) 数码管的显示
①LED数码管的显示原理
HL-1实验板使用的是两个3位7段共阴极数码管,所以在某段发光二极管上施加一定的正向电压时,该段笔画就亮,不加电压即暗。
图2.2 共阴极数码管电路图
如图2.2,若向各控制端a, b, c, …, g, dp顺次送入对应信号,显示器显示相应字型。本设计需要显示数字和少量字符串,所以列出部分字型以及所对应的控制码,如表2.3所示。
表2.3 共阴极7段LED数码管显示字型编码表
显示字符 | 段选码 | 显示字符 | 段选码 |
0 | 3FH | 5 | 6DH |
1 | 06H | 6 | 7DH |
2 | 5BH | 7 | 07H |
3 | 4FH | 8 | 7FH |
4 | 66H | 9 | 6FH |
段选码控制字符的选择,位选码用于控制哪一个数码管能够显示字符。对应的位选码位取0,相应的共阴极数码管可以正常工作。如图2.3所示,HL-1实验板上的数码管位选信号对应位选码的低六位,如果位选码为0FEH,那么第一个数码管可以正常工作。
图2.3 7段共阴极数码管
②数码管的动态显示
静态显示时,需要显示的字符各字段连续通电,所显示的字段连续发光,而且占用I/O资源较多。而时钟模式字符的显示需要实时变化,如果采用静态显示,需要重新设计数码管模块的电路,每一位数码管需要单独进行译码,设计比较复杂。
动态显示时所需字段不连续通电流,在需要多个字符同时显示时,则可以轮流给每个数码管通以电流,逐次显示字符。为了实现多字符同时显示,采用扫描方式。也就是在某一时刻只让某一个LED数码管显示相应字符。在这个时刻,首先P1作为段选控制I/O口输出相应字符段选码,锁存在74HC573-1的输出端,然后P1作为位选控制I/O口输出位选码,通过74HC573直接送给数码管位选信号端,使相应数码管显示字符。如此轮流,就能让每一位数码管都能显示响应字符,通过软件延时1ms,就能达到视觉稳定的效果,能够看到每位数码管都能同时显示不同字符。
相比于静态显示,动态显示占用I/O口资源少,电路简单,成本低,将更多的控制留给软件设计。
2.1.2硬件原理图
如图。
2.2软件部分
2.2.1软件模块
软件模块除了主程序和中断服务程序,还包括其他子程序模块。如图2.4所示。
图2.4 软件模块图
其中主程序中循环调用了键盘扫描程序和按键响应程序,当T0计数器中断溢出标志位TF0发出中断请求时,转而进入中断服务程序,执行完毕后继续执行主程序。
2.2.2流程图
(1)主程序流程图
图2.5 主程序流程图
(2)中断服务程序流程图
图2.6 中断服务程序流程图
(3)键盘扫描程序流程图
图2.7 键盘扫描程序流程图
(4)按键处理程序
图2.8 按键处理程序流程图
(5)数据调整程序
图2.9 数据调整程序流程图
(6)响应程序
图2.10 响应程序流程图
2.2.3代码
见附录A,B。
附录
附录A 头文件Initial.H代码
1 //initial.H 2 3 #ifndef initial_H 4 #define initial_H 5 6 sbit DU= P2^6; //段选信号,控制数码管显示数字的控制数锁存 7 sbit WE= P2^7; //位选信号,控制数码管的选择 8 sbit point= P0^7; //小数点的定义 9 sbit FM= P2^3; //蜂鸣器 10 11 //独立键盘初始化 12 sbit key1=P3^4; 13 sbit key2=P3^5; 14 sbit key3=P3^6; 15 sbit key4=P3^7; 16 17 //LED流水灯模块初始化 18 sbit led0=P1^0; 19 sbit led1=P1^1; 20 sbit led2=P1^2; 21 sbit led3=P1^3; 22 sbit led4=P1^4; 23 sbit led5=P1^5; 24 sbit led6=P1^6; 25 sbit led7=P1^7; 26 27 28 #endif
附录B 源文件ElcLock.c代码
1 #include <reg52.h> 2 #include <initial.H> 3 4 #define uchar unsigned char 5 #define uint unsigned int 6 7 uchar i,num=0,numi=0; //定时器由50ms产生1s时钟信号时所用的循环变量 8 int key=11; //设置按键变量 9 int mode1=0,mode2=0; //设定模式变量 10 int ch; //门是否应该开启的状态 11 int close=0; //关门信号 12 int ok=0; //确认键的状态 13 int sure=0; //账号和密码正确状态,用于修改密码等 14 uchar sec=0,min=0,hour=12; //定义秒,分,时;设置时钟初值 15 uchar alarmh=6,alarmm=0,ah1,ah2,am1,am2; //定义设定时间的分,时 16 uchar code table[]={0x3f, 0x06, 0x5b, 0x4f, 0x66, //对应{0,1,2,3,4,5,6,7,8,9} 17 0x6d, 0x7d, 0x07, 0x7f, 0x6f}; 18 //显示上次开锁时间数组 19 int showlast=0; 20 int lasth=0,lastm=0; 21 //历史开锁次数 22 int opennum=0; 23 //密码数组 24 int pw[]={0,0,0,0,0,0}; 25 //验证数组 26 int id[]={1,1,1,1,1,1}; 27 int id1[]={1,1,1,1,1,1}; 28 //数码管上显示相应数组名的字符串 29 uchar code done[]={0x5e,0x5c,0x54,0xfb,0x80,0x80}; 30 uchar code yes[]={0x6e,0x7b,0xed,0x80,0x80,0x80}; 31 uchar code no[]={0x54,0xdc,0x80,0x80,0x80,0x80}; 32 uchar code login[]={0x38,0x5c,0x6f,0x06,0xd4,0x80}; 33 uchar code edit[]={0x79,0x5e,0x06,0xf8,0x80,0x80}; 34 35 int matrixkeyscan(); //扫描键盘 36 void dealwithkey(); //处理按键(是主要部分) 37 int check(); //检查门是否应该开启的状态 38 void showtime(int s); //显示实时时间和闹钟,参数:0-时间,1-时间 39 void showpwid(int s); //显示当前密码和输入密码,参数:0-密码,1-登录输入 40 void delayms(uint xms); //延时函数 41 void response(); //响应门开启状态,LED和蜂鸣器 42 void showstring(int s); //显示字符串函数,参数指定不同字符串 43 void init(); //定时器初始化 44 45 void main() 46 { 47 init(); 48 while(1) 49 { 50 key=matrixkeyscan(); //获取按键 51 dealwithkey(); //处理按键 52 } 53 } 54 55 void T0_INT(void) interrupt 1 //中断响应函数 56 { 57 i++; 58 TR0=0; 59 TH0=0x4c; 60 TL0=0; 61 if(i==20) //定时器定时50ms,则一个20次的循环可产生1s信号 62 { 63 i=0; 64 sec++; 65 } 66 if(sec==60) 67 { 68 sec=0; 69 min++; 70 } 71 if(min==60) 72 { 73 min=0; 74 hour++; 75 } 76 if(hour==24) 77 hour=0; 78 TR0=1; 79 } 80 81 int matrixkeyscan() 82 { 83 uchar temp,key; 84 P3=0xfe; //1111 1110 85 temp=P3; 86 temp=temp&0xf0; 87 if(temp!=0xf0) 88 { 89 delayms(10); 90 temp=P3; 91 temp=temp&0xf0; 92 if(temp!=0xf0) 93 { 94 temp=P3; 95 switch(temp) 96 { 97 case 0xee: //11101110 98 key=0; 99 break; 100 case 0xde: //11011110 101 key=1; 102 break; 103 case 0xbe: 104 key=2; 105 break; 106 case 0x7e: 107 key=3; 108 break; 109 } 110 while(temp!=0xf0) 111 { 112 temp=P3; 113 temp=temp&0xf0; 114 } 115 return(key); 116 } 117 } 118 P3=0xfd; 119 temp=P3; 120 temp=temp&0xf0; 121 if(temp!=0xf0) 122 { 123 delayms(10); 124 temp=P3; 125 temp=temp&0xf0; 126 if(temp!=0xf0) 127 { 128 temp=P3; 129 switch(temp) 130 { 131 case 0xed: 132 key=4; 133 break; 134 case 0xdd: 135 key=5; 136 break; 137 case 0xbd: 138 key=6; 139 break; 140 case 0x7d: 141 key=7; 142 break; 143 } 144 while(temp!=0xf0) 145 { 146 temp=P3; 147 temp=temp&0xf0; 148 } 149 return(key); 150 } 151 } 152 P3=0xfb; 153 temp=P3; 154 temp=temp&0xf0; 155 if(temp!=0xf0) 156 { 157 delayms(10); 158 temp=P3; 159 temp=temp&0xf0; 160 if(temp!=0xf0) 161 { 162 temp=P3; 163 switch(temp) 164 { 165 case 0xeb: 166 key=8; 167 break; 168 case 0xdb: 169 key=9; 170 break; 171 case 0xbb: 172 key=10; 173 break; 174 case 0x7b: 175 key=11; 176 break; 177 } 178 while(temp!=0xf0) 179 { 180 temp=P3; 181 temp=temp&0xf0; 182 } 183 return(key); 184 } 185 } 186 P3=0xf7; 187 temp=P3; 188 temp=temp&0xf0; 189 if(temp!=0xf0) 190 { 191 delayms(10); 192 temp=P3; 193 temp=temp&0xf0; 194 if(temp!=0xf0) 195 { 196 temp=P3; 197 switch(temp) 198 { 199 case 0xe7: 200 key=12; 201 break; 202 case 0xd7: 203 key=13; 204 break; 205 case 0xb7: 206 key=14; 207 break; 208 case 0x77: 209 key=15; 210 break; 211 } 212 while(temp!=0xf0) 213 { 214 temp=P3; 215 temp=temp&0xf0; 216 } 217 return(key); 218 } 219 } 220 return 16; 221 } 222 223 void dealwithkey() 224 { 225 switch(key) 226 { 227 case 0: 228 { 229 if((mode1==0)&&(mode2==0)) //时钟校准模式 230 { 231 hour++; 232 while(key1==0); 233 if(hour==24) 234 hour=0; 235 } 236 else if((mode1==0)&&(mode2==1)) //时钟定时模式 237 { 238 alarmh++; 239 while(key1==0); 240 if(alarmh==24) 241 alarmh=0; 242 } 243 else if((mode1==1)&&(mode2==0)&&(num<6)&&(ok==1)) //修改密码 244 { 245 pw[num]=0; 246 num++; 247 } 248 else if((mode1==1)&&(mode2==1)&&(numi<6)&&(ok==1)) //输入验证密码 249 { 250 id[numi]=0; 251 numi++; 252 } 253 break; 254 } 255 case 1: 256 { 257 if((mode1==0)&&(mode2==0)) //时钟校准模式 258 { 259 min++; 260 while(key2==0); 261 if(min==60) 262 { 263 min=0; 264 hour++; 265 if(hour==24) 266 hour=0; 267 } 268 } 269 else if((mode1==0)&&(mode2==1)) //时钟定时模式 270 { 271 alarmm++; 272 while(key2==0); 273 if(alarmm==60) 274 { 275 alarmm=0; 276 alarmh++; 277 if(alarmh==24) 278 alarmh=0; 279 } 280 } 281 else if((mode1==1)&&(mode2==0)&&(num<6)&&(ok==1)) //修改密码 282 { 283 pw[num]=1; 284 num++; 285 } 286 else if((mode1==1)&&(mode2==1)&&(numi<6)&&(ok==1)) //输入验证密码 287 { 288 id[numi]=1; 289 numi++; 290 } 291 break; 292 } 293 case 2: 294 { 295 if((mode1==0)&&(mode2==0)) //时钟校准模式 296 { 297 sec++; 298 while(key3==0); 299 if(sec==60) 300 { 301 sec=0; 302 min++; 303 if(min==60) 304 { 305 min=0; 306 hour++; 307 if(hour==24) 308 hour=0; 309 } 310 } 311 } 312 else if((mode1==1)&&(mode2==0)&&(num<6)&&(ok==1)) //修改密码 313 { 314 pw[num]=2; 315 num++; 316 } 317 else if((mode1==1)&&(mode2==1)&&(numi<6)&&(ok==1)) //输入验证密码 318 { 319 id[numi]=2; 320 numi++; 321 } 322 break; 323 } 324 case 3: 325 { 326 if((mode1==1)&&(mode2==0)&&(num<6)&&(ok==1)) //修改密码 327 { 328 pw[num]=3; 329 num++; 330 } 331 else if((mode1==1)&&(mode2==1)&&(numi<6)&&(ok==1)) //输入验证密码 332 { 333 id[numi]=3; 334 numi++; 335 } 336 break; 337 } 338 case 4: 339 { 340 if((mode1==1)&&(mode2==0)&&(num<6)&&(ok==1)) //修改密码 341 { 342 pw[num]=4; 343 num++; 344 } 345 else if((mode1==1)&&(mode2==1)&&(numi<6)&&(ok==1)) //输入验证密码 346 { 347 id[numi]=4; 348 numi++; 349 } 350 break; 351 } 352 case 5: 353 { 354 if((mode1==1)&&(mode2==0)&&(num<6)&&(ok==1)) //修改密码 355 { 356 pw[num]=5; 357 num++; 358 } 359 else if((mode1==1)&&(mode2==1)&&(numi<6)&&(ok==1)) //输入验证密码 360 { 361 id[numi]=5; 362 numi++; 363 } 364 break; 365 } 366 case 6: 367 { 368 if((mode1==1)&&(mode2==0)&&(num<6)&&(ok==1)) //修改密码 369 { 370 pw[num]=6; 371 num++; 372 } 373 else if((mode1==1)&&(mode2==1)&&(numi<6)&&(ok==1)) //输入验证密码 374 { 375 id[numi]=6; 376 numi++; 377 } 378 break; 379 } 380 case 7: 381 { 382 if((mode1==1)&&(mode2==0)&&(num<6)&&(ok==1)) //修改密码 383 { 384 pw[num]=7; 385 num++; 386 } 387 else if((mode1==1)&&(mode2==1)&&(numi<6)&&(ok==1)) //输入验证密码 388 { 389 id[numi]=7; 390 numi++; 391 } 392 break; 393 } 394 case 8: 395 { 396 if((mode1==1)&&(mode2==0)&&(num<6)&&(ok==1)) //修改密码 397 { 398 pw[num]=8; 399 num++; 400 } 401 else if((mode1==1)&&(mode2==1)&&(numi<6)&&(ok==1)) //输入验证密码 402 { 403 id[numi]=8; 404 numi++; 405 } 406 break; 407 } 408 case 9: 409 { 410 if((mode1==1)&&(mode2==0)&&(num<6)&&(ok==1)) //修改密码 411 { 412 pw[num]=9; 413 num++; 414 } 415 else if((mode1==1)&&(mode2==1)&&(numi<6)&&(ok==1)) //输入验证密码 416 { 417 id[numi]=9; 418 numi++; 419 } 420 break; 421 } 422 case 10: //时钟和密码模式的切换,0-时钟,1-密码 423 { 424 if(num!=6) 425 mode1=!mode1; 426 break; 427 } 428 case 11: //小模式的切换 429 { 430 if(num!=6) 431 mode2=!mode2; 432 break; 433 } 434 case 12: //关门键 435 { 436 ch=0; //关门状态 437 close=1; 438 id[0]=1; //验证密码还原 439 id[1]=1; 440 id[2]=1; 441 id[3]=1; 442 id[4]=1; 443 id[5]=1; 444 mode1=0; //回时钟模式 445 mode2=0; 446 showlast=0; 447 break; 448 } 449 case 13: 450 { 451 showlast=!showlast; 452 break; 453 } 454 case 14: 455 { 456 ok=1; //确认变量为1 457 break; 458 } 459 case 15: 460 { 461 break; 462 } 463 } 464 if((mode1==0)&&(mode2==0)&&(showlast==0)) //时钟模式下得显示 465 { 466 showtime(0); //显示x实时时间 467 if((ch==0)&&(close==0)) 468 ch=check(); //先检测门是否到了应该开启的状态 469 response(); //闹钟响应 470 } 471 else if((mode1==0)&&(mode2!=0)&&(showlast==0)) //设置闹钟模式 472 { 473 showtime(1); //显示闹钟时间 474 response(); //闹钟响应 475 } 476 else if((mode1!=0)&&(mode2==0)&&(showlast==0)) //修改密码模式 477 { 478 if((num==0)&&(ok==0)) //先显示edit,等待确认键按下 479 showstring(5); 480 if((num==0)&&(ok==1)&&(sure==0)) //如果确认键按下但是没有先输入原密码,只会回到时钟界面 481 { 482 mode1=0; 483 mode2=0; 484 ok=0; 485 } 486 if((num!=6)&&(ok==1)&&(sure==1)) //先输入了原密码,确认键也按下了,则可以显示编辑密码了 487 { 488 showpwid(0); //参数为0,显示密码 489 if(key==15) //按下15键表示输入完毕,剩下密码位全部置0 490 for(;num<6;num++) 491 pw[num]=0; 492 } 493 else if(num==6) 494 { 495 id1[0]=pw[0]; //把密码赋给验证数组id[],配合登陆时的赋值让登陆时不会显示当前密码 496 id1[1]=pw[1]; 497 id1[2]=pw[2]; 498 id1[3]=pw[3]; 499 id1[4]=pw[4]; 500 id1[5]=pw[5]; 501 sure=0; 502 if(ok==1) //按下确认键,显示输入完毕 503 { 504 showstring(1); 505 key=matrixkeyscan(); 506 if((key==14)||(key==10)) //按下主模式键或确认键都能回到时钟界面 507 { 508 mode1=0; 509 mode2=0; 510 num=0; 511 ok=0; 512 } 513 } 514 } 515 } 516 else if((mode1!=0)&&(mode2==1)&&(showlast==0)) //登陆模式 517 { 518 if((numi==0)&&(ok==0)) 519 showstring(4); //显示login 520 if((numi!=6)&&(ok==1)) //按下确认键后才能显示输入的数字 521 { 522 showpwid(1); 523 if(key==15) //按下15键表示输入完毕,剩下位补0 524 for(;numi<6;numi++) 525 id[numi]=0; 526 } 527 else if(numi==6) 528 { 529 id1[0]=id[0]; //输入的数字赋给id1[],用于验证密码 530 id1[1]=id[1]; 531 id1[2]=id[2]; 532 id1[3]=id[3]; 533 id1[4]=id[4]; 534 id1[5]=id[5]; 535 if(ok==1) 536 { 537 ch=check(); //判断密码是否正确 538 if(ch) 539 { 540 showstring(2); //正确显示yes 541 sure=1; //账号密码都对了,可以修改密码了 542 } 543 else 544 showstring(3); //错误显示no 545 key=matrixkeyscan(); 546 if(key==10) //按下主模式键回到时钟界面,进入edit界面可以修改密码 547 { 548 if(sure==1) 549 { 550 lasth=hour; 551 lastm=min; 552 opennum++; //上次开锁时间和历史开锁次数 553 if(opennum==99) 554 opennum=0; 555 } 556 mode1=0; 557 mode2=0; 558 numi=0; 559 ok=0; 560 sure=0; 561 } 562 if(key==14) //按下确认键回到时钟界面,进入edit界面也不能输入密码 563 { //管理员登陆后必须按下这个键,否则其他人进入edit界面 564 mode1=0; //也能修改密码 565 mode2=0; 566 numi=0; 567 ok=0; 568 if(sure==1) 569 { 570 lasth=hour; 571 lastm=min; 572 opennum++; //上次开锁时间和历史开锁次数 573 if(opennum==99) 574 opennum=0; 575 } 576 } 577 } 578 } 579 } 580 else if(showlast==1) 581 { 582 /*秒个位的计算与显示*/ 583 DU=1; //开锁次数显示 584 P0=table[opennum%10]; 585 DU=0; 586 P0=0xff; 587 WE=1; 588 P0=0xdf; 589 WE=0; 590 delayms(1); 591 /*秒十位的计算与显示*/ 592 DU=1; 593 P0=table[opennum/10]; 594 DU=0; 595 P0=0xff; 596 WE=1; 597 P0=0xef; 598 WE=0; 599 delayms(1); 600 /*分个位的计算与显示*/ 601 am2=lastm%10; 602 DU=1; 603 P0=table[am2]; 604 point=1; //小数点亮 605 DU=0; 606 P0=0xff; 607 WE=1; 608 P0=0xf7; 609 WE=0; 610 delayms(1); 611 /*分十位的计算与显示*/ 612 am1=lastm/10; 613 DU=1; 614 P0=table[am1]; 615 DU=0; 616 P0=0xff; 617 WE=1; 618 P0=0xfb; 619 WE=0; 620 delayms(1); 621 /*时个位的计算与显示*/ 622 ah2=lasth%10; 623 DU=1; 624 P0=table[ah2]; 625 point=1; //小数点亮 626 DU=0; 627 P0=0xff; 628 WE=1; 629 P0=0xfd; 630 WE=0; 631 delayms(1); 632 /*时十位的计算与显示*/ 633 ah1=lasth/10; 634 DU=1; 635 P0=table[ah1]; 636 DU=0; 637 P0=0xff; 638 WE=1; 639 P0=0xfe; 640 WE=0; 641 delayms(1); 642 } 643 } 644 void Showtime(int s) 645 { 646 switch(s) 647 { 648 case 0: //参数0:显示实时时间 649 { 650 uint h1,h2,m1,m2,s1,s2; 651 /*秒个位的计算与显示*/ 652 s2=sec%10; 653 DU=1; 654 P0=table[s2]; 655 DU=0; 656 P0=0xff; 657 WE=1; 658 P0=0xdf; 659 WE=0; 660 delayms(1); 661 /*秒十位的计算与显示*/ 662 s1=sec/10; 663 DU=1; 664 P0=table[s1]; 665 DU=0; 666 P0=0xff; 667 WE=1; 668 P0=0xef; 669 WE=0; 670 delayms(1); 671 /*分个位的计算与显示*/ 672 m2=min%10; 673 DU=1; 674 P0=table[m2]; 675 point=1; //小数点亮 676 DU=0; 677 P0=0xff; 678 WE=1; 679 P0=0xf7; 680 WE=0; 681 delayms(1); 682 /*分十位的计算与显示*/ 683 m1=min/10; 684 DU=1; 685 P0=table[m1]; 686 DU=0; 687 P0=0xff; 688 WE=1; 689 P0=0xfb; 690 WE=0; 691 delayms(1); 692 /*时个位的计算与显示*/ 693 h2=hour%10; 694 DU=1; 695 P0=table[h2]; 696 point=1; //小数点亮 697 DU=0; 698 P0=0xff; 699 WE=1; 700 P0=0xfd; 701 WE=0; 702 delayms(1); 703 /*时十位的计算与显示*/ 704 h1=hour/10; 705 DU=1; 706 P0=table[h1]; 707 DU=0; 708 P0=0xff; 709 WE=1; 710 P0=0xfe; 711 WE=0; 712 delayms(1); 713 break; 714 } 715 case 1: //参数1:显示闹钟时间 716 { 717 /*秒个位的计算与显示*/ 718 DU=1; 719 P0=table[0]; 720 DU=0; 721 P0=0xff; 722 WE=1; 723 P0=0xdf; 724 WE=0; 725 delayms(1); 726 /*秒十位的计算与显示*/ 727 DU=1; 728 P0=table[0]; 729 DU=0; 730 P0=0xff; 731 WE=1; 732 P0=0xef; 733 WE=0; 734 delayms(1); 735 /*分个位的计算与显示*/ 736 am2=alarmm%10; 737 DU=1; 738 P0=table[am2]; 739 point=1; //小数点亮 740 DU=0; 741 P0=0xff; 742 WE=1; 743 P0=0xf7; 744 WE=0; 745 delayms(1); 746 /*分十位的计算与显示*/ 747 am1=alarmm/10; 748 DU=1; 749 P0=table[am1]; 750 DU=0; 751 P0=0xff; 752 WE=1; 753 P0=0xfb; 754 WE=0; 755 delayms(1); 756 /*时个位的计算与显示*/ 757 ah2=alarmh%10; 758 DU=1; 759 P0=table[ah2]; 760 point=1; //小数点亮 761 DU=0; 762 P0=0xff; 763 WE=1; 764 P0=0xfd; 765 WE=0; 766 delayms(1); 767 /*时十位的计算与显示*/ 768 ah1=alarmh/10; 769 DU=1; 770 P0=table[ah1]; 771 DU=0; 772 P0=0xff; 773 WE=1; 774 P0=0xfe; 775 WE=0; 776 delayms(1); 777 break; 778 } 779 } 780 } 781 void delayms(uint xms) //延时xms,用于数码管动态显示 782 { 783 uint i,j; 784 for(i=xms; i>0; i--) 785 for(j=110; j>0; j--); 786 } 787 void response() 788 { 789 // ch=check(); //先检测门是否到了应该开启的状态 790 if(ch) //是 791 { 792 led2=0; //绿灯亮 793 led0=1; //红灯灭 794 if((alarmh==hour)&&(alarmm==min)&&(sec<10)&&(sec%2)) //小时,分钟符合,则响5下蜂鸣器 795 FM=0; 796 else 797 FM=1; 798 } 799 else //否 800 { 801 led2=1; //绿灯灭 802 led0=0; //红灯亮 803 FM=1; 804 } 805 } 806 807 void showstring(int s) 808 { 809 switch(s) 810 { 811 case 1: //参数1:显示done 812 { 813 DU=1; 814 P0=done[5]; 815 DU=0; 816 P0=0xff; 817 WE=1; 818 P0=0xdf; 819 WE=0; 820 delayms(1); 821 822 DU=1; 823 P0=done[4]; 824 DU=0; 825 P0=0xff; 826 WE=1; 827 P0=0xef; 828 WE=0; 829 delayms(1); 830 831 DU=1; 832 P0=done[3]; 833 DU=0; 834 P0=0xff; 835 WE=1; 836 P0=0xf7; 837 WE=0; 838 delayms(1); 839 840 DU=1; 841 P0=done[2]; 842 DU=0; 843 P0=0xff; 844 WE=1; 845 P0=0xfb; 846 WE=0; 847 delayms(1); 848 849 DU=1; 850 P0=done[1]; 851 DU=0; 852 P0=0xff; 853 WE=1; 854 P0=0xfd; 855 WE=0; 856 delayms(1); 857 858 DU=1; 859 P0=done[0]; 860 DU=0; 861 P0=0xff; 862 WE=1; 863 P0=0xfe; 864 WE=0; 865 delayms(1); 866 break; 867 } 868 case 2: //参数2:显示yes 869 { 870 DU=1; 871 P0=yes[5]; 872 DU=0; 873 P0=0xff; 874 WE=1; 875 P0=0xdf; 876 WE=0; 877 delayms(1); 878 879 DU=1; 880 P0=yes[4]; 881 DU=0; 882 P0=0xff; 883 WE=1; 884 P0=0xef; 885 WE=0; 886 delayms(1); 887 888 DU=1; 889 P0=yes[3]; 890 DU=0; 891 P0=0xff; 892 WE=1; 893 P0=0xf7; 894 WE=0; 895 delayms(1); 896 897 DU=1; 898 P0=yes[2]; 899 DU=0; 900 P0=0xff; 901 WE=1; 902 P0=0xfb; 903 WE=0; 904 delayms(1); 905 906 DU=1; 907 P0=yes[1]; 908 DU=0; 909 P0=0xff; 910 WE=1; 911 P0=0xfd; 912 WE=0; 913 delayms(1); 914 915 DU=1; 916 P0=yes[0]; 917 DU=0; 918 P0=0xff; 919 WE=1; 920 P0=0xfe; 921 WE=0; 922 delayms(1); 923 break; 924 } 925 case 3: //参数3:显示no 926 { 927 DU=1; 928 P0=no[5]; 929 DU=0; 930 P0=0xff; 931 WE=1; 932 P0=0xdf; 933 WE=0; 934 delayms(1); 935 936 DU=1; 937 P0=no[4]; 938 DU=0; 939 P0=0xff; 940 WE=1; 941 P0=0xef; 942 WE=0; 943 delayms(1); 944 945 DU=1; 946 P0=no[3]; 947 DU=0; 948 P0=0xff; 949 WE=1; 950 P0=0xf7; 951 WE=0; 952 delayms(1); 953 954 DU=1; 955 P0=no[2]; 956 DU=0; 957 P0=0xff; 958 WE=1; 959 P0=0xfb; 960 WE=0; 961 delayms(1); 962 963 DU=1; 964 P0=no[1]; 965 DU=0; 966 P0=0xff; 967 WE=1; 968 P0=0xfd; 969 WE=0; 970 delayms(1); 971 972 DU=1; 973 P0=no[0]; 974 DU=0; 975 P0=0xff; 976 WE=1; 977 P0=0xfe; 978 WE=0; 979 delayms(1); 980 break; 981 } 982 case 4: //参数4,显示login 983 { 984 DU=1; 985 P0=login[5]; 986 DU=0; 987 P0=0xff; 988 WE=1; 989 P0=0xdf; 990 WE=0; 991 delayms(1); 992 993 DU=1; 994 P0=login[4]; 995 DU=0; 996 P0=0xff; 997 WE=1; 998 P0=0xef; 999 WE=0; 1000 delayms(1); 1001 1002 DU=1; 1003 P0=login[3]; 1004 DU=0; 1005 P0=0xff; 1006 WE=1; 1007 P0=0xf7; 1008 WE=0; 1009 delayms(1); 1010 1011 DU=1; 1012 P0=login[2]; 1013 DU=0; 1014 P0=0xff; 1015 WE=1; 1016 P0=0xfb; 1017 WE=0; 1018 delayms(1); 1019 1020 DU=1; 1021 P0=login[1]; 1022 DU=0; 1023 P0=0xff; 1024 WE=1; 1025 P0=0xfd; 1026 WE=0; 1027 delayms(1); 1028 1029 DU=1; 1030 P0=login[0]; 1031 DU=0; 1032 P0=0xff; 1033 WE=1; 1034 P0=0xfe; 1035 WE=0; 1036 delayms(1); 1037 break; 1038 } 1039 case 5: //参数5:显示edit 1040 { 1041 DU=1; 1042 P0=edit[5]; 1043 DU=0; 1044 P0=0xff; 1045 WE=1; 1046 P0=0xdf; 1047 WE=0; 1048 delayms(1); 1049 1050 DU=1; 1051 P0=edit[4]; 1052 DU=0; 1053 P0=0xff; 1054 WE=1; 1055 P0=0xef; 1056 WE=0; 1057 delayms(1); 1058 1059 DU=1; 1060 P0=edit[3]; 1061 DU=0; 1062 P0=0xff; 1063 WE=1; 1064 P0=0xf7; 1065 WE=0; 1066 delayms(1); 1067 1068 DU=1; 1069 P0=edit[2]; 1070 DU=0; 1071 P0=0xff; 1072 WE=1; 1073 P0=0xfb; 1074 WE=0; 1075 delayms(1); 1076 1077 DU=1; 1078 P0=edit[1]; 1079 DU=0; 1080 P0=0xff; 1081 WE=1; 1082 P0=0xfd; 1083 WE=0; 1084 delayms(1); 1085 1086 DU=1; 1087 P0=edit[0]; 1088 DU=0; 1089 P0=0xff; 1090 WE=1; 1091 P0=0xfe; 1092 WE=0; 1093 delayms(1); 1094 break; 1095 } 1096 } 1097 } 1098 int check() 1099 { 1100 if(alarmh==hour&&alarmm==min) //满足定时要求时,不管密码验证状态,ch=1 1101 return 1; 1102 else //不满足定时要求时,密码验证正确,ch=1 1103 { 1104 if(pw[0]!=id1[0]) 1105 return 0; 1106 else if(pw[1]!=id1[1]) 1107 return 0; 1108 else if(pw[2]!=id1[2]) 1109 return 0; 1110 else if(pw[3]!=id1[3]) 1111 return 0; 1112 else if(pw[4]!=id1[4]) 1113 return 0; 1114 else if(pw[5]!=id1[5]) 1115 return 0; 1116 else 1117 return 1; 1118 } 1119 } 1120 void init() //定时器初始化 1121 { 1122 DU=0; 1123 WE=0; 1124 TMOD=0x01; //定时器T0工作方式为1 1125 TH0=0x4c; //计数初值为4C00H,19456D,可计数65536-19456=46080次 1126 TL0=0; //由于晶振为11.0592MHz,则每次中断可定时46080*12/11.0592*1μs=50ms 1127 ET0=1; 1128 TR0=1; 1129 EA=1; 1130 } 1131 void showpwid(int s) 1132 { 1133 uint p0,p1,p2,p3,p4,p5; 1134 uint i0,i1,i2,i3,i4,i5; 1135 switch(s) 1136 { 1137 case 0: //参数0:显示密码 1138 { 1139 /*6位的计算与显示*/ 1140 p5=pw[5]; 1141 DU=1; 1142 P0=table[p5]; 1143 DU=0; 1144 P0=0xff; 1145 WE=1; 1146 P0=0xdf; 1147 WE=0; 1148 delayms(1); 1149 /*5位的计算与显示*/ 1150 p4=pw[4]; 1151 DU=1; 1152 P0=table[p4]; 1153 DU=0; 1154 P0=0xff; 1155 WE=1; 1156 P0=0xef; 1157 WE=0; 1158 delayms(1); 1159 /*4位的计算与显示*/ 1160 p3=pw[3]; 1161 DU=1; 1162 P0=table[p3]; 1163 DU=0; 1164 P0=0xff; 1165 WE=1; 1166 P0=0xf7; 1167 WE=0; 1168 delayms(1); 1169 /*3位的计算与显示*/ 1170 p2=pw[2]; 1171 DU=1; 1172 P0=table[p2]; 1173 DU=0; 1174 P0=0xff; 1175 WE=1; 1176 P0=0xfb; 1177 WE=0; 1178 delayms(1); 1179 /*2位的计算与显示*/ 1180 p1=pw[1]; 1181 DU=1; 1182 P0=table[p1]; 1183 DU=0; 1184 P0=0xff; 1185 WE=1; 1186 P0=0xfd; 1187 WE=0; 1188 delayms(1); 1189 /*1位的计算与显示*/ 1190 p0=pw[0]; 1191 DU=1; 1192 P0=table[p0]; 1193 DU=0; 1194 P0=0xff; 1195 WE=1; 1196 P0=0xfe; 1197 WE=0; 1198 delayms(1); 1199 break; 1200 } 1201 case 1: //参数1:显示输入数字 1202 { 1203 /*6位的计算与显示*/ 1204 i5=id[5]; 1205 DU=1; 1206 P0=table[i5]; 1207 DU=0; 1208 P0=0xff; 1209 WE=1; 1210 P0=0xdf; 1211 WE=0; 1212 delayms(1); 1213 /*5位的计算与显示*/ 1214 i4=id[4]; 1215 DU=1; 1216 P0=table[i4]; 1217 DU=0; 1218 P0=0xff; 1219 WE=1; 1220 P0=0xef; 1221 WE=0; 1222 delayms(1); 1223 /*4位的计算与显示*/ 1224 i3=id[3]; 1225 DU=1; 1226 P0=table[i3]; 1227 DU=0; 1228 P0=0xff; 1229 WE=1; 1230 P0=0xf7; 1231 WE=0; 1232 delayms(1); 1233 /*3位的计算与显示*/ 1234 i2=id[2]; 1235 DU=1; 1236 P0=table[i2]; 1237 DU=0; 1238 P0=0xff; 1239 WE=1; 1240 P0=0xfb; 1241 WE=0; 1242 delayms(1); 1243 /*2位的计算与显示*/ 1244 i1=id[1]; 1245 DU=1; 1246 P0=table[i1]; 1247 DU=0; 1248 P0=0xff; 1249 WE=1; 1250 P0=0xfd; 1251 WE=0; 1252 delayms(1); 1253 /*1位的计算与显示*/ 1254 i0=id[0]; 1255 DU=1; 1256 P0=table[i0]; 1257 DU=0; 1258 P0=0xff; 1259 WE=1; 1260 P0=0xfe; 1261 WE=0; 1262 delayms(1); 1263 break; 1264 } 1265 } 1266 }