什么是RFID?
“RFID表示射频识别,[…]RFID的作用与信用卡或者ATM卡背面的条形码或磁条相同;它为物体提供了唯一的标识符。而且,就像必须扫描条形码或词条才能获取信息一样,RFID设备必须经过扫描才能获取相关的识别信息。”– 摘自©Technovelgy,一个记录科学技术与科幻创意的网站。
在本项目中通过使用RFID技术来从RFID标签中读取数据,并将信息发送到MCU的非易失性存储器。从标签读取的ID与存储的信息进行比较,如果匹配,则门将被解锁/打开。
硬件
- Arduino Nano
- RFID RC522
- 压电蜂鸣器
- 2x LED
- 2x 330 电阻
- 4×4 键盘
- LCD适配器I2C
- LCD16X2BL
软件
- Arduino IDE
- SketchUp
- Github
将LCD 连接到Arduino
LCD有16个引脚,对于Arduino Nano来说引脚数量过多,因此一定要使用I2C适配器,如此一来可以仅通过Arduino的两个信号引脚来实现显示功能。这很有帮助,因为这种情况下需要通过MCU控制的引脚数量就会很少。
图1:LCD引脚
LCD具有并行接口,这意味着MCU必须同时操控多个接口引脚来对显示进行控制。下表提供了每个引脚的说明:
图2:引脚规格
首先,我们将在LCD和I2C之间建立连接。为此,我们需要一个I2C LCD显示适配器(LCD1602)。该适配器将16 x 2字符LCD显示转换为串行I2C LCD,仅用两根导线连接即可通过Arduino进行控制。
图3:Arduino和LCD之间的连接
接下来,我们将在Arduino IDE中添加库“<LiquidCrystal_I2C.h>”。我们可以通过该库将LCD连接到Arduino。内置的LiquidCrystal_I2C库可以轻松实现在LCD屏幕上显示字母。
您可以点击此处下载LiquidCrystal_I2C.h。
请按照以下步骤将新的库安装到您的Arduino IDE中:
1) 首先,从Github上下载文件(我将要下载的是Keypad库)。
2) 压缩(.zip)每个文件夹。
3) 拷贝.zip文件到您的Arduino文件夹中。
4) 打开Arduino并添加Keypad.zip::Sketch menu > Include Library > Add .ZIP Library。
5) 添加keypad库:Sketch menu > Include Library > Keypad.
测试LCD的代码:
- #include <Wire.h>
- #include <LiquidCrystal_I2C.h>
- LiquidCrystal_I2C lcd(0x27, 16, 2); // Set the LCD address to 0x27 for a 16 chars and 2 line display
- void setup() {
- lcd.begin();// initialize the LCD
- lcd.backlight();// Turn on the blacklight and print a message.
- lcd.backlight();
- lcd.print("Hello, world!");
- }
- void loop() {
- }
图4:连接到Arduino Nano的LCD
连接键盘
现在,要进入键盘部分了!我们将要对键盘进行连接,以实现在LCD上显示从键盘输入的数字。
Keypad.h 是一个让Arduino能够从键盘读取矩阵类型键盘数据的库。
在本教程中我使用的是一个 4×4 键盘。
下表显示了Arduino开发板与键盘之间的连接情况。键盘引脚连接到Arduino的数字输出引脚。D6引脚是PWM引脚,因此用于蜂鸣器。
Keypad pin | Arduino pin |
1 | D2 |
2 | D3 |
3 | D4 |
4 | D5 |
5 | A0 |
6 | D7 |
7 | D8 |
图5:Arduino、LCD以及键盘之间的连接
图6:连接到Arduino的LCD和键盘
连接RFID
接下来,我们将添加RFID。在这种情况下,RFID板使用SPI通信协议,其中Arduino将作为主机,而RFID阅读器将作为从机。读卡器和标签将被设计为以13.56MHz大小的频率进行通信。
这是很重要的一步,因为RFID会帮助我们从卡上读取数据,并且确定ID是否对应于EEPROM中存储的信息。如果匹配,我们就能够进入房间并显示“解锁”。否则,LCD将显示“锁定”。
图7: Arduino、LCD以及RFID之间的连接
图8: Arduino、LCD以及RFID
添加蜂鸣器以及LED
下一步是添加一个蜂鸣器和2个LED,以模拟被控制访问系统的状况。请查看下面的接线图(图9)。我们设置了一个蜂鸣器,可以在获得访问权限(解锁)时蜂鸣。锁定时,红色LED始终亮起,解锁时,绿色LED会亮起。
为了保护这些设备模块,我决定用3D打印制造出收纳的盒子。如果您没有3D打印机,可以使用一个可以盛放所有组件的塑料盒。这会很有帮助,因为这样一来这些模块将会被放置于内部,只有LED、键盘和LCD会放置在盒子外。
图9:Nano、 LCD、键盘、RFID和蜂鸣器连接接线图
制造收纳的盒子
对于本项目,我想要制造一个自定义的盒子来收纳所有的组件,并保护这些组件不被损坏。
我使用SketchUp设计了一个盒子,这个软件具有用户友好型界面,有一些简单的操作按钮,如橡皮擦、线条和卷尺工具等。
盒子的尺寸是 120x125x37 mm。
如果您对Sketchup不熟悉,建议您点击此处阅读一些Sketchup教程。
图10:收纳盒子(顶部视图)
图11:收纳盒子(底部视图)
设计盒子时,我考虑了以下尺寸:
- 顶部视图:
- • 2 个用于LED的开口 (5.2 mm)
- • 1 个用于LCD的开口 (42.2×7.3 mm)
- • 1 个用于线缆的开口(16×10.5 mm)span>
- • 2 个用于LED的开口 (5.2 mm)
- 底部视图
- • 1 个用于键盘的开口(27×10 mm)
- • 1 个用于键盘的开口(27×10 mm)
图12:内部装有模块的完整收纳盒
代码流程图
完整代码
- #include <SPI.h>
- #include <MFRC522.h>
- #include <Wire.h>
- #include <LiquidCrystal_I2C.h>
- #include <Keypad.h>
- #include<EEPROM.h>
- int relPin;
- int state=0;
- byte COD[10];
- byte AUX[10];
- int k=0;
- String accessCode="*123456#";
- String codpairing="*654321#";
- //NFC
- #define RST_PIN 9
- #define SS_PIN 10
- MFRC522 mfrc522(SS_PIN, RST_PIN); // Create MFRC522 instance
- #define NEW_UID {0xDE, 0xAD, 0xBE, 0xEF}
- MFRC522::MIFARE_Key key;
- //LCD
- LiquidCrystal_I2C lcd(0x27,16,2);
- //KEYPAD
- const byte numRows= 4; //number of rows on the keypad
- const byte numCols= 4; //number of columns on the keypad
- char keymap[numRows][numCols]=
- {
- {'1', '2', '3', 'A'},
- {'4', '5', '6', 'B'},
- {'7', '8', '9', 'C'},
- {'*', '0', '#', 'D'}
- };
- //Code that shows the the keypad connections to the arduino terminals
- byte rowPins[numRows] = {2,3,4,5}; //Rows 0 to 3
- byte colPins[numCols]= {A0,7,8,9}; //Columns 0 to 3
- //initializes an instance of the Keypad class
- Keypad myKeypad= Keypad(makeKeymap(keymap), rowPins, colPins, numRows, numCols);
- void setup() {
- pinMode(A0,OUTPUT);
- digitalWrite(A0,HIGH);
- pinMode(A3,OUTPUT);
- digitalWrite(A3,HIGH);
- pinMode(A1,OUTPUT);
- digitalWrite(A1,HIGH);
- pinMode(A2,OUTPUT);
- digitalWrite(A2,LOW);
- //NFC
- Serial.begin(9600); // Initialize serial communications with the PC
- while (!Serial); // Do nothing if no serial port is opened
- SPI.begin(); // Init SPI bus
- mfrc522.PCD_Init(); // Init MFRC522 card
- for (byte i = 0; i < 6; i++) {
- key.keyByte[i] = 0xFF;
- }
- lcd.begin();
- lcd.backlight();
- lcd.setCursor(0,0);
- lcd.clear();
- lcd.print( "BLOCKED" );
- }
- void readNFC(){ // This function will read the code stored on
- for (byte i =0; i<(mfrc522.uid.size); i++) { // the UID
- COD[i]=mfrc522.uid.uidByte[i];
- }
- Serial.print("COD");
- Serial.print(COD[0]);
- Serial.print(COD[1]);
- Serial.print(COD[2]);
- Serial.print(COD[3]);
- }
- void pairNFC(){
- Serial.println("COD in pair");
- Serial.print(COD[0]);
- Serial.print(COD[1]);
- Serial.print(COD[2]);
- Serial.print(COD[3]);
- long r=0;
- int c=0;
- for(int i=1;i<=EEPROM.read(0);i++){ //The UID cannot be stored on
- switch(i%4){ // one variable, it was needed to be
- case 1 :{AUX[0]=EEPROM.read(i); break;} // split
- case 2 :{AUX[1]=EEPROM.read(i); break;}
- case 3 :{AUX[2]=EEPROM.read(i); break;}
- case 0 :{AUX[3]=EEPROM.read(i); break;}
- }
- if((i)%4==0)
- {Serial.println(r);
- if( AUX[0]==COD[0] && AUX[1]==COD[1] && AUX[2]==COD[2] && AUX[3]==COD[3] ){ //Verify if the code is in EEPROM
- lcd.clear();
- lcd.setCursor(0,0);
- lcd.print("CODE ALREADY IN");
- lcd.setCursor(0,1);
- lcd.print("SYSTEM");
- delay(2000);
- c=1;
- break;}
- }
- }
- if(c==0){int aux2=EEPROM.read(0);
- Serial.println("CODE PAIRED");
- Serial.print(COD[0]);
- Serial.print(COD[1]);
- Serial.print(COD[2]);
- Serial.print(COD[3]);
- EEPROM.write(aux2+1,COD[0]); //Writing code in EEPROM
- EEPROM.write(aux2+2,COD[1]);
- EEPROM.write(aux2+3,COD[2]);
- EEPROM.write(aux2+4,COD[3]);
- aux2=aux2+4; // Position for a new code
- Serial.println("aux2");
- Serial.println(aux2);
- EEPROM.write(0,0);
- EEPROM.write(0,aux2);
- lcd.clear();
- lcd.setCursor(0,0);
- lcd.print("CODE PAIRED");
- delay(2000);}
- }
- boolean validationNFC(){
- boolean c=false;
- for(int i=1;i<=EEPROM.read(0);i++){ //Read the EEPROM
- switch(i%4){
- case 1 :{AUX[0]=EEPROM.read(i); break;}
- case 2 :{AUX[1]=EEPROM.read(i); break;}
- case 3 :{AUX[2]=EEPROM.read(i); break;}
- case 0 :{AUX[3]=EEPROM.read(i); break;}
- }
- if((i)%4==0)
- {
- if( AUX[0]==COD[0] && AUX[1]==COD[1] && AUX[2]==COD[2] && AUX[3]==COD[3])
- c=true; //Verify if the code is in EEPROM and make flag=true;
- }
- }
- return c;
- }
- int compareCODE(String a) //We type a code on keypad and this will be compared
- { //with the accessCode;
- if(a.equals(accessCode))
- return 1;
- else if(a.equals(codpairing)) return 2;
- else return 0;
- }
- String takeCode(char x) //Will display on the LCD the code typed
- { char vec[10];
- vec[0]=x;
- lcd.setCursor(0,0);
- lcd.clear();
- lcd.print('X');
- for(int i=1;i<8;i++)
- {vec[i]=myKeypad.waitForKey(); //Waits for 8 keys to be pressed and after that
- lcd.print('X');} //is taking the decision
- vec[8]=NULL;
- String str(vec);
- return str;
- }
- void loop() {
- switch(state){
- case 0: {
- mfrc522.PCD_Init();
- if ( mfrc522.PICC_IsNewCardPresent() && mfrc522.PICC_ReadCardSerial() ){
- readNFC(); //It will read the card and it will search for UID in its
- if(validationNFC()) //memory
- { state=1;
- lcd.clear();
- lcd.setCursor(0,0);
- lcd.print( "VALID NFC CODE" ); //The door will be opened
- delay(1000);
- return;
- }
- else{
- lcd.clear();
- lcd.setCursor(0,0);
- lcd.print( "INVALID NFC CODE" ) //If the code was wrongblocked
- delay(1000);
- lcd.setCursor(0,0);
- lcd.clear();
- lcd.print( "BLOCKED" );
- return;
- }
- }
- char c=myKeypad.getKey();
- if(c != NO_KEY){
- String codcurent=takeCode(c);
- int A=compareCODE(codcurent);
- if(A==0){ //A is a variable that stores the current code
- lcd.clear();
- lcd.print("INVALID CODE");
- delay(2000);
- lcd.setCursor(0,0);
- lcd.clear();
- lcd.print("BLOCKED");
- return;
- }
- if(A==1){
- lcd.setCursor(0,0);
- lcd.clear();
- lcd.print( "VALID CODE " );
- delay(2000);
- state = 1;
- Return;
- }
- if(A==2); {
- state=2;
- lcd.clear();
- lcd.setCursor(0,0);
- lcd.print( " Pairing..." );
- delay(2000);
- return;}
- }
- break;
- }
- case 1:{
- lcd.clear();
- lcd.setCursor(0,0);
- lcd.print( "UNLOCKED" );
- digitalWrite(A3,LOW);
- digitalWrite(A1,LOW); //The red LED will be off
- digitalWrite(A2,HIGH); //The green LED will be on
- tone(6,3000,5010); //The buzzer will make a sound
- delay(5000); //After 5 seconds the system will be blocked
- digitalWrite(A3,HIGH);
- digitalWrite(A1,HIGH);
- digitalWrite(A2,LOW);
- state=0;
- lcd.setCursor(0,0);
- lcd.clear();
- lcd.print( "BLOCKED" );
- return;
- }
- case 2:{
- mfrc522.PCD_Init();
- if ( mfrc522.PICC_IsNewCardPresent() && mfrc522.PICC_ReadCardSerial() ){
- readNFC();
- pairNFC();
- state=0;
- delay(2000);
- lcd.clear();
- lcd.setCursor(0,0);
- lcd.print( "BLOCKED" ); }
- break;
- }
- }
- }
结论
至此,我们成功制作了一款低成本的Arduino RFID门锁。对我来说,这是一个很有趣的项目,因为我是为自己使用而制作的。此外,制作一个这样的设备不仅能让您因为做了一些有用的事而产生满足感,学习到很多知识,还能让您对自制电子设备有初步的尝试和体验。与各种各样的开发板打交道是非常具有挑战性的。本项目还包含了很多有趣的课题,例如:
- • 与其他Arduino库一起使用
- • 理解EEPROM的使用
- • 使用多种通信,如I2C, SPI