MFRC522
Модуль управляет RFID/NFC-считывателем MFRC522 и работает с картами на частоте 13,56 МГц.
Поддерживаемые типы карт
- MIFARE Classic (1K, 2K, 4K, Mini)
- MIFARE Plus (SL0, SL1, SL2, SL3)
- MIFARE Ultralight (стандартный, C, EV1, Nano)
- NTAG (213, 215, 216, 413, 424)
- MIFARE DESFire (EV1, EV2)
- ISO/IEC 14443-4 (EMV карты)
Быстрый старт
Для использования этого модуля нужно сделать следующее:
Настройте UART для связи с MFRC522:
uart.setup(uart.UART1, 115200, 8, uart.PARITY_NONE, uart.STOP_1)Инициализируйте модуль MFRC522:
mfrc522.init(uart.UART1, -1, mfrc522.GAIN_43)Прочитайте UID карты:
uid = mfrc522.uid(uart.UART1, true) if uid then print("UID: " .. uid) end
mfrc522.init([uart_id], [rst_pin], [gain])
Инициализирует модуль MFRC522. Все параметры опциональны — если не указаны, используются значения по умолчанию для данной платы.
Аргументы:
- uart_id (необязательное целое число): идентификатор UART порта.
- rst_pin (необязательное целое число): номер GPIO пина для сброса модуля.
- gain (необязательное целое число): усиление приёмника.
Возвращает: true при успешной инициализации, false при ошибке.
-- Инициализация со значениями по умолчанию для данной платы
ok = mfrc522.init()
-- Инициализация с указанием только порта
ok = mfrc522.init(uart.UART1)
-- Инициализация с явным указанием всех параметров
ok = mfrc522.init(uart.UART1, -1, mfrc522.GAIN_48)
if ok then
print("MFRC522 initialized")
end
mfrc522.reinit(uart_id)
Повторно инициализирует модуль MFRC522 с сохранёнными параметрами.
Аргументы:
- uart_id (целое число): идентификатор UART порта.
Возвращает: true при успешной инициализации, false при ошибке.
-- Переинициализация после ошибки
mfrc522.reinit(uart.UART1)
mfrc522.deinit(uart_id)
Деинициализирует модуль MFRC522: выключает антенну, переводит чип в power-down и опускает линию RST.
Аргументы:
- uart_id (целое число): идентификатор UART порта.
Возвращает: true при успехе, false при ошибке.
-- Освобождение ресурса считывателя
mfrc522.deinit(uart.UART1)
mfrc522.uid(uart_id, halt, [result_type])
Читает UID карты, поднесённой к считывателю.
Аргументы:
- uart_id (целое число): идентификатор UART порта.
- halt (булево): true - остановить карту после чтения (HALT), false - оставить активной.
- result_type (необязательное целое число): формат возвращаемого UID:
- 0 (по умолчанию): строка UID в hex (верхний регистр)
- 1: UID как список чисел (несколько возвращаемых значений)
- 2: UID как uint32 big-endian (для 4-байтного UID)
- 3: таблица с полями str, int, tab, sak, atqa, sz, flags, type
- 4: UID как десятичная строка little-endian (Ur)
- 5: UID в формате Wiegand 26 с запятой (Uc)
- 6: UID в формате Wiegand 26 с точкой (Ud)
- 7: UID как бинарная строка (сырые байты)
Возвращает: значение UID в выбранном формате или nil, если карта не обнаружена.
-- Чтение UID с остановкой карты
uid = mfrc522.uid(uart.UART1, true)
if uid then
print("UID: " .. uid)
end
-- Чтение UID без остановки (для последующих операций)
uid = mfrc522.uid(uart.UART1, false)
-- Полная информация о карте
info = mfrc522.uid(uart.UART1, false, 3)
if info then
print(info.str, info.type)
end
mfrc522.scan([format | result_type], [key_type], [key], [ul_pwd], [scan_mode])
mfrc522.scan(callback, …)
mfrc522.scan([result_type], callback, …)
mfrc522.scan([result_type], [key_type], [key], [ul_pwd], [scan_mode], callback, …)
Сканирует карту с параметрами по умолчанию для данной платы (UART/RST/gain).
На каждом вызове scan для микросхемы применяется один из трёх сценариев (параметр scan_mode, по умолчанию 2):
- 0: базовый режим. После сканирования RF-поле выключается.
- 1: контроль чипа. Перед сканированием вызывается getver; если ответа нет или версия некорректная, выполняется deinit/init.
- 2: one-shot. Перед каждым вызовом выполняется init, после каждого вызова — deinit.
Первый параметр определяет режим работы:
- Строка — форматирует данные через sprintf-парсер (синтаксис см. в mfrc522.sprintf).
- Число — возвращает UID в указанном формате result_type (аналогично параметру result_type в mfrc522.uid).
- Функция — сканирует UID в режиме result_type = 1 и вызывает callback с UID-байтами.
- Не указан / nil — возвращает UID как hex-строку (эквивалентно result_type = 0).
Аргументы:
- format | result_type (необязательный, строка или число): строка форматирования или числовой код формата UID:
- 0 (по умолчанию): строка UID в hex (верхний регистр)
- 1: UID как список чисел (несколько возвращаемых значений)
- 2: UID как uint32 big-endian (для 4-байтного UID)
- 3: таблица с полями str, int, tab, sak, atqa, sz, flags, type
- 4: UID как десятичная строка little-endian (Ur)
- 5: UID в формате Wiegand 26 с запятой (Uc)
- 6: UID в формате Wiegand 26 с точкой (Ud)
- 7: UID как бинарная строка (сырые байты)
- key_type (необязательное целое число): тип ключа mfrc522.KeyA или mfrc522.KeyB. По умолчанию KeyA.
- key (необязательная строка): hex-строка ключа (12 символов). По умолчанию “FFFFFFFFFFFF”.
- ul_pwd (необязательное целое число): пароль для NTAG/Ultralight. По умолчанию 0xFFFFFFFF.
- scan_mode (необязательное целое число): режим обслуживания микросхемы (0, 1 или 2). По умолчанию 2.
- callback (необязательно): функция, вызываемая только после успешного чтения UID. Все следующие аргументы передаются в неё перед UID. Короткая форма использует result_type = 1 и передаёт UID отдельными байтами. В качестве обработчика принимается только функция.
Возвращает: значение UID в выбранном формате, отформатированную строку (включая пустую) или nil если карта не обнаружена.
Если UID не найден, обработчик не вызывается и scan() не возвращает значений. После вызова обработчика функция возвращает true и его результаты либо false, err, если обработчик завершился ошибкой. Ошибки оборудования, аргументов и инициализации по-прежнему вызывают исключение.
-- Простейший вызов — UID в hex
uid = mfrc522.scan()
if uid then
print("UID: " .. uid)
end
-- UID как uint32
uid_int = mfrc522.scan(2)
-- Полная информация о карте в виде таблицы
info = mfrc522.scan(3)
if info then
print(info.str, info.type)
end
-- UID через sprintf-формат
result = mfrc522.scan("HU*")
-- Wiegand 26
result = mfrc522.scan("Uc")
-- Чтение блока MIFARE Classic с ключом
result = mfrc522.scan("HB4%*", mfrc522.KeyA, "A0A1A2A3A4A5")
-- Режим 1: проверка getver с авто-reinit при некорректном ответе
result = mfrc522.scan("HU*", mfrc522.KeyA, "FFFFFFFFFFFF", 0xFFFFFFFF, 1)
-- Режим 2: init/deinit на каждом вызове
uid = mfrc522.scan(nil, nil, nil, nil, 2)
-- Lua callback: UID приходит отдельными байтами (result_type = 1)
local function print_uid(...)
local uid = ""
for i = 1, select("#", ...) do
uid = uid .. string.format("%02X", select(i, ...))
end
print("UID: " .. uid)
end
mfrc522.scan(print_uid)
-- Lua callback с пользовательскими аргументами перед UID
local function store_uid(offset, ...)
modbus.setregs8(offset, ...)
end
mfrc522.scan(store_uid, 0) -- store_uid(0, uid_byte1, uid_byte2, ...)
-- Передать UID напрямую в регистры Modbus
mfrc522.scan(modbus.setregs8, 0)
-- Проверка результата callback: nil/нет значений значит, что карты нет
local ok, err = mfrc522.scan(modbus.setregs8, 0)
if ok == false then
print("Callback error:", err)
end
-- То же самое с явным форматом результата: UID как список байтов
mfrc522.scan(1, modbus.setregs8, 0)
-- UID как hex-строка в callback
mfrc522.scan(0, function(uid)
print("UID: " .. uid)
end)
-- UID как таблица с полями str/int/tab/sak/atqa/sz/flags/type
mfrc522.scan(3, function(info)
print(info.str, info.type)
end)
-- UID как бинарная строка, с префиксным аргументом offset
mfrc522.scan(7, function(offset, uid)
modbus.setregs8(offset, uid)
end, 0)
-- Callback вместе с явным scan_mode
mfrc522.scan(1, nil, nil, nil, 2, modbus.setregs8, 0)
mfrc522.sprintf(uart_id, format, [key_type], [key], [ul_pwd], [halt])
Форматирует данные карты по заданному шаблону. Мощная функция для чтения и форматирования данных с RFID карт.
Аргументы:
- uart_id (целое число): идентификатор UART порта.
- format (строка): строка форматирования (см. ниже).
- key_type (необязательное целое число): тип ключа mfrc522.KeyA или mfrc522.KeyB. По умолчанию KeyA.
- key (необязательная строка): hex-строка ключа (12 символов). По умолчанию “FFFFFFFFFFFF”.
- ul_pwd (необязательное целое число): пароль для NTAG/Ultralight. По умолчанию 0xFFFFFFFF.
- halt (необязательное булево): остановить карту после операции.
Возвращает: отформатированную строку или nil если карта не обнаружена.
Синтаксис форматирования
Режимы вывода:
- a - ASCII режим
- d - десятичный режим
- h - hex (нижний регистр)
- H - hex (верхний регистр)
- D - UID как десятичное число (uint32)
Работа с UID:
- U* - весь UID
- U~ - весь UID (байты в обратном порядке)
- Un - байт UID с индексом n (с 0)
- Un:m - байты UID от n до m включительно
- Ur - UID как uint32 (little-endian)
- Uc - Wiegand 26 через запятую (058,16506)
- Ud - Wiegand 26 через точку (058.16506)
Работа с блоками (MIFARE Classic):
- BN%* - весь блок N
- BN%~ - весь блок N (в обратном порядке)
- BN%n - байт n блока N
- BN%n:m - байты от n до m блока N
Специальные символы:
- S - SAK байт карты
- P - PAN (для EMV карт) или UID
- \n - новая строка
- \t - табуляция
-- Вывод UID в hex формате
result = mfrc522.sprintf(uart.UART1, "HU*")
print(result) -- "04A1B2C3D4E5F6"
-- UID в формате Wiegand 26
result = mfrc522.sprintf(uart.UART1, "Uc")
print(result) -- "058,16506"
-- Чтение блока 4 с ключом по умолчанию
result = mfrc522.sprintf(uart.UART1, "HB4%*")
-- Чтение блока с пользовательским ключом
result = mfrc522.sprintf(uart.UART1, "HB4%*", mfrc522.KeyA, "A0A1A2A3A4A5")
-- Комбинированный вывод
result = mfrc522.sprintf(uart.UART1, "UID: HU*\nType: S")
mfrc522.read_ul(uart_id, page)
Читает страницу (4 байта) с карты Ultralight/NTAG.
Аргументы:
- uart_id (целое число): идентификатор UART порта.
- page (целое число): номер страницы (0-255, зависит от типа карты).
Возвращает: строка с данными (4 байта) или nil, error_message.
-- Сначала нужно прочитать UID чтобы активировать карту
uid = mfrc522.uid(uart.UART1, false)
-- Чтение страницы 4 (первая пользовательская страница)
data, err = mfrc522.read_ul(uart.UART1, 4)
if data then
print("Data: " .. string.tohex(data))
else
print("Error: " .. err)
end
mfrc522.write_ul(uart_id, page, data)
Записывает 4 байта на страницу карты Ultralight/NTAG.
Аргументы:
- uart_id (целое число): идентификатор UART порта.
- page (целое число): номер страницы (0-255).
- data (строка или 4 числа): данные для записи (4 байта).
Возвращает: true при успехе или nil, error_message.
-- Активируем карту
uid = mfrc522.uid(uart.UART1, false)
-- Запись строки
ok, err = mfrc522.write_ul(uart.UART1, 4, "TEST")
-- Запись байтов
ok, err = mfrc522.write_ul(uart.UART1, 5, string.char(0x01, 0x02, 0x03, 0x04))
mfrc522.read_classic(uart_id, block, [key_type], [key])
Читает блок (16 байт) с карты MIFARE Classic с аутентификацией.
Аргументы:
- uart_id (целое число): идентификатор UART порта.
- block (целое число): номер блока (0-255, зависит от типа карты).
- key_type (необязательное целое число): тип ключа mfrc522.KeyA (по умолчанию) или mfrc522.KeyB.
- key (необязательная строка): hex-строка ключа (12 символов). По умолчанию “FFFFFFFFFFFF”.
Возвращает: строка с данными (16 байт) или nil, error_message.
-- Сначала нужно прочитать UID чтобы активировать карту
uid = mfrc522.uid(uart.UART1, false)
-- Чтение блока 4 как текстовой строки (16 байт)
data, err = mfrc522.read_classic(uart.UART1, 4)
if data then
print("Data: " .. data)
else
print("Error: " .. err)
end
-- Проверка ожидаемой строки в блоке
if data == "Hello MIFARE!!!\0" then
print("Text matched")
end
mfrc522.write_classic(uart_id, block, data, [key_type], [key])
Записывает 16 байт в блок карты MIFARE Classic с аутентификацией.
Аргументы:
- uart_id (целое число): идентификатор UART порта.
- block (целое число): номер блока (0-255).
- data (строка или таблица): данные для записи (16 байт как строка или таблица из 16 чисел).
- key_type (необязательное целое число): тип ключа mfrc522.KeyA (по умолчанию) или mfrc522.KeyB.
- key (необязательная строка): hex-строка ключа (12 символов). По умолчанию “FFFFFFFFFFFF”.
Возвращает: true при успехе или nil, error_message.
ВНИМАНИЕ: Запись в sector trailer блоки (3, 7, 11, 15, …) может заблокировать сектор навсегда! Sector trailer содержит ключи доступа и биты контроля доступа.
-- Активируем карту
uid = mfrc522.uid(uart.UART1, false)
-- Запись строки ровно 16 байт
ok, err = mfrc522.write_classic(uart.UART1, 4, "Hello MIFARE!!!\0")
-- Запись с пользовательским ключом B
ok, err = mfrc522.write_classic(
uart.UART1,
5,
"Access granted!\0",
mfrc522.KeyB,
"A0A1A2A3A4A5"
)
if ok then
print("Write successful")
else
print("Error: " .. err)
end
-- Чтение обратно как строки
data, err = mfrc522.read_classic(uart.UART1, 4)
if data then
print("Read back: " .. data)
end
mfrc522.set_classic_keys(uart_id, sector, keyA, keyB, [auth_keytype], [auth_key], [access_bits], [gpb])
Обновляет Key A и Key B в sector trailer выбранного сектора MIFARE Classic.
Аргументы:
- uart_id (целое число): идентификатор UART порта.
- sector (целое число): номер сектора (0-39).
- keyA (строка): новый Key A, 12 hex-символов.
- keyB (строка): новый Key B, 12 hex-символов.
- auth_keytype (необязательное целое число): mfrc522.KeyA (по умолчанию) или mfrc522.KeyB.
- auth_key (необязательная строка): текущий ключ для аутентификации. По умолчанию “FFFFFFFFFFFF”.
- access_bits (необязательная строка): access bits (3 байта, 6 hex-символов). По умолчанию “FF0780”.
- gpb (необязательное целое число): GPB байт (0-255). По умолчанию 0x69.
Возвращает: true при успехе или nil, error_message.
-- Смена ключей сектора 1 (trailer блок 7)
ok, err = mfrc522.set_classic_keys(
uart.UART1,
1,
"A0A1A2A3A4A5", -- новый Key A
"B0B1B2B3B4B5", -- новый Key B
mfrc522.KeyA,
"FFFFFFFFFFFF", -- текущий ключ доступа
"FF0780", -- стандартные access bits
0x69
)
if not ok then
print("Key update error: " .. err)
end
-- После смены ключа читаем блок по новому ключу
data, err = mfrc522.read_classic(uart.UART1, 4, mfrc522.KeyB, "B0B1B2B3B4B5")
if data then
print("Data: " .. data)
end
Структура памяти MIFARE Classic
MIFARE Classic 1K содержит 16 секторов по 4 блока (64 блока всего):
| Сектор | Блоки | Назначение |
|---|---|---|
| 0 | 0-3 | Блок 0 — Manufacturer block (только чтение), 1-2 — данные, 3 — sector trailer |
| 1 | 4-7 | Блоки 4-6 — данные, 7 — sector trailer |
| … | … | … |
| 15 | 60-63 | Блоки 60-62 — данные, 63 — sector trailer |
Sector trailer (блоки 3, 7, 11, …):
- Байты 0-5: Key A (не читается, возвращает нули)
- Байты 6-9: Access bits (определяют права доступа)
- Байты 10-15: Key B (может хранить данные если не используется)
-- Пример: чтение всех блоков сектора 1
uid = mfrc522.uid(uart.UART1, false)
for block = 4, 7 do
local data, err = mfrc522.read_classic(uart.UART1, block)
if data then
print(string.format("Block %d: %s", block, data))
else
print(string.format("Block %d error: %s", block, err))
end
end
MIFARE Plus SL0/SL3
Поддержка защищённых команд MIFARE Plus включается параметром
CONFIG_LUA_RTOS_MFRC522_PLUS. Для сборок с модулем MFRC522 параметр включён
по умолчанию; при необходимости его можно отключить в Kconfig. Реализация
использует AES-128 из Mbed TLS в ESP-IDF. MIFARE Plus SE не поддерживается.
AES-ключ во всех функциях задаётся строкой из 32 шестнадцатеричных символов. Исходный ключ используется только во время вызова и затем удаляется из C-стека. После успешной аутентификации в объекте считывателя остаются только производные сессионные ключи SL3.
Сессия привязана к выбранному UID. Она сбрасывается при исчезновении или новом
выборе карты, HALT, выключении поля, resetfield(), deinit(), ошибке связи или
проверки MAC. После сброса нужно снова вызвать plus_auth().
mfrc522.plus_key_block(sector, key_type)
Возвращает номер AES-блока ключа сектора для MIFARE Plus.
Аргументы:
sector(целое число): номер сектора 0-39.key_type(строка):"A"или"B".
Возвращает: номер блока ключа.
local key_a_sector_1 = mfrc522.plus_key_block(1, "A")
local key_b_sector_1 = mfrc522.plus_key_block(1, "B")
mfrc522.plus_auth(uart_id, key_block, key)
Создаёт или продолжает защищённую сессию с картой MIFARE Plus SL3. Если активной сессии нет, функция заново выбирает карту и выполняет FirstAuth. Если сессия для того же UID уже активна, выполняется FollowAuth с другим ключевым блоком без сброса счётчиков secure messaging.
Аргументы:
uart_id(целое число): идентификатор UART порта.key_block(целое число): блок AES-ключа, например результатplus_key_block()или одна из константPLUS_KEY_*.key(строка): AES-128 ключ, ровно 32 hex-символа.
Возвращает: true при успехе или nil, error_message.
local key_block = mfrc522.plus_key_block(1, "A")
local ok, err = mfrc522.plus_auth(
uart.UART1,
key_block,
"00112233445566778899AABBCCDDEEFF"
)
mfrc522.read_plus(uart_id, block, [count])
Читает от одного до трёх последовательных 16-байтных блоков через активную сессию SL3. Функция не выбирает карту повторно, поскольку это нарушило бы синхронизацию счётчиков secure messaging.
Аргументы:
uart_id(целое число): идентификатор UART порта.block(целое число): номер первого блока, 0-65535.count(необязательное целое число): число блоков 1-3, по умолчанию 1.
Возвращает: бинарную строку длиной count * 16 байт или
nil, error_message.
local data, err = mfrc522.read_plus(uart.UART1, 4, 2)
if data then
print("Прочитано байт: " .. #data) -- 32
end
mfrc522.write_plus(uart_id, block, data, encrypted)
Записывает от одного до трёх последовательных блоков через активную сессию SL3.
Аргументы:
uart_id(целое число): идентификатор UART порта.block(целое число): номер первого блока, 0-65535.data(строка): бинарная строка длиной ровно 16, 32 или 48 байт.encrypted(булево):trueдля зашифрованной записи,falseдля записи с MAC без шифрования. Для системных и ключевых блоков выше0x00FFразрешено только значениеtrue.
Возвращает: true при успехе или nil, error_message.
local block = assert(mfrc522.read_plus(uart.UART1, 4))
assert(mfrc522.write_plus(uart.UART1, 4, block, true))
mfrc522.plus_reset_auth(uart_id)
Завершает активную сессию SL3 и удаляет производные сессионные ключи. Если сессии уже нет, функция также возвращает успех.
Аргументы:
uart_id(целое число): идентификатор UART порта.
Возвращает: true при успехе или nil, error_message.
assert(mfrc522.plus_reset_auth(uart.UART1))
mfrc522.plus_write_perso(uart_id, block, data, expected_uid)
Записывает один 16-байтный блок персонализации карты в SL0. Перед каждой записью функция заново выбирает карту и проверяет уровень SL0 и точное совпадение UID.
Аргументы:
uart_id(целое число): идентификатор UART порта.block(целое число): номер блока персонализации, 0-65535.data(строка): ровно 16 бинарных байт, не hex-строка.expected_uid(строка): UID без разделителей, 8, 14 или 20 hex-символов.
Возвращает: true при успехе или nil, error_message.
local function hex_bytes(hex)
return (hex:gsub("..", function(byte)
return string.char(tonumber(byte, 16))
end))
end
local uid = "04A1B2C3D4E5F6"
local card_master_key = hex_bytes("00112233445566778899AABBCCDDEEFF")
assert(mfrc522.plus_write_perso(
uart.UART1,
mfrc522.PLUS_KEY_CARD_MASTER,
card_master_key,
uid
))
mfrc522.plus_commit_sl3(uart_id, expected_uid, l3_switch_key, confirmation)
Завершает персонализацию SL0 и переводит карту в SL3. Функция принимает только
карту SL0 с указанным UID, выполняет CommitPerso, перезапускает RF-поле и
проверяет тот же UID и итоговый уровень SL3. Если карта временно оказалась в
SL1/SL2, для перехода используется ключ блока PLUS_KEY_L3_SWITCH (0x9003).
Аргументы:
uart_id(целое число): идентификатор UART порта.expected_uid(строка): UID без разделителей, 8, 14 или 20 hex-символов.l3_switch_key(строка): ключ переключения в SL3, 32 hex-символа.confirmation(строка): точная строкаCOMMITи UID в верхнем регистре.
Возвращает: true при подтверждённом переходе в SL3 или
nil, error_message.
Переход из SL0 необратим. Используйте только тестовую карту, заранее сохраните её UID и весь набор ключей. До вызова
plus_commit_sl3()запишите как минимум Card Master, Card Configuration, L3 Switch и все секторные ключи, нужные приложению. После ошибки или потери питания считайте состояние карты неизвестным и проверьте её независимым инструментом перед повторной попыткой.
local uid = "04A1B2C3D4E5F6"
local l3_switch_key = "00112233445566778899AABBCCDDEEFF"
assert(mfrc522.plus_commit_sl3(
uart.UART1,
uid,
l3_switch_key,
"COMMIT " .. uid
))
mfrc522.read_cnt(uart_id, [counter_addr])
Читает 24-битный счётчик с карты Ultralight EV1 или NTAG21x.
Аргументы:
- uart_id (целое число): идентификатор UART порта.
- counter_addr (необязательное целое число): адрес счётчика (0-2 для UL EV1, обычно 0x02 для NTAG21x). По умолчанию 0.
Возвращает: значение счётчика (число 0-16777215) или nil, error_message.
-- Активируем карту
uid = mfrc522.uid(uart.UART1, false)
-- Чтение счётчика
count, err = mfrc522.read_cnt(uart.UART1, 0)
if count then
print("Counter: " .. count)
end
mfrc522.incr_cnt(uart_id, increment, [counter_addr])
Атомарно увеличивает 24-битный счётчик на карте Ultralight EV1.
Аргументы:
- uart_id (целое число): идентификатор UART порта.
- increment (целое число): значение для увеличения (0-16777215).
- counter_addr (необязательное целое число): адрес счётчика (0-2). По умолчанию 0.
Возвращает: true при успехе или nil, error_message.
Важно: Счётчик может только увеличиваться. Сброс невозможен. При достижении 0xFFFFFF счётчик блокируется навсегда.
-- Активируем карту
uid = mfrc522.uid(uart.UART1, false)
-- Увеличить счётчик на 1
ok, err = mfrc522.incr_cnt(uart.UART1, 1, 0)
Счётчики Ultralight/NTAG
Количество и адресация
| Тип тега | Счётчиков | Адреса | Особенности |
|---|---|---|---|
| Ultralight EV1 | 3 | 0, 1, 2 | Ручной инкремент через incr_cnt |
| NTAG213/215/216 | 1 | только 2 | Автоинкремент при чтении через read_cnt |
| Ultralight (старый) | 0 | — | Счётчики не поддерживаются |
| Ultralight C | 0 | — | Счётчики не поддерживаются |
Характеристики счётчиков
- Разрядность: 24 бита (0 - 16 777 215)
- Направление: только увеличение (нельзя уменьшить или сбросить)
- Атомарность: операция инкремента атомарна, потеря питания не повредит значение
- Переполнение: при достижении максимума карта возвращает ошибку NAK (0x04)
- Блокировка: при переполнении счётчик блокируется навсегда
Примеры использования
-- Ultralight EV1: три независимых счётчика
uid = mfrc522.uid(uart.UART1, false)
local balance = mfrc522.read_cnt(uart.UART1, 0) -- счётчик 0: баланс
local visits = mfrc522.read_cnt(uart.UART1, 1) -- счётчик 1: визиты
local bonus = mfrc522.read_cnt(uart.UART1, 2) -- счётчик 2: бонусы
-- Начислить 100 баллов
mfrc522.incr_cnt(uart.UART1, 100, 0)
-- NTAG21x: один счётчик с автоинкрементом
-- Каждое чтение увеличивает счётчик на 1 (если NFC_CNT_EN включен)
local scans = mfrc522.read_cnt(uart.UART1, 2)
print("Карта сканировалась " .. scans .. " раз")
Система лояльности с двумя счётчиками
Поскольку счётчики могут только расти, для реализации баланса баллов используйте два счётчика:
-- cnt0 = начислено всего
-- cnt1 = списано всего
-- баланс = cnt0 - cnt1
uid = mfrc522.uid(uart.UART1, false)
local earned = mfrc522.read_cnt(uart.UART1, 0) or 0
local spent = mfrc522.read_cnt(uart.UART1, 1) or 0
local balance = earned - spent
print("Начислено: " .. earned)
print("Списано: " .. spent)
print("Баланс: " .. balance)
-- Начислить 50 баллов
mfrc522.incr_cnt(uart.UART1, 50, 0)
-- Списать 30 баллов
if balance >= 30 then
mfrc522.incr_cnt(uart.UART1, 30, 1)
end
Различия NTAG21x и Ultralight EV1
| Функция | NTAG21x | Ultralight EV1 |
|---|---|---|
| read_cnt | Работает (авто +1) | Работает |
| incr_cnt | Не поддерживается | Работает |
| Сброс счётчика | Невозможен | Невозможен |
| Назначение | Anti-tampering | Loyalty/Credits |
NTAG21x — счётчик используется для защиты от подделок. Каждое чтение увеличивает значение, что позволяет серверу проверить, не была ли карта клонирована (у клона счётчик не синхронизирован).
Ultralight EV1 — счётчики предназначены для хранения баллов лояльности, количества поездок и т. п.
mfrc522.getver(uart_id)
Возвращает версию чипа MFRC522.
Аргументы:
- uart_id (целое число): идентификатор UART порта.
Возвращает: версия чипа (0x91 или 0x92 для подлинных MFRC522).
ver = mfrc522.getver(uart.UART1)
print(string.format("Chip version: 0x%02X", ver))
mfrc522.setgain(uart_id, gain)
Устанавливает усиление приёмника.
Аргументы:
- uart_id (целое число): идентификатор UART порта.
- gain (целое число): значение усиления (используйте константы GAIN_*).
Возвращает: ничего.
mfrc522.setgain(uart.UART1, mfrc522.GAIN_48)
mfrc522.getgain(uart_id)
Возвращает текущее усиление приёмника.
Аргументы:
- uart_id (целое число): идентификатор UART порта.
Возвращает: значение усиления.
gain = mfrc522.getgain(uart.UART1)
mfrc522.antenna_on(uart_id)
Включает антенну.
Аргументы:
- uart_id (целое число): идентификатор UART порта.
Возвращает: ничего.
mfrc522.antenna_on(uart.UART1)
mfrc522.antenna_off(uart_id)
Выключает антенну. Также сбрасывает состояние активной карты.
Аргументы:
- uart_id (целое число): идентификатор UART порта.
Возвращает: ничего.
mfrc522.antenna_off(uart.UART1)
mfrc522.resetfield(uart_id)
Сбрасывает RF поле (выключает и включает антенну).
Аргументы:
- uart_id (целое число): идентификатор UART порта.
Возвращает: ничего.
-- Сброс поля для повторного обнаружения карты
mfrc522.resetfield(uart.UART1)
Константы
Типы ключей
| Константа | Описание |
|---|---|
| mfrc522.KeyA | Ключ типа A для MIFARE Classic |
| mfrc522.KeyB | Ключ типа B для MIFARE Classic |
MIFARE Plus
| Константа | Значение | Описание |
|---|---|---|
| mfrc522.PLUS_SL0 | 0 | Уровень безопасности SL0 |
| mfrc522.PLUS_SL1 | 1 | Уровень безопасности SL1 |
| mfrc522.PLUS_SL2 | 2 | Уровень безопасности SL2 |
| mfrc522.PLUS_SL3 | 3 | Уровень безопасности SL3 |
| mfrc522.PLUS_KEY_CARD_MASTER | 0x9000 | Card Master Key |
| mfrc522.PLUS_KEY_CARD_CONFIGURATION | 0x9001 | Card Configuration Key |
| mfrc522.PLUS_KEY_L2_SWITCH | 0x9002 | Ключ переключения в SL2 |
| mfrc522.PLUS_KEY_L3_SWITCH | 0x9003 | Ключ переключения в SL3 |
| mfrc522.PLUS_KEY_SL1_AUTH | 0x9004 | Ключ аутентификации SL1 |
Усиление приёмника
| Константа | Описание |
|---|---|
| mfrc522.GAIN_18 | 18 dB |
| mfrc522.GAIN_23 | 23 dB |
| mfrc522.GAIN_33 | 33 dB |
| mfrc522.GAIN_38 | 38 dB |
| mfrc522.GAIN_43 | 43 dB |
| mfrc522.GAIN_48 | 48 dB (максимальное) |
| mfrc522.GAIN_MIN | Минимальное усиление |
| mfrc522.GAIN_MAX | Максимальное усиление |
Полный пример
-- Инициализация MFRC522
if not mfrc522.init(uart.UART1, pio.GPIO26, mfrc522.GAIN_43) then
print("MFRC522 init failed!")
return
end
print("MFRC522 ready. Waiting for card...")
while true do
-- Чтение UID
uid = mfrc522.uid(uart.UART1, false)
if uid then
print("Card detected!")
print("UID: " .. uid)
print("Type: " .. card_type)
-- Для Ultralight/NTAG карт - чтение данных
if card_type:find("ULTRALIGHT") or card_type:find("NTAG") then
data, err = mfrc522.read_ul(uart.UART1, 4)
if data then
print("Page 4: " .. string.tohex(data))
end
end
-- Остановить карту
mfrc522.uid(uart.UART1, true)
-- Пауза перед следующим чтением
tmr.delay(1000)
end
tmr.delay(100)
end
Пример работы с MIFARE Classic
mfrc522.init(uart.UART1, pio.GPIO26, mfrc522.GAIN_43)
uid = mfrc522.uid(uart.UART1, false)
if uid and card_type:find("Classic") then
print("UID: " .. uid)
-- Записали
local ok, err = mfrc522.write_classic(uart.UART1, 4, "Hello MIFARE!!!\0")
if not ok then
print("Write error: " .. err)
else
-- Прочитали
local data, err = mfrc522.read_classic(uart.UART1, 4)
if data then
print("Read back: " .. data)
else
print("Read error: " .. err)
end
end
end
Пример работы с защищённым сектором
Пример записи и чтения данных с использованием пользовательского ключа:
mfrc522.init(uart.UART1, pio.GPIO26, mfrc522.GAIN_43)
-- Пользовательский ключ (12 hex символов = 6 байт)
local MY_KEY = "A0B1C2D3E4F5"
local BLOCK = 4 -- блок данных в секторе 1
local uid = mfrc522.uid(uart.UART1, false)
if uid and card_type:find("Classic") then
-- Записали с пользовательским ключом B
local write_data = "Access granted!\0"
local ok, err = mfrc522.write_classic(
uart.UART1, BLOCK, write_data,
mfrc522.KeyB, MY_KEY
)
if not ok then
print("Write error: " .. err)
else
-- Прочитали тем же ключом
local read_data, err = mfrc522.read_classic(
uart.UART1, BLOCK,
mfrc522.KeyB, MY_KEY
)
if read_data then
print("Read back: " .. read_data)
else
print("Read error: " .. err)
end
end
end
Пример чтения EMV карты
mfrc522.init(uart.UART1, pio.GPIO26, mfrc522.GAIN_43)
-- Чтение PAN (номера карты) с банковской карты
pan = mfrc522.sprintf(uart.UART1, "P*")
if pan then
print("PAN: " .. pan)
end
NDEF (NFC Data Exchange Format)
NDEF — стандартный формат хранения данных на NFC-тегах. Позволяет записывать URL, текст, контакты и другие данные, которые понимают все NFC-устройства.
mfrc522.ndef_read(uart_id)
Читает NDEF сообщение с карты Ultralight/NTAG.
Аргументы:
- uart_id (целое число): идентификатор UART порта.
Возвращает: таблицу с данными или nil, error_message.
Поля возвращаемой таблицы:
- raw (строка): сырые байты NDEF сообщения
- type (строка): “uri”, “text” или “unknown”
- uri (строка): URL (если type == “uri”)
- text (строка): текст (если type == “text”)
- lang (строка): код языка (если type == “text”)
uid = mfrc522.uid(uart.UART1, false)
ndef, err = mfrc522.ndef_read(uart.UART1)
if ndef then
print("Type: " .. ndef.type)
if ndef.uri then
print("URI: " .. ndef.uri)
elseif ndef.text then
print("Text: " .. ndef.text)
print("Lang: " .. ndef.lang)
end
end
mfrc522.ndef_write_uri(uart_id, uri, [prefix_code])
Записывает NDEF URI на карту Ultralight/NTAG.
Аргументы:
- uart_id (целое число): идентификатор UART порта.
- uri (строка): URL (без префикса если используется prefix_code).
- prefix_code (необязательное целое число): код префикса (0x00-0x23). По умолчанию 0.
Коды префиксов:
| Код | Префикс |
|---|---|
| 0x00 | (нет) |
| 0x01 | http://www. |
| 0x02 | https://www. |
| 0x03 | http:// |
| 0x04 | https:// |
| 0x05 | tel: |
| 0x06 | mailto: |
Возвращает: true при успехе или nil, error_message.
uid = mfrc522.uid(uart.UART1, false)
-- Записать https://example.com
mfrc522.ndef_write_uri(uart.UART1, "example.com", 0x04)
-- Записать полный URL без префикса
mfrc522.ndef_write_uri(uart.UART1, "https://example.com/path", 0x00)
mfrc522.ndef_write_text(uart_id, text, [lang])
Записывает NDEF текст на карту Ultralight/NTAG.
Аргументы:
- uart_id (целое число): идентификатор UART порта.
- text (строка): текст в UTF-8.
- lang (необязательная строка): код языка. По умолчанию “en”.
Возвращает: true при успехе или nil, error_message.
uid = mfrc522.uid(uart.UART1, false)
-- Записать текст на английском
mfrc522.ndef_write_text(uart.UART1, "Hello World", "en")
-- Записать текст на русском
mfrc522.ndef_write_text(uart.UART1, "Привет мир", "ru")
Пример: NFC визитка
mfrc522.init(uart.UART1, pio.GPIO26, mfrc522.GAIN_43)
print("Поднесите NTAG карту для записи визитки...")
while true do
uid = mfrc522.uid(uart.UART1, false)
if uid then
-- Записываем ссылку на сайт
ok, err = mfrc522.ndef_write_uri(uart.UART1, "mycompany.com", 0x02)
if ok then
print("Визитка записана!")
else
print("Ошибка: " .. err)
end
mfrc522.uid(uart.UART1, true) -- halt
break
end
tmr.delay(100)
end
Пример: Чтение NFC метки
mfrc522.init(uart.UART1, pio.GPIO26, mfrc522.GAIN_43)
while true do
uid = mfrc522.uid(uart.UART1, false)
if uid and (card_type:find("NTAG") or card_type:find("ULTRALIGHT")) then
local ndef = mfrc522.ndef_read(uart.UART1)
if ndef and ndef.type == "uri" then
print("Открыть: " .. ndef.uri)
-- Здесь можно выполнить действие по URL
end
mfrc522.uid(uart.UART1, true)
tmr.delay(1000)
end
tmr.delay(100)
end
Примечания
- После каждого вызова uid() с halt=false карта остаётся активной для последующих операций
- Для работы с MIFARE Classic используйте read_classic() / write_classic() или sprintf() для форматированного вывода
- Не записывайте в sector trailer блоки (3, 7, 11, …) без понимания структуры access bits — это может заблокировать сектор
- Счётчики на NTAG/Ultralight EV1 могут только увеличиваться