Чтение и запись RFID меток. Модуль RC522 для Arduino

Сегодня урок о том как использовать RFID-ридер с Arduino для создания простой системы блокировки, простыми словами - RFID-замок.

RFID (англ. Radio Frequency IDentification, радиочастотная идентификация) - способ автоматической идентификации объектов, в котором посредством радиосигналов считываются или записываются данные, хранящиеся в так называемых транспондерах, или RFID-метках. Любая RFID-система состоит из считывающего устройства (считыватель, ридер или интеррогатор) и транспондера (он же RFID-метка, иногда также применяется термин RFID-тег).

В уроке будет использоваться RFID-метка с Arduino. Устройство читает уникальный идентификатор (UID) каждого тега RFID, который мы размещается рядом со считывателем, и отображает его на OLED-дисплее. Если UID тега равен предопределенному значению, которое хранится в памяти Arduino, тогда на дисплее мы увидим сообщение «Unlocked» (англ., разблокировано). Если уникальный идентификатор не равен предопределенному значению, сообщение "Unlocked" не появится - см. фото ниже.

Замок закрыт

Замок открыт

Детали, необходимые для создания этого проекта:

  • RFID-ридер RC522
  • OLED-дисплей
  • Макетная плата
  • Провода

Дополнительные детали:

  • Аккумулятор (powerbank)

Общая стоимость комплектующих проекта составила примерно 15 долларов.

Шаг 2: RFID-считыватель RC522

В каждой метке RFID есть небольшой чип (на фото белая карточка). Если направить фонарик на эту RFID-карту, можно увидеть маленький чип и катушку, которая его окружает. У этого чипа нет батареи для получения мощности. Он получает питание от считывателя беспроводным образом используя эту большую катушку. Можно прочитать RFID-карту, подобную этой, с расстояния до 20 мм.

Тот же чип существует и в тегах RFID-брелка.

Каждый тег RFID имеет уникальный номер, который идентифицирует его. Это UID, который показывается на OLED-дисплее. За исключением этого UID, каждый тег может хранить данные. В этом типе карт можно хранить до 1 тысячи данных. Впечатляет, не так ли? Эта функция не будет использована сегодня. Сегодня все, что интересует, - это идентификация конкретной карты по ее UID. Стоимость RFID-считывателя и этих двух карт RFID составляет около 4 долларов США.

Шаг 3: OLED-дисплей

В уроке используется OLED-монитор 0.96" 128x64 I2C.

Это очень хороший дисплей для использования с Arduino. Это дисплей OLED и это означает, что он имеет низкое энергопотребление. Потребляемая мощность этого дисплея составляет около 10-20 мА, и это зависит от количества пикселей.

Дисплей имеет разрешение 128 на 64 пикселя и имеет крошечный размер. Существует два варианта отображения. Один из них монохромный, а другой, как тот, который использован в уроке, может отображать два цвета: желтый и синий. Верхняя часть экрана может быть только желтой, а нижняя часть - синей.

Этот OLED-дисплей очень яркий и у него отличная и очень приятная библиотека, которую разработала компания Adafruit для этого дисплея. В дополнение к этому дисплей использует интерфейс I2C, поэтому соединение с Arduino невероятно простое.

Вам нужно только подключить два провода, за исключением Vcc и GND. Если вы новичок в Arduino и хотите использовать недорогой и простой дисплей в вашим проекте, начните с этого.

Шаг 4: Соединяем все детали

После нескольких лет работы по RFID тематике и разработки разнообразных считывателей для моделей транспондеров популярных стандартов типа Mifare, EMMARINE, TIRIS… меня часто начал озадачивать такой вопрос - буквально в последний год широкую популярность приобрели разного рода эмуляторы под тэги популярных протоколов и разнообразные копировальщики ключей/брелков.

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

Безусловно данная идея не решает глобальных проблем защищенности новой системы и может быть проанализирована другими разработчиками при наличии оборудования, однако суть в том, что все это не совпадает с существующими стандартами и все железки копировальщиков не позволят по-быстрому скопировать и воссоздать подобный алгоритм. Разумеется подобная система не преподносится тут не как полное решение проблем безопасности, а как опыт адаптации RFID под закрытую систему. Хорошим плюсом в вопросе безопасности среди прочих подобных беспроводных систем является сама технология низкочастотных RFID - она не позволяет считать тэги на большом расстоянии. Пассивные тэги достаточно маломощны и нуждаются для своего питания в достаточно мощном генераторе считывателя, особенности распространения радиоволн на данных частотах также ограничивают пределы работы данной системы. Реальная дальность считывания транспондеров редко превышает 20см для 125 Кгц стандартов типа EmMarine, скажем стандарта EM4001, для других протоколов типа Mifare (13,56Мгц) может быть побольше (1,5 метра для iso15693). Можно добиться большего расстояния считывания для низкочастотных ридеров если увеличить размеры катушки и напряжение питания, соответственно и мощность ридера. Однако такие системы имеют громоздки и как правило их тяжело сделать портативными. Как правило, такие системы реализуются только стационарно - скажем для автомобилей.

