查看: 4313|回复: 16
|
Arduino电子密码锁兽
[复制链接]
|
|
![](static/image/common/ico_lz.png)
楼主 |
发表于 18-9-2013 12:22 AM
|
显示全部楼层
为了方便阅读与参考,还是把主文件代码贴在这里- /*
- * Arduino DIY Code Lock with Time
- * by smching www.ediy.com.my
- *
- * LiquidCrystal_I2C library
- * http://www.dfrobot.com/wiki/index.php?title=I2C/TWI_LCD1602_Module_(SKU:_DFR0063)
- *
- * Keypad library
- * http://playground.arduino.cc/code/Keypad
- *
- * keypad columns = 2,3,4,5
- * keypad rows = 6,7,8,9
- * reset settings pin = 11
- * lock open switch = 12
- * door lock relay = 13
- * bell switch = A0 (14)
- * bell = A2 (16)
- * mini_speaker = A3 (17)
- * lcd a4, a5
- */
-
-
- // http://forum.arduino.cc/index.php/topic,46900.0.html
- #define DEBUG //comment this line if you want to disable serial message
- #ifdef DEBUG
- #define DEBUG_PRINT(x) Serial.print(x)
- #define DEBUG_PRINTLN(x) Serial.println(x)
- #else
- #define DEBUG_PRINT(x)
- #define DEBUG_PRINTLN(x)
- #endif
- #include <eeprom_string.h> // http://playground.arduino.cc/Code/EepromUtil
- #include <Wire.h> // I2C library, allows you to communicate with I2C/TWI devices
- #include <LiquidCrystal_I2C.h> // I2C LCD library
- #include <Keypad.h> // library for using matrix style keypads
- #include "pitches.h" // constant value for pitches
- #include "matrixKeypad.h" // define 4x4 or 3x4 matrix keypad
- #include <Time.h>
- // http://www.leonardomiliani.com/2012/come-gestire-loverflow-di-millis/?lang=en
- // Arduino versions have a max value of 4294967295 or about 49 days and 17 hours
- // delay(), millis() and micros() uses timer0
- // millis() will overflow (go back to zero) after 49 days and 17 hours
- // use to reset timer0 in order to prevent timer overflow
- // declaring this after wiring.c
- // extern volatile unsigned long timer0_overflow_count;
- // press and hold variable
- int reset_settings_pin = 11; //hold the switch in order to restore settings
- int sw_state = HIGH;
- int release_lock_switch_pin = 12; //a switch use to release door lock without input password
- #define DOOR_LOCK_PIN 13 //connect relay to digital 13
- #define LOCK_HOLD_TIME 5 //if door lock is released, lock it after 5 seconds
-
- int bell_switch_pin = 14; //connect bell switch to Analog 0 (digital 14)
- #define BELL_PIN 16 //connect BELL to Analog 2 (digital 16)
- boolean isPlayingMelody = false; //indicating melody is playing or not
- boolean stopPlayingMelody = false; // forcing melody to stop playing if stopPlayingMelody = true
- #define MINI_SPEAKER_PIN 17 //connect speaker to Analog 3 (digital 17)
- // set the LCD address to 0x27 for a 16 chars and 2 line display
- // http://www.dfrobot.com/wiki/index.php?title=I2C/TWI_LCD1602_Module_(SKU:_DFR0063)
- // Uno, Ethernet A4 (SDA), A5 (SCL)
- // Mega2560 20 (SDA), 21 (SCL)
- // Leonardo 2 (SDA), 3 (SCL)
- // Due 20 (SDA), 21 (SCL), SDA1, SCL1
- LiquidCrystal_I2C lcd(0x27,16,2);
- // timeout variable
- unsigned long previousMillis = 0; //hold the current millis
- #define KEYBOARD_EVENT_TIMEOUT 10 //timeout (in second) for keyboard input
- // Actions
- #define ADMIN 0 //use to change ADMIN password
- #define USER 1 //use to change USER password
- byte action = USER; //action is set to USER now
- ////////////////////////////////////////////////////////////////////////////////
- // password variable
- ////////////////////////////////////////////////////////////////////////////////
- String userPassword; //variable to hold USER password
- String adminPassword; //variable to hole ADMIN password
- const byte maxPasswordLength = 4; //length of ADMIN & USER password, not more than 10
- char buf[maxPasswordLength + 1]; //temporary storage for EEPROM data, hold the string read/write from EEPROM
- #define USER_PASSWORD_EEPROM_ADDRESS 0 //EEPROM address to store USER password
- #define ADMIN_PASSWORD_EEPROM_ADDRESS 10 //EEPROM address to store ADMIN password
- ////////////////////////////////////////////////////////////////////////////////
- // variable for password retry
- ////////////////////////////////////////////////////////////////////////////////
- const byte MAX_PASSWORD_RETRY = 3; //Maximum number of retry
- byte retryCount = 0; //number of retry, start from 0
- boolean reached_maximum_retries = false; //use to disable keyboard input
- const byte AUTO_RESET_RETRY_COUNT = 1; //use to reset (in minute) for password retry count
- ////////////////////////////////////////////////////////////////////////////////
- // these code will be execute on each Arduino reset
- ////////////////////////////////////////////////////////////////////////////////
- void setup(){
- Serial.begin(19200);
- lcd.init(); // initialize the lcd
- lcd.backlight(); // turn on LCD back light
-
- pinMode(DOOR_LOCK_PIN, OUTPUT); // set DOOR_LOCK_PIN as output
- digitalWrite(DOOR_LOCK_PIN, HIGH); // lock the door
-
- pinMode(release_lock_switch_pin, INPUT); // set release_lock_switch_pin as input
- digitalWrite(release_lock_switch_pin, HIGH); // turn on pullup resistors & set release_lock_switch_pin HIGH
- pinMode(BELL_PIN, OUTPUT); // set BELL_PIN as output
- pinMode(bell_switch_pin, INPUT); // set bell_switch_pin as input
- digitalWrite(bell_switch_pin, HIGH); // turn on pullup resistors & set bell_switch_pin HIGH
-
- //use to initialize EEPROM for first time use
- pinMode(reset_settings_pin , INPUT); // Set the reset_settings_pin as input
- digitalWrite(reset_settings_pin , HIGH); // turn on pullup resistor & set reset_settings_pin to HIGH
- sw_state = digitalRead(reset_settings_pin ); // read input value from reset_settings_pin
- if (sw_state==LOW) reset_settings(); // proceed write configuration routine if reset_settings_pin =high
-
- loadConfiguration(); // load settings from EEPROM
- Serial.println("Arduino DIY Code Lock");
- Serial.println("by smching www.ediy.com.my");
- welcome(); // show welcome message
- }
- ////////////////////////////////////////////////////////////////////////////////
- // main loop
- ////////////////////////////////////////////////////////////////////////////////
- void loop(){
- runEventAnyTime(); // codes inside runEventAnyTime() will keep on updating
- print_date_time();
- // retryCount increase by one each time an incorrect password has been entered
- // retryCount will reset to zero when idle for one minute (set by AUTO_RESET_RETRY_COUNT)
- if (retryCount > 0) { //if someone have entered wrong password
- if (millis() >= previousMillis + AUTO_RESET_RETRY_COUNT * 60000) {
- resetRetryCount();
- }
- }
- if (!reached_maximum_retries) { // if did not reach maximum number of retry
- char key = keypad.getKey(); //waiting for keyboard input (non blocking)
- if (key != NO_KEY){ //if press a key
- beep();
- delay(30); //debounce
- if (key == '#') enterPasswordForMenu(); //require to enter password before proceed to menu selection
- else enterPasswordToRelease_DoorLock(key); //otherwise proceed to enterPasswordToRelease_DoorLock routine
- }
- }
- }
- ////////////////////////////////////////////////////////////////////////////////
- // clear one line from lcd
- ////////////////////////////////////////////////////////////////////////////////
- void clear_lcd_line(byte y) {
- y = y-1;
- lcd.setCursor(0, y);
- lcd.print(" ");
- lcd.setCursor(0, y);
- }
- ////////////////////////////////////////////////////////////////////////////////
- // clear screen & show welcome message
- ////////////////////////////////////////////////////////////////////////////////
- void welcome() {
- DEBUG_PRINTLN(); DEBUG_PRINT("Please enter password. ");
- DEBUG_PRINTLN(retryCount);
- lcd.clear(); lcd.print("Enter Password "); lcd.print(retryCount);
- }
- ////////////////////////////////////////////////////////////////////////////////
- // show date and time on lcd
- ////////////////////////////////////////////////////////////////////////////////
- void print_date_time() {
- lcd.setCursor(0, 1); //second line (x=0, y=1)
- if(day() < 10) lcd.print('0');
- lcd.print(day());
- lcd.print("-");
- if(month() < 10) lcd.print('0');
- lcd.print(month());
- lcd.print(" ");
- if(hour() < 10) lcd.print('0');
- lcd.print(hour());
- lcd.print(":");
-
-
- if(minute() < 10) lcd.print('0');
- lcd.print(minute());
- lcd.print(":");
-
- if(second() < 10) lcd.print('0');
- lcd.print(second());
- }
- ////////////////////////////////////////////////////////////////////////////////
- // load settings from EEPROM
- ////////////////////////////////////////////////////////////////////////////////
- void loadConfiguration() {
- eeprom_read_string(USER_PASSWORD_EEPROM_ADDRESS, buf, maxPasswordLength + 1); //read USER password from EEPROM
- userPassword = buf; //use this password to release door lock
- eeprom_read_string(ADMIN_PASSWORD_EEPROM_ADDRESS, buf, maxPasswordLength + 1); //read ADMIN password from EEPROM
- adminPassword = buf; //use this password to enter menu selection
- }
- ////////////////////////////////////////////////////////////////////////////////
- // press a switch to release door lock
- ////////////////////////////////////////////////////////////////////////////////
- void press_release_lock_switch() {
- if (digitalRead(release_lock_switch_pin) == LOW) {
- lockRelease(); // release door lock
- resetRetryCount();
- }
- }
- ////////////////////////////////////////////////////////////////////////////////
- // press a switch to ring the bell
- ////////////////////////////////////////////////////////////////////////////////
- void press_bell_switch() {
- if (isPlayingMelody) return; // do not play melody if it is currently playing
-
- if (digitalRead(bell_switch_pin) == LOW) {
- playMelody(); // ring the bell
- //generate a short pulse (100 milli seconds) at BELL_PIN
- //digitalWrite(BELL_PIN, HIGH);
- //delay(100);
- //digitalWrite(BELL_PIN, LOW);
- }
- }
- ////////////////////////////////////////////////////////////////////////////////
- // read RFID tag
- ////////////////////////////////////////////////////////////////////////////////
- void read_RFID() {
- /*
- rfid.seekTag(); // start seek mode
- if (rfid.available()) {
- DEBUG_PRINTLN(rfid.getTagString());
- lockRelease(); // release door lock
- resetRetryCount();
- }
- */
- }
- ////////////////////////////////////////////////////////////////////////////////
- // write whatever code here if require continuous updates
- // make sure no delay or blocking
- ////////////////////////////////////////////////////////////////////////////////
- void runEventAnyTime() {
- // press a switch to release door lock without enter password
- press_release_lock_switch();
- // press a switch to ring the bell
- press_bell_switch();
- // read tag & release door lock if verified
- read_RFID();
- }
-
- ////////////////////////////////////////////////////////////////////////////////
- // reset retry count & enable keyboard input
- ////////////////////////////////////////////////////////////////////////////////
- void resetRetryCount() {
- retryCount = 0; //reset retry count
- reached_maximum_retries = false; // enable keyboard input
- welcome();
- }
- ////////////////////////////////////////////////////////////////////////////////
- // input password for menu
- ////////////////////////////////////////////////////////////////////////////////
- void enterPasswordForMenu() {
- String inputPassword = "";
- clear_lcd_line(2); // clear second line
-
- // get input from keyboard
- // only accept 0,1,2,3,4,5,6,7,8,9 key
- // an * is print to the second line of LCD when a key is pressed
- inputPassword = getInput('1','6', maxPasswordLength, false);
- if (inputPassword.length() > 0) { // if user had input the password
- // compare input password with ADMIN password
- // unlock the Door Lock if a correct password had been enter
- // otherwise output warning alert & increase retry by one
- if (isCorrectPassword(inputPassword, adminPassword)) {
- playOKTone();
- playWarningTone();
- menuSelection(); // let user make a selection
- } else {
- processFailedPassword(); //something must be done when user enter wrong password
-
- }
- }
- if (retryCount < MAX_PASSWORD_RETRY) welcome();
- }
- ////////////////////////////////////////////////////////////////////////////////
- // let user make a selection
- // valid key ranged from 1 to 6
- ////////////////////////////////////////////////////////////////////////////////
- void menuSelection() {
- DEBUG_PRINTLN(); DEBUG_PRINT("Selection (1-6): ");
- lcd.clear(); lcd.print("Selection (1-6)");
-
- // get input from keyboard
- // only accept 1,2,3,4,5 key
- String selectedMenuString = getInput('1','6', 1, true);
-
- if (selectedMenuString.length() > 0) { // if user made an selection
- if (selectedMenuString == "1") { // user select 1
- action = USER; // indicated user want to change USER password
- changePassword(); // proceed with change password routine
- }
- if (selectedMenuString == "2") { // user select 2
- action = ADMIN; // indicated user want to change USER password
- changePassword(); // proceed with change password routine
- }
- if (selectedMenuString == "3") { // user select 3
- setDateTime();
- }
- if (selectedMenuString == "4") { // user select 4
- //addTag(); // add an RFID tag
- }
- if (selectedMenuString == "5") { // user select 5
- //deleteTag(); // delete an RFID tag
- }
- if (selectedMenuString == "6") { // user select 6
- //deleteAllTag(); // delete all RFID tag
- }
-
- }
- welcome();
- }
- ////////////////////////////////////////////////////////////////////////////////
- // input password to unlock DOOR LOCK
- ////////////////////////////////////////////////////////////////////////////////
- void enterPasswordToRelease_DoorLock(char key) {
- DEBUG_PRINT("*");
- clear_lcd_line(2); // clear second line
- lcd.print("*");
- // get input from keyboard
- // only accept 0,1,2,3,4,5,6,7,8,9 key
- // an * is print to the second line of LCD when a key is pressed
- String inputPassword = getInput('0','9', maxPasswordLength-1, false);
- if (inputPassword.length() > 0) { // if user had input the password
- inputPassword = key + inputPassword;
-
- // compare input password with USER password
- // open the door if correct password had been enter
- // otherwise output warning alert & increase retry count by one
- if (isCorrectPassword(inputPassword, userPassword)) {
- //DEBUG_PRINTLN("Password accepted.");
- //lcd.clear();
- //lcd.print("Pwd accepted.");
- retryCount = 0;
- lockRelease();
- } else {
- processFailedPassword();
- }
- }
- if (retryCount < MAX_PASSWORD_RETRY) welcome();
- }
- ////////////////////////////////////////////////////////////////////////////////
- // incorrect password had been enter
- ////////////////////////////////////////////////////////////////////////////////
- void processFailedPassword() {
- playWarningTone();
- retryCount = retryCount + 1;
- if (retryCount == MAX_PASSWORD_RETRY) { // reached maximum retries
- DEBUG_PRINTLN(); DEBUG_PRINT("Reached maximum retries, wait ");
- DEBUG_PRINT(AUTO_RESET_RETRY_COUNT);
- DEBUG_PRINTLN(" minute.");
- lcd.clear(); lcd.print("Wait "); lcd.print(AUTO_RESET_RETRY_COUNT); lcd.print(" minute.");
- reached_maximum_retries = true; //cause main loop disable keyboard input
- }
- }
- ////////////////////////////////////////////////////////////////////////////////
- // a sub routine for keyboard input with timeout
- // timeout occured if user did not press any key within certain amount time (set by KEYBOARD_EVENT_TIMEOUT)
- // lowKey & highKey limit input range from lowKey to highKey
- // maxStringLength control how many alphanumeric will be enter
- // show input key when showKey=true, otherwise show "*"
- ////////////////////////////////////////////////////////////////////////////////
- String getInput(char lowKey, char highKey, byte maxStringLength, boolean showKey) {
- boolean inputIsValid = false; // indicate valid password had been enter
- String inputString = "";
- byte inputStringLength = 0;
- previousMillis = millis(); // use by timeout
- while (!isTimeout()) { // loop until timeout
- char key = keypad.getKey(); // waiting for keyboard input
- if (key != NO_KEY){ // if a key is pressed
- previousMillis = millis(); // reset timeout so that the timeout will not occur
- beep();
- if (key == '*') break; // exit loop if user press a * key
- if (key >= lowKey && key <= highKey) { // user press a key which is acceptable
- if (showKey) {
- DEBUG_PRINT(key);
- lcd.print(key);
- } else {
- DEBUG_PRINT("*");
- lcd.print("*");
- }
- inputStringLength++;
- inputString = inputString + key;
- if (inputString.length() >= maxStringLength) { // if input reach maxStringLength
- inputIsValid = true; // indicated user had enter string (eg. password)
- break; // and then exit the loop
- }
- } else playWarningTone(); // alert user if unacceptable key is pressed
- }
- }
- if (!inputIsValid) inputString = ""; // if did not enter any input, return blank
- return inputString; // otherwise return inputString
- }
- ////////////////////////////////////////////////////////////////////////////////
- // compare input password with USER/ADMIN password
- ////////////////////////////////////////////////////////////////////////////////
- boolean isCorrectPassword(String inputPassword, String password) {
- if (inputPassword == password) return true; else return false;
- }
- ////////////////////////////////////////////////////////////////////////////////
- // send LOW to DOOR_LOCK_PIN in order to release the Door Lock
- // lock the door after certain amount of time (defined by LOCK_HOLD_TIME)
- ////////////////////////////////////////////////////////////////////////////////
- void lockRelease() {
- if (isPlayingMelody) stopPlayingMelody = true;
- DEBUG_PRINTLN("Lock released.");
- lcd.clear(); lcd.print("Lock released.");
- digitalWrite(DOOR_LOCK_PIN, LOW); // release door lock
- playOKTone();
-
- clear_lcd_line(2); // clear second line
- previousMillis = millis();
- // wait for 5 seconds (LOCK_HOLD_TIME is set to 5 by default)
- while (true) {
- if (millis() >= previousMillis + LOCK_HOLD_TIME *1000) break;
- print_date_time();
- //lcd.print(lcd.print((millis() / 1000) % 60UL));
- }
- // timer0_overflow_count = 0; //reset timer0 in order to prevent timer overflow after 49 days
-
- digitalWrite(DOOR_LOCK_PIN, HIGH); // lock the door
- playTimeOutTone();
- }
- ////////////////////////////////////////////////////////////////////////////////
- // change USER password or ADMIN password
- ////////////////////////////////////////////////////////////////////////////////
- void changePassword() {
- if (action == ADMIN) {
- DEBUG_PRINTLN(); DEBUG_PRINT("Admin Password: ");
- lcd.clear(); lcd.print("Admin Password");
- } else {
- DEBUG_PRINTLN(); DEBUG_PRINT("User Password: ");
- lcd.clear(); lcd.print("User Password");
- }
-
- clear_lcd_line(2); // clear second line
- String newPassword = getInput('0','9', maxPasswordLength, false); // waiting for new password
- if (newPassword.length() > 0) { // if new password had been enter
- DEBUG_PRINTLN(); DEBUG_PRINT("Confirm Password: ");
- lcd.clear(); lcd.print("Confirm Password");
- clear_lcd_line(2); // clear second line
- String confirmPassword = getInput('0','9', maxPasswordLength, false); // waiting for confirm password
- if (confirmPassword.length() > 0 && newPassword == confirmPassword) {
- action == USER;
- updatePassword(newPassword); // update old password with new password
- playOKTone();
- }
- }
- welcome();
- }
- ////////////////////////////////////////////////////////////////////////////////
- // update old password with new password
- ////////////////////////////////////////////////////////////////////////////////
- void updatePassword(String newPassword){
- char newPasswordChar[maxPasswordLength + 1];
- newPassword.toCharArray(newPasswordChar, maxPasswordLength+1); //convert string to char array
- strcpy(buf, newPasswordChar);
- if (action == ADMIN) {
- adminPassword = newPassword;
- eeprom_write_string(ADMIN_PASSWORD_EEPROM_ADDRESS, buf);
- DEBUG_PRINTLN();
- DEBUG_PRINT("ADMIN password changed to ");
- } else {
- userPassword = newPassword;
- eeprom_write_string(USER_PASSWORD_EEPROM_ADDRESS, buf);
- DEBUG_PRINTLN(); DEBUG_PRINT("USER password changed to ");
- }
-
- DEBUG_PRINTLN(newPassword);
- lcd.clear(); lcd.print("Password changed");
- delay(1000);
- //lcd.print(newPassword);
- welcome();
- }
- ////////////////////////////////////////////////////////////////////////////////
- // set date and time
- ////////////////////////////////////////////////////////////////////////////////
- void setDateTime() {
- byte hh, mm, ss, dd, mo, yy;
- DEBUG_PRINTLN(); DEBUG_PRINT("Date (ddmmyyyy): "); // The full four digit year (eg. 2013)
- lcd.clear(); lcd.print("Date (ddmmyyyy):");
- lcd.cursor(); // show cursor
- lcd.setCursor(0,1); //second line
- if(day() < 10) lcd.print('0'); lcd.print(day());
- if(month() < 10) lcd.print('0'); lcd.print(month());
- if(year() < 10) lcd.print('0'); lcd.print(year()); // show current date
- lcd.setCursor(0,1); //second line
- String newDate = getInput('0','9', 8, true); // date input
- dd = (newDate.substring(0, 2)).toInt(); // get frist two lettter from newDate and convert it to integer
- mo = (newDate.substring(2, 4)).toInt();
- yy = (newDate.substring(4, 8)).toInt();
- if (isValidDate(dd, mo, yy)) { // valid date has been enter
- DEBUG_PRINT("Time (hhmmss): ");
- lcd.clear(); lcd.print("Time (hhmmss): ");
- lcd.setCursor(0,1); //second line
- if(hour() < 10) lcd.print('0'); lcd.print(hour());
- if(minute() < 10) lcd.print('0'); lcd.print(minute());
- if(second() < 10) lcd.print('0'); lcd.print(second()); // show current time
- lcd.setCursor(0,1); //second line
- String newTime = getInput('0','9', 6, true); // time input
- hh = (newTime.substring(0, 2)).toInt();
- mm = (newTime.substring(2, 4)).toInt();
- ss = (newTime.substring(4, 6)).toInt();
- if (isValidTime(hh, mm, ss)) {
- setTime(hh,mm,ss,dd,mo,yy); // set date time
- playOKTone();
- } else {
- DEBUG_PRINT("Invalid Time");
- lcd.clear(); lcd.print("Invalid Time");
- playWarningTone();
- delay(1000);
- }
-
- } else { // invalid date
- DEBUG_PRINT("Invalid Date");
- lcd.clear(); lcd.print("Invalid Date");
- playWarningTone();
- delay(1000);
- }
-
- lcd.noCursor(); // hide cursor
- }
-
- boolean isValidDate(byte dd, byte mo, byte yy) {
- boolean result = true;
- if (dd <1 || dd>31) result = false;
- if (mo <1 || mo>12) result = false;
- //if (yy <1970 || yy>2099) result = false;
- return result;
- }
- boolean isValidTime(byte hh, byte mm, byte ss) {
- boolean result = true;
- if (hh <1 || hh>23) result = false;
- if (mm <1 || mm>59) result = false;
- if (ss <1 || ss>59) result = false;
- return result;
- }
- ////////////////////////////////////////////////////////////////////////////////
- // monitoring a key is pressed
- // return true when idle for 10 seconds (defined by KEYBOARD_EVENT_TIMEOUT)
- ////////////////////////////////////////////////////////////////////////////////
- boolean isTimeout() {
- //user still able run the following code without blocking
- //1. press a switch to release door lock
- //2. press a swtich to ring the bell
- //3. use RFID to release door lock
- runEventAnyTime();
-
- if (millis() >= previousMillis + KEYBOARD_EVENT_TIMEOUT *1000){ //convert KEYBOARD_EVENT_TIMEOUT in milli second to second
- playTimeOutTone();
- return true;
- } else return false;
- }
- ////////////////////////////////////////////////////////////////////////////////
- // reset settings, write configuration to EEPROM
- /// press and hold button for 5 seconds (defined by HOLD_DELAY) to activate reset settings
- ////////////////////////////////////////////////////////////////////////////////
- void reset_settings() {
- unsigned long start_hold = millis(); // mark the time
- int HOLD_DELAY = 5000; // Sets the hold delay
- DEBUG_PRINTLN("Please keep on pressing for 5 sconds.");
- while (sw_state == LOW) {
- sw_state = digitalRead(reset_settings_pin ); // read input value
- if ((millis() - start_hold) >= HOLD_DELAY){ // for longer than HOLD_DELAY
- //initialize_is_running = true; // keep loop running even though reset_settings_pin is low
- initializeEEPROM();
- break; //break the loop after initialized
- }
- }
- }
- ////////////////////////////////////////////////////////////////////////////////
- // initialize EEPROM (write configuration)
- // syntax: eeprom_write_string(int addr, const char* string)
- // addr: the EEPROM address of Arduino, ATMega328 = 0 to 1023 (1024 Byte), ATmega168 = 512 Bytes
- ////////////////////////////////////////////////////////////////////////////////
- void initializeEEPROM(){
- strcpy(buf, "1234"); //set password to 1234
- eeprom_write_string(USER_PASSWORD_EEPROM_ADDRESS, buf); //write password to EEPROM
- strcpy(buf, "1234"); //set password to 1234
- eeprom_write_string(ADMIN_PASSWORD_EEPROM_ADDRESS, buf); //write password to EEPROM
- DEBUG_PRINTLN("Initialize completed");
- lcd.clear();
- lcd.print("Initialized.");
- delay(1000);
- playOKTone();
- }
-
-
- ////////////////////////////////////////////////////////////////////////////////
- // making sound to speaker, tone() function uses timer2
- // syntax: tone(pin, frequency, duration)
- // pin: the pin on which to generate the tone
- // frequency: the frequency of the tone in hertz - unsigned int
- // duration: the duration of the tone in milliseconds (optional) - unsigned long
- ////////////////////////////////////////////////////////////////////////////////
- void beep(){
- tone(MINI_SPEAKER_PIN,NOTE_C7,90);
- delay(20);
- noTone(MINI_SPEAKER_PIN);
- }
- void playTone(int note1, int note2, int note3, byte delayTime=100){
- tone(MINI_SPEAKER_PIN, note1, 90);
- delay(delayTime);
- tone(MINI_SPEAKER_PIN, note2, 90);
- delay(delayTime);
-
- tone(MINI_SPEAKER_PIN, note3, 190);
- delay(delayTime);
- noTone(MINI_SPEAKER_PIN);
- }
- void playOKTone(){
- playTone(NOTE_C5, NOTE_D5, NOTE_E5); //playing Do-Re-Mi
- }
- void playTimeOutTone(){
- playTone(NOTE_E5, NOTE_D5, NOTE_C5); //playing Mi-Re-Do
- }
- void playWarningTone(){
- playTone(NOTE_E5, NOTE_E5, NOTE_E5, 150); //Plaing Mi-Mi-Mi
- }
- ////////////////////////////////////////////////////////////////////////////////
- // play melody
- // http://arduino.cc/en/Tutorial/tone
- ////////////////////////////////////////////////////////////////////////////////
- // notes in the melody: Mi-Do-Re-So So-Re-Mi-Do
- int melody[] = { NOTE_E5, NOTE_C5, NOTE_D5, NOTE_G4, NOTE_G4, NOTE_D5, NOTE_E5, NOTE_C5, 0};
- // note durations: 4 = quarter note, 8 = eighth note, etc.:
- int noteDurations[] = { 4, 4, 4, 2, 8, 8, 8, 4, 8 };
- void playMelody() {
- isPlayingMelody = true; // indicating melody is playing
- stopPlayingMelody = false;
-
- for (int thisNote = 0; thisNote < 8; thisNote++) {
- runEventAnyTime(); // codes inside runEventAnyTime() will keep on updating
- print_date_time();
- if (stopPlayingMelody) break; //cause to exit "for loop" in order stop playing melody if lock is released
-
- // to calculate the note duration, take one second
- // divided by the note type.
- // e.g. quarter note = 1000 / 4, eighth note = 1000/8, etc.
- int noteDuration = 1000/noteDurations[thisNote];
- tone(BELL_PIN, melody[thisNote],noteDuration);
- // to distinguish the notes, set a minimum time between them.
- // the note's duration + 30% seems to work well:
- int pauseBetweenNotes = noteDuration * 1.30;
- delay(pauseBetweenNotes);
- // stop the tone playing:
- noTone(BELL_PIN);
- }
- isPlayingMelody = false;
- }
复制代码 本帖最后由 西门庆33 于 18-9-2013 12:25 AM 编辑
|
|
|
|
|
|
|
|
![](static/image/common/ico_lz.png)
楼主 |
发表于 18-9-2013 12:26 AM
|
显示全部楼层
为了增加一积份又把其余代码贴上![](static/image/smiley/default/lol.gif)
eeprom_string.h- extern boolean eeprom_read_string(int addr, char* buffer, int bufSize);
- extern boolean eeprom_write_string(int addr, const char* string);
复制代码 eeprom_string.ino- // http://playground.arduino.cc/Code/EepromUtil
- // EEPROM utility functions with usage example
- //
- // This example defines some utility functions
- // to write byte arrays, integers and strings
- // to eeprom and read them back.
- //
- // Some usage examples are provided.
- #include <Wire.h>
- #include <SL018.h>
- #include <EEPROM.h>
- //
- // Absolute min and max eeprom addresses.
- // Actual values are hardware-dependent.
- //
- // These values can be changed e.g. to protect
- // eeprom cells outside this range.
- //
- const int EEPROM_MIN_ADDR = 0;
- const int EEPROM_MAX_ADDR = 511;
- //
- // Returns true if the address is between the
- // minimum and maximum allowed values,
- // false otherwise.
- //
- // This function is used by the other, higher-level functions
- // to prevent bugs and runtime errors due to invalid addresses.
- //
- boolean eeprom_is_addr_ok(int addr) {
- return ((addr >= EEPROM_MIN_ADDR) && (addr <= EEPROM_MAX_ADDR));
- }
- //
- // Writes a sequence of bytes to eeprom starting at the specified address.
- // Returns true if the whole array is successfully written.
- // Returns false if the start or end addresses aren't between
- // the minimum and maximum allowed values.
- // When returning false, nothing gets written to eeprom.
- //
- boolean eeprom_write_bytes(int startAddr, const byte* array, int numBytes) {
- // counter
- int i;
- // both first byte and last byte addresses must fall within
- // the allowed range
- if (!eeprom_is_addr_ok(startAddr) || !eeprom_is_addr_ok(startAddr + numBytes)) {
- return false;
- }
- for (i = 0; i < numBytes; i++) {
- EEPROM.write(startAddr + i, array[i]);
- }
- return true;
- }
- //
- // Reads the specified number of bytes from the specified address into the provided buffer.
- // Returns true if all the bytes are successfully read.
- // Returns false if the star or end addresses aren't between
- // the minimum and maximum allowed values.
- // When returning false, the provided array is untouched.
- //
- // Note: the caller must ensure that array[] has enough space
- // to store at most numBytes bytes.
- //
- boolean eeprom_read_bytes(int startAddr, byte array[], int numBytes) {
- int i;
- // both first byte and last byte addresses must fall within
- // the allowed range
- if (!eeprom_is_addr_ok(startAddr) || !eeprom_is_addr_ok(startAddr + numBytes)) {
- return false;
- }
- for (i = 0; i < numBytes; i++) {
- array[i] = EEPROM.read(startAddr + i);
- }
- return true;
- }
- //
- // Writes an int variable at the specified address.
- // Returns true if the variable value is successfully written.
- // Returns false if the specified address is outside the
- // allowed range or too close to the maximum value
- // to store all of the bytes (an int variable requires
- // more than one byte).
- //
- boolean eeprom_write_int(int addr, int value) {
- byte *ptr;
- ptr = (byte*)&value;
- return eeprom_write_bytes(addr, ptr, sizeof(value));
- }
- //
- // Reads an integer value at the specified address.
- // Returns true if the variable is successfully read.
- // Returns false if the specified address is outside the
- // allowed range or too close to the maximum vlaue
- // to hold all of the bytes (an int variable requires
- // more than one byte).
- //
- boolean eeprom_read_int(int addr, int* value) {
- return eeprom_read_bytes(addr, (byte*)value, sizeof(int));
- }
- //
- // Writes a string starting at the specified address.
- // Returns true if the whole string is successfully written.
- // Returns false if the address of one or more bytes
- // fall outside the allowed range.
- // If false is returned, nothing gets written to the eeprom.
- //
- boolean eeprom_write_string(int addr, const char* string) {
- // actual number of bytes to be written
- int numBytes;
- // we'll need to write the string contents
- // plus the string terminator byte (0x00)
- numBytes = strlen(string) + 1;
- return eeprom_write_bytes(addr, (const byte*)string, numBytes);
- }
- //
- // Reads a string starting from the specified address.
- // Returns true if at least one byte (even only the
- // string terminator one) is read.
- // Returns false if the start address falls outside
- // or declare buffer size os zero.
- // the allowed range.
- // The reading might stop for several reasons:
- // - no more space in the provided buffer
- // - last eeprom address reached
- // - string terminator byte (0x00) encountered.
- // The last condition is what should normally occur.
- //
- boolean eeprom_read_string(int addr, char* buffer, int bufSize) {
- // byte read from eeprom
- byte ch;
- // number of bytes read so far
- int bytesRead;
- // check start address
- if (!eeprom_is_addr_ok(addr)) {
- return false;
- }
- // how can we store bytes in an empty buffer ?
- if (bufSize == 0) {
- return false;
- }
- // is there is room for the string terminator only,
- // no reason to go further
- if (bufSize == 1) {
- buffer[0] = 0;
- return true;
- }
- // initialize byte counter
- bytesRead = 0;
- // read next byte from eeprom
- ch = EEPROM.read(addr + bytesRead);
- // store it into the user buffer
- buffer[bytesRead] = ch;
- // increment byte counter
- bytesRead++;
- // stop conditions:
- // - the character just read is the string terminator one (0x00)
- // - we have filled the user buffer
- // - we have reached the last eeprom address
- while ( (ch != 0x00) && (bytesRead < bufSize) && ((addr + bytesRead) <= EEPROM_MAX_ADDR) ) {
- // if no stop condition is met, read the next byte from eeprom
- ch = EEPROM.read(addr + bytesRead);
- // store it into the user buffer
- buffer[bytesRead] = ch;
- // increment byte counter
- bytesRead++;
- }
- // make sure the user buffer has a string terminator
- // (0x00) as its last byte
- if ((ch != 0x00) && (bytesRead >= 1)) {
- buffer[bytesRead - 1] = 0;
- }
- return true;
- }
复制代码 matrixKeypad.h- // http://playground.arduino.cc/code/Keypad
- #define use4x4Keypad //comment this using 3x4 keypad
- #ifdef use4x4Keypad
- ////////////////////////////////////////////////////////////////////////////////
- // define 4x4 keyboard
- ////////////////////////////////////////////////////////////////////////////////
- const byte ROWS = 4; // Four rows
- const byte COLS = 4; // Four columns
- //Define the keymap
- char keys[ROWS][COLS] = {
- {'1','2','3','A'},
- {'4','5','6','B'},
- {'7','8','9','C'},
- {'*','0','#','D'}
- };
- byte rowPins[ROWS] = {6,7,8,9}; //connect to row pinouts
- byte colPins[COLS] = {2,3,4,5}; //connect to column pinouts
- #else
- ////////////////////////////////////////////////////////////////////////////////
- // define 3x4 keyboard
- ////////////////////////////////////////////////////////////////////////////////
- const byte ROWS = 4; //four rows
- const byte COLS = 3; //three columns
- char keys[ROWS][COLS] = {
- {'1','2','3'},
- {'4','5','6'},
- {'7','8','9'},
- {'*','0','#'}
- };
- byte rowPins[ROWS] = {8, 7, 6, 5}; //connect to the row pinouts of the keypad
- byte colPins[COLS] = {4, 3, 2}; //connect to the column pinouts of the keypad
- #endif
- //// Create the Keypad
- Keypad keypad = Keypad( makeKeymap(keys), rowPins, colPins, ROWS, COLS );
复制代码 pitches.h- // http://arduino.cc/en/Tutorial/tone
- #define NOTE_B0 31
- #define NOTE_C1 33
- #define NOTE_CS1 35
- #define NOTE_D1 37
- #define NOTE_DS1 39
- #define NOTE_E1 41
- #define NOTE_F1 44
- #define NOTE_FS1 46
- #define NOTE_G1 49
- #define NOTE_GS1 52
- #define NOTE_A1 55
- #define NOTE_AS1 58
- #define NOTE_B1 62
- #define NOTE_C2 65
- #define NOTE_CS2 69
- #define NOTE_D2 73
- #define NOTE_DS2 78
- #define NOTE_E2 82
- #define NOTE_F2 87
- #define NOTE_FS2 93
- #define NOTE_G2 98
- #define NOTE_GS2 104
- #define NOTE_A2 110
- #define NOTE_AS2 117
- #define NOTE_B2 123
- #define NOTE_C3 131
- #define NOTE_CS3 139
- #define NOTE_D3 147
- #define NOTE_DS3 156
- #define NOTE_E3 165
- #define NOTE_F3 175
- #define NOTE_FS3 185
- #define NOTE_G3 196
- #define NOTE_GS3 208
- #define NOTE_A3 220
- #define NOTE_AS3 233
- #define NOTE_B3 247
- #define NOTE_C4 262
- #define NOTE_CS4 277
- #define NOTE_D4 294
- #define NOTE_DS4 311
- #define NOTE_E4 330
- #define NOTE_F4 349
- #define NOTE_FS4 370
- #define NOTE_G4 392
- #define NOTE_GS4 415
- #define NOTE_A4 440
- #define NOTE_AS4 466
- #define NOTE_B4 494
- #define NOTE_C5 523
- #define NOTE_CS5 554
- #define NOTE_D5 587
- #define NOTE_DS5 622
- #define NOTE_E5 659
- #define NOTE_F5 698
- #define NOTE_FS5 740
- #define NOTE_G5 784
- #define NOTE_GS5 831
- #define NOTE_A5 880
- #define NOTE_AS5 932
- #define NOTE_B5 988
- #define NOTE_C6 1047
- #define NOTE_CS6 1109
- #define NOTE_D6 1175
- #define NOTE_DS6 1245
- #define NOTE_E6 1319
- #define NOTE_F6 1397
- #define NOTE_FS6 1480
- #define NOTE_G6 1568
- #define NOTE_GS6 1661
- #define NOTE_A6 1760
- #define NOTE_AS6 1865
- #define NOTE_B6 1976
- #define NOTE_C7 2093
- #define NOTE_CS7 2217
- #define NOTE_D7 2349
- #define NOTE_DS7 2489
- #define NOTE_E7 2637
- #define NOTE_F7 2794
- #define NOTE_FS7 2960
- #define NOTE_G7 3136
- #define NOTE_GS7 3322
- #define NOTE_A7 3520
- #define NOTE_AS7 3729
- #define NOTE_B7 3951
- #define NOTE_C8 4186
- #define NOTE_CS8 4435
- #define NOTE_D8 4699
- #define NOTE_DS8 4978
复制代码 本帖最后由 西门庆33 于 18-9-2013 12:32 AM 编辑
|
|
|
|
|
|
|
|
发表于 18-9-2013 11:43 AM
|
显示全部楼层
可以加进我之前家里alarm了。![](static/image/smiley/default/biggrin.gif) |
|
|
|
|
|
|
|
发表于 18-9-2013 10:30 PM
|
显示全部楼层
支持下大哥的帖子... 一流的东西啊... 等我的金鱼灯完成了就来玩玩这个东西... |
|
|
|
|
|
|
|
![](static/image/common/ico_lz.png)
楼主 |
发表于 20-9-2013 10:08 PM
|
显示全部楼层
wilson16 发表于 18-9-2013 11:43 AM ![](static/image/common/back.gif)
可以加进我之前家里alarm了。
是alarm clock还是security alarm?
如果是security alarm不太适合吧?不过也不是不能,反正LCD显示、keypad与密码认证都有了,添加几个输入(zone)就行了。
本帖最后由 西门庆33 于 20-9-2013 10:09 PM 编辑
|
|
|
|
|
|
|
|
![](static/image/common/ico_lz.png)
楼主 |
发表于 20-9-2013 10:12 PM
|
显示全部楼层
angels1026 发表于 18-9-2013 10:30 PM ![](static/image/common/back.gif)
支持下大哥的帖子... 一流的东西啊... 等我的金鱼灯完成了就来玩玩这个东西...
你的水族馆需要密码锁?![](static/image/smiley/default/shocked.gif)
|
|
|
|
|
|
|
|
![](static/image/common/ico_lz.png)
楼主 |
发表于 20-9-2013 10:33 PM
|
显示全部楼层
注明一下- boolean isValidDate(byte dd, byte mo, byte yy) {
- boolean result = true;
- if (dd <1 || dd>31) result = false;
- if (mo <1 || mo>12) result = false;
- //if (yy <1970 || yy>2099) result = false;
- return result;
- }
复制代码 上面代码没有月份及闰年(leap year)確认。要做这点,很简单巴了,每四年的二月就出现29曰,用modulo就行了。例:year % 4
如果得出结果是零时,二月就有29曰,否则就是28曰。
1、3、5、7、8月份则是31曰,剩下2、4、6、9、11是30曰 |
|
|
|
|
|
|
|
发表于 20-9-2013 11:17 PM
|
显示全部楼层
西门庆33 发表于 20-9-2013 10:08 PM ![](static/image/common/back.gif)
是alarm clock还是security alarm?
如果是security alarm不太适合吧?不过也不是不能,反正LCD显示、ke ...
其实你有很多功能已经符security alarm 了。![](static/image/smiley/default/loveliness.gif)
|
|
|
|
|
|
|
|
![](static/image/common/ico_lz.png)
楼主 |
发表于 23-9-2013 04:50 PM
|
显示全部楼层
有件事必须注意,微控制器的memory(内存)有限,Arduino UNO只有2KB,因此,编程时尽量节省memory。这个Arduino电子密码锁有一个缺点,就是使用了String(字串)。为什么使用String会是缺点呢?
其实String很好用,也容易使用,为了方便编程(应该是不想动脑胫 ),所以我就使用了String。
String可以用,但要看情况,如果是短时间内使用肯定没问题,如果是一年365天一直开机,且从来没有Reset过,这可能会造成当机。为何会这样呢?
String操作时,是使用动态分配内存方式(allocate memory dynamically),动态内存分配通常会导致内存碎片(memory fragmentation),在短时间内程序会运行正常,长时间使用下可能会耗尽memory而当机。
建议使用char array代替String |
|
|
|
|
|
|
|
发表于 23-11-2013 05:31 PM
|
显示全部楼层
|
|
|
|
|
|
|
![](static/image/common/ico_lz.png)
楼主 |
发表于 23-11-2013 09:59 PM
|
显示全部楼层
wilson16 发表于 23-11-2013 05:31 PM ![](static/image/common/back.gif)
Uploaded with ImageShack.us
注意33至39行,那儿有一系列include程序库,其中一些程序库是没有集成在Arduino软件里,必须来自网页下载,然后保存在libraries文件夹里。比如
LiquidCrystal_I2C.h
matrixKeypad.h
Time.h
|
|
|
|
|
|
|
|
发表于 24-11-2013 12:40 AM
|
显示全部楼层
那keypad 的libraries好像有问题。。。 |
|
|
|
|
|
|
|
发表于 24-11-2013 12:40 AM
|
显示全部楼层
西门庆33 发表于 23-11-2013 09:59 PM ![](static/image/common/back.gif)
注意33至39行,那儿有一系列include程序库,其中一些程序库是没有集成在Arduino软件里,必须来自网页下载 ...
那keypad 的libraries好像有问题。。。 |
|
|
|
|
|
|
|
|
![](static/image/common/ico_lz.png)
楼主 |
发表于 24-11-2013 08:38 AM
|
显示全部楼层
wilson16 发表于 24-11-2013 12:40 AM ![](static/image/common/back.gif)
是什么问题?
代码第九行,列出了keypad的程序库的下载与使用网址
http://playground.arduino.cc/code/Keypad
|
|
|
|
|
|
|
|
发表于 25-11-2013 01:05 AM
|
显示全部楼层
西门庆33 发表于 24-11-2013 08:38 AM ![](static/image/common/back.gif)
是什么问题?
代码第九行,列出了keypad的程序库的下载与使用网址
你直接开一个keypad 的example然后verify看看可以用吗?我试过verify有error。
![](http://img27.imageshack.us/img27/7756/or67.png)
Uploaded with ImageShack.us
|
|
|
|
|
|
|
|
![](static/image/common/ico_lz.png)
楼主 |
发表于 25-11-2013 09:55 AM
|
显示全部楼层
wilson16 发表于 25-11-2013 01:05 AM ![](static/image/common/back.gif)
你直接开一个keypad 的example然后verify看看可以用吗?我试过verify有error。
你的error message是keypad library没有安装或者安装错误。
记得keypad library一定要保存在libraries里,比如\My Documents\Arduino\libraries\keypad
|
|
|
|
|
|
|
| |
本周最热论坛帖子
|