Урок 6. Arduino считываем метки (RFID-модуль RC522)
Для начала необходимо установить библиотеку RFID Library for MFRC522.
Контакты на модуле RFID-модуль RC522 необходимо подключить к Ардуине. Для подключения удобно использовать провода папа-мама.

Описание контактов у RFID-модуля RC522:
- 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 — линия прерываний;
| MFRC522 | Arduino Uno | Arduino Mega | Arduino Nano v3 | Arduino Leonardo/Micro | Arduino Pro Micro |
| RST | 9 | 5 | D9 | RESET/ICSP-5 | RST |
| SDA(SS) | 10 | 53 | D10 | 10 | 10 |
| MOSI | 11 (ICSP-4) | 51 | D11 | ICSP-4 | 16 |
| MISO | 12 (ICSP-1 ) | 50 | D12 | ICSP-1 | 14 |
| SCK | 13 (ICSP-3) | 52 | D13 | ICSP-3 | 15 |
| 3.3V | 3.3V | 3.3V | Стабилизатор 3,3В | Стабилизатор 3,3В | Стабилизатор 3,3В |
| GND | GND | GND | GND | GND | GND |
В комплекте с модулем RFID-RC522 идут две метки, одна в виде пластиковой карточки, а вторая в виде брелка. При необходимости их можно докупить отдельно.
После того как все будет подключено на модуле будет гореть индикатор, это говорит о том что питание поступает на RFID . Пришло время запустить пробный скетч который находится в библиотеке которую мы установили.
Необходимо проверить правильность заданных констант:
#define SS_PIN 10 #define RST_PIN 9 // Данные константы соответствуют
Теперь загружаем скетч в ардуину и включаем Мониторинг последовательного порта.
Подносим метку к ридеру и модуль считает все данные с данной метки, например уникальный идентификатор метки UID.

Видео работы RFID-RC522:
RFID-метка на простой логике

Объявлено новое соревнование 7400, и нужно сделать что-то новое. Нельзя ударить в грязь лицом после победы в прошлом году 😉
У меня было несколько расплывчатых идей, но их было недостаточно, чтобы вызвать реакцию «Ух ты!» или «Ты маньяк!». Нужно серьезно потрудиться, чтобы оставаться на уровне моей предыдущей разработки — емкостного сканера.
Я устроил мозговой штурм с моими товарищами: Педерсеном (Pedersen), Асбьёрном (Asbjørn) и Флеммингом (Flemming), которые тут же придумали множество смешных идей. И вот Флемминг упомянул RFID (он разработчик системы управления доступом, которая основана на RFID). А вот это уже мысль. Конечно, первые мысли были об RFID-считывателе, но мы уже собрали их довольно много, и это было скучно. Однако, появилась идея сделать RFID-метку. Я не знаю, кто упомянул это первым, и, как обычно в мозговом штурме, идеи рождаются коллективным разумом. Итак, решено сделать RFID-метку, собранную исключительно на 7400-ой логике.
Содержание
- Принцип работы метки
- Питание
- Конструкция метки
- Принципиальная схема
- Регистр данных
- Резонансный контур
- Восстановление тактового сигнала
- Делитель частоты
- Счетчик по модулю 128
- Манчестерское кодирование
- Двухфазное кодирование
- Модулятор
- Сборка прототипа
- Отладка
- Проблемы с ФАПЧ
- Дешевые считыватели и мусорный сигнал
- Поиск логических ошибок
- Тест пассивного питания
- В погоне за резонансным питанием
- Печатная плата
- Cпецификация
- Замечания по безопасности
- Корпус
- Сборка печатной платы
- Паразитное питание
- Модуляция током или напряжением
- Законченная версия 1
- Видео-демонстрация
- Заключение
Принцип работы метки
- Несущая частота: 125 кГц, 13,56 МГц, 433 МГц, обычно с амплитудной модуляцией
- Кодирование: манчестерский код, двухфазная (Biphase) или фазовая манипуляция (PSK)
- Скорость передачи: 1, 2, 4 кбит/с или более
- Вшитый неперезаписываемый идентификатор, опционально — перезаписываемая память
- Подсчет контрольных сумм с помощью четности и CRC
Транспондер EM4100 работает на частоте 125 кГц с амплитудной модуляцией. Встречаются все виды кодирования, но чаще используется манчестерское на скорости 2 кбит/с. Транспондер шлет 64 бита данных, которые включают в себя: 32-битный идентификатор, 8-битный код изготовителя/версии, 9-битный заголовок, 14-битную контрольную сумму и 1 стоп-бит. Данные в метке кодируются так, что в них содержится уникальный паттерн для синхронизации. EM4100 отправляет последовательность из девяти единиц, которая не может встретиться нигде, кроме как в начале пакета данных.
Вы можете купить такие метки где угодно, например, на Itead, Seeed или Sparkfun. Там же можно найти RFID-считыватель, который будет с ними работать.

- Несущая 125 кГц
- Амплитудная модуляция и, как минимум, манчестерское кодирование
- Скорость 2 кбит/с или настраиваемая
- Настраиваемые биты данных
- Добавление заголовка и стоп-бита
- Автоматический подсчет контрольных сумм
- Желательно, пассивное питание
Питание
Главной особенностью транспондера является то, что он получает энергию из электромагнитного поля считывателя. Было бы замечательным достижением питать метку на 7400-ых микросхемах исключительно от электромагнитного поля. Для имеющегося RFID-считывателя были проведены измерения с помощью простой установки. Берем катушку, подбираем параллельно включенный конденсатор для резонансной частоты 125 кГц и смотрим, как много энергии можно снять.

К резонансному контуру (3,3 мГн и 470 пФ) подключен мостовой выпрямитель (на диодах Шоттки), а после него — конденсатор 10 мкФ и нагрузка: резисторы 4,7 кОм, 12 кОм или 47 кОм. Получается, что передача максимальной мощности происходит при токе нагрузки около 700 мкА, когда напряжение достигает 19 В. Другими словами, из электромагнитного поля можно извлечь более 13 мВт мощности. При напряжении 3,3 В максимальный ток нагрузки будет около 2 мА. Этого должно хватить для питания множества микросхем серии 74HCxx. (Отечественный аналог — серия КР1564. — Прим. перев.)
Микросхемы 74HCxx — полностью КМОП и имеют почти нулевой статический ток потребления. Они рассеивают мощность только при переключениях, перезаряжая входные и выходные емкости. Принимая напряжение питания равным 3,3 В, ток — 700 мкА и тактовую частоту — 125 кГц, получаем, что резонансный контур может питать схему с суммарной емкостью 1700 пФ (U * C = I * T). Это означает, что мощности должно хватить на множество микросхем и линий ввода-вывода.
Использование метки на более высоких частотах, например, 13,56 МГц, намного проблематичнее. На два порядка более высокая частота означает на два порядка большее энергопотребление. Отсюда следует, что практически невозможно использовать данную метку на высоких частотах.
Что касается серии микросхем HCT (Отечественный аналог — серия КР5564. — Прим. перев.), их нельзя использовать в данной конструкции. Серия HCT имеет в среднем более высокий ток покоя, и, что важнее, дополнительный вытекающий ток через каждый вход, из-за совместимости с уровнями TTL. Вход элемента серии HCT будет источником тока, если он не подтянут к шине питания. Этот ток обозначен в документации как ΔIcc (добавочный ток покоя) на каждый вход. Его значение составляет 10-1000 мкА, в зависимости от подключенной нагрузки. Это означает, что много энергии уходит впустую, что совсем нежелательно.
Некоторые соображения касательно аналоговой части. Важным фактором является добротность резонансного контура. Более высокая добротность при неизменной резонансной частоте означает, что с контура будет сниматься меньше энергии. С другой стороны, высокая добротность облегчает модуляцию. Модуляция есть не что иное, как изменение параллельного сопротивления, что влечет за собой изменение добротности: Q = R * sqrt (C/L). Все переменные, R, C и L, должны быть подобраны для оптимальной производительности в пределах рабочего диапазона. Баланс должен быть определен экспериментальным путем.
Конструкция метки
Метка EM4100 включает в себя регистр данных, схемы питания, тактирования, модуляции и управления. Все компоненты реализованы энергосберегающими и обеспечивают максимальную гибкость.
Принципиальная схема
Следует отметить, что окончательный проект включает в себя все исправления ошибок и некоторые дополнения, которые были сделаны на стадии создания прототипа. Ниже будет подробная информация о внесенных изменениях. Чтобы уберечь читателя от возгласа «многабукв, ниасилил!», сразу приведу окончательный вариант.

Страница 1, 64-битный регистр данных и схема вычисления четности:

Страница 2, схемы питания, тактирования, управления, ввода идентификатора метки, а также временные диаграммы:
Вся схема в PDF.
Схема в формате gschem.
Регистр данных
- Паттерн синхронизации: девять единиц
- Идентификатор производителя/версии: 2 блока по 5 бит, из которых 4 бита — данные, а пятый — четность
- Уникальный идентификатор: 8 блоков по 5 бит, из которых 4 бита — данные, а пятый — четность
- Контрольная сумма: 4 бита четности, подсчитанные по столбцам
- Стоп-бит: «0»
Смотрите описание протокола, там красивая табличка. Данные передаются старшим битом вперед. Всего есть 40 бит (8+32), которые пользователь устанавливает переключателями. Многие RFID-считыватели будут игнорировать поле «ID производителя/версии» и выдавать только 32-битный уникальный идентификатор (в десятичной системе, аррррр!).
Четность по строкам считается среди 4-битных групп (полубайт). Бит четности вычисляется при помощи 4-входового XOR (исключающее ИЛИ) следующим образом:
RPx = D0⊕D1⊕D2⊕D3 = (D0⊕D1)⊕(D2⊕D3),
что реализуется на трех элементах 74HC86. Четность по столбцам вычисляется аналогично, но по 10 битам, используя элемент 74HC280 для первых девяти бит и 74HC86 — для десятого.
Значительная часть меток имеют неизменяемые идентификаторы. Данная конструкция может выдавать все возможные идентификаторы, требуется только задать номер с помощью переключателей, а расчет четности остается прежним. Несмотря на то, что схема вычисления четности содержит много микросхем, она почти не потребляет энергии, так как находится в статическом состоянии. Таким образом, гибкость может быть достигнута только ценой добавления микросхем, без ущерба другим характеристикам.
Резонансный контур
Сердцем схемы питания является резонансный контур из конденсатора и катушки. Напряжение выпрямляется мостом на диодах Шоттки и поступает на накопительный конденсатор. Резонанс в контуре в сочетании с высокой добротностью будет обеспечивать достаточно высокое напряжение. Входное напряжение ограничено цепочкой светодиод+стабилитрон. Светодиод загорается, когда накопитель заряжен, а затем сжигает излишки энергии, защищая схему от перенапряжения.
Накопительный конденсатор вмещает достаточно энергии, чтобы питать метку некоторое время. Стабилитрон ограничивает максимальное напряжение на уровне примерно 12 В, а стоящий после него LDO -стабилизатор требует всего 0,4 вольта сверх рабочего напряжения 3,3 В. При емкости конденсатора 2 мкФ и расчетной нагрузке 800 мкА время работы составит (12В — 3,7В) * 2мкФ/800мкА ≈ 20 мс. Полный цикл передачи 64 бит на скорости 2 кбит/с занимает 32 мс. Накопитель будет заряжаться, по крайней мере, при отключенном модуляторе (около 50% времени), поэтому энергии должно быть достаточно.
Схема разработана так, что можно подключить дополнительный источник питания (3 или 4 батарейки AAA), а также включать/выключать LDO-стабилизатор. Батарея необязательна, но я не могу гарантировать, что все RFID-считыватели будут давать достаточную мощность.
Любопытный читатель может спросить меня, почему блок питания обеспечивает 3,3 В, в то время как семейство 74HC может работать и при 2 вольтах. Причина тому — схема ФАПЧ (см. ниже, «Восстановление тактового сигнала»). ГУН микросхемы 74HC4046 может работать лишь при напряжении питания выше 3 В. Если ФАПЧ не используется, напряжение питания можно уменьшить до 2 вольт. Все микросхемы семейства HC достаточно быстры, чтобы даже при 2 В справляться с тактовой частотой 125 кГц.
Восстановление тактового сигнала
Резонансный контур работает на частоте 125 кГц, которая используется для тактирования всей схемы. Сигнал с катушки через разделительный конденсатор подается на триггер Шмитта 74HC14 и преобразуется в сигнал RAWCLK (таким же образом обычно снимается сигнал 50 Гц с силового трансформатора). Гистерезис триггера Шмитта необходим по причине того, что сигнал имеет пологие фронты и может нести в себе много шума. Главной проблемой являются индуктивные наводки на катушку от электросети 50 Гц, которые приводят к возникновению фазового шума в тактовом сигнале. Триггер Шмитта обеспечивает устойчивость к шумам и убирает большую часть 50-герцовых наводок.
Опциональная схема ФАПЧ ( PLL ), выполненная на микросхеме 74HC4046, синхронизирует тактовый генератор с несущей частотой резонансного контура. ФАПЧ нужна только в том случае, если несущая частота прерывается. Такие разрывы могут возникать у RFID-считывателей, которые периодически подстраивают амплитуду электромагнитного поля, так, что сигнал оказывается ниже порога срабатывания триггера Шмитта. Тем не менее, считыватель остается способен принимать данные и при низких амплитудах поля. ФАПЧ поддерживает тактовый сигнал во время таких периодов. Схема имеет переключатель, позволяющий разрешить или запретить использование ФАПЧ. С отключенной ФАПЧ ниже потребление энергии, но ее включение может быть полезно для работы с некоторыми считывателями.
Проблемы с ФАПЧ могут возникнуть с дешевыми считывателями, которые генерируют несущий сигнал со значительным фазовым шумом (джиттером). Это заставляет ФАПЧ непрерывно работать, подстраивая фазу, что повышает энергопотребление. Другая проблема с ФАПЧ может возникнуть с очень плохими RFID-ридерами, которые восстанавливают принятые данные исключительно по своему внутреннему генератору 125 кГц. Если метка пропустит период, считыватель запутается, и случится Неприятная Штука™.
Делитель частоты
Некоторые тактовые сигналы являются производными (не в математическом значении слова «производная». — Прим. перев.) от главного сигнала MCLK. Метки EM4100 обычно выпускают под скорости передачи данных MCLK/16, MCLK/32 и MCLK/64, хотя значение MCLK/64 (2 кбит/с) наиболее распространено. Переключаемый делитель частоты для настройки скорости передачи собран на половинке счетчика 74HC393. Делитель формирует сигнал DCLK. Набор переключателей задает коэффициент деления для тактового сигнала.
Вторая половина счетчика 74HC393 формирует все внутренние тактовые сигналы (CCLK, PCLK и SCLK). Регистр данных сдвигается по сигналу SCLK, который задает скорость передачи данных.
Полная временая диаграмма приведена на схеме устройства (страница 2).
Счетчик по модулю 128
Регистр данных содержит 64 бита, но проблема в том, что перезагрузка данных занимает еще один такт. Если считать только до 64, то сигнал окончания счета перекроет один сигнал сдвига, что означает пропуск бита в следующем 64-разрядном цикле и приведет к неправильному началу цикла передачи данных. Проще говоря, полный цикл передачи 64 бит и перезагрузки регистра занимает 65 тактов. — Прим. перев.
Микросхема 74HC40103 работает как счетчик по модулю 128, ведя обратный отсчет от 127 до 0 на двойной скорости передачи данных, а затем перезагружаясь. Сигнал конца счета (MOD128) немного сдвинут по времени за счет синхронизации с CCLK для того, чтобы избежать перекрывания фронта с фронтом SCLK. Это выполняется при помощи триггера 74HC74, который формирует сигнал параллельной загрузки регистра ~PLOAD.
Манчестерское кодирование
Схема кодирования, используемая в большинстве меток, как упоминалось ранее, манчестерская. Основное преимущество манчестерского кода — в простоте его генерации. Исключающее ИЛИ между тактовым сигналом и потоком данных дает манчестерский код. Элемент 74HC86 складывает сигналы SCLK и SDELAY для кодирования потока данных.
Фактический поток данных из регистра, SOUT, задерживается на один такт для формирования SDELAY. Когда регистр данных перезагружается, то SOUT сразу же изменяется с «0» на «1» (переход от стоп-бита к старт-биту). Тем не менее, параллельная загрузка регистра, как было сказано выше, не привязана к фронту сигнала сдвига, а генерация манчестерского сигнала должна оставаться синхронной с SCLK, чтобы не было ложных переходов. Задержка на один такт делает все биты в потоке данных синхронными с SCLK.
Манчестерский сигнал, по прогнозам, должен иметь выбросы (глитчи) при переходах 0→1 и 1→0. В этих местах сигнал SCLK инвертируется, но SDELAY и SOUT не синхронны на 100%. Выброс вызывается гонкой сигналов SDELAY и SCLK из-за задержки срабатывания триггера 74HC74. Однако, этот выброс настолько узкий (10-30 нс), что модулятор не успевает на него среагировать, не говоря уже о приемнике, в котором сигнал сильно фильтруется. Так что выброс оставили как есть.
Двухфазное кодирование
Другая разумно легко реализующаяся схема кодирования — это двухфазная. Она идентична дифференциальному манчестерскому кодированию с фазовой задержкой и представляет собой частотно-манипулированный ( FSK ) сигнал, наложенный на несущую с помощью амплитудной манипуляции ( ASK ). Сложность двухфазного кодирования в том, что уровень выходного сигнала всегда переменный, в то время как частота изменяется в соответствии с передаваемыми данными. Эту трудность можно преодолеть, используя двойную скорость генератора, а затем разделив полученный результат на два.
На первом этапе происходит мультиплексирование сигналов PCLK и SCLK на основе потока передаваемых данных при помощи набора элементов 74HC00 (И-НЕ). На выходе мультиплексора наблюдаются выбросы, по тем же причинам, что описаны выше (гонка SDELAY и SCLK), а также потому, что PCLK и SCLK не синхронны. (Приветствую тех, кто дочитал до этого места и не уснул. Дальше будет веселее. — Прим. перев.) Счетчик 74HC393 является асинхронным, и это вызывает проблемы. Сигнал с выбросами не может быть безболезненно пропущен через делитель на два, ведь выбросы тоже могут быть интерпретированы счетчиком как импульсы. Мультиплексированный сигнал очищается от выбросов путем квантования сигналом CCLK, который гарантированно держится на высоком уровне значительно дольше, чем длительность выброса. Наконец, деление частоты на два с помощью триггера 74HC74 завершает формирование двухфазного сигнала.
Предусмотрены переключатели для выбора типа кодирования: манчестерское или двухфазное.
Модулятор
Наконец, закодированный сигнал должен быть направлен обратно в катушку, чтобы его принял RFID-считыватель. На обоих выводах катушки напряжение может быть как положительным, так и отрицательным, поскольку в ней индуцируется переменный ток.
Амплитудная модуляция осуществляется созданием контролируемого замыкания на землю обоих концов обмотки с помощью пары МОП-транзисторов, каждый из которых работает на своем полупериоде сигнала. Выпрямительный мост образует замкнутый путь на землю для каждого из выводов. Несмотря на то, что МОП-транзисторы способны реагировать на вышеупомянутые выбросы сигнала, резонансный контур не может, так как он настроен на частоту, на 2-3 порядка более низкую, чем частота выбросов.
Большинство картинок и диаграмм, которые вы найдете в сети, не показывают эту часть или показывают ее неверно. Замыкание является контролируемым по времени, в соответствии с закодированными данными, и ограниченным по сопротивлению, за счет резисторов. Пассивные RFID-метки, как правило, малы, и оперируют на порядок меньшей мощностью, чем эта. Метки обычно имеют маленькие катушки, и таким образом, могут достичь только очень небольшой глубины модуляции. Если большую катушку в нашей конструкции замкнуть накоротко, посланный сигнал, скорее всего, будет настолько сильным, что собьет с толку большинство считывателей. Также, короткое замыкание катушки требует использования ФАПЧ для поддержания тактовой частоты на то время, пока катушка замкнута.
Сборка прототипа
Теперь, если теория и схема верны, все должно работать как задумано. Тем не менее, практика и теория не всегда соответствуют друг другу, и мое серое вещество тоже подводит меня время от времени.

Прототип имеет 40 красных переключателей для установки идентификаторов метки и 4 синих — для делителя. Верхний ряд из 8 микросхем — это элементы «Исключающее ИЛИ» 74HC86 для вычисления четности по строкам. Средний ряд — восемь сдвиговых регистров 74HC165, которые образуют 64-битный регистр данных. В нижнем ряду левые пять микросхем подсчитывают четность по столбцам — четыре 74HC280 и одна 74HC86. Остальное — это счетчики, ФАПЧ и триггера Шмитта.
Пайка заняла около 6 часов в общей сложности. Основная задача прототипа — показать работоспособность основных функций и возможность работы всего устройства от электромагнитного поля. Прототип содержит только элементы для манчестерского кодирования, включая схему ФАПЧ.

Отладка
Разработка основной схемы была несложной задачей. Это заняло всего несколько часов. Тем не менее, некоторые вещи не были запланированы достаточно тщательно и некоторая функциональность должна была быть проверена экспериментально.
Первоначальные мысли, родившиеся после поиска материалов в сети, говорили о том, что модуляция должна быть глубокой, очень глубокой, и что катушка должна полностью замыкаться при этом. Это заставило меня потратить много времени на отладку ФАПЧ, что не всегда так просто, как кажется.
Проблемы с ФАПЧ
Проблема с ФАПЧ в том, что нужно сбалансировать несколько параметров для обеспечения стабильной работы. С одной стороны, необходимо обеспечить быстрый и стабильный захват фазы, в то же время пытаясь сократить как диапазон захвата, так и дрейф восстановленного тактового сигнала при прерывании несущей. Использование документации на 74HC4046 оказалось сложне, чем я думал. Там нет готовых формул для всех компонентов, а некоторые нужно находить по графикам (для меня осталось загадкой, почему значения графиков расходились с реальностью в два раза, ну да ладно). Потребовалось некоторое время, чтобы найти подходящие номиналы для всех компонентов, и убедиться, что частота 125 кГц пришлась на середину диапазона ГУН, и в то же время дрейф был несущественно мал.

Во время анализа дрейфа я также обнаружил значительную порцию 50-герцовых наводок, дающих частотную модуляцию сигналу ФАПЧ. Сильное сжатие катушки в руке убирало наводки. Проблема была в том, что фазовый компаратор на входе ФАПЧ имеет переменный порог срабатывания, из-за того, что входной сигнал не является двоичным. Устройство восстановления тактового сигнала с емкостной связью давало фронты, неподходящие для логических схем. Было установлено, что триггер Шмитта решает эту проблему.
Важным свойством триггера Шмитта является то, что он потребляет большую мощность во время фронтов сигнала. Причиной этого является то, что входной каскад работает в линейном режиме в сочетании с обратной связью для обеспечения гистерезиса. К счастью, время, проводимое в режиме большой мощности, невелико, и общее энергопотребление ограничено. Но все же использование триггера Шмитта приводит к утечке в системе.
Дешевые считыватели и мусорный сигнал
Когда я начинал проект, я понятия не имел, насколько чувствительным к модулированному сигналу будет RFID-считыватель. Поэтому модуляция была реализована в виде полного замыкания катушки, как было найдено в сети. Вскоре оказалось, что модуляция была слишком глубока, и RFID-считыватель не мог выделить из сигнала стартовые и стоповые биты. Электроника ридера была просто ошеломлена такой модуляцией и выдавала всякий мусор.

Единственный доступный считыватель пришлось вскрыть и припаять несколько проводов к его плате, чтобы посмотреть, какие на самом деле данные он принимает. Оказывается, что RFID-ридер может принять данные с катушки, закороченной источником тока порядка 50-100 мкА. Это несколько далековато от тех 2,5 мА, которые дает полное замыкание катушки. Дополнительным преимуществом является то, что ФАПЧ теперь необязательна. Восстановление тактового сигнала будет идти даже в то время, когда модулятор замыкает обмотку. Остаточной индукции катушки оказалось достаточно, чтобы поддерживать тактирование.

Модулятор был изначально собран на биполярных транзисторах. Это привело к пологим фронтам сигнала, потому что транзисторы работали в режиме низкого энергопотребления, а значит, весьма медленно. Замена их на МОП-транзисторы сделала модулятор быстрее и сэкономила очередные 27 мкА потребляемого тока. У меня были только транзисторы в корпусах SOT-23 (Маленькие тараканчики для SMD-монтажа. — Прим. перев.), и их пришлось ставить на печатную плату при помощи штырьков. 3,3-вольтовый LDO-стабилизатор, имевшийся под рукой, был в корпусе SO-8, он смонтирован проволочками на куске штыревого разъема.
Единственный RFID-считыватель был неизвестного производства и соответствующего качества. Он оправдал самые худшие ожидания. Если вы отправляете на считыватель некорректные данные, вы можете: а) подвесить считыватель, б) получить мусор на вводе в компьютер и в) проклясть все на свете, пытаясь понять, почему что-то не работает как ожидалось. Единственное, что выяснилось, это то, что нужно было собрать свой собственный считыватель в первую очередь. Оказалось, что считыватели на входных дверях здания были гораздо надежнее и смогли переварить все, что я на них передавал.
Поиск логических ошибок
После получения на считывателе нормально декодируемого сигнала он по-прежнему не работал как надо. В схеме обнаружились две ошибки.
Первая была в счетчике по модулю 128, который тактировался по переднему фронту сигнала PCLK. Однако должен был — по заднему. Прототип посылал 10 стартовых бит вместо девяти, потому что сигнал PLOAD перекрывал передний фронт тактового сигнала сдвига. Простой инвертор на PCLK решил эту проблему. Окончательный дизайн, с двухфазным энкодером, формирует правильный сигнал PCLK как часть работы энкодера.
Вторая ошибка заключалась в полярности манчестерского кода. Единственное упоминание в сети гласило: «низкий уровень означает высокий ток» и содержало диаграмму перехода «низкий → высокий уровень» для логической «1». Описание допускает множество интерпретаций. Оказывается, это означает: «низкий уровень означает включенный модулятор (закороченную катушку)». К счастью, задержка потока данных для формирования SDELAY давала и прямой, и инвертированный потоки данных. Переделка манчестерского энкодера для использования инвертированного сигнала была тривиальной.
Тест пассивного питания
Было измерено энергопотребление всего прототипа, чтобы понять, возможно ли пассивное питание. Потребляемый ток при 3,3 В колебался около 780 мкА, это достаточно мало, чтобы замкнуть контур и перевести прототип на пассивное питание.
А затем… ничего не произошло с дешевым считывателем.
Все работало как ожидалось, питание поступало, данные отправлялись, и вдруг, внезапно, «БИП!». Код был корректно распознан и высветился на экране компьютера, к которому подключен ридер. Успех! Теперь можно открывать дверь самодельной RFID-меткой.

