4
Η κατασκευή αυτή προέκυψε απο την ανάγκη προστασίας ενός χώρου με εργαλεία και ειδικά εργαλεία
αφ' ενός κατά τη διάρκεια όλης της ημέρας, αλλά και αφ' ετέρου για να υπάρχει κάποιος υποτυπώδης
έλεγχος εισόδου στον χώρο κατά το μή εργάσιμο ωράριο. Στηρίζεται σε έναν ATmega328P μικροελεγκτή,
ο οποίος τρέχει το πρόγραμμά του στημένο σε περιβάλλον Arduino (Uno για την ακρίβεια).
Επειδή με πίεζε ο χρόνος, έφτιαξα την "πλακέτα" σε διάτρητη, με τις συνδέσεις pin to pin με το χέρι.
Το project, εκτός του μ/ε, περιλαμβάνει μια οθόνη 2x16 χαρακτήρων, ένα πληκτρολόγιο 4x4 κουμπιών
matrix, τα ενδεικτικά LEDs για τροφοδοσία, κλείδωμα και ξεκλείδωμα και ένα buzzer για το ηχητικό
feedback των πλήκτρων, λίγη μουσική (!) και ήχους για τις καταστάσεις του συστήματος.
Ένα αρκετά ενδιαφέρον σημείο για μένα, ήταν η οδήγηση της οθόνης με σειριακό τρόπο (I²C) για
εξοικονόμηση pins που θα χρειαζόντουσαν για την σάρωση του πληκτρολογίου. Και μια και υπάρχει
αυτή η δυνατότητα, ο χρήστης μπορεί να έχει και ρολόϊ πραγματικού χρόνου με ένα M41T80 RTC.
Οι πρώτες φωτογραφίες ακολουθούν, καθώς και ο κώδικας σε σκετσάκι για Arduino:
Σημείωση: ο κώδικας υπολείπεται μερικών λεπτομερειών, όπως τη ρύθμιση του ρολογιού,Κώδικας:#include <Wire.h> #include <Keypad.h> #include <LiquidCrystal_I2C.h> #include <EEPROM.h> #include "pitches.h" //================================================================================= #define LOCKED 9 #define UNLOCKED 10 #define LOCKER_PIN 8 #define BUZZER_PIN 11 //================================================================================= LiquidCrystal_I2C lcd(0x38,16,2); // set the LCD address to 0x20 for a 16 chars and 2 line display const byte ROWS = 4; //four rows const byte COLS = 4; //four columns //define the cymbols on the buttons of the keypads char hexaKeys[ROWS][COLS] = { {'1','2','3','A'}, {'4','5','6','B'}, {'7','8','9','C'}, {'*','0','#','D'} }; byte rowPins[ROWS] = {4, 5, 6, 7}; //connect to the row pinouts of the keypad byte colPins[COLS] = {0, 1, 2, 3}; //connect to the column pinouts of the keypad Keypad customKeypad = Keypad( makeKeymap(hexaKeys), rowPins, colPins, ROWS, COLS); const char* MESSAGE = " PLACE HERE ANY TEXT YOY WANT "; const int MESSAGE_LENGTH = XX;//NUMBER IS EQUAL TO THE ABOVE STRING const int DISPLAY_WIDTH = 16; int g_nPosition = 0; int line = 1; int counter; int melody_1[] = {NOTE_C4, NOTE_G3,NOTE_G3, NOTE_A3, NOTE_G3,0, NOTE_B3, NOTE_C4}; int noteDurations_1[] = {4, 8, 8, 4,4,4,4,4 }; int Dixie[] = {NOTE_A4, NOTE_B4, NOTE_C4, NOTE_D4, NOTE_E4, NOTE_F4, NOTE_G4}; int DixieDurations[] = {16,16,16,16,16,16,16,16}; //================================================================================= void setup() { counter=0; pinMode(LOCKED, OUTPUT); pinMode(UNLOCKED, OUTPUT); pinMode(LOCKER_PIN, OUTPUT); pinMode(BUZZER_PIN, OUTPUT); digitalWrite(LOCKED, HIGH); digitalWrite(UNLOCKED, LOW); digitalWrite(LOCKER_PIN, LOW); lcd.init(); // initialize the lcd // Print a message to the LCD. lcd.backlight(); lcd.print(F("TOOLS WHAREHOUSE")); lcd.setCursor(0,1); lcd.print(F(" M.E.N. /2 ")); delay(2000); lcd.clear(); lcd.print(F(" WELCOME! ")); delay(2000); if(ReadPassFromEEPROM()==25755) { //Password is blank so store a default password WritePassToEEPROM(1234); } } //================================================================================= void loop() { unsigned int password, customKey; password = InputNumber("ENTER PASSWORD: "); //Match Password if(password == ReadPassFromEEPROM()) { // music(Dixie, DixieDurations); music(melody_1, noteDurations_1); lcd.noBlink(); lcd.clear(); lcd.print(F("DOOR UNLOCKED!")); counter = 0; //Now Activate Relay digitalWrite(LOCKED, LOW); digitalWrite(UNLOCKED, HIGH); digitalWrite(LOCKER_PIN, HIGH); delay(2000); lcd.clear(); lcd.print(F("PRESS ANY KEY...")); delay(3000); digitalWrite(LOCKER_PIN, LOW); repeatScroll(); while(customKeypad.getKey() == NO_KEY) { delay(1); } beepBuzzer(); //Now DeActivate Relay digitalWrite(LOCKER_PIN, LOW); digitalWrite(LOCKED, HIGH); digitalWrite(UNLOCKED, LOW); } else if(password == 0) { /* If user enters 0000 as password it indicates a request to change password */ lcd.clear(); password=InputNumber(" OLD PASSWORD: "); if(password==ReadPassFromEEPROM()) { //Allowed to change password unsigned int NewPassword; NewPassword=InputNumber(" NEW PASSWORD: "); WritePassToEEPROM(NewPassword); lcd.clear(); lcd.print(F(" NEW PASSWORD ")); lcd.setCursor(0,1); lcd.print(F(" ENTERED! ")); quadBuzzer(); delay(2000); } else { //Not Allowed to change password lcd.clear(); quadBuzzer(); lcd.print(F(" WRONG ")); lcd.setCursor(0,1); lcd.print(F("PASSWORD ENTERED")); delay(2000); } } else { lcd.noBlink(); lcd.clear(); quadBuzzer(); lcd.print(F(" ACCESS DENIED! ")); digitalWrite(LOCKER_PIN, LOW); counter++; if(counter==3) { counter=0; lcd.clear(); lcd.print(F("YOU HAVE TO WAIT")); lcd.setCursor(0,1); lcd.print(F("60 SECS! SORRY..")); delay(60000); quadBuzzer(); } delay(2000); } } //================================================================================= void buzz(int msec) { int y; for(y=80; y>0; y--) { digitalWrite(BUZZER_PIN, HIGH); // set the LED on delayMicroseconds(400); // wait for a second digitalWrite(BUZZER_PIN, LOW); // set the LED off delayMicroseconds(400); // wait for a second } } //================================================================================= void quadBuzzer() { buzz(500); delay(50); buzz(500); delay(50); buzz(500); delay(50); buzz(500); delay(50); buzz(500); } //================================================================================= void beepBuzzer() { int y; for(y=20; y>0; y--) { digitalWrite(BUZZER_PIN, HIGH); // set the LED on delayMicroseconds(800); // wait for a second digitalWrite(BUZZER_PIN, LOW); // set the LED off delayMicroseconds(800); // wait for a second } digitalWrite(BUZZER_PIN, LOW); } //================================================================================= unsigned int InputNumber(char *msg) { unsigned int keyCode,x,pos,customKey; unsigned int prev_key = 0xFF; while(1) { x=0; pos=0; lcd.clear(); lcd.print(msg); lcd.setCursor(0,1); lcd.print("____"); lcd.setCursor(0,1); lcd.blink(); unsigned char key[] = "####"; unsigned int system_reset = 0; unsigned int backlight_timeout = 16000; while(!system_reset) { if(backlight_timeout>0) { backlight_timeout--; if(backlight_timeout==0) { lcd.noBacklight(); } } // delay(500); customKey = customKeypad.getKey(); keyCode = customKey; //Get the keycode of pressed key if(keyCode == prev_key) continue; else if(keyCode == NO_KEY) { prev_key=0xFF; continue; } else { prev_key=keyCode; } if(keyCode!=0xFF) { lcd.backlight(); backlight_timeout=16000; } if(pos==4) { lcd.setCursor(3,1); lcd.blink(); while(1) { // delay(500); customKey = customKeypad.getKey(); keyCode = customKey; if(keyCode == '#')//4 { break; } } return(((1000*key[0])+(100*key[1])+(10*key[2])+key[3])); //save the password in 16 bit integer lcd.clear(); } switch (keyCode) //generating key characeter to display on LCD { case '1': beepBuzzer(); lcd.setCursor(pos,1); lcd.print("*"); key[x]=1; ++x; pos++; break; case '2': beepBuzzer(); lcd.setCursor(pos,1); lcd.print("*"); key[x]=2; ++x; pos++; break; case '3': beepBuzzer(); lcd.setCursor(pos,1); lcd.print("*"); key[x]=3; ++x; pos++; break; case '4': beepBuzzer(); lcd.setCursor(pos,1); lcd.print("*"); key[x]=4; ++x; pos++; break; case '5': beepBuzzer(); lcd.setCursor(pos,1); lcd.print("*"); key[x]=5; ++x; pos++; break; case '6': beepBuzzer(); lcd.setCursor(pos,1); lcd.print("*"); key[x]=6; ++x; pos++; break; case '7': beepBuzzer(); lcd.setCursor(pos,1); lcd.print("*"); key[x]=7; ++x; pos++; break; case '8': beepBuzzer(); lcd.setCursor(pos,1); lcd.print("*"); key[x]=8; ++x; pos++; break; case '9': beepBuzzer(); lcd.setCursor(pos,1); lcd.print("*"); key[x]=9; ++x; pos++; break; case '0': beepBuzzer(); lcd.setCursor(pos,1); lcd.print("*"); key[x]=0; ++x; pos++; break; case '*': beepBuzzer(); system_reset=1; break; case 'A': beepBuzzer(); lcd.clear(); lcd.print(F("LAST ENTRY WAS: ")); lcd.setCursor(0,1); lcd.print(F("< TIME STAMP> ")); delay(5000); system_reset=1; break; case 'B': beepBuzzer(); lcd.clear(); lcd.print(F("<TIME>")); lcd.setCursor(0,1); lcd.print(F("<DATE>")); lcd.noBlink(); delay(5000); system_reset=1; break; case 'C': beepBuzzer(); lcd.clear(); lcd.print(F(" TIME/DATE ")); lcd.setCursor(0,1); lcd.print(F(" SETTINGS ")); delay(5000); system_reset=1; break; default: ; } delay(150); } } } //================================================================================= void WritePassToEEPROM(unsigned int pass) { EEPROM.write(0,(pass%100)); EEPROM.write(1,(pass/100)); } //================================================================================= unsigned int ReadPassFromEEPROM() { return (EEPROM.read(1)*100 + EEPROM.read(0000)); } //================================================================================= void repeatScroll() { do { scrollDisplay(1); }while(customKeypad.getKey() == NO_KEY) ; } //================================================================================= void scrollDisplay(int line) { int i; if(g_nPosition < MESSAGE_LENGTH - DISPLAY_WIDTH) { for(i=0; i<DISPLAY_WIDTH; i++) { lcd.setCursor(i, line); lcd.print(MESSAGE[g_nPosition + i]); } } else { int nChars = MESSAGE_LENGTH - g_nPosition; for(i=0; i<nChars; i++) { lcd.setCursor(i, line); lcd.print(MESSAGE[g_nPosition + i]); } for(i=0; i<(DISPLAY_WIDTH - nChars); i++) { lcd.setCursor(nChars + i, line); lcd.print(MESSAGE[i]); } } g_nPosition++; if(g_nPosition >= MESSAGE_LENGTH) { g_nPosition = 0; } delay(180); } //================================================================================= void music(int* melody, int* noteDurations) { for (int thisNote = 0; thisNote < 8; thisNote++) { // 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(BUZZER_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(8); } }
την ένδειξη της τελευταίας εισόδου στο χώρο και της ένδειξης του ρολογιού.
Η κατασκευή έχει τη δυνατότητα να παίζει και μουσική! Υπάρχει ένα header file, που περιέχει
πληροφορίες για την οδήγηση ενός digital pin με συχνότητα (όχι PWM) και ενός buzzer. Με την
εισαγωγή του σωστού κωδικού και το ξεκλείδωμα, παίζει ένα μικρό ηχητικό (λίγο cartoon βέβαια!)
για την επιβεβαίωση του ξεκλειδώματος.
Όλα τα αρχεία (lock.ino, pitches.h, καθώς και η βιβλιοθήκη LiquidCrystal_I2C.h) θα ανεβούν σε λίγο
σε zip file.
Είναι σχεδόν εντελώς ασχολίαστος ο κώδικας, αλλά η βιασύνη βλέπετε... Στο μέλλον,
ίσως κάτσω να τον σχολιάσω...