风筝
发表于: 2018-11-14 22:12:34 | 显示全部楼层

在本篇文章中,我们将学习到RFID是什么,它是如何工作的以及如何制作基于Arduino开发板的RFID智能门锁。RFID的全称是Radio Frequency IDentification,中文名叫做射频识别,它是一种非接触式技术,广泛应用于许多行业,用于人员跟踪、访问控制、供应链管理、图书馆书籍跟踪、收费系统等任务。

RFID-applications-and-uses.jpg


RFID是如何工作的?

RFID系统由两个主要部件组成,一个应答器或位于我们想要识别的物体上的标签,以及收发器或读卡器。

RFID-How-It-Works.jpg

RFID读卡器包括一个射频模块、一个控制单元和产生高频电磁场的天线线圈。在另一边,标签通常是无源元件,仅由天线和电子微芯片组成,因此当它靠近读卡器的电磁场时,由于感应,在其天线线圈中产生电压,这电压作为微芯片的电源。

RFID-Working-Principle.png

现在,当标签被供电时,它可以从读卡器中提取传输的消息,并且为了将消息发送回读卡器,它使用一种称为加载操作的技术。打开和关闭标签天线处的负载将影响读取器天线的功耗,可以测量为电压降。这种电压变化将被捕获为1和0,这就是数据从标签传输到读卡器的方式。


读卡器和标签之间还有另一种数据传输方式,称为反向散射耦合。在这种情况下,标签使用部分接收功率来产生另一个电磁场,该电磁场将被读卡器的天线拾取。


RFID和Arduino开发板

以上就是基本的工作原理,现在我们来看看如何使用RFID和Arduino开发板构建我们自己的RFID门锁。我们将使用基于MIFARE协议和MFRC522 RFID读卡器的标签,价格仅为几美元。

RFID-and-Arduino-Tutorial.jpg

这些标签有1kb的内存,并有一个可以进行算术运算的微芯片。它们的工作频率为13.56 MHz,工作距离可达10 cm,具体取决于天线的几何形状。如果我们将它们带到光照前面,就可以注意到上面谈到的天线和微芯片。

RFID-Tag-Inside-Antenna-and-Microchip.jpg

至于RFID读卡器模块,它使用SPI协议与Arduino开发板进行通信,这就是我们需要连接它们的方式。请注意,我们必须将模块的VCC连接到3.3V,而对于其他引脚,我们不必担心,它们是5V耐压的。

Arduino-and-MFRC522-RFID-Reader-Module-Circuit-Schematic.png

连接模块后,我们需要从GitHub下载MFRC522库。该库附带了几个很好的例子,我们可以从中学习如何使用该模块。


首先,我们可以上传“DumpInfo”示例并测试我们的系统是否正常工作。现在,如果我们运行串口监视器并将标签带到模块附近,读卡器将开始读取标签,标签上的所有信息都将显示在串口监视器上。

Arduino-MFRC522-library-Dumpinfo-Example.jpg

这里我们可以注意到标签的UID号以及1 KB的内存,实际上分为16个扇区,每个扇区分成4个块,每个块可以存储2个字节的数据。在本篇文章中,我们不会使用任何标记的内存,我们只使用标记的UID编号。


基于Arduino的RFID门锁控制示例

在我们开始编写RFID门锁的代码之前,来看看该示例的组件和电路原理图。

Arduino-RFID-Door-Lock-Access-Control-Project.png


除RFID模块外,我们还将使用一个接近传感器来检测门是否关闭或打开、以及锁定机构的伺服电机和字符显示器。

此示例所需的组件如下:

●    MFRC522 RFID模块

●    伺服电机

●    液晶显示屏

●    Arduino开发板

●    面包板和跳线

●    接近传感器CNY70


示例的工作流程如下:首先,我们必须设置主标签,然后系统进入正常模式。如果我们扫描未知标签,访问将被拒绝,但如果我们扫描主设备,我们将进入程序模式,我们可以从中添加和授权未知标签。所以,现在如果我们再次扫描标签,将授予访问权限,以便我们可以打开门。

Arduino-RFID-Door-Lock-Access-Control-Project.jpg

我们关门后门会自动锁上。如果我们想要从系统中删除标签,我们只需要再次进入程序模式,扫描已知标签并将其删除。


代码

