ESP32: Obsluha RFID čtečky v MicroPythonu
Přestože jsme slibovali, že se v dalším článku o MicroPythonu na modulu ESP32 budeme věnovat něčemu „hýbacímu“, nakonec zůstaneme u periférie ryze statické.
Dnes se podíváme na čtečku (a vlastně i zapisovačku) čipových RFID karet a tagů. Pro modul RFID čtečky jsme se rozhodli, protože se jedná o modul komunikující přes SPI sběrnici. Takže nám nejen rozšíří naše portfolio ovládnutých periférií a senzorů na této sběrnici, ale především nám umožní si opět trochu pohrát s řízením SPI softwarovým i hardwarovým ovladačem, která nás minule tak nemile překvapilo – viz článek: SPI (I²C) OLED displej SSD1306 v MicroPythonu.

Pro naše RFID hrátky použijeme modul RFID čtečky založený na čipu RC522, která je poměrně levná a běžně k dostání na e-shopech zaměřených na vývoj domácí elektroniky. Čtečka se zpravidla prodává i s několika RFID prvky – přívěskem nebo kartou, případně je lze tamtéž dokoupit. Při případném dokupování RFID tagů (karet, přívěsků…) je třeba vědět, na jaké frekvenci daná čtečka funguje. Námi použitá čtečka funguje na frekvenci 13,56 MHz. Kromě ceny a dostupnosti je pro naše připojení k modulu ESP32 důležitá i 3,3 V napěťová úroveň, kterou je čtečka napájena, a na které také komunikuje. Tato RFID čtečka je zkrátka pro modul ESP32 jako dělaná!
Ale ještě než se pustíme do samotného elektronického připojení modulu RFID čtečky a modulu ESP32 a následného programování v MicroPythonu, nebude na škodu se nejdříve ponořit do trochy teorie ohledně RFID.
RFID
RFID je zkratka pro Radio-Frequency IDentification, což doslova znamená „radiofrekvenční identifikace“. Technologii RFID dnes v každodenním životě používá téměř každý – ať už v obchodě, v práci nebo ve vozidlech veřejné dopravy. Technologie RFID se kromě bezkontaktních plateb nebo kontroly přístupu používá také při prodeji elektronických jízdenek nebo moderních průkazů do knihoven apod. Lze ji také použít k rychlému připojení zařízení, jako jsou sluchátka nebo reproduktory, k mobilnímu telefonu, či k výměně informací (např. fotografií) mezi dvěma zařízeními.
Jak technologie funguje?
Komunikace RFID je fyzikálně založena na indukční vazbě mezi dvěma cívkami – jedna je umístěna ve čtečce a druhá je zabudována v tagu, který má obvykle podobu bezkontaktní karty, klíčenky, nálepky, skleněné kapsle pro podkožní implantaci, náramku…
Každý elektronický štítek má tři hlavní součásti:
- Anténa: Zodpovědná za příjem rádiových vln vysílaných čtečkou a přeměnu energie z těchto vln na elektrickou energii. Tato energie se pak využívá k napájení čipu
- Čip: Zodpovídá za ukládání informací, které budou přenášeny ke čtečce. Řídí také komunikaci a šifruje a dešifruje informace přenášené mezi kartou a čtečkou.
- Nosná konstrukce: (což by v našem případě byl plášť karty nebo přívěsku) Její funkcí je chránit anténu a čip, aby nedošlo k poškození zabudovaných elektronických komponent.
Čtečka RFID generuje střídavé elektromagnetické pole o určité základní frekvenci (s napájecími impulsy). Pokud se RFID tag dostane do dosahu tohoto pole, je energie ze čtečky „zachycena“ cívkou tagu. Přijatá energie je usměrněna a vzniklým napětím je nabit interní kondenzátor. Po ukončení vysílaného pulsu transpondér (odpovídač) okamžitě vyšle zpět svá data. K napájení transpondéru během jeho vysílání slouží právě napětí uchované v kondenzátoru. Odeslaná data jsou zachycena anténou přijímače (čtečky) a dekódována. Tyto informace mohou zahrnovat identifikátory, údaje o uživateli, odkazy nebo jiné nezbytné údaje vyžadované konkrétní aplikací.

