【Proteus仿真】51单片机在线版电子锁案例

【Proteus仿真】51单片机在线版电子锁案例

✨功能描述

📝在线版电子密码锁功能仿真:包含4组初始密码6个0,6个1,6个2,6个3,6个4,在解锁状态下,连续按Reset键5次,进入密码组重设。当重设密码组大于ARR[4]时,ARR[0]则会被覆盖。

🛠功能模块

1. 按键扫描和按键处理。
2.LCD1602驱动。
3.定时器功能。(控制蜂鸣器发声)
  • 📖程序框架
    在这里插入图片描述

📑main程序代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
/\*
编译环境: KEIL5
单片机型号AT89S52 12M
功能描述:Proteus在线电子密码锁的功能仿真:
包含4组初始密码6个0,6个1,6个2,6个3,6个4.
在解锁状态下,连续按Reset键5次,进入密码组重设。
当重设密码组大于ARR[4]时,ARR[0]则会被覆盖。
\*/
#include "LCD1602.h"
//#include <intrins.h>

#define key\_port P3//用KEY\_PORT代替P3

sbit beek_c = P2^2;//定义蜂鸣器控制口
sbit lock_c = P2^3;//定义锁信号输出口

//\*\*\*\*\*\*\*\*\*\*\*\*\*\*函数声明\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*
void init\_t0();//定时器0初始化函数
void judge\_xianshi(void);//显示处理程序
void read\_key(void);//按键键码读取子函数,返回相应的键码
uchar keybord_value;//全局变量,存储最终的键码,其值为0-F
void read\_password(void);//6位数据的读取,也就是密码的读取
uchar deal\_password(void);//输入密码和系统码对比,看是否符合开锁条件

//返回值为1就开锁,返回值为2为密码错误
void makesurekeydeal();//确认键处理程序
void cancelkeydeal();//取消键处理程序

//\*\*\*\*\*\*\*\*\*\*\*矩阵键盘键码\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*
const unsigned char code tabl2[16]={0xee,0xed,0xeb,0xe7,0xde,0xdd,0xdb,0xd7,0xbe,
// s1 s2 s3 s4 s5 s6 s7 s8 s9
0xbd,0xbb,0xb7,0x7e,0x7d,0x7b,0x77};//
// s10 s11 s12 s13 s14 s15 s16
uchar system[4][6];//定义 4\*6个数据作为系统的密码 也就是4组6位数