现在让我们来看看代码。首先,我们需要包括RFID模块、显示屏和伺服电机的库,定义下面程序所需的一些变量,以及创建库的实例。

  1. #include <SPI.h>
  2. #include <MFRC522.h>
  3. #include <LiquidCrystal.h>
  4. #include <Servo.h>
  5. #define RST_PIN   9
  6. #define SS_PIN    10
  7. byte readCard[4];
  8. char* myTags[100] = {};
  9. int tagsCount = 0;
  10. String tagID = "";
  11. boolean successRead = false;
  12. boolean correctTag = false;
  13. int proximitySensor;
  14. boolean doorOpened = false;
  15. // Create instances
  16. MFRC522 mfrc522(SS_PIN, RST_PIN);
  17. LiquidCrystal lcd(2, 3, 4, 5, 6, 7); //Parameters: (rs, enable, d4, d5, d6, d7)
  18. Servo myServo; // Servo motor
复制代码

在setup函数部分,首先我们初始化模块,并将伺服电机的初始值设置到锁定位置。 然后我们将初始消息打印到显示屏,然后使用以下“while”循环,我们等待扫描主标签。 getID()自定义函数获取标记UID,我们将其放入myTags [0]数组的第一个位置。

  1. void setup() {
  2.   // Initiating
  3.   SPI.begin();        // SPI bus
  4.   mfrc522.PCD_Init(); //  MFRC522
  5.   lcd.begin(16, 2);   // LCD screen
  6.   myServo.attach(8);  // Servo motor
  7.   myServo.write(10); // Initial lock position of the servo motor
  8.   // Prints the initial message
  9.   lcd.print("-No Master Tag!-");
  10.   lcd.setCursor(0, 1);
  11.   lcd.print("    SCAN NOW");
  12.   // Waits until a master card is scanned
  13.   while (!successRead) {
  14.     successRead = getID();
  15.     if ( successRead == true) {
  16.       myTags[tagsCount] = strdup(tagID.c_str()); // Sets the master tag into position 0 in the array
  17.       lcd.clear();
  18.       lcd.setCursor(0, 0);
  19.       lcd.print("Master Tag Set!");
  20.       tagsCount++;
  21.     }
  22.   }
  23.   successRead = false;
  24.   printNormalModeMessage();
  25. }
复制代码

我们来看看getID()自定义函数。 首先,它检查读卡器附近是否有新标签,如果有,我们将继续“for”循环,这将获得标签的UID。 我们使用的标签有4个字节的UID编号,这就是我们需要用这个循环进行4次迭代的原因,并且使用concat()函数我们将4个字节添加到单个String变量中。 我们还将字符串的所有字符设置为大写字母,最后我们停止读取。

  1. uint8_t getID() {
  2.   // Getting ready for Reading PICCs
  3.   if ( ! mfrc522.PICC_IsNewCardPresent()) { //If a new PICC placed to RFID reader continue
  4.     return 0;
  5.   }
  6.   if ( ! mfrc522.PICC_ReadCardSerial()) {   //Since a PICC placed get Serial and continue
  7.     return 0;
  8.   }
  9.   tagID = "";
  10.   for ( uint8_t i = 0; i < 4; i++) {  // The MIFARE PICCs that we use have 4 byte UID
  11.     readCard[i] = mfrc522.uid.uidByte[i];
  12.     tagID.concat(String(mfrc522.uid.uidByte[i], HEX)); // Adds the 4 bytes in a single String variable
  13.   }
  14.   tagID.toUpperCase();
  15.   mfrc522.PICC_HaltA(); // Stop reading
  16.   return 1;
  17. }
复制代码

在我们进入主循环之前,在setup函数部分的末尾,我们还调用printNormalModeMessage()自定义函数,该函数在显示器上打印“Access Control”消息。

  1. void printNormalModeMessage() {
  2.   delay(1500);
  3.   lcd.clear();
  4.   lcd.print("-Access Control-");
  5.   lcd.setCursor(0, 1);
  6.   lcd.print(" Scan Your Tag!");
  7. }
复制代码

在主循环中,我们首先读取接近传感器的值,它告诉我们门是否关闭。

  1. int proximitySensor = analogRead(A0);
复制代码

