Ардуино и карты доступа

Не так давно ко мне в руки попало довольно интересное устройство RDM6300, данное устройство предназначено для считывания информации с карт (и брелоков) работающих при помощи RFID (радиочастотной идентификации) по протоколу EM4100. Следует отметить, что очень многие из нас ежедневно пользуются данной технологией, даже не отдавая себе в этом отчет. Пользуются при попытке открыть домофон, а в некоторых офисах – и приходя на работу. В данной статье мы не будем уделять внимания несанкционированному клонированию RFID-меток (карт и брелоков), а изучим на практике, как можно создать простое устройство, которое можно использовать сугубо в мирных, законных целях.

В своих экспериментах мне понадобился ARDUINO UNO (приобретается здесь: arduino-kit.com.ua/uno-r3-new.html или здесь: arduino-kit.com.ua/arduino-leonardo-original-italiya-new-rev3.html) , а также картридер RDM6300 125KHz (по очень демократичной цене приобретается здесь: arduino-kit.com.ua/kardrider-rdm6300.html), если у Вас есть брелок от домофона или карточка 125KHz, то в принципе всё. Если нет – можно еще купить пару брелочков здесь:arduino-kit.com.ua/rfid , а здесь: arduino-kit.com.ua/karta-rfid-tag-125khz-dlya-arduino.html пару карточек.

Почему именно RDM6300, ведь разнообразие считывателей RFID довольно велико? Ну, во-первых демократичная цена. А во-вторых «на все про все» ему нужно всего 2 провода (кроме питания, естественно), а это значит, что конструкция, которую предполагается оснастить данным устройством не будет излишне усложнена.

Итак, приступим. В отличие от многих других ардуино-устройств картридер RDM6300 имеет 3 разъема. 2-пиновый для антенны, причем судя по всему не имеет значения, как именно подключать к нему антенну (она, кстати, идет в комплекте). 3-пиновый для светодиода, а также дополнительное питание. В наших экспериментах он не понадобится. И третий, 5-пиновый разъем это собственно тот разъем, при помощи которого мы и будем подключать нашу плату к Ардуино. Как именно подключать ясно из Таблицы 1.

RDM6300

Arduino Uno

Примечание

1

9

TX

2

8

RX

4

GND

 

5

+5V

 


Таблица 1.Подключение контактов.




Платы Raspberry Pi на портале Arduino-Kit.com.ua




Причем 1-й контакт находится в углу, а сам контакт имеет квадратную форму, зато 5-й зачем-то обведен в рамочку. Оставим это решение на совести разработчиков. Подключение хорошо видно на Рисунке 1. Также там изображены карточки и варианты брелоков. 

 
Рисунок 1. Ардуино и RDM6300, а также брелоки и карточки.



Первое, что нам было-бы интересно узнать – это собственно серийный номер наших брелоков, или карточек. Для этого загружаем простенький (всего 19 строчек) скетч. И на мониторе СОМ-порта наблюдаем номера имеющихся у нас карточек. Карточки к антенне приходится подносить практически вплотную.

#include

SoftwareSerialSoftSerial(9, 8);// Подключение RDM6300 к 8 и 9 пинамArduino Uno

unsignedcharbuffer[64]; //Описание 64-битного массива буфера

intcount=0;//Описание переменной для работы с массивом

void setup(){

SoftSerial.begin(9600);// Запуск RDM6300  

Serial.begin(9600);}//ЗапускСОМ-порта

void loop(){

if (SoftSerial.available()){//Если в RDM6300 есть данные - переписываем из в массив

while(SoftSerial.available()){//Чтение данных из RDM6300

buffer[count++]=SoftSerial.read();//Запись данных в переменную массива

if(count == 64)break; }//Если считали первые 64 бита - обрываем чтение

Serial.write(buffer,count);//Если данных больше нет - записываем значение в порт

clearBufferArray();//Запуск подпрограммы очистки буфера

count = 0;//Обнуление переменной массива

Serial.println();}}//Перевод строки перед записью нового значения

