Сетевой RFID-считыватель на Arduino, ENC28J60 Ethernet и MFRC522
Компоненты и материалы
| Mifare MFRC522 | ×1 |
| Arduino UNO | ×1 |
| ENC28J60 Ethernet-модуль | ×1 |
| Перемычки (универсальные) | ×1 |
| Макетная плата (универсальная) | ×1 |
| Компьютер | ×1 |
Необходимые инструменты и станки
| Ножницы (или обкусиватели) |
Приложения и онлайн-сервисы
| PyCharm |
| Arduino IDE |
О проекте

Хотели ли вы когда-нибудь добавить RFID-систему безопасности или мониторинга в свой дом и/или офис? Если вы здесь, то, вероятно, уже узнали, как безумно они дороги — от $200 до $2000, СЛИШКОМ ДОРОГО!? Друг и я решили сделать систему за менее $100, которая умеет больше, чем просто открывать двери. Вот что у нас получилось: интернет-включённый Arduino RFID-считыватель тегов. За $20 больше он может открывать двери. Система проектировалась для отслеживания учеников в нашей школе, и мы надеемся, что школа её одобрит.
Вот прототип:

Можно подумать, что это займёт много времени, но это заняло у меня около 6 часов (потому что были проблемы с питанием), а вы можете настроить это за 30 минут, как в примере выше. Весь код и картинки ниже, так что если запутаетесь в следующих шагах, смотрите код/картинки ниже.
Перед началом (Необходимо)
Прежде чем начать сканировать карты и отправлять их на Telnet/TCP-сервер, нужны библиотеки:
- UIPEthernet: https://github.com/ntruchsess/arduino_uip
- MFRC522: https://github.com/miguelbalboa/rfid
Положите обе библиотеки в Program Files(x86)/Arduino/Libraries/ и перезапустите Arduino IDE.
Аппаратная часть
- Arduino Nano (можно адаптировать код под другую плату)
- MFRC522 с картами MIFARE
- Перемычки (Male-Male, Male-Female)
- Ethernet-модуль/шилд ENC28J60
- RGB-светодиод
- AC-DC преобразователь 3В или 5В, более 700 мА
Подключение
- Установите Arduino на макетную плату (если Nano или Micro)
- Найдите в интернете распиновку вашей платы для SPI (измените значения ниже)
- Соедините Arduino pin 10 (SS) с Ethernet-модулем SS или CS
- Соедините Arduino pin 12 (MISO) с RFID MISO и Ethernet SO
- Соедините Arduino pin 11 (MOSI) с RFID MOSI и Ethernet SI
- Соедините Arduino pin 13 (SCK) с RFID SCK и Ethernet SCK
- Соедините Arduino pin 9 с RFID RST
- Соедините Arduino pin 8 с RFID SSN
- Соедините Arduino pin 5 с зелёным светодиодом, 4 — с синим, 3 — с красным
- Подключите AC-DC к + и - на макетной плате
- Заземлите Arduino к AC-DC
- Подключите VCC и GND на RFID и Ethernet к AC-DC (ПОМНИТЕ: ЭТИ УСТРОЙСТВА ТОЛЬКО 3В!!!!! НЕ ПОДАВАЙТЕ 5В) Если проблемы — используйте резисторы для снижения напряжения до 3В
- Пин VCC светодиода к 3В Arduino или AC-DC 3В
- Подключите Ethernet-кабель к модулю и убедитесь, что он в той же сети, что и компьютер
- Подключите USB-кабель от компьютера к Arduino
- Подключите компьютер к той же сети
Настройка кода под свои нужды
- Код хорошо прокомментирован, можно просто изменить нужные части, но одно точно — Ethernet-модуль
- MAC-адрес можно оставить прежним (если не планируете строить несколько таких устройств)
- Если используете сеть 192.168.x.x, можно оставить IP
- DNS тоже можно оставить, менять только на 8.8.4.4

