PN532: подключение NFC-модуля к Arduino, три режима и чтение MIFARE
PN532 подключается к Arduino четырьмя проводами в режиме I2C: земля, питание, SDA и SCL. Режим выбирается выводами SEL0 и SEL1, они читаются чипом только в момент подачи питания, поэтому переключатель на плате надо выставить до включения.
Модуль умеет три интерфейса сразу: I2C с адресом 0x24, SPI и UART. По умолчанию у дешёвых плат включён UART, и это главная причина, по которой сканер шины не находит модуль.
Первый раз я потратил на PN532 целый вечер. Модуль отвечал, карту видел, а чтение блока возвращало нули: я забыл, что у MIFARE Classic ключи не всегда пустые, и блок просто не авторизовался.
Три режима: I2C, SPI и UART
Чип один, а интерфейсов три, и выбор между ними делается аппаратно. На дешёвых модулях это переключатель или две перемычки, на плате Adafruit это джемперы с подписями SEL0 и SEL1. Уровни на этих выводах читаются процессором только в момент подачи питания, и сменить режим на ходу нельзя: только выставили переключатель, потом включили питание.
| Режим | Выводы | Когда берут | Особенности |
|---|---|---|---|
| I2C | VCC, GND, SDA, SCL | Когда свободных выводов мало | Адрес 0x24, нужен clock stretching |
| SPI | VCC, GND, SCK, MISO, MOSI, SS | Когда нужна скорость | Быстрее I2C, но пять проводов |
| UART | VCC, GND, TXD, RXD | Режим по умолчанию | 115200 бод, ничего настраивать не надо |
Соответствие уровней SEL0 и SEL1 напечатано рядом с переключателем на самой плате, и читать надо именно свою. Платы разных производителей разводят эти выводы по-разному, и пересказать таблицу для всех невозможно.
Распиновка и что куда втыкать
- VCC это питание платы модуля: у большинства модулей допустимо от 3,3 до 5,5 В, потому что на борту стоит стабилизатор 3,3 В.
- GND это общая земля, её надо соединить с землёй Arduino, иначе модуль не услышит I2C.
- SDA и SCL это линии шины I2C, на Uno это A4 и A5, на ESP32 это выводы 21 и 22.
- TXD и RXD это линии UART, они же выводы SPI в другом режиме, так что смотреть надо на подписи своей платы.
- IRQ это выход прерывания, RSTO это выход состояния сброса, оба необязательны.
- Антенна 13,56 МГц нарисована прямо на плате, карту прикладывают к отмеченному месту.
MIFARE Classic 1K: как устроена карта
Карта MIFARE Classic 1K хранит 1 КБ, и разбита на 16 секторов по 4 блока по 16 байт. В каждом секторе блок 0 это данные производителя, блок 1 содержит UID и тоже только для чтения, блок 2 это пользовательские данные, а блок 3 это трейлер с ключами и битами доступа.
| Блок сектора | Что внутри | Кто может читать |
|---|---|---|
| 0 | данные производителя | все, изменить нельзя |
| 1 | UID и данные производителя | все, изменить нельзя |
| 2 | пользовательские данные | тот, кто прошёл авторизацию |
| 3 | ключи A и B, биты доступа | только по ключу |
Читать блок 2 без авторизации нельзя, и это вторая причина, по которой модуль возвращает нули. Сначала выполняется аутентификация криптографией Crypto1 по ключу A или B, и только потом идёт обмен с блоком. Заводские ключи по умолчанию у карты MIFARE Classic это FFFFFFFFFFFF, но у многих карт в ключе B зашит другой код, и тогда авторизация по ключу B не проходит.
- Ключ A это 6 байт, ключ B это 6 байт, оба хранятся в трейлере сектора.
- Бит доступа в трейлере задаёт, кто читает блок, кто пишет, кто инкрементирует и кто декрементирует счётчик.
- Блоки разных секторов имеют разные ключи, поэтому дешёвая карта на все сектора не читается.
- UID это 4 или 7 байт, для MIFARE Classic 1K он обычно 4 байта и одинаков у всех карт одной партии.
- Записать можно только 16 байт за раз, это ровно размер блока без контрольной суммы.
Чтение UID и чтение блока
#include <Wire.h>#include <Adafruit_PN532.h> Adafruit_PN532 nfc(-1, -1); // rezhim I2C, vyvody IRQ i RSTO ne podklyucheny void setup() { Serial.begin(115200); Wire.begin(); nfc.begin(); uint8_t ver[4]; if (!nfc.getFirmwareVersion(ver)) { Serial.println("PN532 ne nayden: proverit rezhim SEL0 SEL1"); while (true) delay(100); } Serial.print("Firmware: "); Serial.print(ver[1]); Serial.print('.'); Serial.print(ver[2]); Serial.print('.'); Serial.println(ver[3]); nfc.SAMConfig(); // proverka karty v palke} void loop() { uint8_t uid[7]; uint8_t uidLen = 0; if (nfc.readPassiveTargetID(PN532_MIFARE_ISO14443A, uid, &uidLen)) { Serial.print("UID: "); for (uint8_t i = 0; i < uidLen; i++) { if (uid[i] < 16) Serial.print('0'); Serial.print(uid[i], HEX); Serial.print(' '); } Serial.println(); delay(800); }}uint8_t uid[7];uint8_t uidLen = 0; if (nfc.readPassiveTargetID(PN532_MIFARE_ISO14443A, uid, &uidLen)) { uint8_t key[6] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}; // blok 2 vnutri sekora 0, kluc A if (nfc.authenticate(2, 1, key, uid, uidLen)) { uint8_t block[18]; // 16 bait dannyh i 2 bayta kontrolnoy summy if (nfc.mifareTransceive(uid, uidLen, block, 18)) { Serial.print("Blok: "); for (int i = 0; i < 16; i++) { if (block[i] < 16) Serial.print('0'); Serial.print(block[i], HEX); Serial.print(' '); } Serial.println(); } } else { Serial.println("Avtorizaciya ne proshla"); } delay(1000);}PN532 против RC522: где на самом деле разница
Здесь в интернете путают две разные вещи. RC522 тоже работает на 13,56 МГц, как и PN532. А вот настоящие 125 кГц это совсем другие модули на чипах EM4100 и T5577, они несовместимы ни с RC522, ни с PN532. Путаница возникает из-за того, что RC522 в магазинах называют «модуль RFID».
| Критерий | PN532 | RC522 |
|---|---|---|
| Частота | 13,56 МГц | 13,56 МГц |
| Интерфейсы | I2C, SPI, UART | только SPI |
| Стандарты | 14443-A, 14443-B, 18092 | только 14443-A |
| Телефон как карта | да, режим эмуляции | нет |
| Обмен между двумя чипами | да, режим peer to peer | нет |
| Криптография MIFARE | внутри чипа | считает микроконтроллер |
| Свободные выводы Arduino | 2 или 4 | 6 или 7 |
| Цена | 300-700 руб | 150-400 руб |
Вывод простой: для контроля доступа по карте MIFARE Classic RC522 дешевле и проще, и справится. PN532 нужен там, где карту читает телефон, нужен формат NDEF или требуется обмен данными между двумя устройствами. Описание чтения UID карты есть в гайде про MIFARE Classic.
Что сначала не получилось
Первый вечер ушёл на сканер шины. Модуль был в заводском режиме UART, я подключил SDA и SCL и запустил сканер адресов: пусто. Я подозревал сначала питание, потом библиотеку, потом свою пайку, и только на третий день догадался посмотреть на переключатель на плате.
Второй тупик был содержательнее. Карта находилась, UID печатался правильный, а чтение блока возвращало шестнадцать нулей. Я решил, что блок пустой, и полчаса проверял ключ B. Оказалось, что чтение блока 2 без предварительной авторизации так и работает: сначала authenticate, потом обмен.
Личный опыт: замок на карте
Первое устройство с PN532 у меня было электронным замком на карте MIFARE Classic. Задача была простой: приложил карту, реле щёлкнуло, дверь открылась. Мозг Arduino сверял UID с белым списком, и всё.
Что выяснилось по ходу. Скорость считывания UID держится в пределах 30 миллисекунд, но при включённом питании реле в момент опроса давало щелчок в показаниях, поэтому силовую часть я вынес на отдельное питание. Дальше я решил писать в блок 2 карты номер абонемента, и вот тут вылезло то, чего не ожидал: у части карт ключ B был нестандартный, и запись в сектор 4 проходила, а в сектор 5 нет. Пришлось читать ключи из трейлера и проверять, какой сектор доступен.
Авторская позиция: когда брать PN532
Новичку я бы посоветовал сначала купить RC522 и научиться читать UID. Это дешевле, в комплекте с набором он часто уже лежит, и задача «прочитал карту и открыл дверь» закрывается за вечер.
PN532 оправдан, когда рядом живёт телефон. Записать на метку адрес сайта, считать NDEF с телефона, принять данные с другого телефона: вот эти три сценария на RC522 невозможны в принципе. И ещё один довод: PN532 можно запустить по I2C и не занимать выводы Arduino под SPI.
И последнее: не покупайте модули, где распаяна только часть переключателя. Полноценный модуль с тремя режимами стоит чуть дороже, зато вы не привязаны к одному интерфейсу и не будете перепаивать провода, когда упрётесь в число свободных выводов.