Arduino Модуль RFIDRC522

RFID-модуль RC522

RFID-модуль 13.56 МГц с SPI-интерфейсом. В комплекте к модулю идет 2 RFID-метки — в виде карты и брелока. 
Данный модуль может быть использован для различных радиолюбительких и коммерческих применений, в том числе контроля доступа, автоматической идентификации, робототехники, отслеживания вещей, платежных систем и т.д. 
Основные характеристики:
• Основан на микросхеме MFRC522; 
• Напряжение питания: 3.3V; 
• Потребляемый ток :13-26mA 
• Рабочая частота: 13.56MHz 
• Дальность считывания: 0 ~ 60 мм
• Интерфейс: SPI, максимальная скорость передачи 10МБит/с 
• Размер: 40мм х 60мм 
• Чтение и запись RFID-меток.

Комплект модуля мне по душе по 3 причинам:
1. Сам модуль;
2. RFID-карта с возможностью перезаписи;
3. RFID-брелок (да, тот же, который используется для открытия домофонной двери) с возможностью перезаписи.

Даже один взгляд на данный комплект рисует в голове множество способов применения RC522:
1. Автоматический замок для открывания двери, ящика, шкафа;
2. Программатор для домофонных ключей;
3. Организация складского учета (но с этим чуть сложней — нужно закупить RFID-метки, такие же, как и на любом товаре в современном магазине);
4. Открытие закрытых ранее для вас дверей копирование и программирование карт для организации доступа к вашим сокровищам.

Важно заметить, что не каждая карта и ключ имеют возможность перезаписи, поэтому при покупке обращайте внимание на описание товара и ищите на буржуйском следующее «Programmable/ Writable», «can be written over and over again» или что-то в этом духе.

ПОДКЛЮЧЕНИЕ
RC522 имеет интерфейс SPI, а это значит, что костылей в этой статье не будет, т.к. CraftDuino имеет его из коробки.

Модуль RC имеет 8 выводов (написаны по порядку расположения на модуле):
VCC — Питание. Необходимо 3.3V;
RST — Reset. Линия сброса. Ни в коем случае не подключать к пину RESET на CraftDuino! Данный пин цепляется на цифровой порт с PWM;
GND — Ground. Земля=));
MISO — Master Input Slave Output — данные от ведомого к ведущему, SPI;
MOSI — Master Output Slave Input — данные от ведущего к ведомому, SPI;
SCK — Serial Clock — тактовый сигнал, SPI;
NSS — Slave Select — выбор ведомого, SPI;
IRQ — линия прерываний;

Для подключения к CraftDuino необходимо воспользоваться следующей распиновкой:
RC522 --> пин CraftDuino
VCC ----> 3.3V
RST ----> 9
GND ----> GND
MISO ---> 12
MOSI ---> 11
SCK ----> 13
NSS ----> 10
IRQ ----> NС — не подключаем [в рамках этого примера. Далее планируется его использовать]

ТЕСТОВЫЙ СКЕТЧ
Для работы с данным модулем есть 2 разных пути:
1. Изучить работу микросхемы, форматы команд и запросов и написать свой софт;
2. Не заморачиваться на первом этапе и воспользоваться готовой библиотекой и примерами.

Первый путь мы отложим до последующих статей, а пока воспользуемся готовой библиотекой, установим ее в Arduino IDE с помощью копирования в папку %путь установки%/libraries/RFID и зальем тестовый скетч cardRead:

/**
* Read a card using a mfrc522 reader on your SPI interface
* Pin layout should be as follows (on Arduino Uno):
* MOSI: Pin 11 / ICSP-4
* MISO: Pin 12 / ICSP-1
* SCK: Pin 13 / ISCP-3
* SS: Pin 10
* RST: Pin 9
*
* Script is based on the script of Miguel Balboa. 
* New cardnumber is printed when card has changed. Only a dot is printed
* if card is the same.
*
* @version 0.1
* @author Henri de Jong
* @since 06-01-2013
*/

#include <SPI.h>
#include <RFID.h>

#define SS_PIN 10
#define RST_PIN 9

RFID rfid(SS_PIN, RST_PIN); 

// Setup variables:
    int serNum0;
    int serNum1;
    int serNum2;
    int serNum3;
    int serNum4;

void setup()
{ 
  Serial.begin(9600);
  SPI.begin(); 
  rfid.init();
  
}

void loop()
{
    
    if (rfid.isCard()) {
        if (rfid.readCardSerial()) {
            if (rfid.serNum[0] != serNum0
                && rfid.serNum[1] != serNum1
                && rfid.serNum[2] != serNum2
                && rfid.serNum[3] != serNum3
                && rfid.serNum[4] != serNum4
            ) {
                /* With a new cardnumber, show it. */
                Serial.println(" ");
                Serial.println("Card found");
                serNum0 = rfid.serNum[0];
                serNum1 = rfid.serNum[1];
                serNum2 = rfid.serNum[2];
                serNum3 = rfid.serNum[3];
                serNum4 = rfid.serNum[4];
               
                //Serial.println(" ");
                Serial.println("Cardnumber:");
                Serial.print("Dec: ");
		Serial.print(rfid.serNum[0],DEC);
                Serial.print(", ");
		Serial.print(rfid.serNum[1],DEC);
                Serial.print(", ");
		Serial.print(rfid.serNum[2],DEC);
                Serial.print(", ");
		Serial.print(rfid.serNum[3],DEC);
                Serial.print(", ");
		Serial.print(rfid.serNum[4],DEC);
                Serial.println(" ");
                        
                Serial.print("Hex: ");
		Serial.print(rfid.serNum[0],HEX);
                Serial.print(", ");
		Serial.print(rfid.serNum[1],HEX);
                Serial.print(", ");
		Serial.print(rfid.serNum[2],HEX);
                Serial.print(", ");
		Serial.print(rfid.serNum[3],HEX);
                Serial.print(", ");
		Serial.print(rfid.serNum[4],HEX);
                Serial.println(" ");
             } else {
               /* If we have the same ID, just write a dot. */
               Serial.print(".");
             }
          }
    }
    
    rfid.halt();
}