- Выполните ipconfig, чтобы найти шлюз, по умолчанию 192.168.1.1 (если не знаете) (в коде сейчас 192.168.1.5)
- Запустите командную строку и введите ipconfig, чтобы узнать IP компьютера

- Прокрутите вниз до SEND TO SERVER и введите IP вашего компьютера или публичный IP, если пробросили порт на роутере
- УБЕДИТЕСЬ, ЧТО У ВАС УСТАНОВЛЕН PYTHON И ЗАПУЩЕН СЕРВЕР (это просто пример кода для презентации в школе, Python-сервер уже был готов и почти не модифицирован — можно использовать любой Telnet/TCP-сервер)
Другой код, который, вероятно, придётся изменить:

Запуск кода
- Подключите AC-DC к розетке
- Убедитесь, что Arduino подключён к компьютеру
- Убедитесь, что оба устройства в одной сети
- Загрузите модифицированный код на Arduino (или используйте мой, если подходит — почти нет шансов, что не придётся менять)
- Запустите ваш Python, C++ скрипт или любой Telnet/TCP-сервер в сети
- Перезагрузите Arduino для надежности
- Подождите, пока индикатор не станет синим, и попробуйте приложить карту. Если сервер получил ID карты — вы готовы
- Помните значения индикатора: Пурпурный/мигающий красный — загрузка
- Красный — ошибка (карта под неверным углом или сервер не ответил вовремя)
- Зелёный — проход (сервер ответил «го», можно читать следующую карту)
- Синий — ожидание/загрузка (ждёт карту или ответ)
- Если Arduino начинает тормозить и занимает более 30 секунд для показа красного — Ethernet-модуль не смог соединиться с сервером. Причины: недостаточно питания, сервер не запущен, устройства в разных сетях
- Если Arduino 계속 тормозит, попробуйте:
- Отключить брандмауэр Windows
- В дополнительных настройках брандмауэра разрешить входящий/исходящий порт 23
- Пробросить порт 23 на роутере к компьютеру
- Если по Wi-Fi — подключите Arduino и компьютер кабелем к одному роутеру
- Купите более мощный AC-DC адаптер
- Или, возможно, вы ошиблись с IP-адресом
- При проблемах пишите на smerkousdavid@gmail.com
- ВСЁ ГОТОВО!!!

Помните: кода для замка двери нет, у меня его нет, значит, вам придётся добавить код, если хотите использовать это не только как систему отслеживания, но и как систему управления доступом.
Пожалуйста, читайте ниже:
Код
Код для Arduino C/C++
Это прошивка для Arduino, почти готовая к работе — нужно только настроить шлюз, IP, MAC, DNS.
/*
* ----------------------------------
* MFRC522 Arduino
* Reader/PCD Nano v3
* Signal Pin Pin
* ----------------------------------
* RST/Reset RST D9
* SPI SS NSS D10
* SPI MOSI MOSI D11
* SPI MISO MISO D12
* SPI SCK SCK D13
*/
// ПЕРВАЯ БИБЛИОТЕКА — UIPEthernet, ВТОРАЯ — MFRC522, ОБЕ НА GITHUB
#include <UIPEthernet.h>
#include <SPI.h> // Для выбора ключа
#include <MFRC522.h> // Библиотека RFID ключа
#define RST_PIN 9 // Настраиваемо, см. типичную распиновку выше — для Arduino Nano — для RFID
#define SS_PIN 8 // МЫ ИСПОЛЬЗУЕМ 8 ДЛЯ RFID, ПОТОМУ ЧТО ETHERNET МОДУЛЬ ИСПОЛЬЗУЕТ 10
byte sector = 0;
byte blockAddr = 0;
//////// Доступ к определённым секторам/блокам карты, трейлер-блок — последний блок
byte trailerBlock = 1;
int red = 3;
int blue = 4; // Пины для RGB LED
int green = 5;
EthernetClient client; // ЭКЗЕМПЛЯР ETHERNET
MFRC522 mfrc522(SS_PIN, RST_PIN); // Создание экземпляра MFRC522
MFRC522::MIFARE_Key key; // Экземпляр ключа
signed long timeout; // ТАЙМАУТ, ЧТОБЫ НЕ ВИСЕТЬ ВЕЧНО
void setup() {
// UI BEGIN
pinMode(red, OUTPUT);
pinMode(blue, OUTPUT); // Инициализация RGB LED
pinMode(green, OUTPUT);
Reset(); // Старт с выключенными светодиодами
Serial.begin(9600); // Соединение с компьютером 9600 бод
// UI END
// ETHERNET MODULE INITIAL
SPI.begin(); // Инициализация SPI шины
uint8_t mac[6] = {0x00,0x01,0x02,0x03,0x04,0x05}; // MAC = 000102030405
IPAddress mip(192,168,1,160); // IP = 192.168.1.160
IPAddress mdns(8,8,8,8); // DNS = 8.8.8.8
IPAddress mgate(192,168,1,5); // GATEWAY = 192.168.1.5
IPAddress msubnet(255,255,255,0); // SUBNET = 255.255.255.0
Ethernet.begin(mac, mip, mdns, mgate , msubnet); // ПОДКЛЮЧЕНИЕ С ВЫШЕУКАЗАННЫМИ
Serial.println("Succesful connection"); // УСПЕШНОЕ СОЕДИНЕНИЕ
// END OF ETHERNET
for(int t = 255; t > 0; t--) {
analogWrite(red, t); // Просто для красоты, но дайте хотя бы секунду между SPI Ethernet и RFID
delay(10);
}
// RFID INITIAL
mfrc522.PCD_Init(); // Инициализация карты MFRC522
for (byte i = 0; i < 6; i++) { // Подготовка ключа (используется как ключ A и ключ B)
key.keyByte[i] = 0xFF; // Используем FFFFFFFFFFFFh — ключ по умолчанию при поставке
}
Serial.println(F("Scan a Card"));
dump_byte_array(key.keyByte, MFRC522::MF_KEY_SIZE); // Получить размер ключа
timeout = 0;
delay(2000);
Reset();
} // END RFID INITIAL
void loop() { // Запуск навсегда
// Поиск новых карт
if ( ! mfrc522.PICC_IsNewCardPresent()) {
digitalWrite(blue, LOW);
return;
}
// Выбор одной из карт
if ( ! mfrc522.PICC_ReadCardSerial()) return;
digitalWrite(blue, HIGH); // Показать пользователю, что карта прочитана
byte piccType = mfrc522.PICC_GetType(mfrc522.uid.sak);
// Проверка совместимости с картой Mifare
if ( piccType != MFRC522::PICC_TYPE_MIFARE_MINI &&
piccType != MFRC522::PICC_TYPE_MIFARE_1K &&
piccType != MFRC522::PICC_TYPE_MIFARE_4K) {
Error();
return;
}
byte status;
byte buffer[18];
byte size = sizeof(buffer);
status = mfrc522.PCD_Authenticate(MFRC522::PICC_CMD_MF_AUTH_KEY_A, trailerBlock, &key, &(mfrc522.uid));
if (status != MFRC522::STATUS_OK) {
Serial.print(F("PCD_Authenticate() failed: "));
Serial.println(mfrc522.GetStatusCodeName(status));
Error();
return;
}
// Чтение данных из блока
status = mfrc522.MIFARE_Read(blockAddr, buffer, &size);
if (status != MFRC522::STATUS_OK) {
Serial.print(F("MIFARE_Read() failed: "));
Serial.println(mfrc522.GetStatusCodeName(status));
Error();
}
// Остановка PICC
mfrc522.PICC_HaltA();
// Остановка шифрования на PCD
mfrc522.PCD_StopCrypto1();
// ПОСЛЕ ЧТЕНИЯ КАРТЫ ОТПРАВКА НА СЕРВЕР
if (client.connect(IPAddress(192,168,1,100),23)) {
timeout = millis()+1000;
Serial.println("Client connected");
const String ID = dump_byte_array(buffer, size);
client.println(ID);
Serial.println("sent :" + ID);
delay(10);
while(client.available()==0) {
if (timeout - millis() < 0) goto close;
}
int size;
while((size = client.available()) > 0) {
uint8_t* msg = (uint8_t*)malloc(size);
size = client.read(msg,size);
Serial.write(msg,size);
if(size == sizeof("g") - 1) {
Pass();
} else {
Error();
}
free(msg);
}
close:
client.stop();
} else {
Serial.println("Couldn't connect to Server");
Error();
}
// END OF SENDING TO SERVER
Reset(); // ПЕРЕЗАПУСК ЦИКЛА БЕЗ СВЕТОДИОДОВ
}
// ПРЕОБРАЗОВАНИЕ БУФЕРА В ОДНУ СТРОКУ В ВЕРХНЕМ РЕГИСТРЕ — ЭТО НАШ ID СЕКТОРА И БЛОКА
String dump_byte_array(byte *buffer, byte bufferSize) {
String out = "";
for (byte i = 0; i < bufferSize; i++) {
out += String(buffer[i] < 0x10 ? " 0" : " ") + String(buffer[i], HEX);
}
out.toUpperCase();
out.replace(" ", "");
return out;
} // END DUMP_BYTE_ARRAY
// МЕТОДЫ УПРАВЛЕНИЯ СВЕТОДИОДАМИ
void Error() {
digitalWrite(red, LOW);
delay(700);
digitalWrite(red, HIGH);
}
void Pass() {
digitalWrite(green, LOW);
delay(700);
digitalWrite(green, HIGH);
}
void Reset() {
digitalWrite(red, HIGH);
digitalWrite(blue, HIGH);
digitalWrite(green, HIGH);
} // END OF FILE
Пример кода сервера Python
Полный пример использования сервера:
import SocketServer
class MyTCPHandler(SocketServer.BaseRequestHandler):
def handle(self):
# self.request — TCP-сокет, подключённый к клиенту
self.data = self.request.recv(1024).strip()
print "{} wrote:".format(self.client_address[0])
print self.data
"""
SQL STUFF HERE
if(self.data == SQL NAME or something) {
self.request.sendall("g")//send good
//INSERT TIME AND LOCATION INTO SQL HERE
} else {
self.request.sendall("bb")//send bad
//DO NOTHING just send to arduino bad data
}
"""
self.request.sendall("g")
if __name__ == "__main__":
HOST, PORT = "", 23
server = SocketServer.TCPServer((HOST, PORT), MyTCPHandler)
server.serve_forever()
Обновлённый код на GitHub
Самый свежий код здесь: https://github.com/smerkousdavid/InternetRFIDTags
Схемы
Схема простая, поэтому просто фото с проводкой:

Производственный процесс
- Промышленность открыток: история, производство и будущие тренды
- Кредитная карта: история, дизайн, производство и будущие тренды
- Надёжный RFID-замок на Arduino с RC522 (MIFARE 13.56 МГц) и сервоприводом
- Создание надежного RFID-замка на Arduino — пошаговое руководство
- Надежная система учета рабочего времени на Arduino с RFID и Python
- Сборка Bluetooth-робота-шпиона на Arduino с управлением с телефона
- FlickMote: жестовое IR-пульт для умного дома на Arduino 101 и ультразвуковом датчике
- DIY Arduino TV-B-Gone: универсальный пульт для выключения любого телевизора
- Создание пользовательских LED-часов с будильником — видно с 12 метров
- Чтение дискет Amiga на Arduino: открытое решение для восстановления данных