نحوهی کار آر اف آی دی و چگونگی ساخت قفل درب آر اف آی دی بر اساس آردوینو
در این آموزش قصد داریم به مواردی چون: آر اف ای دی چیست ؟، چگونه کار میکند و چگونه یک قفل درب RFID بر اساس آردوینو بسازم، بپردازیم.
بررسی اجمالی: آر اف ای دی چیست ؟
RFID مخفف عبارت Radio Frequency Identification به معنای شناسایی از طریق امواج رادیویی است و یک فناوری غیر تماسی است که به طور گسترده در صنایع برای مواردی چون ردیابی پرسنل، کنترل دسترسی، مدیریت زنجیره تأمین، ردیابی کتابها در کتابخانه، سیستمهای پرداخت عوارض (tollgate) و غیره استفاده میگردد.
نحوهی عملکرد RFID
یک سیستم RFID شامل دو عنصر اصلی است، یک فرستنده یا برچسبی قرار گیرنده روی جسمی که میخواهیم شناخته شود و یک گیرنده یا تجهیزاتی برای خواندن برچسب.
برچسب خوان RFID خود از اجزای مقابل تشکیل شده است. یک ماژول فرکانس رادیویی، یک بخش کنترلی و یک سیم پیچ آنتن که میدان الکترومغناطیسی فرکانس بالا تولید میکند. از سوی دیگر، برچسب معمولاً یک عنصر پسیو (Passive) است که تنها از یک آنتن و یک میکرو چیپ تشکیل شده است؛ بنابراین، هنگامی که به میدان الکترومغناطیسی گیرنده نزدیک میشود، به دلیل ایجاد القای مغناطیسی، ولتاژی در سیم پیچ آنتن تولید میشود و این ولتاژ، به عنوان ورودی توسط میکرو چیپ مورد بهره برداری قرار میگیرد.
حال که برچسب توان لازم را دریافت کرده است، میتواند پیام ارسالی از طرف رادار را انتقال دهد و برای ارسال پیام به رادار از روشی به نام دستکاری بار استفاده میکند. روشن و خاموش کردن بار در آنتن برچسب، روی توان مصرفی برچسب خوان اثر گذار است، به طوری که میتواند به عنوان افت ولتاژ اندازه گیری شود. این تغییرات در ولتاژ به صورت صفر و یک در نظر گرفته میشود و به این ترتیب دادهها از برچسب به برچسب خوان انتقال مییابد.
همچنین راه دیگری برای انتقال دادهها بین برچسب و برچسب خوان وجود دارد که تزویج پس پراکنده (backscattered coupling) نام دارد. در این حالت، برچسب از بخشی از توان دریافت شده برای تشکیل میدان الکترومغناطیسی دیگری استفاده میکند که توسط آنتن برچسب خوان انتخاب میشود.
RFID و آردوینو
تا اینجا اصول پایهای نحوهی کار تشریح شد و حال میتوانیم به بررسی نحوهی استفاده از RFID در کنار آردوینو بپردازیم و قفل درب RFID خودمان را بسازیم. ما از برچسبهایی بر پایهی پروتکل MIFARE و برچسب خوان MFRC522 RFID که قیمت نسبتاً پایینی دارند استفاده میکنیم. همچنین از یک آردوینو نانو استفاده میکنیم که در پروژه های آموزش رباتیک کاربرد زیادی خواهد داشت.
این برچسبها حافظهای 1 کیلو بایتی دارند و از میکرو چیپی با قابلیت محاسبهی عملگرهای حسابی بهره میبرند. فرکانس کاری آنها 13.56 مگاهرتز و فاصلهای که در آن قادر به عملکرد صحیح هستند بیش از 10 سانتی متر بسته به هندسهی آنتن است. اگر یکی از این برچسبها را در مقابل نور قرار دهیم، میتوانیم آنتن و میکرو چیپی که در قبل در مورد آنها صحبت کردیم ببینیم.
ذکر این نکته در مورد ماژول برچسب خوان RFID که از پروتکل SPI برای برقراری ارتباط با برد آردوینو استفاده میکند و موارد مربوط به نحوهی اتصال آنها ضروری به نظر میرسد. توجه داشته باشید که باید Vcc ماژول را به 3.3 ولت متصل کنیم. در مورد سایر پینها، نیازی به نگرانی نیست چرا که تا 5 ولت، قابلیت تحمل دارند.
در صورت نیاز، برای اتصال ماژول، میتوانیم کتابخانهی MFRC522 را از GitHub دانلود کنیم. این کتابخانه شامل چندین مثال خوب برای درک بیشتر نحوهی استفاده از ماژول است. در ابتدا، میتوانیم از بارگذاری مثال “DumpInfo” استفاده کنیم و این موضوع که آیا سیستم ما درست کار میکند یا خیر را بررسی کنیم. حال اگر مانیتور سریال را اجرا کنیم و برچسب را نزدیک ماژول کنیم، برچسب خوان شروع به خواندن برچسب میکند و تمام اطلاعات از برچسب روی مانیتور سریال به نمایش گذاشته خواهد شد.
در اینجا باید به این نکته توجه داشت که شماره UID برچسب و تقسیم حافظهی 1 کیلوبایتی به 16 بخش از اهمیت بالایی برخوردار است. این 16 بخش هرکدام به 4 بلوک تقسیم میشوند که هر بلوک میتواند 2 بایت داده در خود ذخیره کند. برای این آموزش ما از هیچ یک از حافظههای برچسب استفاده نخواهیم کرد و تنها به استفاده از شمارهی UID برچسب بسنده خواهیم کرد.
پروژهی کنترل دسترسی قفل درب RFID با آردوینو
قبل از اینکه کد پروژهی قفل درب RFID را مرور کنیم، نگاهی به اجزا و نمودارهای مدار این پروژه خواهیم داشت.
علاوه بر ماژول RFID، از یک حسگر مجاورت برای بررسی بسته یا باز بودن درب، یک سروو موتور برای ساز و کار قفل درب و یک نمایشگر کاراکتر بهره میبریم.
این پروژه به طور کلی مقابل روال زیر دنبال خواهد شد: در ابتدا، یک برچسب اصلی را تنظیم خواهیم کرد و پس از آن سیستم وارد حالت عادی خواهد شد. اگر یک برچسب ناشناخته را اسکن کنیم، دسترسی محدود خواهد شد اما اگر برچسب اصلی را اسکن کنیم وارد حالت برنامه میشویم و میتوانیم در این حالت برچسب ناشناخته را اضافه و مجاز کنیم؛ بنابراین اگر دوباره برچسب را اسکن کنیم، امکان دسترسی فراهم میشود تا بتوانیم درب را باز کنیم.
پس از بسته شدن درب، به صورت خودکار اقدام به قفل شدن میکند. اگر بخواهیم برچسبی را از سیستم حذف کنیم، کافی است مجدداً به حالت برنامه برویم و برچسب شناخته شده را اسکن کنیم.
کد منبع
حال زمان آن رسیده است که نگاهی به کد بیندازیم؛ بنابراین در اولین گام، باید کتابخانههایی برای ماژول RFID، نمایشگر و سروو موتور بیابیم که متغیرهای مورد نیاز را برای برنامهی زیر تعریف کند و همچنین نمونههای کتابخانهها را ایجاد کند.
#include <SPI.h> #include <MFRC522.h> #include <LiquidCrystal.h> #include <Servo.h> #define RST_PIN 9 #define SS_PIN 10 byte readCard[4]; char* myTags[100] = {}; int tagsCount = 0; String tagID = ""; boolean successRead = false; boolean correctTag = false; int proximitySensor; boolean doorOpened = false; // Create instances MFRC522 mfrc522(SS_PIN, RST_PIN); LiquidCrystal lcd(2, 3, 4, 5, 6, 7); //Parameters: (rs, enable, d4, d5, d6, d7) Servo myServo; // Servo motor
در بخش تنظیمات، ابتدا ماژولها را مقداردهی اولیه میکنیم و مقدار اولیه سروو موتور را در موقعیت قفل تنظیم میکنیم. سپس، پیام اولیه را بر روی صفحه نمایش چاپ میکنیم و با حلقه “while” زیر منتظر میمانیم تا یک برچسب اصلی اسکن شود. تابع سفارشی getID برچسب UID را دریافت میکند و ما آن را در اولین مکان آرایه [0] myTags قرار میدهیم.
void setup() { // Initiating SPI.begin(); // SPI bus mfrc522.PCD_Init(); // MFRC522 lcd.begin(16, 2); // LCD screen myServo.attach(8); // Servo motor myServo.write(10); // Initial lock position of the servo motor // Prints the initial message lcd.print("-No Master Tag!-"); lcd.setCursor(0, 1); lcd.print(" SCAN NOW"); // Waits until a master card is scanned while (!successRead) { successRead = getID(); if ( successRead == true) { myTags[tagsCount] = strdup(tagID.c_str()); // Sets the master tag into position 0 in the array lcd.clear(); lcd.setCursor(0, 0); lcd.print("Master Tag Set!"); tagsCount++; } } successRead = false; printNormalModeMessage(); }
در ادامه به بررسی تابع getID() خواهیم پرداخت. این تابع، این موضوع را بررسی میکند که آیا برچسب جدیدی در کنار برچسب خوان قرار گرفته است یا خیر و در این صورت، به حلقهی “for” که UID برچسب را در اختیار میگذارد، ادامه میدهیم. برچسبهایی که از آن ها استفاده میکنیم، شمارهی UID 4 بایتی دارند که دقیقاً به همین دلیل هم هست که ما به چهار تکرار در این حلقه نیاز داریم و از یک تابع concat() استفاده میکنیم که 4 بایت را در یک متغیر رشته جداگانه قرار میدهد. همچنین، همة کاراکترهای رشته را با حروف بزرگ انگلیسی تنظیم میکنیم و در پایان عملیات خواندن را متوقف میکنیم.
uint8_t getID() { // Getting ready for Reading PICCs if ( ! mfrc522.PICC_IsNewCardPresent()) { //If a new PICC placed to RFID reader continue return 0; } if ( ! mfrc522.PICC_ReadCardSerial()) { //Since a PICC placed get Serial and continue return 0; } tagID = ""; for ( uint8_t i = 0; i < 4; i++) { // The MIFARE PICCs that we use have 4 byte UID readCard[i] = mfrc522.uid.uidByte[i]; tagID.concat(String(mfrc522.uid.uidByte[i], HEX)); // Adds the 4 bytes in a single String variable } tagID.toUpperCase(); mfrc522.PICC_HaltA(); // Stop reading return 1; }
قبل از اینکه وارد حلقة اصلی شویم، در پایان بخش تنظیمات، تابع printNormalModeMessage() را نیز فراخوانی میکنیم که پیام “Access Control” را روی نمایشگر نشان میدهد.
void printNormalModeMessage() { delay(1500); lcd.clear(); lcd.print("-Access Control-"); lcd.setCursor(0, 1); lcd.print(" Scan Your Tag!"); }
در حلقة اصلی، با خواندن مقادیر حسگر مجاورت کار را آغاز میکنیم که به ما اطلاع میدهد که آیا در بسته است یا خیر.
int proximitySensor = analogRead(A0);
بنابراین اگر در بسته باشد، با استفاده از همین خطوط که در تابع getID() تشریح شد، فرایند اسکن کردن آغاز خواهد شد و UID را از برچسب جدید دریافت میکنیم. باید توجه داشته باشید که در اینجا، کد اقدام جدیدی انجام نمیدهد مگر اینکه یک برچسب اسکن شود و این به دلیل قرار گرفتن “return” در عبارت “if” است.
به محض اینکه از برچسب اسکن بگیریم، باید بررسی شود که آیا برچسب اسکن گرفته شده، برچسب اصلی که قبلاً آن را به ثبت رسانده بودیم است یا خیر و اگر درست است، وارد فضای برنامه خواهیم شد. در این حالت، اگر برچسب مجاز را اسکن کنیم، از سیستم حذف میشود یا اگر برچسب ناشناخته است به عنوان مجاز به سیستم اضافه میشود.
// Checks whether the scanned tag is the master tag if (tagID == myTags[0]) { lcd.clear(); lcd.print("Program mode:"); lcd.setCursor(0, 1); lcd.print("Add/Remove Tag"); while (!successRead) { successRead = getID(); if ( successRead == true) { for (int i = 0; i < 100; i++) { if (tagID == myTags[i]) { myTags[i] = ""; lcd.clear(); lcd.setCursor(0, 0); lcd.print(" Tag Removed!"); printNormalModeMessage(); return; } } myTags[tagsCount] = strdup(tagID.c_str()); lcd.clear(); lcd.setCursor(0, 0); lcd.print(" Tag Added!"); printNormalModeMessage(); tagsCount++; return; } } }
در خارج از حالت برنامه، با حلقه بعدی “for” بررسی میکنیم که آیا برچسب اسکن شده برابر با هر یک از برچسبهای ثبت شده است یا اینکه در را باز میکنیم یا دسترسی را محروم میکنیم. در انتهای عبارت “else” منتظر میمانیم تا در بسته شود، سپس در را قفل میکنیم و پیام حالت عادی را دوباره چاپ میکنیم.
// Checks whether the scanned tag is authorized for (int i = 0; i < 100; i++) { if (tagID == myTags[i]) { lcd.clear(); lcd.setCursor(0, 0); lcd.print(" Access Granted!"); myServo.write(170); // Unlocks the door printNormalModeMessage(); correctTag = true; } } if (correctTag == false) { lcd.clear(); lcd.setCursor(0, 0); lcd.print(" Access Denied!"); printNormalModeMessage(); } } // If door is open... else { lcd.clear(); lcd.setCursor(0, 0); lcd.print(" Door Opened!"); while (!doorOpened) { proximitySensor = analogRead(A0); if (proximitySensor > 200) { doorOpened = true; } } doorOpened = false; delay(500); myServo.write(10); // Locks the door printNormalModeMessage(); }
بنابراین تقریباً پروژه به اتمام رسید و کد کامل آن مطابق زیر است:
/* * Arduino Door Lock Access Control Project * * Library: MFRC522, https://github.com/miguelbalboa/rfid */ #include <SPI.h> #include <MFRC522.h> #include <LiquidCrystal.h> #include <Servo.h> #define RST_PIN 9 #define SS_PIN 10 byte readCard[4]; char* myTags[100] = {}; int tagsCount = 0; String tagID = ""; boolean successRead = false; boolean correctTag = false; int proximitySensor; boolean doorOpened = false; // Create instances MFRC522 mfrc522(SS_PIN, RST_PIN); LiquidCrystal lcd(2, 3, 4, 5, 6, 7); //Parameters: (rs, enable, d4, d5, d6, d7) Servo myServo; // Servo motor void setup() { // Initiating SPI.begin(); // SPI bus mfrc522.PCD_Init(); // MFRC522 lcd.begin(16, 2); // LCD screen myServo.attach(8); // Servo motor myServo.write(10); // Initial lock position of the servo motor // Prints the initial message lcd.print("-No Master Tag!-"); lcd.setCursor(0, 1); lcd.print(" SCAN NOW"); // Waits until a master card is scanned while (!successRead) { successRead = getID(); if ( successRead == true) { myTags[tagsCount] = strdup(tagID.c_str()); // Sets the master tag into position 0 in the array lcd.clear(); lcd.setCursor(0, 0); lcd.print("Master Tag Set!"); tagsCount++; } } successRead = false; printNormalModeMessage(); } void loop() { int proximitySensor = analogRead(A0); // If door is closed... if (proximitySensor > 200) { if ( ! mfrc522.PICC_IsNewCardPresent()) { //If a new PICC placed to RFID reader continue return; } if ( ! mfrc522.PICC_ReadCardSerial()) { //Since a PICC placed get Serial and continue return; } tagID = ""; // The MIFARE PICCs that we use have 4 byte UID for ( uint8_t i = 0; i < 4; i++) { // readCard[i] = mfrc522.uid.uidByte[i]; tagID.concat(String(mfrc522.uid.uidByte[i], HEX)); // Adds the 4 bytes in a single String variable } tagID.toUpperCase(); mfrc522.PICC_HaltA(); // Stop reading correctTag = false; // Checks whether the scanned tag is the master tag if (tagID == myTags[0]) { lcd.clear(); lcd.print("Program mode:"); lcd.setCursor(0, 1); lcd.print("Add/Remove Tag"); while (!successRead) { successRead = getID(); if ( successRead == true) { for (int i = 0; i < 100; i++) { if (tagID == myTags[i]) { myTags[i] = ""; lcd.clear(); lcd.setCursor(0, 0); lcd.print(" Tag Removed!"); printNormalModeMessage(); return; } } myTags[tagsCount] = strdup(tagID.c_str()); lcd.clear(); lcd.setCursor(0, 0); lcd.print(" Tag Added!"); printNormalModeMessage(); tagsCount++; return; } } } successRead = false; // Checks whether the scanned tag is authorized for (int i = 0; i < 100; i++) { if (tagID == myTags[i]) { lcd.clear(); lcd.setCursor(0, 0); lcd.print(" Access Granted!"); myServo.write(170); // Unlocks the door printNormalModeMessage(); correctTag = true; } } if (correctTag == false) { lcd.clear(); lcd.setCursor(0, 0); lcd.print(" Access Denied!"); printNormalModeMessage(); } } // If door is open... else { lcd.clear(); lcd.setCursor(0, 0); lcd.print(" Door Opened!"); while (!doorOpened) { proximitySensor = analogRead(A0); if (proximitySensor > 200) { doorOpened = true; } } doorOpened = false; delay(500); myServo.write(10); // Locks the door printNormalModeMessage(); } } uint8_t getID() { // Getting ready for Reading PICCs if ( ! mfrc522.PICC_IsNewCardPresent()) { //If a new PICC placed to RFID reader continue return 0; } if ( ! mfrc522.PICC_ReadCardSerial()) { //Since a PICC placed get Serial and continue return 0; } tagID = ""; for ( uint8_t i = 0; i < 4; i++) { // The MIFARE PICCs that we use have 4 byte UID readCard[i] = mfrc522.uid.uidByte[i]; tagID.concat(String(mfrc522.uid.uidByte[i], HEX)); // Adds the 4 bytes in a single String variable } tagID.toUpperCase(); mfrc522.PICC_HaltA(); // Stop reading return 1; } void printNormalModeMessage() { delay(1500); lcd.clear(); lcd.print("-Access Control-"); lcd.setCursor(0, 1); lcd.print(" Scan Your Tag!"); }