Technologie RFID se dělí do tří kategorií v závislosti na použité části spektra elektromagnetických vln:
- LF (125 kHz),
- HF (13,56 MHz)
- UHF (433 MHz a 860–960 MHz).
Nosná frekvence významně ovlivňuje možnosti dané technologie, a tedy i rozsah aplikací. Například platební karty mají dosah omezený do max. 10 cm (v praxi je to však mnohem méně), což potenciálním zlodějům ztěžuje neoprávněné čtení karet obětí, např. v přeplněném autobuse. Systémy LF RFID se například používají v systémech kontroly přístupu a při označování zvířat pomocí implantovatelných čipů; technologie HF zahrnují standardy NFC (běžně používané mimo jiného právě pro bezkontaktní platby), zatímco tagy a čtečky UHF lze použít například k označování přepravních kontejnerů.
RFID karta MIFARE (Classic)
Bezkontaktní karty MIFARE Classic, které byly uvedeny na trh v roce 1994 společností NXP Semiconductors (dříve Philips Semiconductors), se rychle prosadily především díky své nízké ceně, což jim umožnilo masivně se prosadit v systémech řízení přístupu. MIFARE Classic 1K je základní model, který má kapacitu 1K (existuje i 4K s kapacitou 4K). Všechny tyto modely mají vnitřní strukturu rozdělenou do sektorů a bloků, přičemž každý sektor má sadu datových bloků a dva klíče A a B, které řídí řízení přístupu k tomuto bloku.
Karty MIFARE Classic používají proprietární kryptografii nazvanou Crypto-1, jejímž cílem bylo zaručit bezpečnost komunikace mezi kartou a čtečkou během přenosu informací. Algoritmus byl držen v tajnosti, aby bylo zajištěno, že teoreticky nikdo nebude schopen odhalit zranitelnosti, které se v něm vyskytují. V roce 2007 však dva výzkumníci (Karsten Nohl a Henryk Plotz) provedli reverzní inženýrství části algoritmu a byli schopni rekonstruovat šifru. V současné době jsou karty MIFARE Classic stále velmi oblíbené díky své nízké ceně, ale sám výrobce doporučuje použít některý ze svých novějších modelů karet, jako je MIFARE Desfire, který místo Crypto-1 používá šifrování AES.
Struktura paměti karty MIFARE Classic (1K)
Pro snazší představu o tom, co bude dále popsáno, až se budeme zabývat čtením a zápisem RFID tagů komunikujících na standardu strukturu karet MIFARE Classic (1K), podíváme se podrobněji na logickou strukturu paměti karet MIFARE Classic (1K).
Organizace paměti na čipu je řešena rozdělením do bloků po 16 bytech. Určitý počet bloků je sdružen do tzv. sektoru. Počet přidružených bloků do jednoho sektoru je odlišný pro jednotlivé typy karet. U naší karty Standard o velikosti 1K, je paměť rozdělena na 16 sektorů po 4 datových blocích. Každý blok má 16 bytů, takže 16 B * 4 bloky * 16 sektorů = 1024 B = 1 kB
, udává celkovou kapacitu.
(U karty Standard o velikosti 4K, je prvních 32 sektorů po 4 datových blocích a následujících 8 sektorů po 16 datových blocích.)
Na konci každého sektoru je jeden blok (blok 3, 7, 11…) vyhrazen jako tzv. zavaděč daného sektoru viz tabulka č. 1.
0x00 | UID, BCC, výrobce… (read only) | Sektor 0x01 |
0x01 | Datový blok | |
0x02 | Datový blok | |
0x03 | Klíč A, přístupová práva, Klíč B | |
0x04 | Datový blok | Sektor 0x02 |
0x05 | Datový blok | |
0x06 | Datový blok | |
0x07 | Klíč A, přístupová práva, Klíč B | |
0x08 | Datový blok | Sektor 0x03 |
0x09 | Datový blok | |
0x10 | Datový blok | |
0x11 | Klíč A, přístupová práva, Klíč B | |
… atd. |
… atd. |
… atd. |
Datové bloky mohou být datového nebo číselného typu. Počet příkazů nad těmito daty je u Mifare poměrně strohý, jedná se o příkazy umožňující čtení a zapisování do bloků, inkrementaci a dekrementaci číselné hodnoty, obnovení původní hodnoty a přesun do jiného bloku.
Zvláštní význam má blok 0x00
(viz tab. č. 1), ve kterém jsou pevně uloženy údaje od výrobce jako je například identifikátor karty UID (Unique IDentifier) a jeho kontrolní součet BCC (Bit Count Check), který vzniká provedením operace XOR nad všemi bity UID.
Blok výrobce
Tento blok (blok č. 0x00
) je zodpovědný za uložení jedinečné identifikace karty (UID), to je určité unikátní „razítko" přiřazené každé kartě, která opouští továrnu. Základní teorie popisu karty říká, že se jedná o sadu 4 bajtů, například: 4A F6 C2 AA
, ale jak uvidíme při našich hrátkách, námi použitá karta bude mít UID pěti bajtové (asi se doba trochu pohnula kupředu a 4 byty přestaly stačit). Vedle této sady bajtů je zde i BCC byte, který je zodpovědný za kontrolu integrity UID, aby bylo zajištěno, že UID nebylo žádným způsobem změněno. Zbytek údajů za BCC je v tomto bloku věnován informacím výrobce. Tato data jsou obvykle informace typu: model karty, název výrobce atd. Důležitou vlastností tohoto bloku je to, že je pouze pro čtení (tj. při komunikaci se čtečkou do něj čtenář nemůže zapisovat a měnit vložená data).
- Poznámka:
- Existují karty (tzv. „Čínské magické karty“), které mají přesně stejnou strukturu jako karta MIFARE Classic, ale mají možnost zápisu do bloku č. 0, což umožňuje změnit UID takové karty. K čemupak se asi takové karty mohou používat?
Blok dat
Datový blok je určený pro ukládání uživatelských informací – informace souvisejících s řízením přístupu, další informace, které jsou relevantní pro kontext (jméno uživatele, zbývající kredit, datum očkování proti vzteklině…), ve kterém je RFID tag používán. U datového bloku lze uložit řetězec o maximální délce 16 bytů. U číselného typu je dané číslo uloženo v bloku celkem třikrát, dvakrát v neinvertované podobě (2x4B) a jednou v invertované podobě 4B a poslední 4B slouží k uložení adresy, která může být použita jako ukazatel. My se v tomto textu budeme držet především té řetězcové podoby.
Blok zavaděče
Na konci každého sektoru (blok 3, 7, 11…), je speciální blok „zavaděče“ zodpovědný za uložení klíčů A (povinný) a B (volitelný). Klíče A a B mají shodnou délku 48 bitů, aby nebyly klíče viditelné, při čtení vrací 0
(klíč B jen při svém zapnutí). Pokud není klíč B potřeba (Návěští sektoru musí být odpovídajícím způsobem nakonfigurováno), může být posledních 6 bytů použito jako datové byty. Všechny klíče jsou při dodání čipu nastaveny na FFF
. Pro každý sektor mohou být voleny odlišné klíče i odlišné nastavení způsobu řízení bloku. Tím je možné určité řízení přístupových práv jednotlivých aplikací. Například dotazy s různými klíči tak mohou/nemohou číst různé sektory karty, tím získavat jen některé informace. Klíč A je vždy povinný a běžně se používá ke čtení (zápisu) a ověřování sektoru, zatímco klíč B může být volitelný a běžně se používá k provádění operací s informacemi v datovém bloku sektoru (zápis a mazání).
- Poznámka:
- Jediným blokem, pro jehož čtení žádný klíč nepotřebujeme, je blok výrobce (blok 0). Načtení dat jako je UID daného tagu umí načíst každá čtečka (a musí to tak být z principu funkce celé komunikace).
Práva k sektoru jsou nastavena v bloku zavaděče pomocí hodnoty tzv. přístupových bitech sektoru (uloženo v bytech 6…9), které určují typ požadovaného klíče pro provedení daného příkazu a také určuje typ (data nebo hodnota) datových bloků. Přístupové podmínky pro každý datový blok a blok zavaděče jsou definovány třemi bity, které jsou uloženy neinvertovaně a invertovaně v bloku zavaděče daného sektoru (viz následující obr.). Přístupovým bitům každého bloku odpovídá trojice bitů C1, C2 a C3 (v bytech 6…9; viz obr.). Např. trojice C11, C21, C31 odpovídá trojici bitů určující konfiguraci pro datový blok č. 1 v daném sektoru.