Данный скетч выполняет следующие действия:
1. Инициализирует RC522;
2. Если обнаруживает RFID-метку, то выводит ее номер в десятичной и шестнадцатеричной системах исчисления;
3. Ожидает следующей метки. Если предыдущая метка не убрана от модуля и продолжает считываться, то выводит в com-порт точку.

Я не сказал бы, что данный скетч мне нравится, но пример есть пример.

СВОЙ-ЧУЖОЙ
Для интереса, давайте запилим распознавание определенной карты. Чтобы это выполнить, необходимо выполнить следующую логику работы:
1. Создать массив с номером известной карты в качестве разрешенного;
2. Считать серийный номер и записать его в отдельный массив;
3. Произвести поэлементное сравнение разрешенного номера со считанным;
4. В зависимости от результата, выполнить разные действия.

Не только из-за лени переделаем вышеприведенный пример:

serNum0 = rfid.serNum[0];
serNum1 = rfid.serNum[1];
serNum2 = rfid.serNum[2];
serNum3 = rfid.serNum[3];
serNum4 = rfid.serNum[4];

Этот колхоз заменим на трушное считывание в массив unsigned char readnig_card[5] и его вывод через цикл for

Serial.println("Card found");
Serial.println("Cardnumber:"); 
for (i = 0; i < 5; i++)
{     
  Serial.print(rfid.serNum[i]);
  Serial.print(" ");
  reading_card[i] = rfid.serNum[i];
}

Кроме этого, уберем ненужное выведение точек в случае считывания одной и той же карты и прикрутим сравнение с разрешенным номером карты с соответствующей последующей реакцией. Теперь, изменяя и дополняя функции allow() и denied(), можно получить любое необходимое действие.

for (i = 0; i < 5; i++)
{
  if (reading_card[i]!=master[i])
    {
      break;
    }
}
if (i == 5)
{
  allow();
}
else
{
  denied();
}

Хотя в большинстве примеров, найденных на просторах интернета, проводилось сравнение только одного байта серийного номера, мне показалось это не очень надежным, если есть много меток, причем с одной партии. Поэтому было принято решение на сравнивание всех битов.
Для индикации возьмем 2 светодиода (в моем случае это синий и желтый), и прицепим их на цифровые порты 6 и 7, как показано на рисунке ниже. Кроме того, не забываем об ограничении тока посредством резистора.

Итого, получаем скетч

/*
www.lab409.ru
Danil Borchevkin
15/12/2013

* 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>

#define SS_PIN 10
#define RST_PIN 9
#define BLUE_LED 6
#define YELLOW_LED 7

RFID rfid(SS_PIN, RST_PIN); 

unsigned char reading_card[5]; //for reading card
unsigned char master[5] = {114,13,207,204,124}; // allowed card
unsigned char i;

void indication(int led);
void allow();
void denied();

void setup()
{ 
  Serial.begin(9600);
  SPI.begin(); 
  rfid.init();
  pinMode(BLUE_LED, OUTPUT);
  pinMode(YELLOW_LED, OUTPUT);
}

void loop()
{
    if (rfid.isCard()) 
    {
        if (rfid.readCardSerial()) 
        {
                /* Reading card */
                Serial.println(" ");
                Serial.println("Card found");
                Serial.println("Cardnumber:"); 
                for (i = 0; i < 5; i++)
                {     
		  Serial.print(rfid.serNum[i]);
                  Serial.print(" ");
                  reading_card[i] = rfid.serNum[i];
                }
                Serial.println();
                //verification
                for (i = 0; i < 5; i++)
                {
                  if (reading_card[i]!=master[i])
                  {
                    break;
                  }
                }
                if (i == 5)
                {
                  allow();
                }
                else
                {
                  denied();
                }
         } 
    }
    rfid.halt();
}

void allow()
{
  Serial.println("Access accept!");
  indication(BLUE_LED);
}
void denied()
{
  Serial.println("Access denied!");
  indication(YELLOW_LED);
}
void indication(int led)
{
  digitalWrite(led, HIGH);
  delay(1000);
  digitalWrite(led, LOW);
}

Теперь у нас все довольно серьезней и интересней. Уже можно организовывать доступ в помещение. Но есть огромное НО — то, что мы выводим как серийный номер, нифига им не является (по крайней мере, в таком виде) — советую покопаться в самой библиотеке и понять, что UID номер карты перевернут, а один из байтов — CRC.

16,00 бел.руб
Arduino Модуль RFIDRC522
Arduino Модуль RFIDRC522