Итак, теперь собственно по архитектуре нашей RFID системы. Для экспериментов был выбран контроллер atmel atmega8. Для целей изготовления транспондера это кажется несомненным излишеством. Однако в данном случае решалась первостепенная задача разработки нового интерфейса на готовой отладочной платке c atmega с последующим портированием данного кода на более дешевые контроллеры типа tiny13.

Для транспондера алгоритм работы был построен на основе режима ШИМ генерации при помощи таймера T1 в режиме CTC с прерыванием и сбросом по совпадению с OCR1. Данные для передачи транспондера считываются из EEPROM при включении питания контроллера. Всего транспондер передает 10 байт. Содержимое EEPROM транспондера можно видеть на рисунке 1 . Первый байт 0xE7 является обязательным заголовком пакета, так как его наличие проверяется в первую очередь при разборе пакета считывателем. Первые 8 байт являются содержимым пакета транспондера, последние 2 байта содержат контрольную сумму CRC16 первых восьми байт пакета. Для примера в нашем транспондере были записаны такие данные - пакет 0xE7,0x05,0xE8,0x93,0x43,0x7F,0x20,0xFF и соответственно контрольную сумму 0xF5 0xA8. Для изготовления собственного уникального транспондера нужно кроме первого байта 0xE7 записать семь следующих байт в EEPROM, после чего рассчитать контрольную сумму для первых восьми байт. После этого записать в EEPROM два байта CRC16 в конце пакета. Первый байт оставляем без изменений - 0xE7. При включении транспондера данные этих байт разбиваются по битам и кодируются соответствующей длиной импульса в соответствии со значением регистра OCR. Для передачи используются 2 частоты 2Кгц и 5Кгц для передачи логических “0” и “1”. Кроме того данные разделяются импульсами синхронизации - стартовые метки пакетов.

Рис.1

Рис.2

Схему транспондера можно увидеть на рисунке 3 . Частота задающего генератора 8Мгц. Питание контроллера +5В. Можно использовать контроллер mega8 с маркировкой “L” тогда питание можно осуществлять от литиевой батарейки 3в (параметры для такого чипа +2,7…. +3,5). Вместо данного транзистора можно использовать любой другой маломощный NPN транзистор. Катушка транспондера была намотана на оправке диаметром 50мм проводом 0,22мм и насчитывает 50 витков. На данный момент транспондер сделан активным - с внешним питанием. На следующем этапе планируется сделать пассивный вариант транспондера, что достаточно просто - сделать развязку для питания от данной катушки, добавить диоды моста выпрямителя и стабилизатор.

Рис.3

Теперь поговорим о схеме считывателя для данного транспондера. Схема была адаптирована на основе раннее использованного считывателя для карт EMMARINE. Часть схемы с генератором на 74hc4060 можно на данном этапе смело удалять, так как пока мы используем активную метку.

Однако эта часть схемы нам понадобится в дальнейшем, когда мы будем делать пассивную метку и нам потребуется получить питание от считывателя. В остальном схема не имеет существенных отличий от схемы считывателя для EMMARINE: пассивный пиковый детектор - фильтр - усилитель - компаратор. Схема имеет максимально возможную простоту и позволяет считывать данные транспондера на расстоянии 10-12см при хорошо настроенных контурах.

Можно еще дальше упрощать схему оставив только детектор и фильтр, поставить один транзистор на выходе который будет играть роль компаратора, но я не стал так делать. На выходе мы получаем двоичный сигнал прямоугольной формы в соответствии с кодированными длительностями импульсов передаваемых транспондером. Допустимые отклонения номиналов элементов при котором схема работоспособна 5-10%. Питание контроллера и операционника +5В. Частота кварца задающего генератора контроллера 12Мгц. Выход компаратора на LM358 подключен к ножке внешнего прерывания контроллера INT0. В программе контроллера настроен вызов прерывания по нарастающему фронту на ножке внешнего прерывания INT0.

В обработчике прерывания происходит проверка синхронизирующих импульсов а затем проверка заголовка пакета и запись содержимого в буфер контроллера. Данные считанных пакетов передаются по интерфейсу RS232 на ПК. Для настройки терминалки указываем следующие параметры: скорость 57.6Kb/s, 8 бит данных, 1стоп бит, без контроля четности. При приеме пакета контроллер рассчитывает контрольную сумму принятых байт и передает данные в терминалку (пакет и CRC). В случае совпадения контрольных сумм расчитанной контроллером и принятой в пакете выводится сигнал на ножку PORTB.0 (14) контроллера (LED1 на схеме). Можно подключить в данную точку пищалку со встроенным генератором или светодиод через сопротивление. При считывании корректного ключа контроллер запрещает внешние прерывания и делает задержку 1с перед следующим считыванием.