В погоне за резонансным питанием
Питание от резонансного контура должно быть настроено таким образом, чтобы считыватель не сбивался слишком часто, и в то же время извлекалось достаточно энергии для работы метки. Это оказалось сложнее, чем я думал. Как говорилось ранее, добротность играет значительную роль. На самом деле, нужна небольшая катушка, достаточно крупная для получения энергии, но достаточно маленькая, чтобы не нагружать передатчик слишком сильно и обеспечивать легкую модуляцию.
Обратите внимание, что резонансная LC-цепь работает не точно на резонансной частоте, рассчитанной для выбранных компонентов. Причина в том, что схема метки создает (слегка емкостную) нагрузку для контура. Таким образом, катушка должна быть немного меньше, чем рассчитано. Это имеет то преимущество, что вы можете сделать катушку в соответствии с теорией, а затем удалять витки до достижения правильной частоты.
Оказалось, что дешевый считыватель был очень чувствителен к высокой нагрузке, и чем ниже была нагрузка, тем лучше он работал. Изначальная катушка, 3,3 мГн была уменьшена вдвое несколько раз, пока некий стабильный компромисс не был найден при индуктивности около 680 мкГн. Вторым изменением было снижение емкости накопительного конденсатора с 10 до 2 мкФ. Считыватель по-прежнему сбоит то и дело, но по крайней мере, работает чаще, чем раньше.
Во всяком случае, контроллер на двери, кажется, был рад всему, что я посылал, и не подводил меня ни разу (даже если я забывал свой настоящий ключ во время тестирования).

Безымянный RFID-ридер прекрасно работает, когда метка имеет внешнее питание. При использовании внешнего источника, по-видимому, лучше включить ФАПЧ. Я думаю, они слишком сэкономили на развязывающих конденсаторах 😉
После обсуждения с Марком (парень, который использует этот фиговый ридер) он сказал мне, что видел проблемы с этим считывателем, даже используя нормальные метки. Мы решили устроить ему небольшой сеанс отладки. В цепях питания ридера присутствовали 200 мВ пульсации (на частоте 125 кГц) и некоторые неприятные импульсы здесь и там. Пайка дополнительных конденсаторов 1 мкФ + 100 нФ в места на плате, отмеченные шелкографией, но не использованные, значительно улучшила работу считывателя. Теперь он спотыкается еще реже и может считывать данные с прототипа даже при пассивном питании.
Замечание для всех: не покупайте такие говносчитыватели. Или купите хороший, или соберите его самостоятельно.
Если вы думаете, что история на этом заканчивается, то вы ошибаетесь. Еще есть куда совершенствовать модулятор, и значительные изменения позволили ему работать гораздо лучше. Даже дешевый безымянный считыватель можно заставить работать хорошо.
Печатная плата
Посмотрев на оригинальную конструкцию и обдумав варианты, было решено, что этот гаджет слишком прикольный, чтобы оставить его в покое в качестве прототипа. Он просто напрашивается на несколько большее внимание и доведения разработки до абсурдного конца. Была разработана печатная плата, и, с некоторой осторожностью, все детали поместились на площади 50×100 мм в два слоя, не выдавая ошибок трассировщика «Недостаточно места». Размер 50×100 означает доступность массового производства на ITead или Seeed (Сервисы изготовления заказных печатных плат. — Прим. перев.). Однако, создание платы размером с кредитную карту оказалось слишком трудным.

Плата разработана под SMD-компоненты, чтобы все уместилось. На ней 412 переходных отверстий диаметром 0,3 мм и дорожки/зазоры минимальной ширины 7 mil. Реализованы все возможности, включая идентификатор, полностью настраиваемый при помощи переключателей, возможность внешнего и пассивного питания, переключение между прямым тактированием и ФАПЧ, манчестерское и двухфазное кодирование и настраиваемую скорость передачи: 1, 2, 4 или 8 кбит/с.
- Счетчик по модулю 128 в прототипе был собран на двух микросхемах 74HC163, которые заменили одной 74HC40103 для экономии места
- Входная защита состояла из двух встречно-последовательно включенных стабилитронов (2×24 В). Их заменили на цепочку стабилитрон+светодиод, которая обеспечивает защиту и индикацию
- В прототипе использована микросхема 74HC14, содержащая шесть триггеров Шмитта. Однако, из них нужен только один, и микросхема была заменена на 74HC1G14, у которой только один элемент в корпусе
- На свободном месте платы было решено собрать двухфазный энкодер и сделать возможность выбора кодирования при помощи переключателей
- LDO-стабилизатор заменен на модель с возможностью включения-выключения (и добавлена кнопка «ВКЛ») и с более низким током потребления
- Теперь можно разрешить/запретить использование ФАПЧ при помощи переключателя. Для снижения энергопотребления схема ФАПЧ отключается, когда она не нужна
Cпецификация
Стоимость деталей составляет меньше 30$ без учета платы и катушки. Катушку вам придется сделать самостоятельно (см. ниже). На самом деле, DIP-переключатели и печатная плата являются самыми дорогими компонентами.
Вы можете заменить большинство компонентов на те, что есть у вас. Тем не менее, входные конденсаторы должны быть в состоянии выдержать не менее 16 В. Кроме того, вы должны использовать резисторы точностью 1% и конденсаторы 5% для резонатора и ФАПЧ, чтобы параметры соответствовали расчетным.
Следует отметить, что развязывающие конденсаторы все по 10 нФ (вместо обычных 100 нФ). Это нужно для снижения нагрузки на резонансный контур. Схема работает на низкой частоте и может выдержать слегка увеличенный уровень шума на шине питания, так как напряжение питания выше минимально допустимого.
Согласно расчетам, катушка должна содержать 89 витков провода диаметром 0,4 мм и иметь средний диаметр (измеренный по средней линии обмотки) 50 мм. Катушка была намотана на оправке диаметром 48 мм (картридж от силиконового герметика), а затем с помощью вощеного шнура ей придали красивую тороидальную форму и плотно уложили витки. Нужная частота резонанса, вероятно, достигается с 88 или 87 витками, в зависимости допусков.
Вы можете сделать катушку любой формы, какая вам нравится (например, квадратную или прямоугольную), если вы правильно настроите контур в резонанс. Тем не менее, изменение формы потребует некоторых экспериментов, так как от размеров зависит индуктивность и сила электромагнитной связи (см. ниже для прямоугольной катушки).
Если вы измеряете индуктивность катушки, делайте это на частоте 125 кГц. Индуктивность зависит от частоты из-за паразитной емкости витков и электромагнитной связи между ними (например, катушка 3,3 мГн показывает индуктивность меньше 100 мкГн на частоте 1 кГц). Паразитные параметры будут также влиять на резонансную частоту и достигаемую добротность.
Замечания по безопасности
Как вы можете видеть, эмуляция RFID-меток тривиальна. Все системы, где для доступа требуется только ключ, уязвимы к атакам эмуляции метки. RFID в системах управления доступом должен использоваться только как один из факторов аутентификации, в связке «то, что у вас есть + то, что вы знаете» (хотя, и это может быть неэффективным).
Даже метки с шифрованием уязвимы для множества атак. Кроме того, становится все легче эмулировать метки на смартфонах с поддержкой NFC (которые обычно работают на 13,56 МГц). Просто правильно напишите приложение для модуляции поля, и вы сможете делать все, что хотите.
В качестве стандартной отмазки напомню, что автор (И переводчик! — Прим. перев.) не несет никакой ответствености за последствия использования информации из данной статьи. Читатель должен сам отвечать за все свои действия.
Корпус
Иногда очень везет. Красивый корпус не помешал бы именно сейчас, когда прототип закончен, а печатная плата заказана. И именно в это время Флеминг закончил собирать и запустил станок лазерной резки OSAA PhotonSaw. После года работы над проектом лазер готов вырезать свои первые детали. Флемминг и Рун делают последние юстировки и ставят на место алюминиевую крышку лазерного шкафа. Вы можете себе представить, как все мы были рады видеть, что эта штука работает.
С работающим станком мы получили возможность протестировать наш проект в реальной жизни. Корпус для нашей RFID-метки сделали из 2-миллиметрового огрстекла. Этот корпус — первый объект, сделанный на PhotonSaw, да!

Родилась идея расположить катушку на внешней стороне корпуса. Сперва было решено использовать половину высоты корпуса, но это не работало на практике (дополнительные отверстия в длинных сторонах, таким образом, не используются). Катушка просто великолепно разместилась по периметру всего корпуса, хотя у меня были сомнения, не будет ли прямоугольная обмотка (105×55 мм) слишком большой для нормальной электромагнитной связи.
Тестовая катушка была намотана, без всяких расчетов, проводом 0,4 мм в 66 витков. И, очевидно, нам опять повезло, потому что катушка получилась точно такой как надо, индуктивностью 645 мкГн, с подключенной меткой давая резонансную частоту 125,2 кГц. Тест на дверном считывателе показал, что прототип работает просто прекрасно с этой катушкой.
С катушкой снаружи корпуса толщину последнего можно уменьшить. Внутренняя толщина теперь зависит только от высоты деталей на плате, и с учетом толщины платы должна составлять около 6 мм. Кроме того, было бы хорошо добавить гравировку. Флемминг предложил скруглить боковые стороны корпуса из эстетических и эргономических соображений. Изогнутый корпус также будет лучше защищать боковые стороны катушки, потому что там, где нет сильного натяжения, витки провода любят вылезать наружу.

Станок PhotonSaw еще не совсем в нормальном состоянии: гравировка на верхней крышке значительно съехала. Необходимо его окончательно отладить перед изготовлением финальной версии корпуса. Изогнутые контуры также подверглись ошибке расчета в программном обеспечении, так как луч не вернулся в начальное положение после прохода замкнутой траектории. Но во всяком случае, кривые выглядят действительно гладкими.
Сборка печатной платы
Прибыла заказанная плата:

Сборка была не очень сложной. На плату по трафарету нанесли паяльную пасту, разместили все детали, а затем запаяли в самодельной печи.

- Площадки для DIP-переключателей расположены слишком близко друг к другу. Пришлось слегка сошлифовать корпуса переключателей с боков, чтобы они встали на место. В следующей версии зазоры увеличили на 10 mil.
- Шелкография с обозначением скоростей передачи сделана неправильно. Значения должны идти в порядке «1 2 4 8», а не «8 4 2 1». Исправим в следующей версии.
- Изменения, внесенные в прототип, видимо, работают слишком хорошо в энергетическом отношении, что привело к целому ряду неожиданных проблем. Было обнаружено паразитное питание схемы в выключенном состоянии.
- Модуляция работает тяжело и неустойчиво. Основная причина заключается в различных уровнях входного напряжения в сочетании с модулятором, который работает в режиме модуляции напряжением.
Паразитное питание
Новый отключаемый стабилизатор (MCP1804) позволяет сэкономить много энергии. Смысл его в том, что подключенного аккумулятора хватит надолго, если метка будет находиться в состоянии сверхнизкого потребления. Но когда катушка находится вблизи считывателя, появляется обходной путь для питания через схему восстановления тактового сигнала.

Через разделительную емкость (47 пФ имеют сопротивление примерно 27 кОм на частоте 125 кГц) и защитные диоды ток поступает на шины питания. Энергии, поступающей с катушки, хватает на поддержание напряжения питания около 1 В. Ток может достигать 250-500 мкА. Удивительно, но микросхемы 74HC, похоже, работают при таком питании. К сожалению, при таком напряжении происходят довольно странные вещи. Микросхемы 74HC имеют внутреннюю схему сброса, и нужно убедиться, что она срабатывает. Обратите внимание, что отключение защитных диодов не помогает. На входах микросхем есть внутренние защитные диоды, которые в этом случае открываются и выполняют ту же работу.
Сброс по питанию срабатывает только если напряжение питания падает ниже определенного уровня в течение некоторого периода времени. Если напряжение остается слишком высоким, то внутренняя логика может запутаться, потому что некоторые ее части могут быть в неопределенном состоянии, в то время как другие работают должным образом. Необходим внутренний сброс для установки всех микросхем в согласованное состояние. Таким образом, схема будет неустойчиво работать при очень низком напряжении питания.
Симптомы наблюдались следующие: метка работает некоторое время, при этом посылая корректные данные. Если катушку убрать от считывателя, а затем вернуть обратно, можете делать ставки, выключится ли при этом метка. Иногда срабатывает, иногда — нет. Отключение ФАПЧ ухудшает ситуацию. Низкое энергопотребление приводит к тому, что ридер время от времени будет принимать данные от выключенной метки. Вот что значит «энергоэффективная система».
Существует два решения: 1) уменьшить конденсатор в цепи восстановления тактового сигнала до 15 пФ, и 2) включить между питанием и землей резистор 22-100 кОм для сброса лишней энергии. Второй метод приводит к росту утечек во время работы и на самом деле не требуется при уменьшении емкости конденсатора. Тем не менее, он предусмотрен как опция, и это все равно лучше, чем неопределенное состояние микросхем.
Модуляция током или напряжением
Модулятор принес свежую порцию головной боли. Модуляция полностью исчезала при помещении катушки на определенном расстоянии от считывателя. Также это могло случиться при перемещении катушки к ридеру или от него.
Причина оказалась в схеме модулятора. МОП-транзисторы замыкают катушку на резистор определенного сопротивления. Однако, если потребление энергии из контура велико, сопротивление модулятора значительно выше, чем сопротивление цепей питания. Это приводит к тому, что глубина модуляции зависит от потребляемого тока, а это не очень хорошо. Ситуацию ухудшил выбор ограничительного стабилитрона на более низкое напряжение, чем в прототипе.

