بسم الله الرحمن الرحيم
في هذه التجربة سنقوم بتصميم نظام ذكـي للبوابات يتميز بالمواصفات التالية :
- يستخدم تقنية الـ RFID للتعرف على الاشخاص المسموح لهم بالدخول .
- يحسب عدد ساعات العمل لكل شخص عند الخروج .
- يمكن فتح البوابة من خلال البلوتوث للأجهزة الموثوقة .
- يمكن تغير وضع الجهاز ليفتح البوابة تلقائياً عن اقتراب شخص منه .
- يمكن وصله مع أنظمة الحماية, ليفتح البوابة مباشرة في حالات الطـوارئ .
• نحتاج الى :
- متحكم اردوينو (يفضل نوع ميجا ).
- قارئ بطاقات RFID13.56MHz , يمكن شراؤه من هـنـا.
- حساس حركة (PIR) , يمكن شراؤه من هـنـا .
- موديول بلوتوث , يمكن شراؤه من هـنـا.
- H-Bridge , يمكن شراؤه من هـنـا .
- Door Lock Actuator , يمكن شراؤه من هنا .
- مفتاح كهربائي (switch & push button ).
- شاشة LCD16x2 يمكن شراؤها من هـنـا .
- مقاومات .
- ليدات (LEDs).
- طنان كهربائي (buzzer).
- لوحة تجارب و اسلاك توصيل .
• وضـع RFID :
تتكون هذه التقنية ببساطة من ثلاثة أجزاء رئيسية هي:
- البطاقة التي تحتوي على جهاز الإرسال والمعلومات.
- جهاز القراءة والإرسال.
- برامج الحاسوب وقواعد البيانات.
تحتوى كل البطاقات (RFID tag) علي كود خاص مكون من خمسة خانات يتم بثها لاسلكيا بمجرد أن تقرب البطاقة من جهاز القراءة (RFID Reader) و تتعدد أشكال البطاقات و ألوانها على حسب الشركة المصنعة و الجهة التي تستخدمها
و جهاز القراءة هو من سيقرأ الكود الخاص بالبطاقة , ويرسله للآردوينو .
استخدمنا في هذه التجربة قارئ من نوع RFID-RC522 RF IC Card Sensor
يعتمد هذا الموديول على بروتوكول SPI للتواصل مع الاردوينو .
لذلك نصل هذا الموديول مع المداخل الخاصة بالـSPI في الاردوينو كالتالي :
لذلك نصل هذا الموديول مع المداخل الخاصة بالـSPI في الاردوينو كالتالي :
MOSI : Pin 11
MISO : Pin 12
SCK : Pin 13
SS : Pin 10
RST : Pin 9
اضغط على الصورة لتكبيرها |
- الموديول يعمل على 3.3V و ليس 5V !
- مخرج IRQ يترك بدون توصيل !
الموديول اصبح جاهزاً لبرمجتـه .
قم بتحميل المكتبة الخاصة بهذا الموديول من هـنـا .
ستقوم هذه المكتبة بقراءة البطاقة و تخزين الكود الخاص بها في مصفوفة مكونة من خمسة خانات اسمها rfid.serNum .
اذن يمكن قراءة رقم البطاقة و عرضها بسهولة (يمكن الاطلاع على الامثلة المرفقة بالمكتبة ) , لكن كيف سيتم التعرف على البطاقات الموثوقة , و كيف نحفظ وقت الدخول و الخروج ؟!
يجب ان يتم تخزين ارقام البطاقات الموثوقة مسبقاً في كود الاردوينو.
و عند قراءة اي بطاقة يقارنها الاردوينو مع ارقام البطاقات المخزنة , و في حال وجود تطابق تكون هذه البطاقة موثوقة و يُفتح لها الباب !
و يجب ايضأ تخزين وقت الدخول لهذه البطاقة , و عند الخروج نطرح وقت الخروج من وقت الدخول لمعرفة عدد ساعات العمل !
لاحظ انه يجب ايضاً تحديد حالة البطاقة (دخول أو خروج ) لتحديد الوظيفة التي سينفذها الاردوينو .
يبدو ان لدينا كمية كبيرة من البيانات يجب ان نتعامل معها , و اسهل طريقة لترتيبها هو وضعها في مصفوفة .( كما في الشكل ) .
نعمل مصفوفة مكونة من 7 صفوف , و اي عدد أعمدة تريد ( يجب ان يكون عدد الاعمدة اكبر من عدد البطاقات ) , كل عامود سيمثل ارقام البطاقة و بياناتها .
اول خمسة صفوف ستحتوي على رقم البطاقة .
الصف السادس سيحتوي على حالة البطاقة ( 1=في الداخل , 0 = في الخارج).
الصف السابع يحتوي على زمن الدخول .
هذا مثلاً كود عمل مصفوفة مكونة من 7 صفوف و 50 عامود اسمها Employee .
int Employee[7][50];
و لنخزن في العامود الاول رقم البطاقة الاولى في اول خمسة صفوف .
(العد في لغة C++ يبدأ من الصفر , أي ان العامود الاول رقمه 0 )
Employee[0][0] =110; Employee[1][0] =241; Employee[2][0] =127; Employee[3][0] =161; Employee[4][0] =65;
و لنجعل الاردوينو يقارن رقم بطاقة معينة مع ارقام البطاقات المخزنة ( في rfid.serNum ذكرناها سابقا) .
سنستخدم جملة For للمرور على جميع الأعمدة ...
و جملة IF لمقارنة ارقام البطاقت معاً ..
كالآتي :
سنستخدم جملة For للمرور على جميع الأعمدة ...
و جملة IF لمقارنة ارقام البطاقت معاً ..
كالآتي :
for ( Employee_Number=0 ; Employee_Number<50 ; Employee_Number++ ) { if( Employee[0][Employee_Number] == rfid.serNum[0]&& Employee[1][Employee_Number] == rfid.serNum[1]&& Employee[2][Employee_Number] == rfid.serNum[2]&& Employee[3][Employee_Number] == rfid.serNum[3]&& Employee[4][Employee_Number] == rfid.serNum[4]) { //do something break ;} } }
اذاً .. عند تقريب بطاقة مـا من الموديول , يقرأ الاردوينو ارقام هذة البطاقة و يخزنها في (rfid.serNum ) , ثم يدخل الى جملة For و يبدأ بمقارنة هذه الارقام مع الارقام المخزنة
في مصفوفة (Employee).
اذا لـم يجد تطابق (يعني البطاقة ليست موثوقة ) لا يقم بعمل شيء .
اما اذا وجد تطابق مع احد البطاقات المخزنة , يقوم اولاً بفتح الباب , ثم و حسب حالة البطاقة ينفذ وظيفة معينة .
اذا كانت حالة البطاقة دخول : سيخزن زمن الدخول , و يعرض Welcome و رقم الموظف على الشاشة !
اما اذا كانت حالة البطاقة خروج : سيطرح زمن الدخول من الوقت الحالي و يعرض وقت العمل على الشاشة .
يمكن تنفيذ ذلك من خلال الكود التالي :
- قيمة X هي رقم البطاقة التي حصل عندها التطابق.
اذا لـم يجد تطابق (يعني البطاقة ليست موثوقة ) لا يقم بعمل شيء .
اما اذا وجد تطابق مع احد البطاقات المخزنة , يقوم اولاً بفتح الباب , ثم و حسب حالة البطاقة ينفذ وظيفة معينة .
اذا كانت حالة البطاقة دخول : سيخزن زمن الدخول , و يعرض Welcome و رقم الموظف على الشاشة !
اما اذا كانت حالة البطاقة خروج : سيطرح زمن الدخول من الوقت الحالي و يعرض وقت العمل على الشاشة .
يمكن تنفيذ ذلك من خلال الكود التالي :
- قيمة X هي رقم البطاقة التي حصل عندها التطابق.
void a(int x){ digitalWrite(buzzer,1);//تنبيه بسيط delay(100); digitalWrite(buzzer,0); delay(100); digitalWrite(LED_1,0); if (Employee[5][x] == 0) { Employee[5][x] = 1; Employee[6][x] = (millis()/60000 ); lcd.clear() ; lcd.setCursor(0, 0); lcd.print("WELCOME : "); lcd.setCursor(10, 0); lcd.print(x); OPEN(); delay(3000); CLOSE(); } else if (Employee[5][x] == 1) { Employee[5][x] = 0; start_time = Employee[6][x] ; now = millis()/60000; work_time = now - start_time ; Employee[6][x] = 0; lcd.clear() ; lcd.setCursor(0, 0); lcd.print("GOODBYE : "); lcd.setCursor(0, 1); lcd.print(work_time); lcd.setCursor(10, 0); lcd.print(x); lcd.setCursor(8, 1); lcd.print("minute"); OPEN(); delay(3000); CLOSE(); } }
يجب ان نتذكر ان هذا النظام يمكن تشغيله باكثر من وضع ( وضع الطوارئ وضع حساس الحركة , البلوتوث ) ,و يتم التنقل بينهم من خلال المفاتيح , لذلك يجب ان نتأكد من حالة المفاتيح قبل ان يعمل كود الـ RFID ..
في هذا الوضع ستفتح البوابة تلقائاً عند اقتراب شخص منها .
عن وجود حركة (اقتراب شخص ) سيعطي الحساس اشارة (HIGH) , ثم يقوم الاردوينو بقتح البوابة لمدة زمنية ثم اغلاقها .
• وضع PIR :
في هذا الوضع ستفتح البوابة تلقائاً عند اقتراب شخص منها .
عن وجود حركة (اقتراب شخص ) سيعطي الحساس اشارة (HIGH) , ثم يقوم الاردوينو بقتح البوابة لمدة زمنية ثم اغلاقها .
- اولاً يتأكد من انه لا توجد اشارة طوارئ (button) .
- يتأكد ان المفتاح على وضع الـ PIR .
- يعرض على الشاشة الوضع الحالي .
- الحساس موصول على المدخل A3 .
while( digitalRead(button)== LOW && digitalRead(main_button)== HIGH ){ lcd.clear() ; lcd.print("Smart Door System"); lcd.setCursor(0, 1); lcd.print(" PIR"); if (digitalRead(A3)){ OPEN(); delay(10000); CLOSE(); } delay(1000); }
• وضع البلوتوث :
وضع البلوتوث يعمل مع وضع الـ RFID , و الهدف منه هو تجاوز حماية الـRFID و فتح البوابة دون الحاجة لبطاقة .
توصيل موديول البلوتوث كالتالي :
و يمكن اختيار اي تطبيق لاستخامه . في تطبيق Blue Control مثلاً سوف نستخدم الزر في الوسط لفتح البوابة . ( سيرسل التطبيق حرف C عند الضغط عليه )
- لاحظ ان موديول البلوتوث موصول على المداخل 0 و1 الخاصة بالتواصل التسلسلي في الآردوينو , لذلك يجب فصلها عند تحميل الكود على الاردوينو .
if (Serial.available()) { int data = Serial.read(); if ( data == 'C' ){ OPEN(); delay(3000); CLOSE(); } }
• وضع الطوارئ :
ببساطة سيقوم الاردوينو في هذا الوضع بفتح البوابة حال وجود اشارة طوارئ .
في هذه التجربة اشارة الطوارئ قادمة من مفتاح كهربائي (push button) , لكن يمكن ربط الجهاز مباشرة مع انظمة الحماية في المبنى .
while(digitalRead(button)== HIGH){ E_OPEN(); digitalWrite(LED_1,1); digitalWrite(buzzer,1); delay(50); digitalWrite(LED_1,0); digitalWrite(buzzer,0); delay(50); lcd.clear() ; lcd.setCursor(0, 0); lcd.print("Emergency"); }
• قفل البوابة
لإغلاق و فتح البوابة سنتحكم بالقفل الخاص بها , باستخدام Door Lock Actuator الخاص بأقفال السيارات .و هو عبارة عن محرك 12V موصول بآلية معينة لتحويل حركته الدائرية لحركة افقية .
سنتحكم به من خلال H-Bridge بالاتجاهين للداخل و الخارج .
و يتم توصيله كالتالي :
اضغط على الصورة لتكبيرها |
و الآن سنكتب كود لفتح البوابة و اغلاقها ..
- بعد اغلاق او فتح القفل سيستمر المحرك بسحب تيار لكن بدون حركة , و بالتالي تبدأ حرارته و حرارة الـ H-Bridge بالارتفاع , لذلك يجب قطع التيار عنهم بعد مدة قصيرة ( هذا سبب استخدام void OFF )!
- IN1 و IN2 موصولين على A4 و A5 في الاردوينو
void CLOSE (){ // void this part to close the door . digitalWrite(IN1,1); digitalWrite(IN2,0); delay(100); OFF(); } void OPEN (){ // void this part to open the door . digitalWrite(IN1,0); digitalWrite(IN2,1); delay(100); OFF(); } void OFF (){ digitalWrite(IN1,0); digitalWrite(IN2,0); } void E_OPEN (){ // emergency open // void this part to open the door . digitalWrite(IN1,0); digitalWrite(IN2,1); }
شاهـــــــد النتيجـــــــة
كــود الاردوينــو كــامــلاً
توصيلات الشاشة و الأضواء(LEDs) و الـBuzzer واضحة من خلال الكود .
// Smart Door System. // Ali Hadabeen 2014. // http://ali-madness.blogspot.com/
/*
* MOSI: Pin 11 / ICSP-4 * MISO: Pin 12 / ICSP-1 * SCK: Pin 13 / ISCP-3 * SS: Pin 10 * RST: Pin 9 */ #include <SPI.h> #include <RFID.h> #include <LiquidCrystal.h> // Setup variables: int Employee[7][50]; int Employee_Number; int new_Employee =1 ; float start_time ; float now ; float work_time ; boolean door_state = false ; #define SS_PIN 10 #define RST_PIN 9 #define buzzer A1 #define LED_1 A0 #define button 8 #define main_button A2 const int IN1=A4; const int IN2=A5; RFID rfid(SS_PIN, RST_PIN); LiquidCrystal lcd(2, 3, 4, 5, 6, 7); void setup() { Serial.begin(9600); lcd.begin(16, 2); lcd.clear() ; SPI.begin(); rfid.init(); pinMode(LED_1 ,OUTPUT); pinMode(button ,INPUT); pinMode(buzzer ,OUTPUT); //-----CARD_1--------- Employee[0][0] =110; Employee[1][0] =241; Employee[2][0] =127; Employee[3][0] =161; Employee[4][0] =65; //-----CARD_2--------- Employee[0][1] =253; Employee[1][1] =109; Employee[2][1] =196; Employee[3][1] =234; Employee[4][1] =190; //-----CARD_3--------- Employee[0][2] =77; Employee[1][2] =78; Employee[2][2] =228; Employee[3][2] =198; Employee[4][2] =33; lcd.clear() ; lcd.print("Smart Door System"); CLOSE(); } void loop() { CLOSE(); lcd.clear() ; lcd.print("Smart Door System"); lcd.setCursor(0, 1); lcd.print(" RFID"); while(digitalRead(button)== LOW && digitalRead(main_button)== LOW){ //---------------------------------- if (Serial.available()) { int data = Serial.read(); if ( data == 'C' ){ OPEN(); delay(3000); CLOSE(); } } //---------------------------------- int time =millis(); if (time > now+10000){ lcd.clear() ; lcd.print("Smart Door System"); lcd.setCursor(0, 1); lcd.print(" RFID");} digitalWrite(LED_1,0); if (rfid.isCard()) { if (rfid.readCardSerial()) { //Serial.println("card read"); } for ( Employee_Number=0 ; Employee_Number<15 ; Employee_Number++ ) { if( Employee[0][Employee_Number] == rfid.serNum[0]&& Employee[1][Employee_Number] == rfid.serNum[1]&& Employee[2][Employee_Number] == rfid.serNum[2]&& Employee[3][Employee_Number] == rfid.serNum[3]&& Employee[4][Employee_Number] == rfid.serNum[4]) { a(Employee_Number); delay (1000); break ;} } } rfid.halt(); } while( digitalRead(button)== LOW && digitalRead(main_button)== HIGH ){ lcd.clear() ; lcd.print("Smart Door System"); lcd.setCursor(0, 1); lcd.print(" PIR"); if (digitalRead(A3)){ OPEN(); delay(10000); CLOSE(); } delay(1000); } while(digitalRead(button)== HIGH){ E_OPEN(); digitalWrite(LED_1,1); digitalWrite(buzzer,1); delay(50); digitalWrite(LED_1,0); digitalWrite(buzzer,0); delay(50); lcd.clear() ; lcd.setCursor(0, 0); lcd.print("Emergency"); } } //-------------------------------------- void a(int x){ digitalWrite(buzzer,1); delay(100); digitalWrite(buzzer,0); delay(100); digitalWrite(LED_1,0); if (Employee[5][x] == 0) { Employee[5][x] = 1; Employee[6][x] = (millis()/60000 ); lcd.clear() ; lcd.setCursor(0, 0); lcd.print("WELCOME : "); lcd.setCursor(10, 0); lcd.print(x); OPEN(); delay(3000); CLOSE(); } else if (Employee[5][x] == 1) { Employee[5][x] = 0; start_time = Employee[6][x] ; now = millis()/60000; work_time = now - start_time ; Employee[6][x] = 0; lcd.clear() ; lcd.setCursor(0, 0); lcd.print("GOODBYE : "); lcd.setCursor(0, 1); lcd.print(work_time); lcd.setCursor(10, 0); lcd.print(x); lcd.setCursor(8, 1); lcd.print("minute"); OPEN(); delay(3000); CLOSE(); } } void CLOSE (){ // void this part to open the door . digitalWrite(IN1,1); digitalWrite(IN2,0); delay(100); OFF(); } void OPEN (){ // void this part to open the door . digitalWrite(IN1,0); digitalWrite(IN2,1); delay(100); OFF(); } void OFF (){ // void this part to open the door . digitalWrite(IN1,0); digitalWrite(IN2,0); } void E_OPEN (){ // void this part to open the door . digitalWrite(IN1,0); digitalWrite(IN2,1); }
• اقـرأ ايضاً :
كتاب [ تقنيات الاختراق المادي ]
لـ عبدالله علي عبدالله .
يحتوي هذا الكتاب على فصل كامل يتحدث فيه عن اقفال الـ RFID و كيفية تجاوزها
و فيه معلومات اخرى مهمة و ممتعة :) .
يمكن تحميله من هــنــا .
يمكنك ايضاً اضافة حساس بصمة الاصبع للنظام , لتتمكن من فتح البوابة مباشرة من خلال التعرف على بصمة الاصبع !
هذا مقال لصديقنا مهنـد الرواشدة , يشرح فيه طريقة عمل الحساس بالتفصيل .
من هــنــا !