Предусмотрен также режим работы данного считывателя в качестве основы RFID замка. Для этого необходимо в EEPROM контроллера считывателя записать полностью байты дампа транспондера - 10 байт. Данные пишутся в EEPROM считывателя точно также, как в EEPROM транспондера. В данном случае при считывании очередного транспондера и совпадении его с записанным в EEPROM считывателя выводится сигнал на ножку PORTB.1 (15) контроллера (LED2 на схеме). В данную точку можно подключить светодиод через сопротивление или выходной ключ (транзистор) на реле исполнительного устройства. Теперь мы получили RFID замок под конкретный ключ и обычный считыватель в одном флаконе.

Итак, подведем промежуточные итоги. Изготовлен собственный ридер и транспондер под данный считыватель. Мы защитили свое оборудование от посторонних устройств работающих с популярными протоколами RFID. Следующим шагом будет изготовление пассивной метки для нашего считывателя как делают известные производители промышленных транспондеров и портирование кода оборудования на более дешевые модели контроллеров. В архиве к статье прилагаю прошивки для транспондера и считывателя.

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

Применение

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

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

История

В 1945 году Леон Термен изобрел прослушивающее устройство для Советского Союза, которое повторно передавало радиоволны с добавленной аудиоинформацией. Звуковые колебания при вибрации влияли на диафрагму, которая слегка меняла форму резонатора, модулировавшего отраженную радиочастоту. Несмотря на то что это устройство было скрытым прибором для прослушивания, а не идентификационным тегом, оно считается предшественником USB RFID-считывателя, поскольку активировалось аудиоволнами из внешнего источника. Транспондеры по-прежнему используются большинством работающих самолетов. А раньше подобная технология, такая как считыватель RFID-меток, регулярно использовалась союзниками и Германией во Второй мировой войне для идентификации самолетов.

Устройство Марио Кардулло, запатентованное 23 января 1973 года, было первым истинным предшественником современной RFID, поскольку это был пассивный радиоприемник с памятью. Первоначальное устройство было пассивным, с питанием от опросного сигнала. Оно было продемонстрировано в 1971 году администрации Нью-Йорка и другим потенциальным пользователям и состояло из транспондера с 16-разрядной памятью для использования в качестве платного устройства. Основной патент Cardullo охватывает использование радиочастот, звука и света в качестве среды передачи.

Область использования

Первоначальный бизнес-план, представленный инвесторам в 1969 году, демонстрировал следующие сферы применения считывателя RFID:

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

Ранняя демонстрация отраженной мощности (модулированного обратного рассеяния) RFID-меток, как пассивных, так и полупассивных, была выполнена Стивеном Деппом, Альфредом Коелле и Робертом Фрайманом в Национальной лаборатории Лос-Аламоса в 1973 году. Портативная система работала на частоте 915 МГц и использовала 12-битные теги. Этот метод применяется большинством современных UHFID и микроволновых RFID-считывателей. В современной жизни такие устройства очень востребованы.

Спецификация

Система радиочастотной идентификации использует метки, прикрепленные к идентифицируемым объектам. При изготовлении RFID-считывателя своими руками следует учитывать, что двусторонние радиопередатчики-приемники, называемые запросчиками или считывателями, посылают сигнал тегу и считывают его ответ. Метки RFID могут быть пассивными, активными или пассивными. Активный тег имеет встроенный аккумулятор и периодически передает его ID-сигнал. Пассивный аккумулятор (BAP) имеет небольшую батарею на борту и активируется при наличии считывателя RFID. Пассивная бирка дешевле и меньше, потому что у нее нет батареи. Вместо этого тег использует радиоволну, переданную считывателем. Однако для работы пассивного тега он должен быть освещен уровнем мощности примерно в тысячу раз сильнее, чем для передачи сигнала. Это влияет на интерференцию и облучение.

В какой-то момент мне снова стало скучно, и я, как мне показалось, придумал хорошую причину для покупки считывателя карточек. Концепция была такова: карточку приклеиваем на дно ноутбука, а считыватель ставим в то место, где компьютер обычно заряжается.

Результат: когда кладем ноутбук на «зарядку», то автоматически включается розетка с его зарядным устройством. А в остальное время розетка, понятно, выключена. Не сказать, что особо полезно, но - развлечение.

Но, как обычно, что-то пошло не так. То есть, вместо ударного труда на ниве розеток я в первую очередь зачем-то научился узнавать, сколько поездок осталось на моем билете местного метрополитена.

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

Что обычно делают? Чаще всего - замки с открытием по карточке, учет рабочего времени, СКД для домашних животных (допуск к корму, например).

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

Скорее всего, вы неоднократно встречались с такими карточками. Чаще всего - в виде офисного пропуска. Другой яркий пример - бесконтактные билеты для прохода в метро.

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

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

Гребенок в комплекте было две, но одну (угловую) я, простите уже запаял. Поэтому вида платы без гребенок нет

Этот комплект включает в себя считыватель, гребенку для простого макетирования и даже монтажа на «материнскую» плату и два идентификатора: карточку MIFARE 1K и аналогичный по возможностям брелок. То есть, вполне достаточно для экспериментов.