因此,如果门是关着的,使用与我们在getID()自定义函数中描述的相同的行,我们将扫描并获取新标记的UID。 我们在这里可以注意到,由于“if”语句中的“return”行,在我们扫描标签之前代码将不再继续。

  1. // Checks whether the scanned tag is the master tag
  2.     if (tagID == myTags[0]) {
  3.       lcd.clear();
  4.       lcd.print("Program mode:");
  5.       lcd.setCursor(0, 1);
  6.       lcd.print("Add/Remove Tag");
  7.       while (!successRead) {
  8.         successRead = getID();
  9.         if ( successRead == true) {
  10.           for (int i = 0; i < 100; i++) {
  11.             if (tagID == myTags[i]) {
  12.               myTags[i] = "";
  13.               lcd.clear();
  14.               lcd.setCursor(0, 0);
  15.               lcd.print("  Tag Removed!");
  16.               printNormalModeMessage();
  17.               return;
  18.             }
  19.           }
  20.           myTags[tagsCount] = strdup(tagID.c_str());
  21.           lcd.clear();
  22.           lcd.setCursor(0, 0);
  23.           lcd.print("   Tag Added!");
  24.           printNormalModeMessage();
  25.           tagsCount++;
  26.           return;
  27.         }
  28.       }
  29.     }
复制代码

一旦我们扫描了标签,我们检查该标签是否是我们之前注册的主标签,如果确实如此,我们将进入程序模式。 在此模式下,如果我们扫描已经授权的标签,它将从系统中删除,或者如果标签未知,它将被授权添加到系统中。

  1. // Checks whether the scanned tag is the master tag
  2.     if (tagID == myTags[0]) {
  3.       lcd.clear();
  4.       lcd.print("Program mode:");
  5.       lcd.setCursor(0, 1);
  6.       lcd.print("Add/Remove Tag");
  7.       while (!successRead) {
  8.         successRead = getID();
  9.         if ( successRead == true) {
  10.           for (int i = 0; i < 100; i++) {
  11.             if (tagID == myTags[i]) {
  12.               myTags[i] = "";
  13.               lcd.clear();
  14.               lcd.setCursor(0, 0);
  15.               lcd.print("  Tag Removed!");
  16.               printNormalModeMessage();
  17.               return;
  18.             }
  19.           }
  20.           myTags[tagsCount] = strdup(tagID.c_str());
  21.           lcd.clear();
  22.           lcd.setCursor(0, 0);
  23.           lcd.print("   Tag Added!");
  24.           printNormalModeMessage();
  25.           tagsCount++;
  26.           return;
  27.         }
  28.       }
  29.     }
复制代码

在程序模式之外,通过下一个“for”循环,我们检查扫描的标签是否与任何已注册的标签相同,我们要么解锁门,要么拒绝访问。 在“else”语句的最后,我们等到门关闭,然后我们锁门并再次打印正常模式消息。

  1. // Checks whether the scanned tag is authorized
  2.     for (int i = 0; i < 100; i++) {
  3.       if (tagID == myTags[i]) {
  4.         lcd.clear();
  5.         lcd.setCursor(0, 0);
  6.         lcd.print(" Access Granted!");
  7.         myServo.write(170); // Unlocks the door
  8.         printNormalModeMessage();
  9.         correctTag = true;
  10.       }
  11.     }
  12.     if (correctTag == false) {
  13.       lcd.clear();
  14.       lcd.setCursor(0, 0);
  15.       lcd.print(" Access Denied!");
  16.       printNormalModeMessage();
  17.     }
  18.   }
  19.   // If door is open...
  20.   else {
  21.     lcd.clear();
  22.     lcd.setCursor(0, 0);
  23.     lcd.print(" Door Opened!");
  24.     while (!doorOpened) {
  25.       proximitySensor = analogRead(A0);
  26.       if (proximitySensor > 200) {
  27.         doorOpened = true;
  28.       }
  29.     }
  30.     doorOpened = false;
  31.     delay(500);
  32.     myServo.write(10); // Locks the door
  33.     printNormalModeMessage();
  34.   }
复制代码

以上就是本篇文章的全部内容,如果有任何问题,欢迎在本帖下面进行回复。

跳转到指定楼层
sky
发表于: 2018-12-16 17:20:56 | 显示全部楼层

Arduino 驱动显示编译有误
回复

使用道具 举报

fenghanjie
发表于: 2024-8-20 17:19:38 | 显示全部楼层

请问id存在eeprom中没呢?
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

主题 714 | 回复: 1501



手机版|

GMT+8, 2024-12-21 20:29 , Processed in 0.058360 second(s), 9 queries , Gzip On, MemCache On. Powered by Discuz! X3.5

YiBoard一板网 © 2015-2022 地址:河北省石家庄市长安区高营大街 ( 冀ICP备18020117号 )

快速回复 返回顶部 返回列表