uchar passin[6];//定义全局变量,储存输入的6个按键数据
uchar temppassin[6];//输入的数据暂存
uchar flag1;//按键键入是否成功的标准,为1成功 为0失败
uchar passcount;//键入次数的统计
uchar flag2;//密码是否对的标志单位 ,为1成功 ,为2失败
uchar flag4;//蜂鸣器鸣响计时
uchar flag5;//reset重置密码累加次数
uchar flag7;//开锁状态
uchar t0_crycle;
uchar error_count;//密码输入次数
static uchar CNT =0;//修改密码组
//\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*主程序\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*
void main()
{
uchar i;
for(i=0;i<6;i++)
{
system[0][i]=1;//设置第一组6位系统密码为111 111
}
for(i=0;i<6;i++)
{
system[1][i]=2;//设置第2组6位系统密码为222 222
}
for(i=0;i<6;i++)
{
system[2][i]=3;//设置第3组6位系统密码为333 333
}
for(i=0;i<6;i++)
{
system[3][i]=4;//设置第2组6位系统密码为444 444
}
passcount=0;
flag5=0;
flag7=0;
flag4=0;
flag1=0;
beek_c=1;//关闭蜂鸣器
lock_c=0;//关闭锁
LCMInit();//液晶初始化设置
init\_t0();
TR0=0;//关闭定时器T0
error_count=0;
while(1)
{
read\_key();//读取键码
read\_password();//把键码转为密码
judge\_xianshi();//显示
}
}
//显示处理程序
void judge\_xianshi()
{
uchar i;
if(flag5 >= 5){//修改密码期间输入显示
DisplayListChar(0,0,0, "Set New password");//
DisplayListChar(1,0,0, "ARR[");
DisplayOneChar(1,4, CNT + 0X30);
DisplayListChar(1,5,0, "]:");
for(i=0;i<passcount&&i<6;i++)//显示输入的6个数据
DisplayOneChar( 1, 9+i,temppassin[i]+0x30);//修改密码时显示输入内容

}
else if (flag5 == 0)
{
lock_c = 0;//断开锁信号输出
DisplayListChar(0,4,0, "Elec-Lock");//常规开锁显示输入界面
DisplayListChar(1,0,0, "Password:");
for(i=0;i<passcount&&i<6;i++)//显示输入的6个数据
// DisplayOneChar( 1, 9+i, '\*'); //启用则,第二行为隐藏,并注释下面一句
DisplayOneChar( 1, 9+i, passin[i]+0x30);//第二行为真实显示,可以把这句注释,并启用上面一行,就隐藏密码了
}
else if ((flag5 > 0) && (flag5 <5))
{
DisplayListChar(0,2,0, "Unlock Status");//常规开锁显示输入界面
DisplayListChar(1,0,0, "Password:");
for(i=0;i<passcount&&i<6;i++)//显示输入的6个数据
// DisplayOneChar( 1, 9+i, '\*');//启用则,第二行为隐藏,并注释下面一句
DisplayOneChar( 1, 9+i, passin[i]+0x30);//第二行为真实显示,可以把这句注释,并启用上面一行,就隐藏密码了

}

}
//6位数据的读取,也就是密码的读取
void read\_password()
{
if(flag1==1 )//判断键入是否成功
{
flag1=0;
if(passcount<6 && flag5==0)
{
if(keybord_value<10){ //只接收0-9数字
passin[passcount] = keybord_value;
passcount++;
}
}

if(passcount<6 && flag5!=0)
{
if(keybord_value < 10 )//只接收0-9数字
{
temppassin[passcount]=keybord_value;
passcount++;
}
}
cancelkeydeal();//取消键处理程序
makesurekeydeal();//确认键处理程序
if(keybord_value==15 && flag7==1)//在开锁状态下,连续按#15按键5次或以上判断为重置密码
{
flag5++;//重复按5次#15按键或以上,进入修改密码
if(flag5>=5){
passcount = 0;//清除按键输入
WriteCommandLCM(0x01,1); //清除显示一下
}

}
}
}
//\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*
//确认键处理程序
void makesurekeydeal()
{
uchar i;

if(keybord_value==12 && flag7==0 )//判断是否为确认键
{
flag2 = deal\_password();// 判断输入的密码是否正确
passcount=0;
if(flag2==1)//输入的密码正确
{
flag7 = 1;
beek_c=0;//开蜂鸣器
lock_c=1;//开锁
flag5=1;
DisplayListChar(1,0,0, "Opening........");//在液晶的第二行显示字符"OPERING
TR0=1;//开启定时器
flag4=0;//定时器(TR0=1)开启后,FLAG4每0.1秒自加1
error_count=0;//错误统计次数归零
while(flag4<=20);//密码正确开锁信号闭合2秒 蜂鸣器响2秒
flag4=0;
TR0=0;//关闭定时器,蜂鸣器停止
WriteCommandLCM(0x01,1); //清除显示一下
beek_c=1;//关闭蜂鸣器
}
if(flag2==2)//输入的密码错误
{
beek_c=0;
TR0=1;
error_count++;//密码输入错误后,计数器+1
DisplayListChar(1,0,0, "Input Error TIS");
DisplayOneChar( 1,12,error_count+0x30);//显示输入多少次错误
while(flag4<=5);//密码输入错误蜂鸣器响0.5秒,关0.5秒的频率响2次
beek_c=1;
flag4=0;
while(flag4<=5);
beek_c=0;
flag4=0;
while(flag4<=5);
beek_c=1;
flag4=0;
flag2=0;
TR0=0;
if(error_count>=3)//如果密码输入3次错误经锁定2.54分钟或需要重新断电
{
DisplayListChar(0,0,0, "Input Error 3 Ts");
DisplayListChar(1,0,0, "locked 3 minutes");
TR0=1;
while(flag4<=254);//锁定时间过后系统恢复
DisplayListChar(0,0,0, "Electronics Lock");
TR0=0;
error_count=0;
flag4=0;
}
}

WriteCommandLCM(0x01,1); //清除显示一下
}
if(flag5 >=5){//在开锁状态下,连续按reset按键5次以上,进入密码组重置
if(keybord_value==12 && flag7==1 )//确认修改密码
{
for(i=0;i<6;i++)
{
system[CNT][i]=temppassin[i];//把暂存单元的数据传给对应的开始密码
temppassin[i]=0;//暂存单元清零,下次修改密码可以再次利用
}
flag7=0;//各种标志单元清零
flag2=0;
flag5=0;
passcount=0; //按键次数计数清零
CNT++;
CNT %=4;
WriteCommandLCM(0x01,1); //清除显示一下
DisplayListChar(0,0,0, "Reset Succeed!");
delayms(1000);
delayms(1000);
delayms(1000);
WriteCommandLCM(0x01,1); //清除显示一下
}
}
}
//\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*
//取消键处理程序
void cancelkeydeal()
{
uchar i;
if(keybord_value==13 )//判断是否为取消键
{
if(flag7==0)//没有开锁状态下
{
for(i=0;i<passcount;i++)
{
passin[i]=0;
}//清零
passcount=0;//按取消键后,键入按键次数的计数单元清零
}
else if(flag7==1)//开锁状态下
{
if(flag5>=5)CNT--;//在重置密码状态下,放弃修改密码
flag7=0;//关闭开锁状态
flag2=0;
flag5=0;//重置密码累加次数归零
passcount=0;


}
WriteCommandLCM(0x01,1); //清除显示一下
}
}