.

.

.

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

С батарейкой ААА

Т.е. можно не мучить себя компромиссом между удобством и универсальностью (гребенкой) и экономией места в расчете на встраивание (прямой пайкой проводов).

Среди прочего на плате также есть красный светодиод, который, увы, совершенно неинформативен. Суть в том, что он горит даже при оторванном питании - очевидно, достаточно уровней на SPI-интерфейсе. Да и на карточки он никак не реагирует.

Одним словом - горит, когда считыватель хоть как-то подключен к Arduino, что не гарантирует его работоспособности.

Что касается дальности срабатывания, то субъективно порог находится на расстоянии 2 см от поверхности платы. В пределах 2 - 2.5 см - область неуверенного срабатывания.

Характеристики (от продавца):

Напряжение: 3.3В

Потребляемый ток в активном состоянии:13-26 мА

Потребляемый ток в состоянии ожидания: 10-13 мА

Ток в режиме сна: менее 80 мкА

Пиковое потребление: менее 30 мА

Рабочая частота: 13.56 МГц

Поддержвиаемые типы карт: MIFARE S50, MIFARE S70, MIFARE UltraLight, MIFARE Pro, MIFARE DESfire

Интерфейс: SPI

Размеры: 40х60 мм

Из приведенного выше видно, что отличился я дважды. Во-первых, не посмотрел на напряжение питания. А 3.3В, между прочим, означает, что проще всего использовать эту плату с Arduino Uno, Mega и прочими (или аналогичными платами), оснащенными регуляторами напряжения и выходом 3.3В. Благо максимальный потребляемый ток не выходит за пределы возможностей платформы.

В противном случае необходимо либо использовать единое питание 3.3В, либо дополнительный регулятор/стабилизатор/преобразователь напряжения.

Во-вторых, интерфейс SPI в требует 5 (!) проводов для подключения. Т.е. в сумме к считывателю подходит шлейф из 7 проводников, а это довольно расточительно. Для экономии имело смысл ориентироваться на I2C, но где я и где этот смысл?!

Подключение
Я бы хотел разделить подключение на софт и хард, но все так тесно переплелось - и вылилось в не очень интересную проблему.

Одним словом, все знают для RC522. Но почему-то никто не задается вопросом, почему в ридми, приложенном к библиотеке и в табличке в одном из ее примеров совершенно разная «распиновка» подключения считывателя.

Полагаю, это как раз одна из причин вечных проблем с этой библиотекой. Вторая причина в том, что подключение для Arduino Uno и Mega производится к разным пинам. Это связано с особенностью платформ.

Наконец, третья причина - два пина (SS и RST) допускают произвольное подключение и конфигурируются в коде. При этом по умолчанию в коде примера забита конфигурация для Arduino Uno, а если у вас Mega и вы подключали по агитке из ридми или таблички в начале примера, то, разумеется, промахнетесь.

Но фишка в том, что третья причина довольно очевидна, и ее я более-менее обошел, сразу задав свои пины, потому что у меня под руками была плата Arduino Mega. Поэтому же, кстати, меня обошла и вторая беда.

А вот первая - подключение пинов SPI помучила меня вдоволь. Я же и предположить не мог, что человек, сделавший успешную библиотеку, мог так накосячить в банальном подключении трех проводочков.

Иными словами, подключение ни по первому, ни по второму варианту, указанному в описании библиотеки, не помогло. Сначала я подумал, что у меня «мертвая плата». Поэтому, несмотря на позднее время, взял себя в руки и распаял гребенку на вторую (я запасливый и купил сразу три). Результат оказался аналогичным, несмотря на то, что я неоднократно проверял подключение по имеющимся на руках «распиновкам».

Даже не спрашивайте, почему я не пошел на Arduino.cc, чтобы посмотреть, как разведен SPI на Mega. По-моему, это случилось какое-то помутнение.

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

И обе платы заработали.

Чтобы очистить совесть - загрузил пример с «проблемной» библиотекой, и он оказался рабочим тоже.

Вот такими карточками я мучил считыватель. Слева направо: карточка из комплекта, карточка с буквой N, билет метро MIFARE UltraLight, карточка РЖД

А это - как примерно выглядит дамп содержимого и вообще распознавание карточек с библиотекой RFID и ее же примером DumpInfo

Резюме по мучениям: распиновка от упомянутого товарища совпадает с и, что удивительно, совпадает с распиновкой в ридми библиотеки RFID. Учитывая последнее, могу предположить, что либо я ночью все же перепутал пины и с этого начались все мои несчастья, либо родная китайская библиотека как-то хитро инициализирует считыватель, после чего он начинает работать.

В завершение правильная распиновка для китайской библиотеки и Mega, к которой я подключался:

Mega RC522
3.3V VCC
GND GND
RESET RST

50 MISO
51 MOSI
52 SCK
53 NSS

И для Uno (ее не проверял):

Uno RC522
3.3V VCC
GND GND
5 RST