Následující tabulky ukazují jednotlivé konfigurace přístupových bitů a z toto plynoucí požadavky autentizace provedení příkazu (čtení, zápis, inkrementace…) pro datové bloky a blok zavaděče sektoru. Hodnota „A“ znamená nutnost použití klíče A, hodnota „A|B“ představuje autentizaci pomocí klíče A nebo klíče B. Hodnota „ne“ znamená, že je daný přístup nebo příkaz zakázaný.
Možnosti nastavení přístupových práv datových bloků | ||||
---|---|---|---|---|
Hodnota C1 C2 C3 |
Příkaz: | |||
čtení | zápis | inkrementace číselné hodnoty |
dekrementace, přenos, obnovení |
|
0 0 0 | A|B | A|B | A|B | A|B |
0 0 1 | A|B | ne | ne | A|B |
0 1 0 | A|B | ne | ne | ne |
0 1 1 | B | B | ne | ne |
1 0 0 | A|B | B | ne | ne |
1 0 1 | B | ne | ne | ne |
1 1 0 | A|B | B | B | A|B |
1 1 1 | ne | ne | ne | ne |
Možnosti nastavení přístupových práv bloku zavaděče | ||||||
---|---|---|---|---|---|---|
Hodnota C13 C23 C33 |
klíč A | bity přístupu | klíč B | |||
čtení | zápis | čtení | zápis | čtení | zápis | |
0 0 0 | ne | A | A | ne | A | A |
0 0 1 | ne | A | A | A | A | A |
0 1 0 | ne | ne | A | ne | A | ne |
0 1 1 | ne | B | A|B | B | ne | B |
1 0 0 | ne | B | A|B | ne | ne | B |
1 0 1 | ne | ne | A|B | B | ne | ne |
1 1 0 | ne | ne | A|B | ne | ne | ne |
1 1 1 | ne | ne | A|B | ne | ne | ne |
Z tabulek vidíme, že například u datového bloku s přístupovou podmínkou „001“ je možné pouze čtení a dekrementace, což představuje nenabíjecí kartu. Při přístupové podmínce „110“ je možné dobíjení pomocí klíče B.
- My si při našich začátečnických hrátkách s RFID budeme pamatovat, že se bloku zavaděče zdaleka vyhneme a nebudeme v něm nic měnit!
- Při čtení a zápisu budeme využívat jen výchozí klíč A nastavený výrobcem na hodnotu:
FF FF FF FF FF FF
.
I když je pravda, že v „ostrém“ provozu bychom se naopak měli řídit pravidlem, které říká, že z bezpečnostních důvodů je třeba všechny (!) továrně přednastavené klíče změnit (a to i u sektorů, do kterých nikdy nebudeme zapisovat!)
Teorie, teorie a zase jen nějaká teorie…
Ne nadarmo jsme se přece nenarodili rovnou s pájkou místo jedné ruky, abychom tu jen teoretizovali?
Ve vrcholně teoretickém okamžiku to tedy utínáme a už se pouštíme do bastlení! 😉
Připojení RFID čtečky RC522 k modulu ESP32
Jak jsme naznačili, námi použitá RFID čtečka komunikuje pomocí sběrnice SPI. Podle různých informací by námi používaný modul RFID čtečky měl komunikovat i po sériové lince nebo po sběrnici I²C. To nám naznačuje i následující obrázek, který ukazuje rozložení jednotlivých vývodů a jejich funkci na modulu RFID čtečky. Vidíme na něm, že jsou zde dva vývody prezentované i jako linky SDA a SCL sběrnice I²C. Bohužel se nám zatím nikde nepodařilo najít jediné zapojení nebo návod, který by zapojení I²C prakticky ukazoval. A jak jsme viděli u OLED displeje slibujícího možnost jak SPI, tak I²C, ono to nebývá jen nějaké „jiné zapojení“ drátků (i když bychom se v tomto rádi mýlili).

Pro připojení čtečky tedy použijeme sběrnici SPI. Protože budeme chtít primárně využít hardwarového SPI řadiče modulu ESP32, musíme pro připojení zvolit GPIO piny, plynoucí z výchozího (pevného) nastavení pinů sběrnice SPI modulu ESP32. Modul čtečky můžeme připojit k jedné ze dvou SPI sběrnic. Zvolíme tu označovanou jako VSPI
– v MicroPythonu je dostupná pod označením SPI(2)
a odpovídají ji piny: GPIO18
(sck
), GPIO23
(mosi
), GPIO19
(miso
), GPIO5
(cs
).
Následující obrázek a tabulka č. 4 ukazuje propojení RFID čtečky s modulem ESP32. Pro začátek použijeme nejjednodušší (základní) zapojení, kdy nezapojíme pin IRQ
(pin reagující na přítomnost RFID tagu a vyvolávající hardwarové přerušení připojeného kontroléru) a můžeme (či nemusíme) zapojit pin RST
(reset čtečky). K zapojení pinu RST
si ještě něco povíme, až se budeme bavit o použití obslužné knihovny.