voidclearBufferArray(){//Подпрограммаочисткибуфера

for (int i=0; i

{ buffer[i]=NULL;}}//Обнуление ячейки массива



Результаты работы данного скетча видно на Рисунке 2. Следует отметить, что считывание карточек происходит довольно быстро, если карточку (или брелок) немного задержать рядом с антенной поле монитора порта заполнится довольно быстро. 

 
Рисунок 2. Пример работы программы определения номеров карточек.




А теперь вернемся к предназначению RFID-меток – идентификация их владельцев по признаку «свой-чужой». Для этого немного усложним скетч – укажем «свой» серийный номер, а все остальные, соответственно, будут «чужими».

#include

#include //Библиотека работы с памятью

prog_char tag_0[] PROGMEM = "565A1132E0CF";//Значение нулевого слота памяти

prog_char tag_1[] PROGMEM = "000000000000";//Значение первого слота памяти

prog_char tag_2[] PROGMEM = "000000000000";//Значение второго слота памяти

prog_char tag_3[] PROGMEM = "000000000000";//Значение третьего слота памяти

prog_char tag_4[] PROGMEM = "000000000000";//Значение четвертого слота памяти

prog_char tag_5[] PROGMEM = "000000000000";//Значение пятого слота памяти

prog_char tag_6[] PROGMEM = "000000000000";//Значение шестого слота памяти

PROGMEM const char *tag_table[] ={tag_0,tag_1,tag_2,tag_3,tag_4,tag_5,tag_6};

SoftwareSerial SoftSerial(9, 8);// Подключение RDM6300 к 8 и 9 пинам Arduino Uno

unsigned char buffer[64]; //Описание 64-битного массива буфера

int count=0;//Описание переменной для работы с массивом

char tagNumber[14];

boolean receivedTag;

void setup(){

 SoftSerial.begin(9600);// Запуск RDM6300  

  Serial.begin(9600);}//Запуск СОМ-порта

  void loop(){

if (SoftSerial.available()){//Если в RDM6300 есть данные - переписываем из в массив

receivedTag=false;

  while(SoftSerial.available()){//Чтение данных из RDM6300

    int BytesRead = SoftSerial.readBytesUntil(3, tagNumber, 15);

  receivedTag=true;} 

    Serial.print(tagNumber);//Если данных больше нет - записываем значение в порт

     if (checkTag(tagNumber)){// Запрос сравнения значения с тем, что хранится в памяти

      Serial.print(" Svoy");}// Если значение есть, значит свой

    else{

      Serial.print(" Chuzhoy");}// Если значения нет, значит чужой

    clearBufferArray();//Запуск подпрограммы очистки буфера

    count = 0;//Обнуление переменной массива

    Serial.println();}}//Перевод строки перед записью нового значения

     boolean checkTag(String tag){// Определение значения переменной

   char testTag[14];

   for (int i = 0; i < sizeof(tag_table)/2; i++)

  {strcpy_P(testTag, (char*)pgm_read_word(&(tag_table[i])));

    if(tag.substring(1,13)==testTag){

      return true;// Возвращаем значение "Истина"

      break;}}

   return false;}// Возвращаем значение "Ложь"

void clearBufferArray(){//Подпрограмма очистки буфера

for (int i=0; i

    { buffer[i]=NULL;}}//Обнуление ячейки массива



То, что получилось видно на рисунке 3. 

 
Рисунок 3.



Теперь остались сущие пустяки: сделать данную программу практически полезной. Это совершенно не сложно. Пропишем и подключим 2 светодиода. Аноды светодиодов подключим на 10 (зеленый) и 11 (красный) пины Ардуино, а катоды, через токоограничительный резистор (мне под руки попался на 200Ом) к GND. Пусть для «своих» зажигается зеленый, а для «чужих» – красный. То, что получилось видно на рисунке 4. Более опытные ардуинщики улыбнутся, а менее опытным предоставляю следующий скетч. Да, и еще одно, думаю, что всем понятно, что вместо (или совместно) со светодиодами можно подключить реле, которое сможет управлять электрозамком или каким-либо оборудованием, а это уже простейшая система доступа.

#include

#include //Библиотека работы с памятью

prog_char tag_0[] PROGMEM = "565A1132E0CF";//Значение нулевого слота памяти

prog_char tag_1[] PROGMEM = "000000000000";//Значение первого слота памяти

prog_char tag_2[] PROGMEM = "000000000000";//Значение второго слота памяти

prog_char tag_3[] PROGMEM = "000000000000";//Значение третьего слота памяти

prog_char tag_4[] PROGMEM = "000000000000";//Значение четвертого слота памяти

prog_char tag_5[] PROGMEM = "000000000000";//Значение пятого слота памяти

prog_char tag_6[] PROGMEM = "000000000000";//Значение шестого слота памяти

PROGMEM const char *tag_table[] ={tag_0,tag_1,tag_2,tag_3,tag_4,tag_5,tag_6};

SoftwareSerial SoftSerial(9, 8);// Подключение RDM6300 к 8 и 9 пинам Arduino Uno

unsigned char buffer[64]; //Описание 64-битного массива буфера

int count=0;//Описание переменной для работы с массивом

char tagNumber[14];

boolean receivedTag;

void setup(){

 SoftSerial.begin(9600);// Запуск RDM6300  

  Serial.begin(9600);//Запуск СОМ-порта

  pinMode(10,OUTPUT);// Указываем порт светодиода "Свой"

  pinMode(11,OUTPUT);}// Указываем порт светодиода "Чужой"

  void loop(){

if (SoftSerial.available()){//Если в RDM6300 есть данные - переписываем из в массив

receivedTag=false;

  while(SoftSerial.available()){//Чтение данных из RDM6300

    int BytesRead = SoftSerial.readBytesUntil(3, tagNumber, 15);

  receivedTag=true;} 

    Serial.print(tagNumber);//Если данных больше нет - записываем значение в порт

     if (checkTag(tagNumber)){// Запрос сравнения значения с тем, что хранится в памяти

      Serial.print(" Svoy");// Если значение есть, значит свой

    digitalWrite(10,HIGH);// Зажигаем диод "Свой"

  delay(1000);// Ждем секунду

  digitalWrite(10,LOW);}// Гасим диод "Свой"

    else{

      Serial.print(" Chuzhoy");// Если значения нет, значит чужой

        digitalWrite(11,HIGH);// Зажигаем диод "Чужой"

  delay(1000);// Ждем секунду

  digitalWrite(11,LOW);}// Гасим диод "Чужой"

    clearBufferArray();//Запуск подпрограммы очистки буфера

    count = 0;//Обнуление переменной массива

    Serial.println();}}//Перевод строки перед записью нового значения

     boolean checkTag(String tag){// Определение значения переменной

   char testTag[14];

   for (int i = 0; i < sizeof(tag_table)/2; i++)

  {strcpy_P(testTag, (char*)pgm_read_word(&(tag_table[i])));

    if(tag.substring(1,13)==testTag){

      return true;// Возвращаем значение "Истина"

      break;}}

   return false;}// Возвращаем значение "Ложь"

void clearBufferArray(){//Подпрограмма очистки буфера

for (int i=0; i

    { buffer[i]=NULL;}}//Обнуление ячейки массива




Рисунок 4.




Обзор подготовил Павел Сергеев