Радиочастотная идентификация (RFID) — это технология бесконтактной идентификации объектов при помощи радиочастотного канала связи. Иными словами, это способ опознания объектов, при котором радиосигналы записывают или считывают информацию, хранящуюся на RFID-метках (ещё их называют трансподерами).
RFID относится к беспроводной системе, состоящей из двух компонентов: метки и считывателя. Считыватель – это устройство, которое имеет одну или несколько антенн, которые излучают радиоволны и принимают сигналы обратно от RFID-метки.
RFID-метки могут хранить различную информацию от одного серийного номера до нескольких страниц данных.
В Arduino в качестве считывателя используют популярный модуль RFID-RC522. Модуль выполнен на микросхеме MFRC522 фирмы NXP, которая обеспечивает работу с метками HF (на частоте 13,56 МГц). В комплекте с модулем RFID-RC522 идут две метки, одна в виде карты, другая в виде брелока.
На основе RFID-модуля RC522 можно сделать простой электронный замок который будет управлять работой например электромагнитного замка или другим исполнительным механизмом.
Индикация RFID-меток происходит путем считывания ID UID (уникальный индефикационный номер). Таким образом UID позволяет отличить две с виду идентичные метки. UID как правило состоит из 4х байт, свободно считывается.
Ранее в http://rcl-radio.ru/?p=50041 был описан пример создания электронного замка при помощи RFID-модуля RC522, в нем необходимо было заранее в скетч записать несколько номеров UID RFID-меток, которые так же необходимо было заранее считать с RFID-меток. В этой статье будет рассмотрен пример электронного замка с возможностью занесения и стирания UID RFID-меток без предварительной их записи их в скетч.
Как и ранее в http://rcl-radio.ru/?p=50041 в скетч необходимо записать UID RFID-мету, но только одну, назовем ее мастер-метка. При помощи одной мастер-метки программно в процессе работы электронного замка можно добавить в память до 50 UID RFID-меток, а так же, то же программно удалить из памяти ненужную UID RFID-метку. Так как необходимы определенные действия в памятью (EEPROM), то для визуализации работы с памятью необходим дисплей, а так же 2 кнопки. Дисплей и две кнопки необходимы для добавления и стирания UID RFID-меток, поэтому они могут располагаются в недоступной для общего доступа части электронного замка. В доступной части расположен считыватель меток и два светодиода отображающие режим работы электронного замка.
Схема электронного замка
В памяти микроконтроллера содержаться несколько UID RFID-меток, при поднесении UID RFID-мети к считывателю ID UID метки считывается и сравнивается с содержимым памяти, если есть совпадение, то на 3 секунды загорается светодиод «open» (на выходе D4 появляется лог 1), звучит звуковой сигнал и на дисплее появляться надпись «OPEN». Если совпадение не обнаружено, то на 3 секунды загорается светодиод «closed» (на выходе D4 лог 0), звучит звуковой сигнал (но более короткий) и на дисплее появляться надпись «ERROR».
Для добавления UID RFID-меток в память (EEPROM) необходимо нажать и удерживать кнопку UP/SAVE и поднести мастер-метку, далее на дисплее появится надпись «OK» и произойдет переход в меню добавления UID RFID-меток. Кнопками UP или DW выберите любой свободный (все нули) адрес памяти и поднесите RFID-метку ID адрес которой необходимо записать. Далее адрес RFID-метки появится на экране дисплея. Для выхода из меню необходимо подождать 20 секунд не нажимая ни одной кнопки.
Чтобы мастер-метка могла открывать электронный замок ее ID UID так же необходимо занести в память.
Для стирания UID RFID-метки необходимо нажать и удерживать кнопку DW/CLEAR и поднести мастер-метку, далее на дисплее появится надпись «OK» и произойдет переход в меню стирания UID RFID-меток. Кнопками UP или DW выберите любой ID метки и поднесите мастер-метку для стирания ID UID.
Для выхода из меню необходимо подождать 20 секунд не нажимая ни одной кнопки.
Номер UID мастер-метки и других меток доступны в мониторе порта:
В примере использовалась плата разработчика на базе микроконтроллера LGT8F328 (LGT8F328P-LQFP32 MiniEVB) — http://rcl-radio.ru/?p=129966.
Скетч
#include <SPI.h> #include <MFRC522.h> // http://rcl-radio.ru/wp-content/uploads/2024/08/rfid-master.zip #include <EEPROM.h> #include <Wire.h> #include <U8glib.h> // https://github.com/olikraus/u8glib/ U8GLIB_SH1106_128X64 u8g(U8G_I2C_OPT_DEV_0|U8G_I2C_OPT_FAST); int x; int uid[4]; int master_kart[4]{129,71,80,131}; int set,eeprom; unsigned long times,times_open,tim; bool open_,tim1; MFRC522 mfrc522(10,9); //(SS_PIN, RST_PIN) void setup() { Serial.begin(9600); pinMode(2,INPUT_PULLUP); pinMode(3,INPUT_PULLUP); if(EEPROM.read(500)!=0){for(int i=0;i<501;i++){EEPROM.update(i,0);}} SPI.begin(); mfrc522.PCD_Init(); pinMode(4,OUTPUT); pinMode(5,OUTPUT); pinMode(7,OUTPUT);// zummer digitalWrite(7,HIGH); } void loop() { // Чтение UID ////////////////////////////////////////////////////////////////////////////////// if (mfrc522.PICC_IsNewCardPresent() && mfrc522.PICC_ReadCardSerial()){delay(100);x=0; for (int i = 0; i < 4; i++) { uid[i] = mfrc522.uid.uidByte[i]; if(uid[i]==master_kart[i]){ x++; }}} else{cl();} //////////////////////////////////////////////////////////////////////////////////////////////// //set ==0 read, set == 1 SAVE, set == 2 clear if(x==4 && digitalRead(2)==LOW && uid[0]!=0 && set==0){set=1;ok();times=millis();cl();delay(2000);} if(x==4 && digitalRead(3)==LOW && uid[0]!=0 && set==0){set=2;ok();times=millis();cl();delay(2000);} if(set>0){ if(digitalRead(2)==LOW){eeprom++;if(eeprom>49){eeprom=49;}times=millis();delay(200);} if(digitalRead(3)==LOW){eeprom--;if(eeprom<0){eeprom=0;}times=millis();delay(200);} } //////////////////////////////////////////////////////////////////////////////////////////////// if(uid[0]!=0 && uid[1]!=0 && uid[2]!=0 && uid[3]!=0){ Serial.print("UID: "); for(int i1=0;i1<4;i1++){Serial.print(uid[i1]);Serial.print(" ");}Serial.println();} //////////////////////////////////////////////////////////////////////////////////////////////// u8g.firstPage(); do { ///////////////////////////////////////////////////////////////////////////// if(set==1){ u8g.setFont(u8g_font_profont17r);u8g.drawStr(0,12,"SAVE UID"); u8g.setFont(u8g_font_profont12r); u8g.drawLine(0, 17, 128, 17); u8g.drawStr(0,45,"UID:"); u8g.drawStr(0,30,"Number:");u8g.setPrintPos(50, 30);u8g.print(eeprom); if(uid[0]!=0 && uid[1]!=0 && uid[2]!=0 && uid[3]!=0){ EEPROM.update(0+eeprom*4,uid[0]); EEPROM.update(1+eeprom*4,uid[1]); EEPROM.update(2+eeprom*4,uid[2]); EEPROM.update(3+eeprom*4,uid[3]); } u8g.setPrintPos(30, 45);u8g.print(EEPROM.read(0+eeprom*4)); u8g.setPrintPos(55, 45);u8g.print(EEPROM.read(1+eeprom*4)); u8g.setPrintPos(80, 45);u8g.print(EEPROM.read(2+eeprom*4)); u8g.setPrintPos(105, 45);u8g.print(EEPROM.read(3+eeprom*4)); } //////////////////////////////////////////////////////////////////////////// if(set==2){ u8g.setFont(u8g_font_profont17r);u8g.drawStr(0,12,"CLEAR UID"); u8g.setFont(u8g_font_profont12r); u8g.drawLine(0, 17, 128, 17); u8g.drawStr(0,45,"UID:"); u8g.drawStr(0,30,"Number:");u8g.setPrintPos(50, 30);u8g.print(eeprom); if(uid[0]==master_kart[0]&&uid[1]==master_kart[1]&&uid[2]==master_kart[2]&&uid[3]==master_kart[3]){ EEPROM.update(0+eeprom*4,0); EEPROM.update(1+eeprom*4,0); EEPROM.update(2+eeprom*4,0); EEPROM.update(3+eeprom*4,0); } u8g.setPrintPos(30, 45);u8g.print(EEPROM.read(0+eeprom*4)); u8g.setPrintPos(55, 45);u8g.print(EEPROM.read(1+eeprom*4)); u8g.setPrintPos(80, 45);u8g.print(EEPROM.read(2+eeprom*4)); u8g.setPrintPos(105, 45);u8g.print(EEPROM.read(3+eeprom*4)); } ////////////////////////////////////////////////////////////////////////////// if(set==0){ u8g.setFont(u8g_font_profont17r); if(uid[0]!=0 && uid[1]!=0 && uid[2]!=0 && uid[3]!=0 && millis()-times_open>3000){ for(int i=0;i<50;i++){ if( uid[0]==EEPROM.read(0+i*4)&& uid[1]==EEPROM.read(1+i*4)&& uid[2]==EEPROM.read(2+i*4)&& uid[3]==EEPROM.read(3+i*4)) {open_=1;times_open=millis();tim=millis();break;}else{open_=0;times_open=millis();tim1=1;} } } }//set=0 if(tim1==1){tim1=0;digitalWrite(7,LOW);delay(100);digitalWrite(7,HIGH);} if(open_==1 && millis()-times_open<3000){u8g.drawStr(40,30,"OPEN");digitalWrite(4,HIGH); if(millis()-tim<200){digitalWrite(7,LOW);} if(millis()-tim>200){digitalWrite(7,HIGH);} if(millis()-tim>400){tim=millis();} } else{digitalWrite(4,LOW);digitalWrite(7,HIGH);} if(open_==0 && millis()-times_open<3000){u8g.drawStr(35,30,"ERROR");digitalWrite(5,HIGH);} else{digitalWrite(5,LOW);} } while( u8g.nextPage() ); if(millis()-times>20000){set=0;eeprom=0;} } void ok(){ u8g.firstPage(); do { u8g.setFont(u8g_font_profont17r); u8g.drawStr(55,30,"OK"); } while( u8g.nextPage() ); } void cl(){uid[0]=0;uid[1]=0;uid[2]=0;uid[3]=0;}
Форум — http://forum.rcl-radio.ru/viewtopic.php?pid=10620#p10620
RFID-RC522 + LCD1602_I2C
Ниже показан скетч где вместо OLED дисплея применен LCD1602 с модулем I2C. Функционал электронного замка с использованием LCD1602 аналогичен первому варианту примера.
Скетч
#include <SPI.h> #include <MFRC522.h> // http://rcl-radio.ru/wp-content/uploads/2024/08/rfid-master.zip #include <EEPROM.h> #include <Wire.h> #include <LiquidCrystal_I2C.h> // http://forum.rcl-radio.ru/misc.php?action=pan_download&item=45&download=1 LiquidCrystal_I2C lcd(0x27,16,2); int x; int uid[4]; int master_kart[4]{129,71,80,131}; int set,eeprom; unsigned long times,times_open,tim; int open_,tim1; MFRC522 mfrc522(10,9); //(SS_PIN, RST_PIN) void setup() { Serial.begin(9600); lcd.init();lcd.noBacklight();lcd.clear(); pinMode(2,INPUT_PULLUP); pinMode(3,INPUT_PULLUP); if(EEPROM.read(500)!=0){for(int i=0;i<501;i++){EEPROM.update(i,0);}} SPI.begin(); mfrc522.PCD_Init(); pinMode(4,OUTPUT); pinMode(5,OUTPUT); pinMode(7,OUTPUT);// zummer digitalWrite(7,HIGH); } void loop() { // Чтение UID ////////////////////////////////////////////////////////////////////////////////// if (mfrc522.PICC_IsNewCardPresent() && mfrc522.PICC_ReadCardSerial()){delay(200);x=0; for (int i = 0; i < 4; i++) {uid[i] = mfrc522.uid.uidByte[i];if(uid[i]==master_kart[i]){x++;}}} else{cl();} //////////////////////////////////////////////////////////////////////////////////////////////// //set ==0 read, set == 1 SAVE, set == 2 clear if(x==4 && digitalRead(2)==LOW && uid[0]!=0 && set==0){set=1;lcd.clear();ok();times=millis();cl();delay(2000);} if(x==4 && digitalRead(3)==LOW && uid[0]!=0 && set==0){set=2;lcd.clear();ok();times=millis();cl();delay(2000);} if(set>0){ if(digitalRead(2)==LOW){lcd.clear();eeprom++;if(eeprom>49){eeprom=49;}times=millis();delay(200);} if(digitalRead(3)==LOW){lcd.clear();eeprom--;if(eeprom<0){eeprom=0;}times=millis();delay(200);} } //////////////////////////////////////////////////////////////////////////////////////////////// if(uid[0]!=0 && uid[1]!=0 && uid[2]!=0 && uid[3]!=0){ Serial.print("UID: "); for(int i1=0;i1<4;i1++){Serial.print(uid[i1]);Serial.print(" ");}Serial.println();} //////////////////////////////////////////////////////////////////////////////////////////////// if(set==1){ lcd.backlight(); lcd.setCursor(0, 0);lcd.print("SAVE UID|NUM:"); lcd.setCursor(14, 0);lcd.print(eeprom); if(uid[0]!=0 && uid[1]!=0 && uid[2]!=0 && uid[3]!=0){lcd.clear(); EEPROM.update(0+eeprom*4,uid[0]); EEPROM.update(1+eeprom*4,uid[1]); EEPROM.update(2+eeprom*4,uid[2]); EEPROM.update(3+eeprom*4,uid[3]); } lcd.setCursor(0, 1);lcd.print(EEPROM.read(0+eeprom*4));lcd.print("."); lcd.setCursor(4, 1);lcd.print(EEPROM.read(1+eeprom*4));lcd.print("."); lcd.setCursor(8, 1);lcd.print(EEPROM.read(2+eeprom*4));lcd.print("."); lcd.setCursor(12, 1);lcd.print(EEPROM.read(3+eeprom*4)); } //////////////////////////////////////////////////////////////////////////// if(set==2){ lcd.backlight(); lcd.setCursor(0, 0);lcd.print("CLEAR UID|NUM:"); lcd.setCursor(14, 0);lcd.print(eeprom); if(uid[0]==master_kart[0]&&uid[1]==master_kart[1]&&uid[2]==master_kart[2]&&uid[3]==master_kart[3]){lcd.clear(); EEPROM.update(0+eeprom*4,0); EEPROM.update(1+eeprom*4,0); EEPROM.update(2+eeprom*4,0); EEPROM.update(3+eeprom*4,0); } lcd.setCursor(0, 1);lcd.print(EEPROM.read(0+eeprom*4));lcd.print("."); lcd.setCursor(4, 1);lcd.print(EEPROM.read(1+eeprom*4));lcd.print("."); lcd.setCursor(8, 1);lcd.print(EEPROM.read(2+eeprom*4));lcd.print("."); lcd.setCursor(12, 1);lcd.print(EEPROM.read(3+eeprom*4)); } ////////////////////////////////////////////////////////////////////////////// if(set==0){ if(uid[0]!=0 && uid[1]!=0 && uid[2]!=0 && uid[3]!=0){ for(int i=0;i<50;i++){ if(uid[0]==EEPROM.read(0+i*4)&&uid[1]==EEPROM.read(1+i*4)&&uid[2]==EEPROM.read(2+i*4)&&uid[3]==EEPROM.read(3+i*4)){open_=1;break;}else{open_=2;}}}}//set=0 if(open_==1){open_=0;lcd.backlight();lcd.setCursor(6, 0);lcd.print("OPEN");digitalWrite(4,HIGH); for(int n=0;n<8;n++){digitalWrite(7,LOW);delay(200);digitalWrite(7,HIGH);delay(200);} lcd.noBacklight();lcd.clear();digitalWrite(4,LOW);digitalWrite(7,HIGH);} if(open_==2){open_=0;lcd.backlight();lcd.setCursor(5, 0);lcd.print("ERROR");digitalWrite(5,HIGH); digitalWrite(7,LOW);delay(100);digitalWrite(7,HIGH);delay(3000);digitalWrite(5,LOW);lcd.noBacklight();lcd.clear();} if(millis()-times>10000){lcd.noBacklight();lcd.clear();set=0;eeprom=0;} } void ok(){ lcd.backlight();lcd.setCursor(0, 0);lcd.print("OK");} void cl(){uid[0]=0;uid[1]=0;uid[2]=0;uid[3]=0;}
Форум — http://forum.rcl-radio.ru/viewtopic.php?pid=10625#p10625