Было принято решение перевести модулятор из режима модуляции напряжением в режим модуляции током. Для первого режима резистор находился в цепи стока, а теперь он включен между истоком и землей. На этом резисторе будет падать напряжение затвор-исток, пока не останется значение чуть выше порога открывания транзистора (0,9-1,1 В), которое переведет транзистор в линейный режим. Теперь ток через транзистор будет стабильным, независимо от напряжения на стоке.
Тестирование на прототипе показало, что модуляция током работает очень хорошо. Дешевый безымянный считыватель больше не сбоит (ну ладно, может быть один раз на сотню или около того). Можно предположить, что это изменение будет работать чудесно и на других ридерах, и метка теперь, вероятно, сможет работать на большинстве из них.
Законченная версия 1
Можно заметить внесенные изменения на печатной плате. У меня не было 15 пФ SMD-конденсатора, пришлось впаять обычный, с ногами. Модулятор оброс дополнительными резисторами на истоках транзисторов. В целом приемлемо для первой версии.
(картинки кликабельны) 


Видео-демонстрация
Заключение
Вы можете подумать, что этот проект, собранный на логике 7400, можно отнести к ретро-схемотехнике, но это не совсем так. Во-первых, современное семейство 74HC не такое уж и старое. Во-вторых, низкопотребляющие схемы всегда актуальны. В-третьих, микросхемы одиночных логических элементов (такие, как использованный триггер Шмитта) часто используются в современных разработках. Часто забывают, что развитие технологий не прекращается и для старых семейств микросхем. Они просто стали менее заметны на фоне общего разнообразия.
Аналоговая часть оказалась сложнее в разработке, чем цифровая. Частично из-за отсутствия спецификаций, но в основном, за счет множества компромиссов, необходимых для соответствия параметрам, и непредвиденных побочных эффектов. Цифровые конструкции имеют относительно мало вариантов, в то время как аналоговые обычно требуют баланса между различными (и часто противоположными) критериями.
Я должен признаться, что микросхемы 74HC сделаны очень, очень хорошо. Разработчики знали, что они делают, и достигли очень низкого энергопотребления. Сперва у меня были некоторые сомнения, сможет ли метка работать от пассивного питания, но после прочтения спецификаций это осталось лишь вопросом правильной схемотехники. Хотя, есть еще возможности для оптимизации различных частей метки.
Теперь посмотрим, как этот проект покажет себя на конкурсе 7400 2012 года. Подача заявок на конкурс заканчивается 31 ноября. Пожелаем автору удачи! — Прим. перев.
- RFID
- 7400 Contest
- overengineering
- логические схемы
- грабли повсюду
Эмулятор RFID

Наверняка каждому из нас, кто хоть раз бывал в обычных офисах, было интересно, как же функционируют эти бесконтактные пропуска. В данной статье мы разберёмся с принципом работы бесконтактных карт и сделаем эмулятор буквально из трёх радиодеталей.
Технология RFID

Внешний вид RFID-меток
RFID (англ. Radio Frequency IDentification, радиочастотная идентификация) — имеет достаточно широкий частотный диапазон и достаточно большое количество различных стандартов, которые так или иначе применимы к данной технологии. Для справки: используются частоты: 125-135кГц, 400 кГц, 6.78МГц, 13.56МГц (карты метро и банковские карты), 27.125МГц, 40.68 МГц, 433.29 МГц, 869 МГц, 915 МГц, 2.45 ГГц, 5.8 ГГц и 24.125ГГц. Как видно частотный диапазон очень широкий.
Мы же будем говорить о самых распространённых и наименее защищённых картах частотного диапазона 125 кГц. Я разберу стандарт EM Marine 4102, так как именно с ним лучше всего знаком. Однако код эмулятора позволяет работать и с другими стандартами, работающими на частоте 125 кГц.
Чтобы мы могли дальше углубиться в теорию, следует рассказать пару слов о принципе работы RFID. Далее в тексте будет приводиться информация, относящаяся к стандарту 125 кГц EM Marine, прочие RFID решения устроены подобным образом.

Считыватель, кроме информационного обмена осуществляет подачу питания. Метка из себя представляет ПЗУ, которое питается от электромагнитного поля, и после подачи питания просто отдаёт записанную информацию.

Из этой схемы хорошо видно, как устроен передатчик и приёмник. Оба колебательных контура настроены в резонанс и используются для передачи данных и передачи энергии, для питания пассивной метки, в роли которой выступает наша карта.
Более детально о принципе работы можно прочитать в [1]

Внутренности разобранной карты
Если разобрать карту, то можно увидеть антенну в виде катушки и чип залитый компаундом, в котором находится ПЗУ и конденсатор ёмкостью 75 пФ.
Описание протокола EM4102
Прежде, чем мы пойдём дальше, давайте разберёмся со стандартом EM4102, который мы будем эмулировать. EM4102 совместимая RFID-метка содержит 64 бита памяти только для чтения. По сути — это и есть ПЗУ, то есть информация может быть считана из неё, но не может быть изменена либо записана, проще говоря этот чип единожды прошивается на заводе. Структуру памяти метки можно посмотреть на рисунке ниже.

Когда метка попадает в электромагнитное поле, излучаемое считывателем RFID, она получает энергию от поля (питание) и начинает передачу данных. Первые 9 битов – это логическая единица. Эти биты используются как последовательность маркеров для обозначения начала передачи. Поскольку во всех остальных данных используется контроль чётности, эта девятибитная последовательность единиц больше не встретится ни в каком другом месте. Далее идут 10 групп по 4 бита данных и 1 бит чётности на каждую группу. Наконец, есть 4 бита контрольной суммы и последний стоповый бит, который всегда равен нулю.
Метка повторяет цикл передачи данных, пока на неё приходит питание. Поэтому мы на ридере наблюдаем постоянное считывание метки.
Приведу пример данных, которые передаёт метка с номером: 0x06 — номер версии, и 0x001259E3 — данные.

Кстати, номер, напечатанный на карте можно перевести в hex-номер, который получит считыватель. Например, на карте записан номер: 116,23152
- 116 в десятичной системе счисления – это 0x74 в шестадцатиричной;
- 23152 в десятичной – это 0x5A70 в шестнадцатиричной;
Модуляция сигнала
Передача данных от метки до считывателя осуществляется с помощью модуляции несущего сигнала считывателя (в нашем случае несущей частоты 125 кГц). Обратите внимание, что от этой несущей частоты идёт и питание и ей же осуществляется модуляция сигнала. Для начала рассмотрим упрощённую схему взаимодействия считывателя и метки. Запомните эту картинку, мы ещё будем к ней обращаться.

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

Пример модуляции несущего сигнала
Если я вас окончательно не запутал, то едем дальше. Для того чтобы передать данные, нам необходимо модулировать сигнал. То есть на несущую частоту наложит биты передаваемой информации.
По стандарту RFID есть три популярных схемы модуляции:
- Манчестер код
- Двухфазный манчестер код
- Кодирование фазовым сдвигом

При таком кодировании метка изменяет уровень передачи сигнала строго в середине периода передачи одного бита. Переход от низкого к высокому уровню в эти моменты означает состояние логической «1», а переход от высокого уровня к низкому, представляет состояние логического «0».

Реальный промодулированный сигнал, снятый на катушке считывателя.
Делаем RFID-эмулятор
Ну что же, если вы ещё здесь и голова не опухла, от таких выкладок, то пришла пора делать RFID-эмулятор, всего из двух деталей. В этой простоте кроется гениальность. Устройство я собрал, позаимствовав идею и код у Micah Dowty, фотографии мои.

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

Катушка индуктивности около 1 мкГн и микроконтроллер ATtiny85
Вот это дамы и господа и есть настоящее Хакерство, когда уровень понимания особенностей работы оборудования позволяет создавать технические решения, выходящие за рамки, обозначенные производителем! И это работает, проверено лично. Вот истинное значение слова «хакер», это не про взлом и воровство.
Забегая вперёд скажу, что данной катушки для нормальной работы недостаточно, и всё же пришлось cделать нормальную антенну, повесить конденсаторы по питанию, резонансный конденсатор. Но вот для демонстрации принципов работы вполне подойдёт.
Как же это работает:
- Катушка фактически питает микроконтроллер AVR через контакты ввода/вывода. Каждый такой контроллер имеет диоды на портах ввода/вывода, которые предотвращает повышение напряжения на этом выводе выше напряжения питания микросхемы или опускание уровня сигнала ниже уровня земли. Они используются также для предотвращения статического пробоя, который приводит к выходу из строя микросхемы. При поднесении катушки к считывателю, в ней наводится ЭДС равная нескольким вольтам. Когда напряжение на катушке превышает напряжение питания контроллера, то часть этой энергии через эти ограничивающие диоды передаются к шине питания микросхемы. В результате получается, что микроконтроллер получает питание. А верх и низ синусоидальной волны усекается, и сигнал становится более похож на прямоугольный меандр.
- Фильтрация питания с использованием ёмкости кристалла AVR. Обычно, когда ставят микросхему, то ставят конденсаторы по питанию, для фильтрации помех (обычно 0,1 мкФ керамику и электролит параллельно). В данном решении фильтрация осуществляется только внутренней ёмкостью шин питания в кремниевом кристалле микроконтроллера AVR. Она небольшая, но даже её достаточно для стабильного питания и работы, при питании от импульсов с частотой 125кГц!
- Работа осуществляется при очень низком напряжении. Микроконтроллер ATtiny85 предназначен для работы при напряжении всего 2,5 В. Существует версия с расширенным диапазоном напряжений до 1,8 В. При этих напряжениях обычные тактовые генераторы AVR не работают, но этого можно избежать применив следующий хак.
- Катушка индуктивности применяется не только для питания микросхемы, но ещё и для тактирования микроконтроллера! Выше мы говорили, что получаем прямоугольную волну, которая остаётся после того как ограничивающие диоды забрали немного энергии. Эта форма волны является входом Clock нашего микроконтроллера! И весь код работает на частоте 125 кГц, синхронно с несущей частотой считывателя RFID. Это гениально, ребята!
- Прошивка? На таких низких скоростях микропрограммное обеспечение микросхемы больше похоже на последовательность операций ввода-вывода, выполняемых синхронно с каждым тактовым циклом несущей. Но остается много лишних циклов. В протоколе EM4102 вы потенциально можете выполнить некоторую полезную работу с 32 тактовыми циклами между каждым битом. Однако с протоколом HID вам необходимо выводить фронт FSK каждые 4 тактовых цикла. В результате прошивка на RFID-метке крайне тупая. «Исходный код» на самом деле представляет собой просто набор причудливых макросов ассемблера, которые преобразуют код метки RFID в длинную последовательность инструкций ввода-вывода.
Прежде чем мы пойдём разбирать код данного эмулятора давайте сделаем ему нормальную антенну. Мои эксперименты с текущей схемотехникой выявили крайнюю нестабильность её работы. Она работает только совсем рядом со считывателем и то не всегда. Поэтому сначала я припаял конденсатор 0,1 мкФ на ножки питания контроллера, а потом решил сделать настоящий большой колебательный контур, как в настоящей метке.

Первая модификация — конденсатор 0,1 мкФ по питанию
Создание антенны
Никаких хитростей в создании катушечной антенны нет, но всё же необходимо ознакомиться с документацией и понимать физику процесса… Это не сложно, и справится даже школьник, требуется только немного терпения и усидчивости.
Собрать и настроить антенну очень просто, прямо как в картинке из [1].

Для расчёта антенны надо вспомнить немного теории. Нам необходимо сделать колебательный контур, который будет настроен на частоту 125 кГц. Откроем курс Теоретических Основ Электротехники и прочитаем, что же такое колебательный контур:
Колебательный контур, электрическая цепь, содержащая катушку индуктивности и конденсатор, в которой могут возбуждаться электрические колебания.