12 MISO
11 MOSI
13 SCK
10 NSS

Вместе с большой сестрой

.

.

В результате простых испытаний, которые я все-таки выполнил, также выяснилось, что считыватель нормально записывает (вот такая игра слов) карты MIFARE 1K из тех, что были с ним в комплекте.

Вторая особенность в том, что эта штука адекватно реагирует, если к нему одновременно поднести несколько карт. Я подносил две карты, опять же, из тех, что были в комплекте. При этом пример DumpInfo из библиотеки RFID по порядку выводит содержимое обеих карт. Т.е. сначала - содержимое одной карты, а следом за ней - второй.

И шашечки, и ехать
Итак, подключили, полюбовались на дамп содержимого памяти карточек MIFARE 1K. Что дальше? А дальше мне было немного лень возиться с розеткой, и я вспомнил, что карточки метро, вроде бы, работают по тому же протоколу.

Сходил, взял свою, приложил, полюбовался на ее содержимое. Как и обещали: MIFARE UltraLight, 64 байта памяти и не очень понятно, где там поездки, где срок действия, ну и вообще не очень понятно.

Гугление на тему использования Arduino с этими карточками не дало ничего особо полезного. Чаще всего карточки метро, как выяснилось, используют в качестве ультрадешевых (т.е. бесплатных) NFC-меток во всяких самодельных системах вроде замков, исполнения сценариев и прочего, где достаточно знать серийный номер карты для идентификации. А вот готовых библиотек и решений для вывода информации о поездках я почему-то не нашел: то ли так спать хотел, то ли их действительно нет (см. синдром «Неуловимого Джо»).

Зато я нашел замечательный и очень романтичный текст авторства Александра «Dark Simpson» Симонова под заголовком " ", опубликованный, судя по всему, в каком-то из номеров Хакера. Несмотря на любопытную природу текста, в нем есть масса полезной информации о структуре хранения данных, в том числе на интересующих меня билетах.

Значащая часть билета - номер - проверяемая визуально

Так что на следующий день я постарался переборость свое отвращение к HEX и полез разбираться. Вот такой дамп билета я получил с помощью библиотеки RFID:

Card UID: 04 6F 25 62 04 33 82
PICC type: MIFARE Ultralight or Ultralight C

Page 0 1 2 3
0 04 6F 25 C6
1 62 04 33 82
2 D7 48 F0 00
3 00 07 FF FC
4 45 DA 21 06
5 D0 E5 3D 00
6 1F E8 00 00
7 1F E8 00 00
8 1F 8F 5A 00
9 40 19 2E D2
10 19 91 59 7C
11 1F AB 91 C8
12 1F 8F 5A 00
13 40 19 2E D2
14 19 91 59 7C
15 1F AB 91 C8

Здесь Card UID - уникальный идентификатор карты (суть серийный номер), а остальное - 16 страниц памяти, каждая из которых содержит по 4 байта. Вместе - 64 байта.

Из чтения текста про билеты метро отметил наиболее полезные моменты:

1) Номер билета (который отпечатан на нем) зашит в 32 битах, начиная с 21 бита на странице 4: 10 6D 0E 53;

2) Дата выдачи билета в днях, прошедших с 01.01.1992 г. - первые два байта странице 8: 1F 8F;

3) Срок действия в днях - третий байт на странице 8: 5А.

4) Наконец, количество оставшихся поездок - второй байт на странице 9: 19.

С этим уже можно было работать.

Немного поковырялся в примере DumpInfo из библиотеки RFID, в ее же коде, чтобы понять, какие функции за что отвечают и чем могут быть полезны, в форумах Arduino, чтобы посмотреть реализацию вычисления даты (вообще, можно на любом языке смотреть, но мне было проще искать ближе к целевой платформе).

В итоге на свет появился монстр. То есть, скетч скроен из лоскутов, местами результат подогнан под ответ, но в целом все более-менее соответствует реальности. Поэтому нечего стрелять в пианиста, который играет, как умеет. Там, между прочим, даже базовая обработка ошибок есть: скетч предупредит о неподдерживаемой карте или о невозможности чтения.