uchar deal\_password()//输入密码和系统码对比,看是否符合开锁条件
{
uchar i,j,temp2,temp;
temp2=0;
for(j=0;j<4;j++)//依次判断4组
{
temp=0;
for(i=0;i<6;i++)
{
if(system[j][i]==passin[i])temp++;//如果系统密码和键入的密码对应的位一样,则暂存单元自加1
}
if(temp==6)
{
temp2=1;
return(1);//如果TEMP为6,证明键入的密码和4组系统密码中的一组一样;
break;//退出判断
}
}
return(2);//没有比对成功的密码组
}
void read\_key(void)
{
uchar key_value,i=1;
uchar key_high_value,key_low_value;//定义变量暂存高四位和低四位按键的键码
key_port=0xf0;//置按键控制口为1,准备读入数据
key_value=key_port & 0xf0;
if(key_value!=0xf0)//如果没有按键按下,则相等
{
delay\_50us(200);//延时10ms去除抖动
key_port=0xf0;//再次讲IO置1,准备读入去除抖动后的数据
key_value=key_port & 0xf0;
switch (key_value)
{ case 0xf0:break;//经软件延时后,判断为误判,则退出函数,返回
case 0x70:key_high_value=0x70;break;
case 0xb0:key_high_value=0xb0;break;
case 0xd0:key_high_value=0xd0;break;
case 0xe0:key_high_value=0xe0;break;
default:key_high_value=0x00;break;//多个按键同时按下,显示0,然后退出
}
key_port=0x0f;//交换高四位和低四位的状态,再次读取键码
key_value = key_port & 0x0f;
switch(key_value)
{
case 0x07:key_low_value=0x07;break;
case 0x0b:key_low_value=0x0b;break;
case 0x0d:key_low_value=0x0d;break;
case 0x0e:key_low_value=0x0e;break;
default:key_low_value=0x00;break;
}
key_value = key_high_value | key_low_value;
for(i=0;i<16;i++)//只取前14位数值进行处理,最后2个按键不计入
{
if(key_value==tabl2[i])
{
keybord_value=i;
flag1=1;//置按键码读取成功标志位1;
if(flag5 >0 && keybord_value==14)//已开锁标志位
{
flag1=0;
}
break;
}
}
beek_c=0;//开蜂鸣器
TR0=1;
while(flag4<=1);//按按键的时候蜂鸣器响0.1秒
flag4=0;
TR0=0;//关闭定时器
beek_c=1;//关闭蜂鸣器
key_port=0xf0;//置按键控制口为1,准备读入数据
while((key_port & 0xf0 )!=0xf0 && keybord_value!=14 ); //等待按键释放,按键释放后才往下执行程序
}
}
//定时器0中断服务程序
void timer0() interrupt 1
{
TH0=(65536-50000)/256;
TL0=(65536-50000)%256;//定时器设置为定时50MS
t0_crycle++;
if(t0_crycle==2)// 0.1秒
{
t0_crycle=0;
flag4++; //定时器开启后,FLAG4每0.1秒自加1
if(flag5!=0 && flag4>=40)//输入密码正确开锁后超过2分钟后不能进入修改开锁密码的界面
{
flag4=0;
TR0=0;
}
}
}
//定时器0初始化
void init\_t0()
{
TMOD=0x01;//设定定时器工作方式1,定时器定时50毫秒
TH0=(65536-50000)/256;
TL0=(65536-50000)%256;
EA=1;//开总中断
ET0=1;//允许定时器0中断
t0_crycle=0;//定时器中断次数计数单元
}


📚仿真资源和程序源码

本案例基于Proteus8.12平台。

1
2
3
链接:https://pan.baidu.com/s/1B8NPrh76x3YZScLGSQp1og 
提取码:iaqs