Параллельный колебательный контур
Если оставить всю математику и перейти к сути, у колебательного контура есть такой параметр, как резонансная частота, которая определяется по формуле.
Где f — частота колебаний, L — индуктивность катушки, C — ёмкость конденсатора.
В данном случае у нас есть фиксированный параметр — частота, а с ёмкостью и индуктивностью мы можем играться. Для того чтобы рассчитать катушку, воспользуемся документом [2]. Все кто хоть как-то собираются делать антенны для RFID меток (любых частот), обязаны с ним ознакомиться!
Многие умельцы, как для ридеров, так и для эмуляторов (суть не важна) делают круглые катушки. Их проще считать и изготавливать, но они имеют существенный недостаток — их линейные размеры больше карточки. Я хочу изготовить катушку индуктивности в форме прямоугольника, с линейными размерами меньше размеров стандартной карты и, чтобы результирующее устройство было размером со стандартную карту RFID. В результате выбираю размер будущей катушки индуктивности практически такой же, как стоит в настоящей метке, то есть примерно 70х40 мм. Если конденсатор выбрать 10 нФ, то индуктивность катушки (из формулы выше), должна составлять у нас 162 мкГн. Теперь смотрим в документацию по расчёту прямоугольной катушки. Для намотки катушки выбрал провод сечением 0,2 мм. В результате открываем соответствующий раздел документации, и нашему взору представляется следующая славная формула.

Как видим параметры толщины и ширины катушки у нас неизвестные и изменяемые (упираются в толщину провода 0,2 мм), но общие прикидки мне дали цифру в 42 витка. Можно было бы сделать несколько итераций, и сделать прям точный-точный расчёт, но в нашем штучном случае, и так сойдёт.
После чего, необходимо изготовить каркас 70х40 мм для намотки катушки. Его я изготовил из текстолита и на него намотал катушку.

Каркас из текстолита


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

Начнём подбор резонансного конденсатора
Сначала я проверил конденсатор емкостью 10 нФ, который должен быть резонансным. Но амплитуда сигнала сразу просела, по сравнению с пустой катушкой. Тогда я взял конденсатор меньшего номинала. И так перебирал конденсаторы, пока не поймал резонанс. Таким образом резонансная ёмкость конденсатора составила 3,2 нФ.

Сигнал без конденсатора, пустая катушка

Сигнал 10 нФ


3 нФ, 4 нФ, 2,2 нФ

Видно, что пробовал разные варианты, и было ясно что максимум лежит где-то между 3 и 4 нФ и результатом стал конденсатор 3,2 нФ (состоящий из двух конденсаторов в параллели). Всё, наша катушка готова к дальнейшим опытам.
Вообще, хочу заметить, что катушку можно сделать вообще в виде дорожек на печатной плате, и при небольшой серии изделий так и стоит делать. Вот, пример такой платы, именно на 125 кГц от Alexander Guthmann. К сожалению, сайт практически умер, а автор давно не выходит на связь, так что довольствуемся только моими фото. Если кто поможет его найти, буду признателен! Не знаю что с ним случилось.

Таким образом, делать эмулятор сразу в виде печатной платы — нет никаких проблем. Думаю имея руководство [2], сможете рассчитать такое самостоятельно, раз это смог сделать четырнадцатилетний немецкий школьник.
Пробежимся по коду
Давайте кратенько пробежимся по коду, который можно посмотреть вот тут. Там пример эмуляции двух типов карт, я разберу только EM4102.
Перво-наперво, как гласит код, нам при прошивке микроконтроллера надо прошить fuse-биты в значение lfuse to 0xC0: таким образом, чтобы контроллер тактировался от внешнего генератора. Обращаю внимание, что любая перепрошивка контроллера будет сопряжена с тем, что его надо будет тактировать от внешнего источника, так как мы устанавливаем fuse биты с генерацией от внешнего генератора!
Весь код основан на макросах. Напомню, что такое макросы — это программа, которая подготавливает код к компиляции. Наша программа состоит всего из нескольких ассемблеровских инструкций: rjmp, call (2 такта), nop, ldi, out и ret (все по 1 такту)! Всё, весь остальной код формируется макросами в зависимости от макроса серийного номера (дефайна). Особенность работы в том, что у нас достаточно мало тактов для нормальной работы. Попробуй успей за 32 такта сделать что-то, учитывая что инструкции перехода в контроллере AVR занимают 2 такта. Поэтому весь код генерируют макросы в зависимости от ID-карты.
#define FORMAT_IS_EM4102 #define EM4102_MFR_ID 0x12 #define EM4102_UNIQUE_ID 0x3456789A
Дефайнами задаём какой тип карты мы эмулируем и задаём ID-карты. Это главный макрос, на основании которого и формируется остальной код. И, тадам, его величество макросы.
.macro delay cycles .if \cycles > 1 rjmp .+0 delay (\cycles - 2) .elseif \cycles > 0 nop delay (\cycles - 1) .endif .endm
Макрос задержки, принимает на вход количество тактов задержки. Достаточно очевидный рекурсивный макрос, осуществляет задержку с помощью команды nop (нет операции, 1 такт) и команды rjmp .+0 (перейти на следующую строку, 2 такта). Комбинируя эти команды между собой, можно сделать задержку нужной длинны в тактах. По сути код ничего не делает, только тратит машинное время.
Если вы ещё соображаете, то дальше я вам совсем изнасилую мозг, но код так гениален что вам придётся потерпеть.
Рекурсивный макрос кодирования манчестер-кодом.
.macro manchester bit, count=1 .if \count manchester (\bit >> 1), (\count - 1) .if \bit & 1 baseband_1 baseband_0 .else baseband_0 baseband_1 .endif .endif .endm .macro stop_bit baseband_0 baseband_1_last .endm
Собственно тут и осуществляется вся логика. Принимает на вход битовую маску и счётчик битов. Если счётчик не нуль, то вызываем ещё раз сами себя, декрементируя счётчик (рекурсивный макрос, ага). Далее в самом теле идут вызовы макросов baseband_0, baseband_1 и baseband_1_last. В зависимости от того, какой бит у нас “1” или “0”, мы модулируем сигнал манчестер кода с нуля на единицу или с единицы на нуль.
Помните выше я приводил таблицу в статье, как идёт кодирование содержимого карты, где идут биты чётности, и стоп биты в конце. Так вот, наша задача теперь ID-метки закодировать этим методом, для этого у нас существуют два макроса.
#define ROW_PARITY(n) ( (((n) & 0xF) > 1) ^ ((n) >> 2) ^ ((n) >> 3)) & 1) ) #define COLUMN_PARITY ( (EM4102_MFR_ID >> 4) ^ \ (EM4102_MFR_ID) ^ \ (EM4102_UNIQUE_ID >> 28) ^ \ (EM4102_UNIQUE_ID >> 24) ^ \ (EM4102_UNIQUE_ID >> 20) ^ \ (EM4102_UNIQUE_ID >> 16) ^ \ (EM4102_UNIQUE_ID >> 12) ^ \ (EM4102_UNIQUE_ID >> 8) ^ \ (EM4102_UNIQUE_ID >> 4) ^ \ (EM4102_UNIQUE_ID) )
ROW_PARITY — расчёт бита чётности в строке из четырёх бит, COLUMN_PARITY — расчёт контрольной суммы всей посылки.
Вся логика работы у нас описывается в макросе в .main
header manchester ROW_PARITY(EM4102_MFR_ID >> 4), 5 manchester ROW_PARITY(EM4102_MFR_ID >> 0), 5 manchester ROW_PARITY(EM4102_UNIQUE_ID >> 28), 5 manchester ROW_PARITY(EM4102_UNIQUE_ID >> 24), 5 manchester ROW_PARITY(EM4102_UNIQUE_ID >> 20), 5 manchester ROW_PARITY(EM4102_UNIQUE_ID >> 16), 5 manchester ROW_PARITY(EM4102_UNIQUE_ID >> 12), 5 manchester ROW_PARITY(EM4102_UNIQUE_ID >> 8), 5 manchester ROW_PARITY(EM4102_UNIQUE_ID >> 4), 5 manchester ROW_PARITY(EM4102_UNIQUE_ID >> 0), 5 manchester COLUMN_PARITY, 4 stop_bit
Ну то есть, так же точно передаём заголовочные 9 бит, потом манчестер кодинг, высчитывая бит чётности для каждых 4-х бит, в конце контрольная сумма и стоп бит.
Осталось разобраться, что же такое baseband. Для этого у нас служат ещё одни макросы обёртки (да сколько можно-то, а?).
.macro baseband_0 rcall baseband30_0 rjmp .+0 .endm .macro baseband_1 rcall baseband30_1 rjmp .+0 .endm .macro baseband_1_last rcall baseband30_1 rjmp main .endm .macro header manchester 0x1FF, 9 .endm
Макросы baseband* — выполняют ассемблеровский код: вызывают соответствующие функции, и потом делают переход на другую команду. Макрос baseband_1_last — аналогична макросу baseband_1, кроме того что делает безусловный переход не на команду ниже, а в начало функции main. Макрос header — служит для вывода заголовка из девяти однотипных бит равных единице, и вызывает макрос манчестера с передачей числа и количества передаваемых бит.
Последнее, что осталось разобрать — это функции baseband30_0 и baseband30_1. Они описываются следующим кодом.
baseband30_0: ldi r16, OUT_PINS // 1 rjmp baseband30 // 2 /* * Emit a 1 at the baseband layer. * Takes a total of 30 clock cycles, including call overhead. */ baseband30_1: ldi r16, 0 // 1 rjmp baseband30 // 2 /* * Internal routine for baseband32_0 and _1. Must use * a total of 24 clock cycles. (32 - 1 ldi - 2 rjmp - 3 rcall) */ baseband30: out _SFR_IO_ADDR(DDRB), r16 // 1 delay 19 // 19 ret // 4
В зависимости от того, какая функция вызывается baseband30_0 или baseband30_1 в регистр r16 записывается значение того что должно быть на пине ввода/вывода: 1 или 0. После этого идёт безусловный переход на baseband30 осуществляется вывод и задержка на 19 тактов, после чего идёт возврат.
Самая большая магия этого кода, что он просчитан точно до каждого такта, каждый такт передачи манчестерского кода занимает ровно столько периодов, сколько допустимо стандартом, а именно 32 такта процессора! Это фантастически гениально, надо помнить сколько тактов занимает каждая команда.
Давайте его скорее скомпилируем и посмотрим как он выглядит, как развернутся все эти макросы. Компилируем командой make (предварительно установив avr-gcc) и дизассемблируем получившийся elf-файл
00000000 __vectors: 0: 0e c0 rjmp .+28 ; 0x1e __ctors_end 2: 15 c0 rjmp .+42 ; 0x2e __bad_interrupt .
Вначале у нас вектора прерываний, но нас интересует только первый jump. Так как остальные вектора никуда не ведут.
0000001e __ctors_end: 1e: 11 24 eor r1, r1 20: 1f be out 0x3f, r1 ; 63 22: cf e5 ldi r28, 0x5F ; 95 24: d2 e0 ldi r29, 0x02 ; 2 26: de bf out 0x3e, r29 ; 62 28: cd bf out 0x3d, r28 ; 61 2a: 02 d0 rcall .+4 ; 0x30 main 2c: 11 c1 rjmp .+546 ; 0x250 _exit
Здесь мы настраиваем порты ввода/вывода, и вызываем функцию main. A main состоит из безумного количества вызовов функций baseband30* и jump (так развернулся наша адский цирк макросов).
00000030 main: 30: 01 d1 rcall .+514 ; 0x234 baseband30_1 32: 00 c0 rjmp .+0 ; 0x34 main+0x4 34: fd d0 rcall .+506 ; 0x230 baseband30_0 36: 00 c0 rjmp .+0 ; 0x38 main+0x8 38: fd d0 rcall .+506 ; 0x234 baseband30_1 3a: 00 c0 rjmp .+0 ; 0x3c main+0xc 3c: f9 d0 rcall .+498 ; 0x230 baseband30_0 3e: 00 c0 rjmp .+0 ; 0x40 main+0x10 40: f9 d0 rcall .+498 ; 0x234 baseband30_1 42: 00 c0 rjmp .+0 ; 0x44 main+0x14 44: f5 d0 rcall .+490 ; 0x230 baseband30_0 46: 00 c0 rjmp .+0 ; 0x48 main+0x18 48: f5 d0 rcall .+490 ; 0x234 baseband30_1 4a: 00 c0 rjmp .+0 ; 0x4c main+0x1c 4c: f1 d0 rcall .+482 ; 0x230 baseband30_0 . 22e: 00 cf rjmp .-512 ; 0x30 main
И так далее… пока не джампнемся снова на main
Ну и глянем как же выглядит наш baseband модуль.
00000230 baseband30_0: 230: 08 e1 ldi r16, 0x18 ; 24 232: 02 c0 rjmp .+4 ; 0x238 baseband30 00000234 baseband30_1: 234: 00 e0 ldi r16, 0x00 ; 0 236: 00 c0 rjmp .+0 ; 0x238 baseband30 00000238 baseband30: 238: 07 bb out 0x17, r16 ; 23 23a: 00 c0 rjmp .+0 ; 0x23c baseband30+0x4 23c: 00 c0 rjmp .+0 ; 0x23e baseband30+0x6 23e: 00 c0 rjmp .+0 ; 0x240 baseband30+0x8 240: 00 c0 rjmp .+0 ; 0x242 baseband30+0xa 242: 00 c0 rjmp .+0 ; 0x244 baseband30+0xc 244: 00 c0 rjmp .+0 ; 0x246 baseband30+0xe 246: 00 c0 rjmp .+0 ; 0x248 baseband30+0x10 248: 00 c0 rjmp .+0 ; 0x24a baseband30+0x12 24a: 00 c0 rjmp .+0 ; 0x24c baseband30+0x14 24c: 00 00 nop 24e: 08 95 ret
В конце видно как delay развернулся в список jump и nop для задержки. Вот такая красивая магия.
Ну что же, с кодом разобрались. Соберите вытекший мозг с ушей, переходим к испытаниям.
Испытания
Применим все полученные знания и проведём испытания. Компилируем прошивку, прошиваем контроллер, не забывая правильно выставить Fuse-биты.