Modul ESP32 | Čtečka RFID-RC522 | Pozn. |
---|---|---|
3V3 | 3,3V | Napájení 3,3 V |
GPIO17 zde nezapojeno |
RST | Reset čtečky |
GND | GND | Zemnění |
nezapojeno | IRQ | Pin pro vyvolání přerušení |
GPIO19 | MISO | Master In, Slave Out (data ze čtečky) |
GPIO23 | MOSI | Master Out, Slave In (data do čtečky) |
GPIO18 | SCK | Hodinový takt sběrnice |
GPIO5 | SS/CS (ozn. SDA) |
Slave/Chip Select (výběr modulu) |
Máme-li „zadrátováno“, můžeme se podívat na to, jak naprogramovat načítání a později i zápis dat z/do RFID tagu. Nejdříve se podíváme na obecné schéma komunikace mezi čtečkou s tagem, pak to aplikujeme do programového kódu MicroPythonu.
Softwarová komunikace mezi čtečkou a RFID tagem
Jak tedy funguje proces komunikace mezi čtečkou RFID a kartou z hlediska softwarového handshake?
Komunikační proces si lze představit v následujících krocích:
- Aktivace pole: Když je karta přítomna v určitém okruhu, ve kterém ji může čtečka detekovat, čtečka odešle požadavek.
- Odpověď karty: Jakmile karta obdrží tento požadavek, odpoví čtečce, o jaký typ karty se jedná, což čtečce umožní vědět, jak má v komunikaci pokračovat.
- Anti-Collision: Po obdržení odpovědi karty odešle čtečka několik dalších požadavků, aby zjistila, zda se v blízkosti nenacházejí nějaké další karty, čímž se zabrání rušení komunikace s požadovanou kartou. Pokud na signály reaguje pouze jedna karta, čtečka tuto kartu vybere a může pokračovat v komunikaci.
Pokud RFID tag využíváme pro jednoduchý typ přístupu, zpravidla nyní je tag identifikován podle svého UID a pokud se shoduje s povolenou hodnotou, dveře se otevřou a komunikace končí. Chceme-li využít sofistikovanější způsob komunikace, například zjistit, zda je na kartě dostatečný kredit (jízdného, půjčovného v knihovně apod.), musí komunikace pokračovat dále a to již za pomoci přístupových klíčů (zpravidla klíče A).
- Autentizace: Před výměnou informací s kartou se musí čtečka autentizovat pomocí příslušného klíče (A nebo B), jinak nebude operace provedena. Čtečka a karta poté provedou proces handshake typu výzva-odpověď pomocí šifry Crypto-1. Tento krok zajišťuje, že čtečka má příslušný klíč, pro přístup k informacím na kartě.
- Výměna dat: Po úspěšné autentizaci si čtečka a karta vymění informace zašifrované klíči a budou provedeny operace požadované čtečkou. (Může dojít i k zápisu! Např. snížení počtu zbývajících přístupů)
- Finalizace: Jakmile čtečka dokončí požadovaný proces, odešle povel, který uvede kartu do „spánkového“ stavu. Karta pak již nereaguje na povely čtečky, dokud se k ní znovu nepřiblíží a celý proces se nezopakuje od samého začátku.
Nejdříve si ukážeme, jak nejjednodušším způsobem načíst pouhé UID přiblíženého tagu (informace z bloku 0), což většinou stačí pro jednoduchý přístupový systém. Ale pokud jsme tolik úsilí věnovali teorii okolo uspořádání paměti karty, určitě si budeme chtít ukázat, jak načíst i další data z karty (třeba vypsat i celý obsah paměti). Dívat se na data prázdné karty asi není příliš atraktivní, tak se pokusíme na kartu nějaké ty informace zapsat! Rázem tedy poznáme, že jsme si za „ty prachy“ koupili nejen čtečku, ale i zapisovačku! 😊
Knihovna mfrc522.py
S RFID čtečkou budeme v MicroPythonu komunikovat prostřednictvím knihovny. Problém trochu nastává při výběru té správné knihovny. Správce „balíků“ v prostředí Thonny IDE nám žádný vhodný modul nenabídne, takže se musíme podívat po internetu a knihovnu nainstalovat ručně – jak se nám nyní hodí, že jsme si v předešlých článcích ukázali i tuto možnost! Druhým problémem je to, že pod stejným názvem, tedy mfrc522.py
, lze najít různé knihovny (tento problém jsme už viděli i u modulu pro OLED displej). Všechny knihovny slibují totéž, tedy pracovat s RFID čtečkou postavenou na čipu RC522, všechny mají přibližně stejné příkazy. A to je právě to, že bohužel „přibližně stejné“…
Osobně jsme zkusili dvě knihovny mfrc522.py
, které vlastně pracují stejně, jen se liší v počátečním nastavení ovládacích pinů. První knihovnou byl soubor, který lze stáhnout z: https://mfrc522.py
, který nabízí podporu více mikrokontrolérů s instalovaným MicroPythonem, jsme nakonec použili i pro tento tutoriál. Soubor mfrc522.py
lze v tomto případě získat z adresy: https://mfrc522.py
a nakopírovat jej do složky lib
v našem MicroPython zařízení (modul ESP32 s firmwarem MicroPythonu).
Jak jsme zmínili, pro další text používáme knihovnu (modul) mfrc522.py
od autora vystupujícího pod jménem Cefn Hoile. Pro tento modul jsme se rozhodli tak trochu ze zcela iracionálního důvodu, neboť nám (jen) učarovalo to, že tato knihovna oproti tomu předchozí umožňuje ovládat i resetovací pin RST
RFID čtečky. My tento pin v našem zapojení sice nemáme zapojený, ale ta možnosti, že kdykoliv jej můžeme připojit např. k GPIO19
a tím lze v případě potřeby čtečku resetovat… tomu se přece nedá odolat! 😊
1. Načtení UID RFID tagu
Našim prvním úkolem je zdetekovat přítomnost RFID tagu u čtečky a načíst jeho UID. To je základ každé další operace s RFID kartou. Ve většině aplikací, které slouží jako jednoduchý přístupový systém, toto bohatě stačí.
Následující kód tedy má jediný úkol: Načíst UID přiblíženého RFID tagu a na 2 vteřiny rozsvítit vestavěnou LED modulu ESP32. Zatím to není žádný kódový zámek, neboť se vestavená LED rozsvítí při jakémkoliv přiblíženém tagu, ale doplnění kódu o jednoduchou podmínku snad už pro nás není problém. Abychom měli i další kontrolu nad činností programu, jsou vypisovány do výstupu prostředí Thonny IDE jednotlivé akce.
import mfrc522 # https://github.com/cefn/micropython-mfrc522
from machine import Pin, SPI
from time import sleep_ms
# RFID ctecka - SPI sbernice
# sck = Pin(18, Pin.OUT)
# mosi = Pin(23, Pin.OUT)
# miso = Pin(19, Pin.IN)
cs = Pin(5, Pin.OUT)
rst = Pin(17, Pin.OUT)
# vestavena LED simulujici rele zamku
rele = Pin(2, Pin.OUT)
# vspi = SPI(2, baudrate=1000000, polarity=0, phase=0, sck=sck, mosi=mosi, miso=miso)
vspi = SPI(2)
rdr = mfrc522.MFRC522(spi=vspi, gpioRst=rst, gpioCs=cs)
print('Prilozte kartu')
while True:
rele.off()
(stat, tag_type) = rdr.request(rdr.REQIDL)
if stat == rdr.OK:
(stat, raw_uid) = rdr.anticoll()
if stat == rdr.OK:
print('Detekovano!')
print('type: 0x%02X' % tag_type)
print('uid: %02X-%02X-%02X-%02X-%02X' % (raw_uid[0], raw_uid[1], raw_uid[2], raw_uid[3], raw_uid[4]))
print('')
rele.on()
sleep_ms(2000)
print('Prilozte kartu')
Pojďme si postupně vysvětlit jednotlivé části kódu. Úvodní část pochopitelně importuje potřebné moduly (knihovny):
import mfrc522
from machine import Pin, SPI
from time import sleep_ms
Následuje nastavení potřebných GPIO pinů modulu ESP32. Neboť používáme hardwarového SPI ovladače (SPI(2)
), není třeba piny SCK
, MOSI
a MISO
nastavovat. V programu je zakomentována i možnost nastavení těchto údajů při deklaraci objektu vspi
. Kdybychom používali softwarový ovladač SoftSPI
sběrnice SPI, bylo by třeba jak jednotlivé piny, tak údaje komunikace, nastavit dle zakomentované části.
Po deklaraci objektu pro komunikaci po sběrnici SPI je třeba definovat i objekt rdr pro přístup k samotné čtečce:
vspi = SPI(2)
rdr = mfrc522.MFRC522(spi=vspi, gpioRst=rst, gpioCs=cs)
Zde je dobré mít proměnné rst
a cs
definované jako příslušné objekty Pin
. Zadání pinu rst
(parametr gpioRst
) je dobrovolné, zadání pinu cs
(parametr gpioCs
) je povinné.
Následuje hlavní nekonečná smyčka, ve které je načítána přítomnost RFID tagu:
(stat, tag_type) = rdr.request(rdr.REQIDL)
Proměnná stat
obsahuje stavový kód, tag_type
určuje typ přiblíženého tagu a naznačuje knihovně mfrc522.py
, jak má s tagem dále pracovat.
Pokud je stavový kód odpovídající přítomnosti tagu (rdr.OK
), začíná komunikace s tagem:
if stat == rdr.OK:
(stat, raw_uid) = rdr.anticoll()
Je provedeno „antikolizní“ ověření přítomnosti jediného tagu, následně je načteno pole raw_uid
, které obsahuje pětici čísel (indexy 0–4) unikátní adresy přítomného tagu. Výsledný stav načtení opět udává proměnná stat
.
Je-li návratová hodnota načtení UID opět rdr.OK
, je vypsáno UID a je sepnuta interní LED na dobu 2 vteřin.
if stat == rdr.OK:
print("Detekovano!")
print("type: 0x%02X" % tag_type)
print("uid: %02X-%02X-%02X-%02X-%02X" % (raw_uid[0], raw_uid[1], raw_uid[2], raw_uid[3], raw_uid[4]))
rele.on()
sleep_ms(2000)
Unikátní UID přiloženého tagu je vypsáno v podobě šestnáctkové soustavy, oddělené pomlčkami. Je vypsán i typ použitého RFID přívěsku. Následující obrázek znázorňuje výstup v prostředí Thonny IDE, po načtení RFID přívěsku naším programem:

2. Načtení bloku paměti
Načtení UID RFID karty (tagu) jsme zvládli, tak co dál? Říkali jsme, že RFID tagy mohou obsahovat i nějaké jiné informace, než je jen UID. Naším dalším úkolem tedy bude načtení jednoho konkrétního bloku paměti a možná to nakonec rovnou rozšíříme i na výpis celé paměti (tj. 64 bloků paměti).
První část programového kódu, tedy načtení typy RFID tagu a jeho UID, necháme stejnou. Pokud se vrátíme kousek výše, je tam popis komunikace mezi čtečkou a RFID tagem, kde vidíme, že stejně musíme navázat spojení a stejně potřebujeme získat UID pro autentizaci požadavku.
Stávající kód, konkrétně větev podmínky, která vypsala UID doplníme následující strukturou podmínek:
if rdr.select_tag(raw_uid) == rdr.OK:
key = b'ff\xff\xff\xff\xff\xff'
blockArray = bytearray(16)
if rdr.auth(rdr.AUTHENT1A, 8, key, raw_uid) == rdr.OK:
rdr.read(8, into=blockArray)
print("Blok dat c.8: %s" % blockArray)
else:
print("Chyba autentizace")
rdr.stop_crypto1()
else:
print("Chyba vyberu")
Po úspěšném načteni UID do proměnné raw_uid v první podmínce spárujeme danou RFID kartu metodou select_tag(raw_uid). Pokud to skončí úspěchem, můžeme začít přistupovat ke kartě.
Do proměnné key nastavíme hodnotu přístupového klíče (zde klíče A). Jelikož pracujeme s novou kartou, která má nastavené výchozí hodnoty klíče na hodnoty 0xFF
, nastavíme proměnnou key na binární řetězec složený z šestice těchto hodnot.
key = b'\xff\xff\xff\xff\xff\xff'
Pro načtení obsahu bloku (16 bytů) si vytvoříme pomocné pole blockArray, do kterého se načtou jednotlivé byty z paměti karty.
Následuje pokus o autentizaci přístupu:
rdr.auth(rdr.AUTHENT1A, 8, key, raw_uid)
První parametr určuje typ autentizace (zda zadáváme klíč A nebo B), další parametr je číslo bloku, ke kterému chceme přistupovat (v některých návodech se uvádí, že zde má být číslo bloku zavaděče, pod který dále dotazovaný blok patří, ale nám to v této knihovně funguje s číslem dotazovaného bloku). Poslední parametr je UID tagu, ke kterému přistupujeme. Pokud tato autentizace proběhne bez problémů, začne probíhat šifrované spojení, skrz které můžeme načítat/zapisovat data z/do zadaného bloku:
rdr.read(8, into=blockArray)
Zde načítáme data z osmého bloku a data se uloží do připraveného pole blockArray. Získaný obsah vypíšeme na výstup prostředí Thonny IDE.
Nakonec nesmíme šifrované spojení ukončit příkazem:
rdr.stop_crypto1()
Tím jsme si vysvětlili nejdůležitější část načítání dat z RFID karty. Kompletní kód programu pro načtení dat z osmého bloku karty uvádíme zde.
import mfrc522 # https://github.com/cefn/micropython-mfrc522
from machine import Pin, SPI
from time import sleep_ms
cs = Pin(5, Pin.OUT)
rst = Pin(17, Pin.OUT)
vspi = SPI(2)
rdr = mfrc522.MFRC522(spi=vspi, gpioRst=rst, gpioCs=cs)
print('Prilozte kartu')
while True:
(stat, tag_type) = rdr.request(rdr.REQIDL)
if stat == rdr.OK:
(stat, raw_uid) = rdr.anticoll()
if stat == rdr.OK:
print('Detekovano!')
print('typ: 0x%02X' % tag_type)
print('uid: %02X-%02X-%02X-%02X-%02X' % (
raw_uid[0], raw_uid[1], raw_uid[2], raw_uid[3], raw_uid[4]))
print('')
if rdr.select_tag(raw_uid) == rdr.OK:
key = b'\xff\xff\xff\xff\xff\xff'
blockArray = bytearray(16)
if rdr.auth(rdr.AUTHENT1A, 8, key, raw_uid) == rdr.OK:
rdr.read(8, into=blockArray)
print("Blok dat c.8: %s" % blockArray)
else:
print("Chyba autentizace")
rdr.stop_crypto1()
else:
print("Chyba vyberu")
sleep_ms(1000)
print("Prilozte kartu")
Výstup našeho pokusu o načtení 8. paměťového bloku vidíme na následujícím obrázku:

Vidíme, že data byla vrácena ve formě bitového řetězce, čemuž odpovídá i forma výstupu. Jelikož máme novou kartu, nemůžeme se divit, že získaná data jsou samé nuly.
3. Výpis celé paměti
Umíme-li načíst jeden blok, kód jednoduše upravíme tak, aby dokázal načíst a vypsat celou paměť. Akorát je třeba upozornit na dvě základní věci:
- Pro přístup budeme stále používat stejný klíč, takže karta musí mít nastavený u všech bloků stejný výchozí přístupový klíč A (u nové prázdné karty to není problém).
- Načítání karty není kdovíjak rychlé, takže dokud se nenačte poslední (tj. 63.) blok paměti, musíme kartu (tag) držet u čtečky. (asi 15 s)
Do původního kódu přidáme cyklus for
, který zvyšuje hodnotu bloku přístupu (proměnná sector
):
for sector in range(0, 64):
# tady bude načtení dat daného sektoru
Jinak by se v následujícím kódu nic měnit nemuselo. Ale aby zde byla aspoň nějaká další změna, trochu upravíme výpis dat do výstupu. (Micro)Python pokud vypisuje binární řetězec, tak znaky, které nemají ASCII „tisknutelnou“ podobu, vypisuje jako hexadecimální kódy, zatímco znaky „viditelné“ vypíše jako daný znak. Dokud jsme vypisovali část paměti, která byla plná hodnot 0, vypisovalo se nám samé \x00
, ale nyní (zejména oblasti bloků zavaděčů) by to byla směsice hexadecimálních čísel a znaků. To by nebylo moc přehledné! Vytvoříme tedy výstup tak, aby se vše vypisovalo jako hexadecimální čísla oddělená pomlčkami.
Výpis proměnné blockArray
upravíme následujícím způsobem:
print("Blok dat c.%d: " % sector, end="")
print('-'.join(f'{b:02x}' for b in blockArray))
Nejdříve vypíšeme číslo bloku a bez odřádkování (end=""
) začneme vytvářet výstupový řetězec, který pak vytiskneme. Použijeme pro to vcelku zajímavou „vychytávku“, kterou nám Python umožňuje. Skládáme výstupní řetězec spojováním (join
) obsahu proměnné b
v podobě dvouciferného hexadecimálního čísla (f'{b:02x}'
), ale místo klasického předání jedné proměnné b
zde máme cyklus for
, který postupně proměnnou b
naplňuje hodnotami z načteného pole blockArray
. Výledkem bude textový řetězec hexadecimálních čísel oddělených pomlčkami. Pochopitelně to lze vytvořit i běžným způsobem. Tohle je zkrátka taková „Pythomina“! 😉
import mfrc522 # https://github.com/cefn/micropython-mfrc522
from machine import Pin, SPI
from time import sleep_ms
cs = Pin(5, Pin.OUT)
rst = Pin(17, Pin.OUT)
vspi = SPI(2)
rdr = mfrc522.MFRC522(spi=vspi, gpioRst=rst, gpioCs=cs)
print('Prilozte kartu')
while True:
(stat, tag_type) = rdr.request(rdr.REQIDL)
if stat == rdr.OK:
(stat, raw_uid) = rdr.anticoll()
if stat == rdr.OK:
print('Detekovano!')
print('typ: 0x%02X' % tag_type)
print('uid: %02X-%02X-%02X-%02X-%02X' % (
raw_uid[0], raw_uid[1], raw_uid[2], raw_uid[3], raw_uid[4]))
print('')
if rdr.select_tag(raw_uid) == rdr.OK:
key = b'\xff\xff\xff\xff\xff\xff'
blockArray = bytearray(16)
for sector in range(0, 64):
if rdr.auth(rdr.AUTHENT1A, sector, key, raw_uid) == rdr.OK:
rdr.read(sector, into=blockArray)
print("Blok dat c.%d: " % sector, end="")
print('-'.join(f'{b:02x}' for b in blockArray))
else:
print("Chyba autentizace")
rdr.stop_crypto1()
else:
print("Chyba vyberu")
sleep_ms(2000)
print("Prilozte kartu")
Následující obrázek ukazuje výpis paměti přiložené karty „netrpělivého“ uživatele 😊

A něco navíc…
Přestože jsme se před chvílí tvářili, jak se o blok zavaděče vlastně vůbec nebudeme zajímat, přecejen se na něj trochu podíváme. Zejména se podíváme na 6.–9. byty, které obsahují přístupové bitu. Z předešlého výpisu paměti vidíme, že například blok č. 3, což je blok zavaděče 1. sektoru, má v 6.–9. bytech tyto hodnoty: xFF, x07, x80 a x69. Rozepíšeme si hodnoty 6.–8. bytu v binární podobě a podíváme se na nastavenou konfiguraci (byte 9 obsahuje uživatelská data, tak nás nezajímá).
6. byte | C23 | C22 | C21 | C20 | C13 | C12 | C11 | C10 | hex (dec) |
---|---|---|---|---|---|---|---|---|---|
1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | xFF (255) |
7. byte | C13 | C12 | C11 | C10 | C33 | C32 | C31 | C30 | hex (dec) |
---|---|---|---|---|---|---|---|---|---|
0 | 0 | 0 | 0 | 0 | 1 | 1 | 1 | x07 (7) |
8. byte | C33 | C32 | C31 | C30 | C23 | C22 | C21 | C20 | hex (dec) |
---|---|---|---|---|---|---|---|---|---|
1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | x80 (128) |
Z výše uvedené konfigurace si vypíšeme odpovídající bity C1, C2 a C3 pro blok zavaděče (označeny žlutě).
- Poznámka:
- Všimněte si, že kromě hodnot přístupových bitů, jsou zde uloženy i jejich negace. To je dobré si uvědomit, pokud bychom se chtěli pustit do dobrodružství jménem „zápis do bloku zavaděče“. Zapomenuté nastavení některého z bitů by lehce ilustroval platnost docela důležité věty z datového listu: „Pokud vnitřní logika zjistí porušení formátu, celý sektor se nevratně zablokuje.“
C13 | C23 | C33 |
---|---|---|
0 | 0 | 1 |
Podíváme-li se do tabulky č. 3 (viz dříve), která nám ukazuje možnosti nastaveného přístupu do bloku zavaděče, vidíme, že se jedná o plný přístup autorizovaný klíčem A. Což se u nové a prázdné karty ve výchozím nastavení dá očekávat.
Nyní si vypíšeme konfiguraci odpovídající bitům C1, C2 a C3 pro některý z datových bloků – např. blok 2 (bity označeny modře).
C12 | C22 | C32 |
---|---|---|
0 | 0 | 0 |
Význam této konfigurace přístupu ke zvolenému datovému bloku najdeme v tabulce č. 2 (viz dříve). V tabulce č. 2 vidíme, že hodnota 000 odpovídá povolení všech operací (čtení, zápis, inkrementace, dekrementace ), pochopitelně při dodržení autentizace klíčem A nebo klíčem B. To je opět nejvolnější možné nastavení, které je u nové prázdné karty zcela pochopitelné.
To, že jsme nyní trochu pochopili význam přístupových bitů, ale neznamená, že se stále nebudeme od bloku zavaděče držet v úctyhodné vzdálenosti. Zvláště nyní, když se chystáme začít do RFID karty zapisovat!
4. Zápis dat na RFID tag
4.1 Zápis dat do karty
Jestliže jsme pochopili přístup k určitému bloku karty, tak nyní nemusíme řešit nic nového. Máme-li čtečku spárovanou s daným RFID tagem a máme provedenou autentizaci, stačí jen zadat příkaz zápisu s parametrem dat, které chceme zapsat. Data budeme zapisovat v podobě šestnáctibytového binárního řetězce. Pokusíme zapsat text „FyzKAB 4ever!“ v podobě ASCII kódů. Jelikož je náš text kratší než 16 bytů celého bloku, zbylá místa v našem řetězci doplníme hodnotami 0x00. Binární řetězec pro zápis do bloku dat bude vypadat takto:
b'\x46\x79\x7A\x4B\x41\x42\x20\x34\x65\x76\x65\x72\x21\x00\x00\x00'
Metoda pro zápis dat do paměťového bloku se jmenuje rdr.write()
a má dva parametry – první je číslo bloku, kam budeme zapisovat (pochopitelně po úspěšné autentizaci přístupu), druhý je šestnáctibytový binární řetězec hodnot určených pro zápis do bloku. Následující kód by měl do bloku č. 8 zapsat zvolený text.
- POZOR!
- Případné „hračičky“ a „modifikátory“ následujícího kódu je třeba upozornit, že je vždy třeba si vzpomenout na to, že se v paměti nalézají i bloky zavaděče (3, 7, 11,… 63). Omyl v podobě zápisu obecných dat do oblasti bloku zavaděče má fatální následek, který nás rázem připraví o možnost práce s částí paměti!
import mfrc522 # https://github.com/cefn/micropython-mfrc522
from machine import Pin, SPI
from time import sleep_ms
cs = Pin(5, Pin.OUT)
rst = Pin(17, Pin.OUT)
vspi = SPI(2)
rdr = mfrc522.MFRC522(spi=vspi, gpioRst=rst, gpioCs=cs)
print("Prilozte kartu")
while True:
(stat, tag_type) = rdr.request(rdr.REQIDL)
if stat == rdr.OK:
(stat, raw_uid) = rdr.anticoll()
if stat == rdr.OK:
print("Detekovano!")
print("typ: 0x%02X" % tag_type)
print("uid: %02X-%02X-%02X-%02X-%02X" % (
raw_uid[0], raw_uid[1], raw_uid[2], raw_uid[3], raw_uid[4]))
print('')
if rdr.select_tag(raw_uid) == rdr.OK:
key = b'\xff\xff\xff\xff\xff\xff'
if rdr.auth(rdr.AUTHENT1A, 8, key, raw_uid) == rdr.OK:
stat = rdr.write(8, b'\x46\x79\x7A\x4B\x41\x42\x20\x34\x65\x76\x65\x72\x21\x00\x00\x00')
if stat == rdr.OK:
print("Data zapsana na kartu")
else:
print("Nepovedlo se zapsat data na kartu")
rdr.stop_crypto1()
else:
print("Chyba autentizace")
else:
print("Nepodarilo se vybrat tag")
Na obrázku vidíme průběh zápisu dat na RFID kartu ve výstupu prostředí Thonny IDE.

Máme zapsáno! A jak to poznáme?
4.2 Kontrola zapsaného obsahu
Abychom mohli vidět, co jsme skutečně zapsali na RFID kartu, nahrajeme do prostředí Thonny IDE znova program pro načtení a výpis dat z datového bloku č. 8. Nyní skvěle využijeme vlastnosti MicroPythonu, který při výpisu binárního řetězce vypisuje tisknutelné ASCII znaky jako skutečná písmena, zatímco znaky netisknutelné vypíše jako hexadecimální kódy.
Na následujícím obrázku vidíme načtený obsah bloku č. 8, do kterého jsme předtím zapsali naše „sdělení celému světu“.

Obrázek nám též ukazuje, že zpráva složená z 13 znaků je doplněna do 16 bytové délky datového bloku zbylými třemi byty obsahujími nulové hodnoty (vypsány v podobě \x00
). Vidíme tedy, že se naše data na kartu opravdu zapsala, takže je pravda, že modul RFID čtečky dokáže na RFID tagy i zapisovat!
Závěr
Dnešní hrátky s RFID čtečkou nám nejen ukázaly, jak lze v MicroPythonu na modulu ESP32 pracovat s RFID tagy, ale i to, jak je možné pracovat s hardwarově řízenou SPI sběrnicí (což nás v minulém článku při experimentování s OLED displejem trochu vypeklo). Neukázali jsme si, jak lze RFID čtečku řídil pomocí softwarového ovladače SoftSPI, ale vězte, že v tom případě to funguje úplně stejně. Pokud nevěříte, změňte použitý modul SPI za SoftSPI a podle parametrů naznačených v komentáři prvního programového kódu nastavte konfiguraci SPI pinů potřebné pro SoftSPI. Jak na práci se SoftSPI též najdete v článku o OLED displeji se SPI sběrnicí: SPI (I²C) OLED displej SSD1306 v MicroPythonu.
V článku jsme si ale dnes především ukázali, jak načíst unikátní UID RFID tagu, což nám může posloužit jako identifikace pro jednoduchý přístupový systém. Zajímavou nadstavbou je jistě možnost zápisu a načítání dat z datového prostoru RFID karty – například adresu školní jídelny, do které tag patří a kde tedy lze pak dohledat majitele ztraceného tagu. Naopak nechráněné uložení adresy domu, ve kterém tento ztracený tag slouží jako přístupové klíče, by asi byla vyloženě hloupost.
Jistě by bylo třeba se zaměřit i na problematiku změny přístupových klíčů (A, B) a nastavení přístupových práv (viz tabulky č. 2 a 3). To však již překračuje původní účel tohoto článku (i když jsme zde cosi již naznačili), proto tuto problematiku necháváme pro případné samostudium a experimenty zvídavých (a ztrátchtivých) čtenářů.
V minulém článku jsme sice slibovali, že by bylo hezké se postupně podívat na nějakou hýbající se periférii, ale při psaní tohoto článku, kde jsme narazili na to, že by čtečka RFID s RC522 měla komunikovat i na sběrnici I²C, nás napadlo, že jsme si se sběrnicí I²C také ještě nehráli. Tak uvidíme… Třeba se nám podaří najít něco, co se hýbe a přitom to komunikuje přes I²C. Nebo tu nyní prostě máme inspiraci na další dva budoucí články. 😊
Autor článku: „K. Z. MÁCHAČ“
(aneb Kdo Zrovna MÁ CHuť A Čas)