#include #include #define SS_PIN 53 #define RST_PIN 9 MFRC522 mfrc522(SS_PIN, RST_PIN); // объект MFRC522 unsigned long uidDec, uidDecTemp; // для отображения номера карточки в десятичном формате byte bCounter, readBit; unsigned long ticketNumber; void setup() { Serial.begin(9600); SPI.begin(); // инициализация SPI mfrc522.PCD_Init(); // инициализация MFRC522 Serial.println("Waiting for card..."); } void loop() { // Поиск новой карточки if (! mfrc522.PICC_IsNewCardPresent()) { return; } // Выбор карточки if (! mfrc522.PICC_ReadCardSerial()) { return; } uidDec = 0; // Выдача серийного номера карточки Serial.print("Card UID: "); for (byte i = 0; i < mfrc522.uid.size; i++) { // Serial.print(mfrc522.uid.uidByte[i] < 0x10 ? " 0" : " "); // Serial.print(mfrc522.uid.uidByte[i], HEX); uidDecTemp=mfrc522.uid.uidByte[i]; uidDec=uidDec*256+uidDecTemp; } Serial.println(uidDec); Serial.println(); // Выдача типа карты byte piccType = mfrc522.PICC_GetType(mfrc522.uid.sak); // запрос типа Serial.print("Card type: "); Serial.println(mfrc522.PICC_GetTypeName(piccType)); // трансляция типа в читаемый вид if (piccType != MFRC522::PICC_TYPE_MIFARE_UL) { // если не билетная карта Serial.print("Not a valid card: "); // так и говорим Serial.println(piccType); // Halt PICC mfrc522.PICC_HaltA(); // остановка чипа return; } // сюда мы приедем, если чип правильный byte status; byte byteCount; byte buffer; // длина массива (16 байт + 2 байта контрольная сумма) byte pages={4, 8}; // страницы с данными byte pageByte; // счетчик байтов страницы byteCount = sizeof(buffer); byte bCount=0; for (byte i=0; i<2; i++) { // начинаем читать страницы status = mfrc522.MIFARE_Read(pages[i], buffer, &byteCount); if (status != MFRC522::STATUS_OK) { Serial.print("Read error: "); Serial.println(mfrc522.GetStatusCodeName(status));} else { if (pages[i] == 4) { bCounter = 0; // 32-битный счетчик для номера // биты 0-3 for (bCount=0; bCount<4; bCount++) { readBit = bitRead(buffer, (bCount+4)); setBitsForGood(readBit); } // биты 4 - 27 for (pageByte=5; pageByte > 2; pageByte--) { for (bCount=0; bCount<8; bCount++) { readBit = bitRead(buffer, bCount); setBitsForGood(readBit); } } // биты 28-31 for (bCount=0; bCount<4; bCount++) { readBit = bitRead(buffer, bCount); setBitsForGood(readBit); } Serial.print("Ticket number: "); Serial.println(ticketNumber, DEC); } if (pages[i] == 8) { // читаем дату выдачи Serial.print("Issued: "); unsigned int issueDate = buffer * 256 + buffer; // количество дней с 01.01.1992 в десятичном формате, 256 - сдвиг на 8 бит printIssueDate(issueDate); Serial.print("Good for (days): "); // срок действия Serial.print(buffer, DEC); Serial.println(); Serial.print("Trip reminder: "); // количество оставшихся поездок Serial.print(buffer, DEC); Serial.println(); } } } // Halt PICC mfrc522.PICC_HaltA(); } void printIssueDate(unsigned int incoming) { boolean isLeap = true; // признак високосного года int days={0,31,59,90,120,151,181,212,243,273,304,334}; // последний по порядку день месяца для обычного года byte dayOfMonth, monthCounter; unsigned int yearCount; incoming = incoming+1; // подогнал под ответ, но возможно это как раз необходимая коррекция, потому что начало отсчета - 01.01.1992, а не 00.01.1992 for (yearCount = 1992; incoming >366; yearCount++) { // считаем год и количество дней, прошедших с выдачи билета if ((yearCount % 4 == 0 && yearCount % 100 != 0) || yearCount % 400 == 0) { incoming = incoming - 366; isLeap = true; } else { incoming = incoming - 365; isLeap = false; } } for (monthCounter = 0; incoming > days; monthCounter++) { // узнаем номер месяца } // считаем день месяца if (isLeap == true) { // если високосный год if (days>31) { // если не первый месяц, то добавляем к последнему дню месяца единицы dayOfMonth = incoming - (days+ 1); } else { dayOfMonth = incoming - (days); // если первый - ничего не добавляем, потому что сдвиг начинается с февраля } } else { dayOfMonth = incoming - (days); // если не високосный год } Serial.print(dayOfMonth); Serial.print("."); Serial.print(monthCounter); Serial.print("."); Serial.print(yearCount); Serial.println(); } void setBitsForGood(byte daBeat) { if (daBeat == 1) { bitSet(ticketNumber, bCounter); bCounter=bCounter+1; } else { bitClear(ticketNumber, bCounter); bCounter=bCounter+1; } }

Что мне дает этот скетч? Ну, во-первых, небольшую тренировку головы - приходилось, знаете, думать, когда разбирался со считывателем и кодом. Во-вторых, я всегда могу узнать, сколько осталось поездок, и когда закончится карточка. С учетом того, что у меня в смартфоне NFC нет, получается довольно удобно.

Результат работы монстра

Разумеется, в данном случае даже речь не идет о том, чтобы сделать «копию» билета. Это исключительно информационная функция, дублирующая терминал в вестибюле метро.

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

Итак, розетка, которая включается, когда нужна. Здесь карта (любая поддерживаемая считывателем и подходящая для размещения в целевом устройстве) используется исключительно как пропуск, то есть интересует только ее серийный номер.