Платка для прошивки
Подключаем наш колебательный контур и тестируем на настоящем промышленном считывателе, никаких полумер, честные боевые условия.

Испытательный стенд
И, о чудо! Оно работает, корректно считывается и в цикле даёт корректный ID! Без внешнего питания, с работой только от поля. Осталось всё это привести в порядок и сделать настоящую RFID-метку.

Окончательный “заламинированный” вариант метки
Итого
Могу честно признаться, что до конца не верил, что это заработает. Питание от поля, нестандартные режимы работы контроллера, работа строго по тактам, самодельная катушка индуктивности. Плюс ещё работа самого RFID. И вот, вроде плёвая поделка растекается на пару месяцев чтения документации и разбора полётов. Но это работает, и эта штука по-настоящему гениальна. Так что ребята, вот такие штуки и есть настоящее хакерство. Дерзайте!
Домашнее задание
Раз вы всё-таки прочитали эту крутую статью, я её писал, старался, делал, теперь пора и вам что-то попробовать сделать. В коде эмулятора есть раздел, который эмулирует карты стандарта HID Proximity, с кодированием фазовым сдвигом. Вам в качестве развлечения и лучшего усвоения материала следует разобраться со стандартом HID и этим кодированием. Решение присылайте в комментарии. Удачи.
Список литературы

- AppNote 411 RFID Made Easy
- AN710 Antenna Circuit Design for RFID Applications
- При подготовке статьи использованы материалы сайта priority1design.com
- Блог компании RUVDS.com
- Ненормальное программирование
- Программирование микроконтроллеров
- Схемотехника
- DIY или Сделай сам
Работа с Arduino и RFID MFRC522

Технология RFID (Радиочастотная идентификация) позволяет при помощи радиосигнала быстро и безопасно передавать данные между специальными “считывателями” и “метками” – карточками, брелоками, браслетами и т.д. на небольшом расстоянии.
Одно из широко известных развитий технологии – NFC, при помощи которого можно оплачивать покупки или подключать устройства бесконтактно. Нам же доступны менее сложные, но не менее полезные и интересные применения, о которых будет сказано ниже.
Применение
Комплект RFID модуль + метки может быть использован:
- Как часть самодельных охранных систем
- При создании простых электронных замков (метка является ключом)
- В системах контроля доступа (однократный, многократный пропуск)
- В качестве электронного “кошелька” внутри собственного предприятия
- В роли интерактивного предмета в квестах и т.д.
Железо
RFID работает в нескольких частотных диапазонах, в свою очередь RFID модули и метки можно поделить на низкочастотные “LF” (125 кгц) и высокочастотные “HF” (13,56 MHz), существуют так же и ультравысокочастотные “UHF”, но они нас не интересуют.
Наиболее распространенные RFID Arduino-модули основаны на микросхеме MFRC522, работающей с HF метками 13,56 МГц. Поиск модулей и библиотек производится по этому же имени.
Существует два типа модулей MFRC522, с которыми вы скорее всего столкнетесь:

Отвечая на главный вопрос – не смотря на значительную разницу в размере, ощутимой разницы в работе модулей нет, можно брать любой. В комплекте к модулю как правило уже идет несколько меток.
Библиотеки
Для работы с модулем MFRC522 понадобится библиотека https://github.com/miguelbalboa/rfid. Библиотека тяжелая, индусская и имеет немало проблем, но достойных альтернатив просто нет – несколько других “облегченных” библиотек значительно уступают в функциональности и удобстве использования.
Подключение
Модуль MFRC522 подключается по аппаратному интерфейсу SPI, выбранная библиотека предоставляет следующую таблицу подключения к Arduino:
| Сигнал | Модуль MFRC522 | UNO/NANO | Leonardo | Pro micro | Mega |
| Reset | RST | D9 | RST/ISCP-5 | RST | D5 |
| Chip select | SDA (SS) | D10 | D10 | D10 | D53 |
| MOSI | MOSI | D11 | ISCP-4 | D16 | D51 |
| MISO | MISO | D12 | ISCP-1 | D14 | D50 |
| SCK | SCK | D13 | ISCP-3 | D15 | D52 |
- Контакты модуля RST и SDA (SS) указываются в скетче – можно использовать любые.
- У Leonardo подключение производится к 6-ти контактному ICSP разъему программатора.
Пример подключения модуля к Arduino Nano:

О RFID метках
Прежде всего самая сложная для понимания, но и самая важная часть – работа с RFID метками. В комплекте с модулем идут пара меток MIFARE Classic 1K, как понятно из названия – на 1 килобайт (на самом деле меньше, но об этом позже).
Чтобы изучить организацию памяти такой метки, можно воспользоваться примером из библиотеки, открыв Примеры > MFRC522 > DumpInfo. Однако для вашего удобства я подготовил вот такую карту:

Обратите внимание – память организована в виде 16-ти секторов, по 4 блока каждый. Итого – 64 блока по 16 Байт, как раз набегает 1 Килобайт. Деление по секторам носит скорее условный характер, так как адресация в памяти будет производиться по блокам.
Все сектора кроме нулевого имеют одинаковое строение – 3 блока данных + 1 блок безопасности, так называемый sector trailer. Каждый из этих блоков может быть прочитан и перезаписан (при соблюдении условий), исключение составляет нулевой блок (сектор 0).
Нулевой блок хранит в себе уникальный ID “UID”, тип метки и прочую информацию, записанную заводом-изготовителем. Нулевой сектор не может быть перезаписан, если речь идет о “классических” метках, к которым относятся комплектные с модулем. Таким образом UID позволяет отличить две с виду идентичные метки. UID как правило состоит из 4х байт, свободно считываемых из метки. Важно: китайский рынок может предложить вам “перезаписываемые” метки, UID в которых можно менять, путем перезаписи нулевого блока. Если в вашей системе используется только UID – учтите возможность очень простого копирования UID в метки-болванки (в том числе злоумышленниками).
Блоком безопасности является каждый 4й блок, каждый блок безопасности отвечает за свой сектор (предыдущие 3 блока данных) – он хранит 2 ключа доступа по 6 байт (ключи A и B), а также специальные “Access bits” (Биты доступа), грубо говоря настройки доступа. Ключи A и B могут быть использованы для аутентификации и последующего доступа к блокам данных в пределах сектора. То есть да, для того чтобы получить доступ к любому из блоков внутри сектора необходимо “разблокировать” этот сектор, при помощи одного из ключей.
Поэтому будьте уверены, если производитель позаботился о смене секретных ключей в своих RFID метках – скопировать или как-нибудь изменить содержимое штатными средствами вы уже не сможете, а ведь так хотелось? Идем дальше.
Биты доступа позволяют настроить условия доступа и возможности работы каждого блока в отдельности (каждого блока данных + блока безопасности). Наилучшим инструментом в работе с метками MIFARE Classic 1K является вот этот онлайн-калькулятор http://calc.gmss.ru/Mifare1k/. Если хотите разобраться чуть глубже – обязательно полистайте и опробуйте.
Я же хочу сэкономить ваше время, поэтому сразу уточню, что наиболее удачным решением в большинстве ситуаций будет оставить блоки данных в состоянии transport configuration, то есть по умолчанию.

Однако есть возможность настроить блоки на некоторые интересные сценарии, например защитить от записи (конфигурация 1-0-1 или 0-1-0). Или же сделать так, что прочитать блок можно при помощи как ключа A, так и ключа B, а вот для записи обязательно понадобится ключ B (конфигурация 1-0-0), в таком случае можно ограничить права некоторого оборудования и сделать систему безопаснее. И да, конфигурация 1-1-1 превращает блок в кирпич (обратимо).
В примерах ниже мы будем использовать конфигурацию блоков данных по умолчанию (0-0-0) и следующие принципы:
- Создаем ключ B, значение которого знаем только мы, длина ключа – 6 Байт.
- Ключ A будет полностью аналогичен ключу B, однако он не будет использоваться.
- Биты доступа для блоков безопасности будем использовать в конфигурации 0-1-1

Таким образом для всех операций с меткой применяется только ключ B, который невозможно считать из метки (впрочем, как и ключ A), даже если сектор предварительно разблокирован. Если хотите намертво зашить ключи A и B в блок безопасности – подойдет конфигурация 1-0-1, поменять будет уже невозможно. Ну а последняя 1-1-1 конфигурация блока безопасности заблокирует еще и настройки доступа к блокам данных!
Некоторые варианты необратимы, но не переживайте – у вас есть целых 16 попыток! По одной на каждый сектор.
В итоге 3 байта настроек доступа приняли следующие значения: 0x7F 0x07 0x88, байт USER может быть любой.

Важно: изначально ключи A и B от всех секторов метки содержат значение 0xFFFFFFFFFFFF, так что если хотите защитить данные в ваших метках, не забывайте сменить оба ключа! Кстати, нулевой блок и соответственно UID свободно читаются из метки, даже если нулевой сектор был заблокирован секретными ключами.
Ну и последнее, что касается меток – реальный объем пользовательской памяти. Если не создавать костыли, а использовать только блоки для хранения данных – (по 3 блока в 15-ти секторах, и 2 блока в нулевом секторе) получаем 47 доступных блоков по 16 байт или 752 байта, что тоже неплохо.
Начало работы
Подключили модуль, распаковали свежие метки – начинаем работать!
Прежде всего создаем необходимые объекты, инициализируем интерфейс SPI и MFRC522, не забываем про ключ доступа. Изначально все ключи состоят из FF-ок, так что “наполняем” ключ.
#include #include #define RST_PIN 9 // Пин rfid модуля RST #define SS_PIN 10 // Пин rfid модуля SS MFRC522 rfid(SS_PIN, RST_PIN); // Объект rfid модуля MFRC522::MIFARE_Key key; // Объект ключа MFRC522::StatusCode status; // Объект статуса void setup() < Serial.begin(9600); // Инициализация Serial SPI.begin(); // Инициализация SPI rfid.PCD_Init(); // Инициализация модуля for (byte i = 0; i < 6; i++) < // Наполняем ключ key.keyByte[i] = 0xFF; // Ключ по умолчанию 0xFFFFFFFFFFFF >> void loop() <>
Работу с RFID модулем удобнее всего производить в конце главного цикла программы, сейчас поймете почему. Для отслеживания поднесенной метки библиотека предлагает использовать пару методов с замысловатыми названиями:
if (!rfid.PICC_IsNewCardPresent()) return; // Если новая метка не поднесена - вернуться в начало loop if (!rfid.PICC_ReadCardSerial()) return; // Если метка не читается - вернуться в начало loop
Если поднесенная метка успешно считана – программа идет дальше, в противном случае происходит возврат в начало главного цикла, а весь блок кода связанный с RFID пропускается.
В итоге наш скетч имеет следующую структуру:
#include #include #define RST_PIN 9 // Пин rfid модуля RST #define SS_PIN 10 // Пин rfid модуля SS MFRC522 rfid(SS_PIN, RST_PIN); // Объект rfid модуля MFRC522::MIFARE_Key key; // Объект ключа MFRC522::StatusCode status; // Объект статуса void setup() < Serial.begin(9600); // Инициализация Serial SPI.begin(); // Инициализация SPI rfid.PCD_Init(); // Инициализация модуля for (byte i = 0; i < 6; i++) < // Наполняем ключ key.keyByte[i] = 0xFF; // Ключ по умолчанию 0xFFFFFFFFFFFF >> void loop() < // Занимаемся чем угодно if (!rfid.PICC_IsNewCardPresent()) return; // Если новая метка не поднесена - вернуться в начало loop if (!rfid.PICC_ReadCardSerial()) return; // Если метка не читается - вернуться в начало loop // Работаем с RFID >
Теперь давайте идти по порядку, осваивая основные методы для работы с RFID.
Обратите внимание: примеры ниже содержат специальные блоки кода, повышающие стабильность работы, о них подробно сказано в конце статьи.
Чтение UID
Самое простое, что можно сделать с RFID меткой – прочитать UID, в некоторых системах уже этого функционала вполне достаточно, например – в простых электронных замках. Как уже сказано ранее, некоторые метки позволяют сменить UID, в свою очередь запретить считать UID из ваших меток не получится – учтите это при разработке.
Так или иначе пример чтения UID и вывод в порт приведен ниже:
Чтение UID
#include #include #define RST_PIN 9 // Пин rfid модуля RST #define SS_PIN 10 // Пин rfid модуля SS MFRC522 rfid(SS_PIN, RST_PIN); // Объект rfid модуля MFRC522::MIFARE_Key key; // Объект ключа MFRC522::StatusCode status; // Объект статуса void setup() < Serial.begin(9600); // Инициализация Serial SPI.begin(); // Инициализация SPI rfid.PCD_Init(); // Инициализация модуля rfid.PCD_SetAntennaGain(rfid.RxGain_max); // Установка усиления антенны rfid.PCD_AntennaOff(); // Перезагружаем антенну rfid.PCD_AntennaOn(); // Включаем антенну for (byte i = 0; i < 6; i++) < // Наполняем ключ key.keyByte[i] = 0xFF; // Ключ по умолчанию 0xFFFFFFFFFFFF >> void loop() < // Занимаемся чем угодно static uint32_t rebootTimer = millis(); // Важный костыль против зависания модуля! if (millis() - rebootTimer >= 1000) < // Таймер с периодом 1000 мс rebootTimer = millis(); // Обновляем таймер digitalWrite(RST_PIN, HIGH); // Сбрасываем модуль delayMicroseconds(2); // Ждем 2 мкс digitalWrite(RST_PIN, LOW); // Отпускаем сброс rfid.PCD_Init(); // Инициализируем заного >if (!rfid.PICC_IsNewCardPresent()) return; // Если новая метка не поднесена - вернуться в начало loop if (!rfid.PICC_ReadCardSerial()) return; // Если метка не читается - вернуться в начало loop Serial.print("UID: "); for (uint8_t i = 0; i < 4; i++) < // Цикл на 4 итерации Serial.print("0x"); // В формате HEX Serial.print(rfid.uid.uidByte[i], HEX); // Выводим UID по байтам Serial.print(", "); >Serial.println(""); >
После успешного чтения метки, ее UID появляется в массиве rfid.uid.uidByte[] который можно прочитать и использовать.
Чтение блока
Если чтением UID ваш интерес не ограничился – давайте узнаем, как читать блок данных из метки. Прежде чем что-либо читать или писать, необходимо аутентифицировать (разблокировать) сектор, в котором находится интересующий нас блок.

В примерах ниже будем работать с блоком под номером 6 (сектор 1), за первый сектор и соответственно блоки 4, 5 и 6 отвечает блок безопасности под номером 7. То есть запомнили – блок данных 6, блок безопасности 7.
Аутентификацию сектора производит метод PCD_Authenticate() , по умолчанию все манипуляции с меткой возможны при помощи ключа A, а сам процесс аутентификации выглядит следующим образом:
status = rfid.PCD_Authenticate(MFRC522::PICC_CMD_MF_AUTH_KEY_A, 7, &key, &(rfid.uid)); if (status != MFRC522::STATUS_OK) < // Если не окэй Serial.println("Auth error"); // Выводим ошибку return; >
Обратите внимание на …KEY_A в первом аргументе и цифру 7 вторым аргументом – это и есть номер блока безопасности. Отслеживать статус не обязательно, но крайне желательно.
После успешной аутентификации можно свободно манипулировать разблокированным сектором, в нашем случае будем читать содержимое методом MIFARE_Read() . Читать нужно в байтовый массив, размером 18 (!) байт, чтение происходит из блока 6 (первый аргумент) и выглядит так:
uint8_t dataBlock[18]; // Буфер для чтения uint8_t size = sizeof(dataBlock); // Размер буфера status = rfid.MIFARE_Read(6, dataBlock, &size); // Читаем 6 блок в буфер if (status != MFRC522::STATUS_OK) < // Если не окэй Serial.println("Read error"); // Выводим ошибку return; >
Важно: Не смотря на то, что блоки имеют размер 16 байт, буферный массив создается на 18 байт, а количество байт на чтение передается именно в виде указателя на переменную. В противном случае чтение закончится ошибкой, примите это как факт.
В случае успешного чтения, выведем содержимое блока 6 в монитор порта, все как обычно:
Serial.print("Data:"); // Выводим 16 байт в формате HEX for (uint8_t i = 0; i < 16; i++) < Serial.print("0x"); Serial.print(dataBlock[i], HEX); Serial.print(", "); >Serial.println("");
А завершать работу с меткой нужно при помощи еще двух замысловатых методов:
rfid.PICC_HaltA(); // Завершаем работу с меткой rfid.PCD_StopCrypto1();
В итоге полный скетч для чтения блока 6 из новой метки со стандартными ключами выглядит так:
Чтение блока
#include #include #define RST_PIN 9 // Пин rfid модуля RST #define SS_PIN 10 // Пин rfid модуля SS MFRC522 rfid(SS_PIN, RST_PIN); // Объект rfid модуля MFRC522::MIFARE_Key key; // Объект ключа MFRC522::StatusCode status; // Объект статуса void setup() < Serial.begin(9600); // Инициализация Serial SPI.begin(); // Инициализация SPI rfid.PCD_Init(); // Инициализация модуля rfid.PCD_SetAntennaGain(rfid.RxGain_max); // Установка усиления антенны rfid.PCD_AntennaOff(); // Перезагружаем антенну rfid.PCD_AntennaOn(); // Включаем антенну for (byte i = 0; i < 6; i++) < // Наполняем ключ key.keyByte[i] = 0xFF; // Ключ по умолчанию 0xFFFFFFFFFFFF >> void loop() < // Занимаемся чем угодно static uint32_t rebootTimer = millis(); // Важный костыль против зависания модуля! if (millis() - rebootTimer >= 1000) < // Таймер с периодом 1000 мс rebootTimer = millis(); // Обновляем таймер digitalWrite(RST_PIN, HIGH); // Сбрасываем модуль delayMicroseconds(2); // Ждем 2 мкс digitalWrite(RST_PIN, LOW); // Отпускаем сброс rfid.PCD_Init(); // Инициализируем заного >if (!rfid.PICC_IsNewCardPresent()) return; // Если новая метка не поднесена - вернуться в начало loop if (!rfid.PICC_ReadCardSerial()) return; // Если метка не читается - вернуться в начало loop /* Аутентификация сектора, указываем блок безопасности #7 и ключ A */ status = rfid.PCD_Authenticate(MFRC522::PICC_CMD_MF_AUTH_KEY_A, 7, &key, &(rfid.uid)); if (status != MFRC522::STATUS_OK) < // Если не окэй Serial.println("Auth error"); // Выводим ошибку return; >/* Чтение блока, указываем блок данных #6 */ uint8_t dataBlock[18]; // Буфер для чтения uint8_t size = sizeof(dataBlock); // Размер буфера status = rfid.MIFARE_Read(6, dataBlock, &size); // Читаем 6 блок в буфер if (status != MFRC522::STATUS_OK) < // Если не окэй Serial.println("Read error"); // Выводим ошибку return; >/* Выводим содержимое блока в Serial */ Serial.print("Data:"); // Выводим 16 байт в формате HEX for (uint8_t i = 0; i < 16; i++) < Serial.print("0x"); Serial.print(dataBlock[i], HEX); Serial.print(", "); >Serial.println(""); rfid.PICC_HaltA(); // Завершаем работу с меткой rfid.PCD_StopCrypto1(); >
После поднесения метки в мониторе порта должны отобразиться 16 байт – содержимое прочитанного блока.
Запись блока
При записи все 16 байт записываются в блок единовременно, для чего должен быть заранее подготовлен байтовый массив на 16 Байт, например такой:
uint8_t dataToWrite[16] = < 0x00, 0x00, 0x00, 0x00, 0xAA, 0xBB, 0xCC, 0xDD, 0xAA, 0xBB, 0xCC, 0xDD, 0x00, 0x00, 0x00, 0x00 >;
Как в случае и с чтением, сектор в котором находится нужный блок 6 нужно предварительно аутентифицировать, об этом уже сказано выше, так что переходим непосредственно к записи. Запись производится методом MIFARE_Write() , в отличии от MIFARE_Read() тут все несколько проще – указываем записываемый блок, массив и число 16 (количество байт на запись):
status = rfid.MIFARE_Write(6, dataToWrite, 16); // Пишем массив в блок 6 if (status != MFRC522::STATUS_OK) < // Если не окэй Serial.println("Write error"); // Выводим ошибку return; >
Итоговый скетч записи массива в блок 6 выглядит так:
Запись блока
#include #include #define RST_PIN 9 // Пин rfid модуля RST #define SS_PIN 10 // Пин rfid модуля SS MFRC522 rfid(SS_PIN, RST_PIN); // Объект rfid модуля MFRC522::MIFARE_Key key; // Объект ключа MFRC522::StatusCode status; // Объект статуса void setup() < Serial.begin(9600); // Инициализация Serial SPI.begin(); // Инициализация SPI rfid.PCD_Init(); // Инициализация модуля rfid.PCD_SetAntennaGain(rfid.RxGain_max); // Установка усиления антенны rfid.PCD_AntennaOff(); // Перезагружаем антенну rfid.PCD_AntennaOn(); // Включаем антенну for (byte i = 0; i < 6; i++) < // Наполняем ключ key.keyByte[i] = 0xFF; // Ключ по умолчанию 0xFFFFFFFFFFFF >> void loop() < // Занимаемся чем угодно static uint32_t rebootTimer = millis(); // Важный костыль против зависания модуля! if (millis() - rebootTimer >= 1000) < // Таймер с периодом 1000 мс rebootTimer = millis(); // Обновляем таймер digitalWrite(RST_PIN, HIGH); // Сбрасываем модуль delayMicroseconds(2); // Ждем 2 мкс digitalWrite(RST_PIN, LOW); // Отпускаем сброс rfid.PCD_Init(); // Инициализируем заного >if (!rfid.PICC_IsNewCardPresent()) return; // Если новая метка не поднесена - вернуться в начало loop if (!rfid.PICC_ReadCardSerial()) return; // Если метка не читается - вернуться в начало loop /* Аутентификация сектора, указываем блок безопасности #7 и ключ A */ status = rfid.PCD_Authenticate(MFRC522::PICC_CMD_MF_AUTH_KEY_A, 7, &key, &(rfid.uid)); if (status != MFRC522::STATUS_OK) < // Если не окэй Serial.println("Auth error"); // Выводим ошибку return; >/* Запись блока, указываем блок данных #6 */ uint8_t dataToWrite[16] = < // Массив на запись в блок 0x00, 0x00, 0x00, 0x00, 0xAA, 0xBB, 0xCC, 0xDD, 0xAA, 0xBB, 0xCC, 0xDD, 0x00, 0x00, 0x00, 0x00 >; status = rfid.MIFARE_Write(6, dataToWrite, 16); // Пишем массив в блок 6 if (status != MFRC522::STATUS_OK) < // Если не окэй Serial.println("Write error"); // Выводим ошибку return; >Serial.println("Write OK"); // Завершаем работу с меткой rfid.PICC_HaltA(); rfid.PCD_StopCrypto1(); >
После поднесения метки в мониторе порта должно отобразиться сообщение “Write OK“.
К слову ничто не мешает нам объеденить запись и чтение в одном скетче:
Запись + чтение блока
#include #include #define RST_PIN 9 // Пин rfid модуля RST #define SS_PIN 10 // Пин rfid модуля SS MFRC522 rfid(SS_PIN, RST_PIN); // Объект rfid модуля MFRC522::MIFARE_Key key; // Объект ключа MFRC522::StatusCode status; // Объект статуса void setup() < Serial.begin(9600); // Инициализация Serial SPI.begin(); // Инициализация SPI rfid.PCD_Init(); // Инициализация модуля rfid.PCD_SetAntennaGain(rfid.RxGain_max); // Установка усиления антенны rfid.PCD_AntennaOff(); // Перезагружаем антенну rfid.PCD_AntennaOn(); // Включаем антенну for (byte i = 0; i < 6; i++) < // Наполняем ключ key.keyByte[i] = 0xFF; // Ключ по умолчанию 0xFFFFFFFFFFFF >> void loop() < // Занимаемся чем угодно static uint32_t rebootTimer = millis(); // Важный костыль против зависания модуля! if (millis() - rebootTimer >= 1000) < // Таймер с периодом 1000 мс rebootTimer = millis(); // Обновляем таймер digitalWrite(RST_PIN, HIGH); // Сбрасываем модуль delayMicroseconds(2); // Ждем 2 мкс digitalWrite(RST_PIN, LOW); // Отпускаем сброс rfid.PCD_Init(); // Инициализируем заного >if (!rfid.PICC_IsNewCardPresent()) return; // Если новая метка не поднесена - вернуться в начало loop if (!rfid.PICC_ReadCardSerial()) return; // Если метка не читается - вернуться в начало loop /* Аутентификация сектора, указываем блок безопасности #7 и ключ A */ status = rfid.PCD_Authenticate(MFRC522::PICC_CMD_MF_AUTH_KEY_A, 7, &key, &(rfid.uid)); if (status != MFRC522::STATUS_OK) < // Если не окэй Serial.println("Auth error"); // Выводим ошибку return; >/* Запись блока, указываем блок данных #6 */ uint8_t dataToWrite[16] = < // Массив на запись в блок 0x00, 0x00, 0x00, 0x00, 0xAA, 0xBB, 0xCC, 0xDD, 0xAA, 0xBB, 0xCC, 0xDD, 0x00, 0x00, 0x00, 0x00 >; status = rfid.MIFARE_Write(6, dataToWrite, 16); // Пишем массив в блок 6 if (status != MFRC522::STATUS_OK) < // Если не окэй Serial.println("Write error"); // Выводим ошибку return; >/* Чтение блока, указываем блок данных #6 */ uint8_t dataBlock[18]; // Буфер для чтения uint8_t size = sizeof(dataBlock); // Размер буфера status = rfid.MIFARE_Read(6, dataBlock, &size); // Читаем 6 блок в буфер if (status != MFRC522::STATUS_OK) < // Если не окэй Serial.println("Read error"); // Выводим ошибку return; >Serial.print("Data:"); // Выводим 16 байт в формате HEX for (uint8_t i = 0; i < 16; i++) < Serial.print("0x"); Serial.print(dataBlock[i], HEX); Serial.print(", "); >Serial.println(""); rfid.PICC_HaltA(); // Завершаем работу с меткой rfid.PCD_StopCrypto1(); >
Смена ключей безопасности и настройка блоков
Если вы хотите не только уметь читать и писать данные в метки, но и защить хранящуюся там информацию от стороннего вмешательства – необходимо сменить ключи доступа как минимум от тех секторов, в которых вы собираетесь хранить данные, однако в идеале установить новые ключи для всех секторов, чтобы усложнить задачу потенциальным взломащикам.
Для того, чтобы изменить ключи доступа к сектору, необходимо перезаписать блок безопасности, ответственный за данный сектор. В наших примерах фигурировал блок данных под номером 6 и соответственно блок безопасности под номером 7. Задача по смене ключей безопасности сводится к следующим шагам:
- Создать байтовый массив на 16 ячеек, включающий:
- Ключ A
- Байты настроек доступа
- Ключ B
- Провести аутентификацию выбранного сектора, пока что используя стандартный ключ 0xFFFFFFFFFFFF
- Произвести запись подготовленного массива в блок безопасности, в точности так же, как в случае с обычным блоком.
После этого ключи безопасности будут изменены, а мы сможем безопасно хранить данные в одном или нескольких блоках выбранного сектора! Сейчас покажу по шагам.
- Для создания образа блока безопасности (содержимого массива) придется вернуться вверх по тексту и вспомнить, что при выбранных нами настройках сектора, байты доступа получили значения 0x7F 0x07 0x88. Осталось придумать ключи доступа, имеющие длину 6 байт. Я буду использовать ключ 0xABABABABABAB, данный ключ не является безопасным и подходит исключительно для демонстрации! Так же напоминаю, что ключи A и B будут идентичны, однако использоваться будет только ключ B.

-
1 После того, как мы определились с настройками сектора (“Access Bits“) и ключами безопасности – создаем нужный байтовый массив:
uint8_t secBlockDump[16] = < // Дамп блока безопасности 0xAB, 0xAB, 0xAB, 0xAB, 0xAB, 0xAB, // < Ключ A 0x7F, 0x07, 0x88, // < Access Bits 0xFF, // < User байт (любой) 0xAB, 0xAB, 0xAB, 0xAB, 0xAB, 0xAB // < Ключ B >;
status = rfid.PCD_Authenticate(MFRC522::PICC_CMD_MF_AUTH_KEY_A, 7, &key, &(rfid.uid)); if (status != MFRC522::STATUS_OK) < // Если не окэй Serial.println("Auth error"); // Выводим ошибку return; >
status = rfid.MIFARE_Write(7, secBlockDump, 16); // Пишем массив в блок 6 if (status != MFRC522::STATUS_OK) < // Если не окэй Serial.println("Write error"); // Выводим ошибку return; >
Итоговый скетч записи новых ключей и настроек доступа:
Запись блока безопасности
#include #include #define RST_PIN 9 // Пин rfid модуля RST #define SS_PIN 10 // Пин rfid модуля SS MFRC522 rfid(SS_PIN, RST_PIN); // Объект rfid модуля MFRC522::MIFARE_Key key; // Объект ключа MFRC522::StatusCode status; // Объект статуса void setup() < Serial.begin(9600); // Инициализация Serial SPI.begin(); // Инициализация SPI rfid.PCD_Init(); // Инициализация модуля rfid.PCD_SetAntennaGain(rfid.RxGain_max); // Установка усиления антенны rfid.PCD_AntennaOff(); // Перезагружаем антенну rfid.PCD_AntennaOn(); // Включаем антенну for (byte i = 0; i < 6; i++) < // Наполняем ключ key.keyByte[i] = 0xFF; // Ключ по умолчанию 0xFFFFFFFFFFFF >> void loop() < // Занимаемся чем угодно static uint32_t rebootTimer = millis(); // Важный костыль против зависания модуля! if (millis() - rebootTimer >= 1000) < // Таймер с периодом 1000 мс rebootTimer = millis(); // Обновляем таймер digitalWrite(RST_PIN, HIGH); // Сбрасываем модуль delayMicroseconds(2); // Ждем 2 мкс digitalWrite(RST_PIN, LOW); // Отпускаем сброс rfid.PCD_Init(); // Инициализируем заного >if (!rfid.PICC_IsNewCardPresent()) return; // Если новая метка не поднесена - вернуться в начало loop if (!rfid.PICC_ReadCardSerial()) return; // Если метка не читается - вернуться в начало loop /* Аутентификация сектора, указываем блок безопасности #7 и ключ A */ status = rfid.PCD_Authenticate(MFRC522::PICC_CMD_MF_AUTH_KEY_A, 7, &key, &(rfid.uid)); if (status != MFRC522::STATUS_OK) < // Если не окэй Serial.println("Auth error"); // Выводим ошибку return; >/* Запись блока, указываем блок безопасности #7 */ uint8_t secBlockDump[16] = < // Дамп блока безопасности 0xAB, 0xAB, 0xAB, 0xAB, 0xAB, 0xAB, // < Ключ A 0x7F, 0x07, 0x88, // < Access Bits 0xFF, // < User байт (любой) 0xAB, 0xAB, 0xAB, 0xAB, 0xAB, 0xAB // < Ключ B >; status = rfid.MIFARE_Write(7, secBlockDump, 16); // Пишем массив в блок 7 if (status != MFRC522::STATUS_OK) < // Если не окэй Serial.println("Write error"); // Выводим ошибку return; >Serial.println("Write OK"); // Завершаем работу с меткой rfid.PICC_HaltA(); rfid.PCD_StopCrypto1(); >
Важно: при повторном поднесении метки мы неизбежно получим ошибку аутентификации, это связано с тем, что стандартный ключ больше не подходит к перенастроенному сектору!
Не забываем сменить “наполнение” ключа в void setup()<> :
for (byte i = 0; i < 6; i++) < // Наполняем ключ key.keyByte[i] = 0xAB; // Пишем свой ключ >
Так же напоминаю, что отныне для сектора 1 (блоков 4…7) мы используем только ключ B, соответственно и команда аутентификации отныне выглядит чуть иначе:
status = rfid.PCD_Authenticate(MFRC522::PICC_CMD_MF_AUTH_KEY_B, 7, &key, &(rfid.uid)); if (status != MFRC522::STATUS_OK) < // Если не окэй Serial.println("Auth error"); // Выводим ошибку return; >
Работа с защищенным сектором
Теперь, после того как мы сменили ключи безопасности от сектора 1, в качестве примера будем выводить количество поднесений метки к считывателю в последовательный порт. Количество поднесений хранится в нулевом байте защищенного блока 6 и увеличивается при каждом поднесении:
Инкремент при поднесении
#include #include #define RST_PIN 9 // Пин rfid модуля RST #define SS_PIN 10 // Пин rfid модуля SS MFRC522 rfid(SS_PIN, RST_PIN); // Объект rfid модуля MFRC522::MIFARE_Key key; // Объект ключа MFRC522::StatusCode status; // Объект статуса void setup() < Serial.begin(9600); // Инициализация Serial SPI.begin(); // Инициализация SPI rfid.PCD_Init(); // Инициализация модуля rfid.PCD_SetAntennaGain(rfid.RxGain_max); // Установка усиления антенны rfid.PCD_AntennaOff(); // Перезагружаем антенну rfid.PCD_AntennaOn(); // Включаем антенну for (byte i = 0; i < 6; i++) < // Наполняем ключ B key.keyByte[i] = 0xAB; // Пишем свой ключ >> void loop() < // Занимаемся чем угодно static uint32_t rebootTimer = millis(); // Важный костыль против зависания модуля! if (millis() - rebootTimer >= 1000) < // Таймер с периодом 1000 мс rebootTimer = millis(); // Обновляем таймер digitalWrite(RST_PIN, HIGH); // Сбрасываем модуль delayMicroseconds(2); // Ждем 2 мкс digitalWrite(RST_PIN, LOW); // Отпускаем сброс rfid.PCD_Init(); // Инициализируем заного >if (!rfid.PICC_IsNewCardPresent()) return; // Если новая метка не поднесена - вернуться в начало loop if (!rfid.PICC_ReadCardSerial()) return; // Если метка не читается - вернуться в начало loop /* Аутентификация сектора, указываем блок безопасности #7 и ключ B */ status = rfid.PCD_Authenticate(MFRC522::PICC_CMD_MF_AUTH_KEY_B, 7, &key, &(rfid.uid)); if (status != MFRC522::STATUS_OK) < // Если не окэй Serial.println("Auth error"); // Выводим ошибку return; >/* Чтение блока, указываем блок данных #6 */ uint8_t dataBlock[18]; // Буфер uint8_t size = sizeof(dataBlock); // Размер буфера status = rfid.MIFARE_Read(6, dataBlock, &size); // Читаем блок 6 if (status != MFRC522::STATUS_OK) < // Если не окэй Serial.println("Read error"); // Выводим ошибку return; >/* Выводим количество поднесений метки */ Serial.print("Count: "); // Выводим количество Serial.println(dataBlock[0]); // Хранится в нулевом байте массива dataBlock[0]++; // Инкремент /* Запись блока, указываем блок данных #6 */ status = rfid.MIFARE_Write(6, dataBlock, 16); // Пишем массив в блок 6 if (status != MFRC522::STATUS_OK) < // Если не окэй Serial.println("Write error"); // Выводим ошибку return; >rfid.PICC_HaltA(); // Завершаем работу с меткой rfid.PCD_StopCrypto1(); >
Количество поднесений ограничено 255, потому что используется лишь 1 Байт, но для примера это и не важно.
Инкремент и декремент
Наболее продвинутые могут обратить внимание на то, что пример выше не имеет смысла, поскольку метки уже имеют функционал инкремента и декремента, позволяющего использовать защищенный блок в качестве электронного кошелька.
Для реализации данного функционала библиотека имеет методы MIFARE_Increment() и MIFARE_Decrement() , однако независимо от установленных байтов доступа данный функционал не показал работоспособность на десятке меток и нескольких модулях. Возможно всему виной поддельные чипы MFRC522, установленные в модули. В любом случае перечисленные методы возвращают ошибку при поднесении метки, а потому и пример для работы не привожу.
Особенности и костыли
Несмотря на то, что данные модули выпускаются много лет, в течение которых дорабатывалась и библиотека, пара модуль + библиотека имеют критическую проблему зависания (!). Через случайный промежуток времени система просто перестает считывать поднесенные метки – помогает только перезагрузка микроконтроллера. Этот критический баг может сыграть злую шутку, при использовании данного комплекта в электронных замках. Что является причиной? На данный момент достоверного ответа нет… однако есть кое-какие решения!
- Периодическая перезагрузка и повторная инициализация. В главный цикл программы добавляется таймер на millis() с периодом 500…3000 мс, внутри которого производится принудительный сброс и инициализация модуля. Данный код располагается в начале главного цикла программы. Данный костыль является наиболее эффективным в борьбе с зависанием модуля.
static uint32_t rebootTimer = millis(); // Важный костыль против зависания модуля! if (millis() - rebootTimer >= 1000) < // Таймер с периодом 1000 мс rebootTimer = millis(); // Обновляем таймер digitalWrite(RST_PIN, HIGH); // Сбрасываем модуль delayMicroseconds(2); // Ждем 2 мкс digitalWrite(RST_PIN, LOW); // Отпускаем сброс rfid.PCD_Init(); // Инициализируем заного >
rfid.PCD_SetAntennaGain(rfid.RxGain_max); // Установка усиления антенны rfid.PCD_AntennaOff(); // Перезагружаем антенну rfid.PCD_AntennaOn(); // Включаем антенну
if (!rfid.PICC_IsNewCardPresent()) return; // Если новая метка не поднесена - вернуться в начало loop if (!rfid.PICC_ReadCardSerial()) return; // Если метка не читается - вернуться в начало loop
Фокус заключается в добавлении еще одной попытке чтения метки, в случае неудачи. Таким образом наша конструкция принимает следующий вид:
if (!rfid.PICC_IsNewCardPresent()) return; // Если новая метка не поднесена - вернуться в начало loop if (!rfid.PICC_ReadCardSerial()) < // Если метка не читается - пробуем еще раз if (!rfid.PICC_ReadCardSerial()) return; // Все равно не читается - вернуться в начало loop >
Наиболее эффективным и важным является первый костыль, располагайте его перед работой с модулем, желательно в начале цикла void loop()<> , но ни в коем случае не в прерывании таймера. Однако несмотря на то, что приведенные выше хитрости действительно работают и многократно повышают стабильность работы RFID модуля – в случае с электронными замками и прочими системами контроля доступа рекомендуется иметь резервные способы входа, помимо RFID.