Ардуино и карты доступа
Не так давно ко мне в руки попало довольно интересное устройство 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 |
|
Платы 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.
Обзор подготовил Павел Сергеев
