Print this page
Saturday, 29 June 2013 16:25

Arduino电子密码锁

Written by
Rate this item
(7 votes)
一个基于Arduino微控制器的密码锁,一般上用于防盗门。为了方便初学者学习与操作,这里提供了两个版本的电子密码锁源码。
 
读完文章与明白程序操作后,你将会如何应用:
  1. EEPROM字串存取
  2. 运用#include文件,把谋些函数(function)调去外部文件
  3. 简单的旋律处理
  4. 日期与时间处理
  5. 如何形成Press and hold
  6. 矩阵键盘应用与空闲(idle)侦察
  7. 密码处理与验证
  8. i2c LCD
  9. 非阻塞编程(Non blocking programming) 
 
 
零件与材料
  • Arduino UNO
  • 4x4(或3x4)矩阵键盘
  • 用于释放门锁的按键(Door button exit switch)
  • 1K电阻器
  • NPN 晶体管
  • 12V继电器
  • 电磁锁
  • I2C 16X2 LCD(如果不需要显示,可以省略)
  • 电脑主板扬声器(如果不需要声音提醒,可以省略)
  • 100 ohm电阻器(随意,连接扬声器与Arduino之间)
  • 扬声器,最好有低功率扩音器(如果不需要按铃通知,可以省略)
  • 门铃按键(如果没有使用按铃通告,可以省略)
 
功能
  • LCD显示
  • 时间显示
  • 键盘密码输入与验证
  • 3次密码重试,之后键盘将会禁用一分鈡
  • 紧急门锁释放
  • 电源故障门锁自动释放
  • 按键声响与声音提醒
  • 门铃按键与旋律
  • 通过串口与电脑连接,以便显示密码锁状况
 
操作与使用
密码锁预设了两个不同级密码,称之为USER密码和ADMIN密码。USER密码用于开锁,ADMIN密码于设定与更换所有密码。第一次使用密码锁时,EEPROM是空的,因此必须做一次设定重置以便把USER密码和ADMIN密码写入EEPROM
设定重置
按着RESET键开电,维持按键五秒。听到Do Re Mi声响表示完成重置
 
开锁与
输入正确的USER密码(预设是1234)开锁。如果用户是在屋内,可以按下紧急按键来开锁。五秒后,门锁将会自动上锁。
更换密码
  • 按#进入菜单
  • 输入ADMIN密码预设是1234)
  • 想要更改USER密码,请按1。按2则是更ADMIN密码
  • 输入新密码。如不想换密码,隨时按下星(*)键退出
  • 输入确认密码,(同样新密码
  • 听到Do Re Mi声响表示完成更换密码
更换日期与时间
  • 按#进入菜单
  • 输入ADMIN密码 预设是1234)
  • 按3进入日期与时间设定。不想更换改日期*键退出
  • 输入日期,格式为DDMMYYYY,年份必须是四位数例:三十一曰,十二月,二零一三年,则是输入31122013,年份必须是四位数
  • 输入时间,格式为HHMMSS,小时(HH)为二十四小时。例:下午五时,四十三分,二十一秒,输入174321
  • 听到Do Re Mi示完成更换日期与时间
 
代码分析
如果纯粹是自制,且不想进一步了Arduino编程,可以跳过以下说明
从Arduino IDE里打开CodeLock_with_Time.ino主文件时,在同一文件夹里的所有xxx.h文件会隨之打开,这是由于动用了#include。#include文件的目的是把多个编译单元(也就是c或者cpp文件)公用的内容,单独放在一个文件里减少整体代码尺寸,或者提供跨工程公共代码。
Arduino libraries
eeprom_string.h文件里只有两个函数定义(function header),分别为eeprom_read_string()和eeprom_write_string(),功能如其名,eeprom_read_string()用以读取EEPROM谋地址的字串,eeprom_write_string()则是写入字串至谋EEPROM地址。eeprom_string.h打开后,eeprom_string.ino也开。
eeprom_string.ino是我更改于Arduino官方网站的EepromUtil例子,由于EepromUtil例子里包含了多个没有使用到的函数,所以我把它简化了以方便编写及容易明白。
Arduino软件已经包含了EEPROM程序库,为何还要编写多一个eeprom程序呢?理由很简单,因为Arduino软件里的EEPROM程序库不支持存取字串(String)。
接下来是matrixKeypad.h文件,这是矩阵键盘的设定。之前是编写在CodeLock_with_Time.ino主文件里,为了更容易处理代码,所以又将之分开了。
最后的是pitches.h文件,用来定义音调。运用了#define谋个常数(constant value)为音调,编写旋律变得很容易了。
 
#include文件运行完后接下来是变数与常数设置,可以根据自己的要求设定

void setup()

setup创建函数一般用来作初始化,开机后,setup只运行一次。setup里有几行比较特别的代码必须交代一下。
sw_state = digitalRead(RESET_SETTINGS_PIN ); 
if (sw_state==LOW) reset_settings();
机时,检查sw_state状态,如果是LOW的话将会执行reset_settings()程序。在什么状况下sw_state才会LOW呢?那就是按着RESET_SETTINGS按钮开机,检验到sw_state是低平后,reset_settings() 程序会运行。以下是reset_settings() 程序的代码
第五行代码while (sw_state == LOW)是用来侦察RESET_SETTINGS按钮,如果是LOW的话将会继续运行第七行代码if ((millis() - start_hold) >= HOLD_DELAY),否则将会回返原来的呼叫位置。维持按着RESET_SETTINGS按钮五秒 ,initializeEEPROM()程序将会运行。这就是所谓的Press and Hold了。
USER_PASSWORD和ADMIN_PASSWORD同时设定为1234,然後写入EEPROM里。完EEPROM写入后,将会听到Do-Re-Mi音调,表示成功EEPROM初始化。
上面程序完成后,接下来是loadConfiguration()程序
loadConfiguration()程序里暂时没有太多的设定,只是把USER_PASSWORD和ADMIN_PASSWORD从EEPROM里读取,然後分别分配给userPassword和adminPassword。当然你也可以把更多的设定值如LOCK_HOLD_TIME,KEYBOARD_EVENT_TIMEOUT,maxPasswordLength等存入EEPROM,隋后读取。
setup创建函数里的最後一行就是welcome()程序了。此时LCD将出现Enter Password字符
 
 

void loop()

顾名思义,所有的代码将会在这里不停的运行。
 
runEventAnyTime()是在loop里的第一个程序。凡事需要不间断处里的事件都可以编写在runEventAnyTime()程序里。
上面的代码用来释放门锁,门铃以及RFID(这功能暂时还没实现),将来还可以置入别的事件,但不允许有delay代码。为何不采用定时器中断(timer interrupt)方式来解决delay问题呢?这是由于ATMega328的所有三个timer(8 bit timer0, 16 bit timer1, 8 bit timer2)都被占用了,逼不得已之下,只好使用polling方式了。
print_date_time()程序是用来显示日期与时间。当然你也可以将之编写在runEventAnyTime()程序里,不过你会遇到一个小问题,我忘记了是什么。
此电子密码锁设计並没有使用RTC(Real Time Clock)IC,当电源中断后,日期与时间会隋之重置,因此必须从新设置日期与时间。不过这并不重要,因为使用这类密码锁通常都设有后备电源以防止电磁锁自动释放。
每次输入错误的密码时,retryCount的值会增一。如果输入三次错误的密码,键盘将会禁用,所以必须有一程序来恢复启动键盘。
当下面代码侦察到retryCount大于零(用户输入了错误的密码)时,将会比较当前的时间和之前的时间加一分钟(AUTO_RESET_RETRY_COUNT * 60000)。AUTO_RESET_RETRY_COUNT预设为一,60000则表示一分钟(1000 millisecond x 60 ),如果超过了一分钟,resetRetryCount()程序将会运行。
resetRetryCount()运行后,键盘又重新启动了
下面 代码用于键盘输入,keypad.getKey()是一个非阻塞矩阵键盘输入,keypad.getKey()是没有等待输入的,它下面的程序会继续运行的。毎一次按键都会产生一beep声响,用来提醒,各自的按键值将会赋予key。输入#号时,就会进入 enterPasswordForMenu()菜单,否则会执行enterPasswordToRelease_DoorLock(key)以便让用户输入密码来打开门锁。当输入了三次(reached_maximum_retries=3)错误的密码 ,键盘输入将会禁用一分钟。
 
 
这里有一段很好玩的代码,那就是boolean isTimeout()程序。
每次用户按键时,此程序会不停的运行直至timeout。isTimeout()程序会侦察键盘输入,当用户在谋一段时间内没有按键输入时,我们称之idle(空闲)。空闲10秒后(KEYBOARD_EVENT_TIMEOUT预设为10),程序将会自动退出。
CodeLock_with_Time.ino文件里共有746行代码,似乎很长及复杂,其实不然,这是因为运用了许多print指令丶空白行以及置入了许多注解,另外音调程序方面也占用了不少空间。
 
Read 68826 times Last modified on Sunday, 12 June 2016 11:11