Логика простая: если считыватель видит карту с определенным номером, то включает розетку. Если не видит - выключает.

РОЗЕТОЧНЫЙ МОНСТР

#include #include #define SS_PIN 53 #define RST_PIN 9 MFRC522 mfrc522(SS_PIN, RST_PIN); // Create MFRC522 instance. unsigned long uidDec, uidDecTemp; #include RCSwitch mySwitch = RCSwitch(); boolean switchOn = false; boolean cardRead = false; void setup() { Serial.begin(9600); // Initialize serial communications with the PC SPI.begin(); // Init SPI bus mfrc522.PCD_Init(); // Init MFRC522 card mySwitch.enableTransmit(8); Serial.println("Waiting for card..."); } void loop() { byte status; byte byteCount; byte buffer; // длина массива (16 байт + 2 байта контрольная сумма) byteCount = sizeof(buffer); uidDec = 0; status = mfrc522.PICC_RequestA(buffer, &byteCount); if (mfrc522.PICC_ReadCardSerial()) { for (byte i = 0; i < mfrc522.uid.size; i++) { uidDecTemp=mfrc522.uid.uidByte[i]; uidDec=uidDec*256+uidDecTemp; } if ((uidDec==2218415941) && (switchOn == false)) { mySwitch.sendTriState("00110000F000"); switchOn = true; // Serial.println("Switched On"); } mfrc522.PICC_ReadCardSerial(); } else { if (switchOn == true) { mySwitch.sendTriState("001100000000"); // Serial.println("Switched Off"); switchOn = false; } } }

Аналогичным образом, используя карту как триггер, можно выполнять и различные сценарии домашней автоматизации. Например, положить карточку в электронную книгу, а на прикроватной тумбе разместить считыватель.

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

Вот так работает розеточный монстр

Подводя итог: недорого, просто, довольно удобно и стимулирует фантазию.

Ps. Я уверен, что вы можете лучше, и что я ничего не понимаю в Arduino и программировании.

Ссылочки всякие
Обзор понравился +67 +173

  • Программирование микроконтроллеров
  • Как известно, во многих системах доступа используются карты RFID стандарта EM-Marin с частотой 125 КГц. Не исключением стал и домофон моего дома. Одна проблема – неплохо бы научиться копировать такие карты, ибо ценники на их копирование не радуют. В сети, конечно, существует довольно много схем копировщиков (да и китайцы продают свои копировщики за копейки - правда, они часто при копировании ставят свой пароль на болванки), но почему бы не собрать свой собственный копировщик? Вот об этом и нижеприведённая статья.

    Начинать разработку копировщика стоит с выяснения, а на что вообще можно скопировать такие метки? Почитав форумы, можно узнать, что наиболее распространёнными болванками для копирования являются T5577, T5557, EM4305.

    Теперь нужна схема. Возьмём аналоговую часть такого копировщика у RECTO и подключим её к микроконтроллеру atmega8. Дополним преобразователем уровней для подключения к COM-порту на базе max232 (желающие могут использовать ST232 или ещё что, чтобы подключится по USB, но у меня на компьютере COM-порт есть, как есть и переходник USB-COM, так что у меня такой задачи не стояло).

    Получится вот такая схема:

    Что она из себя представляет? Сдвоенный эмиттерный повторитель, колебательный контур, детектор и RC-фильтры. За счёт того, что RC-фильтры имеют разные постоянные времени, сравнивая между собой уровни напряжения между каскадами можно выделять изменение сигнала RFID-метки. Данной задачей у нас будет заниматься встроенный в atmega8 компаратор. Генерацию 125 КГц сигнала у нас будет обеспечивать встроенный в atmega8 ШИМ-контроллер.

    Комбинация RFID-метка – считыватель образуют трансформатор, где метка является вторичной обмоткой. Передача информации меткой производится путём изменения нагрузки вторичной обмотки. В результате в катушке считывателя (первичной обмотке) изменяется ток. Выделением этих импульсов тока и занимается приведённая выше аналоговая часть схемы. Колебательный контур нужно настроить на максимальное напряжение в контрольной точке, например, сматывая/наматывая витки катушки. Правда, говорят, лучше всё же напряжение немного меньше максимума - стабильнее работает. У меня в контрольной точке около 40 В.

    Копируемая метка использует кодирование типа манчестер . Для того чтобы расшифровать данный код, достаточно по любому изменению фронта сигнала пропускать три четверти периода слота бита и по следующему за ним перепаду сигнала фиксировать значение бита, которое будет соответствовать значению сигнала после перепада. При декодировании стоит задать окно, в которое должен произойти перепад сигнала – не более половины периода слота бита.

    Метод расшифровки манчестерского кодирования и код для этого я взял у Shads . Можно, конечно, было написать свой собственный, но я торопился запустить копировщик - хотелось убедиться, что схема рабочая и приём меток производится. Так этот фрагмент и остался в коде копировщика. Также оказалось, что у меня компаратор настроен инверсно, чем нужно коду декодирования. Изменил в коде. Итак, мы получили последовательности нулей и единиц. Как из них получить код карты?

    А очень просто. Примем, что номер карты по нибблам имеет вид AB CD EF GH IJ . Карта выдаёт вот что:

    1) Девять единиц в начале;
    2) Ниббл A;
    3) Чётность ниббла A (1 бит);
    4) Ниббл B;
    5) Чётность ниббла B (1 бит);

    16) Ниббл I;
    17) Чётность ниббла I (1 бит);
    18) Ниббл J;
    19) Чётность ниббла J (1 бит);
    20) Ниббл чётности колонок для нибблов A B C D E F G H I J;
    21) Бит 0.

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

    Карту мы читать научились, а вот как передать данные карте? Для этого нужно просто включать или выключать частоту 125 КГц в соответствии с протоколом обмена с картой. На время “молчания” считывателя карта питается запасённой энергией.

    Болванки T5557/T5577 полностью совместимы между собой по протоколам записи, однако, имеют немного разные минимальные и максимальные времена импульсов (к счастью, времена T5557 перекрываются с T5577). У EM4305 протокол записи иной.

    Чтобы записать T5557 я воспользовался кодом BolshoyK . В таблице ниже указаны параметры сигналов для брелока T5557.

    Запись начинается с сигнала StartGape – требуется отключить сигнал 125 КГц примерно на 300 мкс. Это сигнал карте, что сейчас ей начнут передавать данные. Дальше следует передать болванке информацию. Кодирование передаваемых данных – тот же манчестер.

    Болванки T5557/T5577 и EM4305 многофункциональные и умеют разные виды модуляций, поддерживают пароли и ещё много чего. В каждой болванке на борту имеется набор блоков по 32 бита. Назначение этих блоков разное. В некоторых – выдаваемый код ключа (он занимает два блока). В других – конфигурация. В третьих – идентификатор производителя. Мы будем использовать ограниченный функционал, поэтому желающие разобраться, что значат все эти биты, могут заглянуть в документацию к болванкам (я приложил её к архиву).

    Блоки собраны в две страницы (0 и 1).

    В нулевой странице есть блок конфигурации с индексом 0. Его мы и будем задавать. Для T5557/T5577 у нас будут следующие конфигурационные байты: 0x00,0x14,0x80,0x40 в соответствии с таблицей из документации (красным я отметил выбранные единичными битами режимы):

    Таким образом, у нас выбрано: частота передачи данных RF/64 (125 КГц/64), кодирование типа манчестер, выдача блоков до второго (в блоках 1 и 2 у нас будет располагаться код, выдаваемый картой). Перед записью следует отправить код операции (2 бита opcode) и один бит защёлки (lockbit). Коды операции 10b и 11b предшествуют записи данных для страниц 0 и 1 (младший бит задаёт номер страницы, старший - код записи страницы). У нас выдаётся 10b для кода операции (вся работа идёт с нулевой страницей) и 0b для бита защёлки. После передачи всех этих данных необходимо передать трёхбитный адрес записываемой страницы. Все передачи данных для T5557/T5577 ведутся от старшего бита к младшему.

    Задав код карты в блоках 1 и 2 и конфигурацию в блоке 0 можно получить дубликат RFID-метки. Как видите, всё просто.

    Следующий тип болванок – это EM4305. Вот разбираться с записью этой болванки мне пришлось самому. Она также состоит из блоков по 32 бита, но назначение их иное.

    Кодирование передаваемых карте данных – по перепадам за интервал времени. Если перепад за интервал времени был, то это ноль, а если не было - единица. Конфигурационное слово хранится в 4 байте и для себя я определил его так: 0x5F,0x80,0x01,0x00 (кодирование манчестер, RF/64, выдача слова 6). В слова 5 и 6 я записываю код карты (те самые 64 бита, что выдаёт карта). EM4305 требует чтобы передача велась от младшего бита к старшему. Карта понимает, что с ней начинают обмен после выдачи ей комбинации импульсов:

    1. Отключаем поле на 48 мкс.
    2. Включаем поле на 96 мкс.
    3. Выключаем поле на 320 мкс.
    4. Включаем поле на 136 мкс.
    5. Отключаем поле до следующей команды.
    Команда на запись блока карте передаётся так:
    1. Шлём вышеуказанную последовательность импульсов.
    2. Шлём 0b.
    3. Передаём CC0-CC1 и их чётность P. (0101b для записи, см. таблицы ниже).
    4. Передаём адрес блока (см. таблицу), два дополняющих нуля и чётность адреса.
    5. Передаём данные блока (32 бита).

    Формат команды


    Коды команд

    Формат адреса блока

    Таким образом задаётся конфигурация болванки EM4305 и её код.

    Собственно, ничего большего простому копировщику и не требуется.

    Я сделал несколько вариантов копировщика с разными дисплеями. Например, вот копировщик с дисплеем 1602:

    А вот видео работы копировщика на дисплее LPH9157-02.

    Статьи по теме: