12. Arduino RFID-tagien luku ja kirjoitus RC522-piirin avulla

Julkaistu: sunnuntai 5.1.2020

RFID-tagit ovat nykypäivänä monelle ihmiselle hyvin tuttuja kapistuksia. Esimerkiksi kulunvalvonnassa langatonta tunnisteavainta käytetään hyvin paljon ja erilaisten ovien avaamiseen se soveltuu oikein mainiosti. Myös lemmikkien tunnisteissa tätä tekniikkaa käytetään ja monissa päivittäistavarakaupan tuotteita on suojattu varastamiselta juurikin RFID-tagin avulla. Teollisuudessa taas tuotantolinjalla voidaan vaikkapa automatisoida prosesseja RFID-tunnistuksien avulla.

Mutta hetkinen, mikäs tämä RFID nyt onkaan? Selvitetäänpä se ensin, ennen kuin aloitetaan tekemään yhtikäs mitään.

HUOM! Tämä artikkeli on vain pintaraapaisu aiheeseen, joten kaiken kattava opas RFID:n toimintaan tämä ei missään tapauksessa ole. Näillä tiedoilla pääset kuitenkin alkuun ja eteenpäin, mikäli tarvitset RFID-tunnisteita (13,56 MHz) projektissasi.

RFID = Radio Frequency IDentification

Lyhenne RFID tulee otsikon mukaisista englannin kielen sanoista ja tarkoittaa suomeksi sanottuna radiotaajuista tunnistusta. Tunnistus perustuu siihen, että lähetin-vastaanotin laite (engl. transceiver) lähettää tietyllä ennakkoon tunnetulla taajuudella moduloitua radioaaltoa, minkä tagi vastaanottaa.

Vastaanotetusta radioaallosta kerätään tagin tarvitsema energia sen toimintaan ja kun sähköä on saatu tarpeeksi, tagi pystyy vastaamaan isäntälaitteelle omalla yksilöllisellä tunnisteellaan. Kaikki tämä tapahtuu langattomasti radioaaltojen avulla, joten tagiä ei tarvitse kaivaa edes näkyville, sillä radioaallot kulkeutuvat monen eri aineen läpi.

RFID-tagit voivat olla passiivisia, kuten tämän esimerkin tapauksessa, tai niillä voi olla oma virtalähteensä jolloin ne ovat aktiivisia. Myös paristo-avusteisia, niin sanotusti semi-passiiveja tageja on olemassa.

Aktiivinen RFID-tagi lähettää säännöllisesti ID-signaalia kun taas passiivinen lähettää ID:nsä vain kun lukulaite on lähellä, eli tagi saa energiaa lukulaitteelta. Paristo-avusteinen tagi aktivoituu lähettämään ID:tä silloin, kun se huomaa että lukija on lähellä. Toisin kuin passiivinen tagi, energian määrä mitä tagille pitää lähettää on paljon pienempi paristo-avusteisella tagilla.

RFID-tageja on erilaisia ja niiden ominaisuudet hieman vaihtelevat. Jotkut ovat vain-luku -tilassa, jolloin tagia ei voi uudelleenohjelmoida. Toiset ovat luku/kirjoitus-tageja, joihin voidaan tarpeen mukaan ohjelmoida uutta tietoa. Myös kertaohjelmoitavia tageja löytyy eli näitä voi käyttäjä ohjelmoida vain kerran tagin elinkaaren aikana.

Arduino RFID RC522

Arduino RFID tagit ja lukija
MFRC522-piirilevy ja RFID-tageja

Arduino puuhaboxista löytyy yllä olevan kuvan mukainen piirilevy, mihin on juotettu NXP:n MFRC522-piiri oheiskomponentteineen ja piirilevyyn on integroitu RFID:n tarvitsema, 13,56 MHz:n taajuudelle sovitettu antenni. Lisälevyn avulla voidaan lukea ja kirjoittaa RFID-tagille haluamaansa tietoa ja tämä mahdollistaa esimerkiksi omanlaisensa kulunvalvonnan toteutuksen tai vaikkapa kirjautumisen palveluun - tai mitä ikinä keksiikään! Tietenkin tälle tarvitaan myös "juttukaveri", eli itse RFID tagi, joka on kuvassa piirilevystä vasemmalla. Tageja on kaksi erilaista kuten näkyy, eli toinen tagi on kortti ja toinen on avaimenperä.

MFRC522-piirin datalehdessä kerrotaan General description kappaleessa seuraavasti:

2. General Description

The MFRC522 is a highly integrated reader/writer IC for contactless communication at 13.56 MHz. The MFRC522 reader supports ISO/IEC 14443 A/MIFARE and NTAG. The MFRC522’s internal transmitter is able to drive a reader/writer antenna designed to communicate with ISO/IEC 14443 A/MIFARE cards and transponders without additional active circuitry. The receiver module provides a robust and efficient implementation for demodulating and decoding signals from ISO/IEC 14443 A/MIFARE compatible cards and transponders. The digital module manages the complete ISO/IEC 14443 A framing and error detection (parity and CRC) functionality.

ISO/IEC 14443 -standardi pitää sisällään määritykset lyhyen matkan RFID-kommunikointiin ja tarkemmat speksit voi lukaista tästä linkistä. Lyhyesti kuitenkin sanottuna, MFRC522-piiriä voidaan käyttää kaikkien tätä standardia tukevien A-tyyppin laitteiden kanssa. A-tyypin laitteiden ominaisuuksia ovat:

Lukija (PCD) -> Kortti (PICC)Type AType B
Taajuus (Frequency)13,56 MHz 13,56 MHz
Modulaatio (Modulation)100 % ASK10 % ASK
Bittikoodaus (Bit coding)Modified MillerNRZ
Datanopeus (Data rate)106 kb/s106 kb/s
Kortilta (PICC) -> Lukijalle (PCD)Type AType B
Modulaatio (Modulation) LoadLoad
Bittikoodaus (Bit coding) OOKBPSK
Apukantoaalto (Subcarrier)847 kHz847 kHz
Bittikoodaus (Bit Coding)ManchesterNRZ
Datanopeus (Data rate)106 kb/s106 kb/s

PCD = Proximity Coupling Device (lukija)
PICC = Proximity Inductive Coupling Card (luettava tagi)
NRZ = Non-Return to Zero
ASK = Amplitude-shift Keying
OOK = On-Off keying
BPSK = Binary phase-shift keying
Modified Miller / Manchester = Bittikoodauksia
kb/s = kilobits per second = kilobittiä sekunnissa.
Transponder = lähetin/vastaanotin -laite avioniikassa, tässä yhteydessä termi transceiver on mielestäni osuvampi.

Yllä olevat listaukset sisältävät paljon asiaa, mutta ei mennä tässä kohtaa kuitenkaan syvemmälle näihin. Näitä voi halutessaan opiskella tarkemmin. Toisaalta jos yllä olevat termit ja asiat tuntuvat menevän yli hilseen, suosittelen klikkailemaan laittamiani linkkejä ja lukemaan niistä hieman lisää.

RC522 RFID lukijan/kirjoittajan speksit

On hyvä tietää hieman kyseisen piirin spekseistä eli ominaisuuksista, ennen kuin aletaan kytkemään mitään. Emmehän halua savujen karkaavan piirien sisältä ulkoilmaan.

MFRC522-piiri toimii 3,3 voltin tyypillisellä käyttöjännitteellä, eli tätä ei voida kytkeä 5 voltin linjaan kuten Arduinon levyt yleensä kytketään. Uno levyltä kuitenkin löytyy onneksi 3,3 voltin lähtö, joten erillistä LDO-regulaattoria tai muuta virtalähdettä ei tarvita. Piiri kuluttaa virtaa alle 10 mA valmiustilassa ja huippuvirratkin jäävät alle 100 mA:n, joten Arduino Uno jaksaa tätä piiriä syöttää.

Kommunikointi piirin kanssa tapahtuu SPI-väylän avulla (lue SPI:stä lisää tältä sivulta). MFRC522-piirin datalehdessä sanotaan, että pinnit eivät ole 5V tolerantteja, joten virallisesti en minä ainakaan kytke näitä suoraan Arduinon 5V pinneihin (kytkennästä lisää alempana).

Antennipuolelle spekseissä luvataan toimintaetäisyyttä jopa 50 mm:iin asti, joten tässä testailussa etäisyys on riittävä. Jos tätä haluaa käyttää esimerkiksi ovenpielessä, niin kannattaa mitoittaa lukijan etäisyys ottamalla huomioon (ei-metallisen) elektroniikkakotelon seinämävahvuus. Lisää muista spekseistä voit lukea piirin datalehdestä.

RFID-lukijan kytkeminen Arduinolle

Ensin täytyy tehdä kytkennät, joiden avulla päästään RFID-tagien kanssa kommunikoimaan. Kytkennän tekoon löytyy ohjeet netistä, mutta lisätään ohjeet vielä tähän alle kuitenkin. Käytän SPI-väylän kytkemiseen 220 ohmin vastuksia rajoittamaan virtaa ja suojaamaan IO:ta, koska datasivujen mukaan kyseinen piiri sallii vain 4 voltin jännitteen IO-pinneihinsä. Yleensäkin kannattaa aina tarkistaa 3,3 voltin laitteista, että voidaanko niitä kytkeä ristiin rastiin 5 voltin laitteiden kanssa. Vastusten avulla rajoitetaan virtaa, mikä voisi vahingoittaa piirin nastoja kun/jos suurin sallittu tulojännite ylitetään.

Tämä vastuksellinen "kikka" ei ehkä ole kaikista ammattimaisin tapa toteuttaa tällainen yhteensovitus logiikkatasoille, mutta tässä tapauksessa nopeudet signaalilinjoissa ovat sen verran pieniä, että hajakapasitanssit ja muut "häiriökomponentit" eivät aiheuta ongelmia toimintaan. Tämäkin olisi oma aihe-alueensa kirjoittaa, miksi näin ei tehtäisi jos kyseessä olisi esimerkiksi sarjatuotantolaite... Mutta palataanpa asiaan. Kytkentä siis alla:

Lukijapiirille kytketään pinnit seuraavassa järjestyksessä:

SignaaliPinni Arduino
Unolla
Pinni RC522:lla
CS/SS101
SCK132
MOSI113
MISO124
RST87
GNDGND6
+3.3V+3.3V8

Huomaathan, että koekytkentälevyllä on jokaisen signaalipinnin välissä 220 ohmin vastus! Pinnejä ei voi myöskään kytkeä miten sattuu, koska käytettävä ohjelmakirjasto "lukitsee" tiedonsiirtoon käytetyt MISO, MOSI ja SCK -signaalit. CS/SS ja RST -pinnit voidaan kuitenkin vapaasti valita. Lisätietoa kirjaston Githubilla: https://github.com/miguelbalboa/rfid

RFID-lukijan ohjelmakirjasto

Ennen kuin päästää vauhtiin koodin kirjoituksen kanssa, täytyy ladata MFRC522 piirin "ajuritiedostot" Arduinolle niin sanotusti, eli kirjasto minkä avulla piiriä voidaan komentaa. Jos kirjastoa ei olisi olemassa, se pitäisi itse luoda, mutta onneksi pyörää ei tässäkään tapauksessa ole tarvinnut keksiä uudelleen niin voimme vain ladata kirjaston.

Avataan ensin Arduino IDE ja ladataan Library Managerin kautta MFRC522 kirjasto käyttöön:

Arduino kirjaston asennus
MFRC522-kirjaston asennus

Kirjaston asentamisen jälkeen voidaan aloittaa kirjoittamaan ensimmäinen testikoodi.

Arduino RFID yksinkertainen testikoodi

Lisätään kirjaston komponentit eli .h -tiedostot Arduinon valikosta Sketch -> Include Library... -> MFRC522.

Lisätään samaan tapaan myös SPI-kirjasto. Pääohjelman ensimmäisille riveillä pitäisi olla nyt viisi kirjastoa:

#include <SPI.h>
#include <deprecated.h>
#include <MFRC522.h>
#include <MFRC522Extended.h>
#include <require_cpp11.h>

Aloitetaan esimerkkiohjelman tekeminen määrittelemällä käytetyt pinnit, jotka löytyvät siis yllä olevasta taulukosta:

#define SS_PIN  10
#define RST_PIN  8

Kokeillaan kirjaston toimintaa ensiksi ihan yksinkertaisella toiminnalla, eli testataan onnistuuko kommunikointi MFRC522 piirin kanssa ja jos onnistuu niin mitä kaikkea tällä voidaan havaita.

Tehdään yksinkertainen peruskoodi:

MFRC522 rfid(SS_PIN, RST_PIN);    // Luodaan instanssi
MFRC522::PICC_Type korttiTyyppi;  // Luodaan varasto korttityypin tiedolle

void setup() {
  Serial.begin(9600);
  SPI.begin();
  rfid.PCD_Init();
  Serial.println("Skannaa kortti tai avain...");
}
void loop() {
  if( ! rfid.PICC_IsNewCardPresent())
  {  return;  }
  if(! rfid.PICC_ReadCardSerial())
  {  return;  }

  korttiTyyppi = rfid.PICC_GetType(rfid.uid.sak);

  Serial.print("Kortin tyyppi:");
  Serial.println(rfid.PICC_GetTypeName(korttiTyyppi));

  // Pysäytetään skannaus yhteen tagiin
  rfid.PICC_HaltA();
  rfid.PCD_StopCrypto1();
}

Testikoodin selitys

PICC_IsNewCardPresent()-funktiolla tarkastetaan onko lukija havainnut uuden tagin lukuetäisyydeltään. Jos tagia ei ole (huutomerkki if-sulkujen sisällä), niin käsky return palauttaa suorituksen takaisin loop-lohkon alkuun.

Jos tagi taas tunnistetaan, edetään loop-lohkossa seuraavaan if-lauseeseen, missä pyritään lukemaan tagin sarjanumero. Jos luku onnistuu, edetään lukemaan lisää tietoja kortilta ja tulostetaan ne sarjaporttiin, mutta muussa tapauksessa palataan taas ohjelman alkuun (return if-lohkon sisällä). Ohjelma siis pyrkii koko ajan "skannaamaan" uutta tagia ja lukemaan tiedot havaitusta tagista välittömästi. Lopuksi pysäytetään skannaus, ettei saman tagin tietoja lueta koko ajan uudelleen ja uudelleen ja tavallaan "floodata" sarjaporttia samoilla tiedoilla.

Yllä oleva koodi voidaan nyt ladata Arduinolle. Toimintaa voidaan testata puuhasetin omilla tageilla ja myös muillakin mitä sattuu löytymään.

Tagityyppien luku

Yllä olevaa testikoodi siis tunnistaa piirin mukana tulleiden RFID-tagien lisäksi esimerkiksi kertakäyttöisen HSL:n bussilipukkeen ja näköjään myös Veikkaus-kortin.

Korttien ja tagien sisältöä ei ole vielä tarkasteltu, koodi ainoastaan pyrkii havaitsemaan millaisen tagin se tunnistaa. Luetaan tagien sisältöä hieman myöhemmin, mutta tutustutaan ensin hieman lisää siihen, kuinka lukijaa voidaan ohjata ja komentaa.

Skannattuja RFID-tageja
Tunnistettuja RFID-tageja

MFRC522-piirin rekisterien lukeminen

Käytetty kirjasto tarjoaa SPI-rajapinnan MFRC522 piirin rekisterien lukemista ja kirjoittamista varten. Tämä voi olla hyödyllistä varsinkin silloin, kun piiriä halutaan ohjata suoraan rekisteritasolta ja ikään kuin ohittaa käytetyn kirjaston tarjoamat edistyneemmät funktiot. Toisaalta voi olla myös tarpeellista toteuttaa omia funktioita, joita käytetty kirjasto ei tarjoa valmiiksi.

PCD_ReadRegister() -funktio on määritetty MFRC522-kirjaston lähdekoodissa ja sen parametreinä voidaan antaa pelkästään haluttu rekisteri joka halutaan lukea, kuten seuraavassa koodissa on tehty.

Funktio kätkee sisäänsä SPI-kutsut, joiden avulla rekistereitä luetaan bittitasolla, näin ollen ohjelmoijan ei tarvitse huolehtia esimerkiksi bittien ajoituksista tai viestin formaatista. Kaiken voisi kirjoittaa myös hyödyntäen Arduinon SPI-kirjastoa sellaisenaan, mutta miksi tehdä jotain minkä joku muu on jo toimivaksi tehnyt.

Lisätään yllä olevaan ohjelmaan seuraava aliohjelma loop()-funktion alle:

byte readRC552FwVersion()
{
  byte ver = 0;
  ver = rfid.PCD_ReadRegister(MFRC522::VersionReg);
  return ver;
}

Muutetaan setup()-lohkon koodia seuraavaksi:

void setup() {
  Serial.begin(9600);
  SPI.begin();
  rfid.PCD_Init();
  Serial.print("Lukijan versio: ");
  Serial.println(readRC552FwVersion(),HEX);
  Serial.println("Skannaa kortti tai avain...");
}

Nyt voidaan esimerkiksi tarkastaa piirin ohjelmaversio, joka voidaan lukea suoraan rekisteristä 0x37 (piirin datalehti sivu 66):

Versioinnin tarkistaminen rekisteritasolta
Rekisteristä luku

Yllä olevan version tarkistuksen hoitaa myös MFRC522-kirjaston funktio PCD_DumpVersionToSerial().

MFRC522-kirjasto tarjoaa paljon muitakin erilaisia funktioita, joita voidaan käyttää ja näihin kannattaa tutustua tarkemmin esimerkkikoodien avulla. Esimerkkikoodit löytyvät kätevimmin Arduino IDE:stä kohdasta File -> Examples -> MFRC522:

RFID-tagin sisältö (MIFARE)

RFID-tagit pitävät sisällään ID:n lisäksi mahdollisesti myös muuta tietoa. Tunnistetuissa RFID-tageissa (kuva ylempänä) oli mainittu MIFARE 1KB niminen tagi. Yksinkertaisesti sanottuna kyseessä on NXP:n omistama tuotemerkki RFID-tagille. RFID-tagien ominaisuudet vaihtelevat valmistajan ja käyttökohteen mukaan, mutta keskitytään tässä vain tähän kyseiseen tagiin. Periaatteessa ei ole väliä millainen tagi on vastassa, mikäli kirjasto ja MFRC522 piiri pystyy kommunikoimaan ko. tagin kanssa.

Käytetty valkoinen kortti ja avaimenperä sisältävät molemmat NXP:n piirin malliltaan MF1S50YYX_V1. Tämä on siis se piiri, minkä kanssa MFRC522 kommunikoi antennin välityksellä.

Kun katsotaan tagien sisältämän piirin datasivua (https://www.nxp.com/docs/en/data-sheet/MF1S50YYX_V1.pdf) niin voidaan todeta että sekä kortti, että avain sisältävät 1 kilotavun (1024 kB) EEPROM-muistia.

Tagien sisältöä päästään ehkä parhaiten tutkimaan, kun käytetään kirjaston tarjoamaa funktiota PICC_DumpToSerial(). Lisätään alla olevat rivit kortin tyypin tulostuksen alle ja ladataan koodi Arduinolle:

  Serial.print("Kortin sisalto:");
  rfid.PICC_DumpToSerial(&(rfid.uid));

Kun nyt avataan sarjaportin terminaali ja tagia pidetään lukijan lähellä, saadaan sarjaporttiin tulostumaan tagin kaikki tiedot heksalukuina:

Mifare 1kB tagin tiedot
Tagin kaikki tiedot "dumpattuna" sarjaporttiin.

Dumpatuista tiedoista huomataan, että suurin osa biteistä on nollassa, eli käytännössä juuri skannattu tagi on tyhjä. Toisaalta, äkkiseltään katsottuna yllä olevasta kuvasta tulee informaatioähky. Sen vuoksi palastellaanpa kakkua datasivujen ja muiden lähteiden avulla helpommin sulateltaviksi siivuiksi.

RFID-tagin muistikartta ja tagin ID

Kyseisen tagin (Mifare Classic 1K) muisti on järjestetty sektoreihin (sector) ja lohkoihin (block). Sektoreita on 16 kappaletta ja kussakin sektorissa on neljä lohkoa. Lohkot eli blokit on vielä jaoteltu neljään ryhmään, joista viimeisin blokki pitää sisällään salausavaimet A ja B ja pääsybitit (Access Bits). Sektorin viimeisintä blokkia kutsutaan myös nimellä "Trailer block".

Sektorit on numeroitu siis 0-15 ja blokit 0-63. MFRC522-kirjaston käytön kannalta on hyvä tiedostaa, että tietojen kirjoitus tapahtuu aina blokki kerrallaan, mutta lukea voi vaikka kaikki blokit putkeen.

Avain A on käyttäjän (ohjelmoijan) vaihdettavissa ja lisäksi aina tiedettävä jos tietoja halutaan lukea tai manipuloida. Avain B on myöskin vaihdettavissa, mutta sen käyttötarkoitus vaihtelee hieman sovelluksesta riippuen. Yleensä yksinkertaisissa autentikointisovelluksissa riittää, että ohjelmoidaan haluttu avain A ja käytetään sitä turvaamaan blokkien sisältö.

Access bits -tavuilla (biteillä) voidaan vaikuttaa siihen, mihin avainta A ja B käytetään. Oletuksena ne ovat niin, että avainta A ei voida lukea (PCD:n eli lukijan osalta), mutta se voidaan muuttaa. Koska avainta A tarvitaan aina, kun yritetään tietoa lukea, tulee se tietää ennakolta ja tyhjissä tageissa se onkin oletuksena 0xFFFFFFFFFFFF (6 kertaa 0xFF).

Alla oleva kuvakaappaus on otettu MIFARE käyttäjän manuaalista ja se havainnollistaa juuri selitettyä muistirakennetta tagissa:

Kuvan lähde: https://shop.sonmicro.com/Downloads/MIFARECLASSIC-UM.pdf

Sektorin 0, blokki 0 pitää sisällään valmistajan tietoja. Kyseinen lohko on tagin valmistajan tuottama erityinen vain-luku-tyyppinen muistialue, mihin on ohjelmoitu muun muassa tagin tunniste (UID = Unique Identifier) minkä perusteella tagit voidaan erotella toisistaan. Tagien tunnisteet voivat olla 4, 7 tai 10 tavua pitkiä.

Tässä tapauksessa UID on neljä tavua, mistä käytetään nimitystä NUID (Non-Unique Identifier), mutta mistä kirjasto tietää että se on 4 eikä 7, tai 10 tavua? (Vastaus tässä dokumentissa: https://www.nxp.com/docs/en/application-note/AN10927.pdf ).

ID-tunnistetta tarvitaan jos halutaan muokata tagilla olevaa tietoa. Jos tarvitaan pelkästään yksilöity tagi, niin silloin jo ylläolevat koodit riittävät esimerkiksi tunnistus ja "oven avaus" -juttujen tekoon. Turvallisuutta saadaan kuitenkin reilusti lisää jo esimerkiksi avainta A muuttamalla.

RFID-tagin tietoihin pääsy

RFID-tagin tietoja ei pääse siis lukemaan ilman oikeaa turva-avainta, joten se pitää olla tiedossa. Uusissa tageissa turva-avaimet ovat oletuksena 6 tavua pitkiä, kaikki 0xFF -tavuja - kuten jo edellä mainittu. MFRC522-kirjasto käyttääkin oletuksena tätä avainta, kun käytetään funktiota PCD_DumpVersionToSerial().

Muita mahdollisia yleisesti tiedossa olevia avaimia (A/B) ovat:

0XFF 0XFF 0XFF 0XFF 0XFF 0XFF
0XD3 0XF7 0XD3 0XF7 0XD3 0XF7
0XA0 0XA1 0XA2 0XA3 0XA4 0XA5
0XB0 0XB1 0XB2 0XB3 0XB4 0XB5
0X4D 0X3A 0X99 0XC3 0X51 0XDD
0X1A 0X98 0X2C 0X7E 0X45 0X9A
0XAA 0XBB 0XCC 0XDD 0XEE 0XFF
0X00 0X00 0X00 0X00 0X00 0X00
0XAB 0XCD 0XEF 0X12 0X34 0X56

Joskus voi olla tarpeellista tallentaa tietoa tagiin ja MFRC522 kirjastosta löytyy onneksi metodit tätäkin käyttötapausta varten.

Tagin tietojen muuttamiseksi tarvitaan periaatteessa vain kolme askelta:

  1. Tagin yksilönumeron eli ID:n lukeminen (UID / NUID)
  2. Sektorin A-avaimen tietäminen
  3. Autentikointi avaimella A halutulle sektorille, missä muutettavat datablokit sijaitsevat

Arduino esimerkki RFID-tagiin tallentamisesta

Oletetaan, että halutaan tallentaa tietoa tiedossa olevan tagin sektorin 1 ensimmäiseen blokkiin (tyhjä blokki uudessa tagissa oletuksena) - eli ao. kuvan osoittamaan vihreään blokkiin. Sektorissa 1 on avain B merkitty 0xFF:ksi ja pääsybitit (Access bits) oletusarvoonsa, näistä ei tarvitse välittää.

Tiedetään, että tagin ID (NUID) on heksalukuna tässä tapauksessa 51 04 E4 ja että avain A on FF FF FF FF FF FF. MFRC522 -kirjaston esimerkkikoodeja hyödyntämällä saadaan tehtyä alla oleva koodi, joka tutkii onko oikea tagi skannattuna ja jos on, niin kirjoitetaan tagin muistiin tekstirimpsu.

Voit ladata täydellisen koodin ylläolevasta linkistä. Alle olen ottanut muutaman otteen koodista selitettäväksi.

Koodin selityksiä

Kolme pistettä alla olevien lohkojen alussa, lopussa tai välissä tarkoittaa sitä, että koodia on kyseisen kohdan ylä/alapuolella.

... (rivit 11-19)
// HUOMIO: MUUTA sallittu_ID vastaamaan omaa tagiasi, niin kirjoitus toimii!
byte sallittu_ID[4] = 
      {0x51, 0x04, 0xE4, 0x45};   // Sallitun kortin ID 
byte kortin_ID[4];                // Skannatun kortin ID-tunnisteen tallennuspaikka
byte sektori = 1;                 // Sektori minne kirjoitetaan
byte blokkiosoite = 4;            // Blokki minne kirjoitetaan
byte traileriblokki = 7;          // Blokki, mistä löytyy sektorin traileri (eli avain A + sallintabitit)
char tiedot[16] =                 // Tiedot, mitä kirjoitetaan. Täytyy olla 16 tavua pitkä.
{'-','w','w','w','.','h','u','t','a','s','u','.','n','e','t','-'}; 
...

Koodin alussa kerrotaan ohjelmalle haluttu sektori ja blokki minne kirjoitus kohdistetaan. Samoin myös tagin ID jota myöhemmin verrataan skannattuun tagiin sekä tietenkin 16 tavua pitkä kirjoitettava data. Tässä on käytetty char-tyyppiä, koska kyseessä on ASCII-muodossa olevaa tekstiä joka mahtuu byte-tyyppiseen muuttujaan. Char-määritys saa kuitenkin kääntäjän käsittelemään ilmoitettuja merkkejä ASCII-merkkeinä jolloin ne tulevat myös sarjaporttiin oikealla tavalla näkymään.

 void setup() {
 .... (rivit 28-33)
 for(int i=0; i < 6; i++)
  {
    avain_A.keyByte[i] = 0xFF;  // Asetetaan salausavain A   
  }
  // F("teksti") <-- talletetaan tekstit Arduinon FLASH-muistiin, ei tuhlata RAMmia.
  Serial.print(F("Lukijan versio: ")); 
.... 

Setup-lohkossa avain A alustetaan tiedettyyn arvoon. Jos olet vaihtanut tehdasasetettua avainta, tämän tulee vastata oikeaa avainta. Printtifunktion sisällä oleva F("..")-makro säästää ohjelmassa RAM-muistia, joten käytännössä sarjaporttiin tulostettavat kiinteät tekstit löytyvät Arduinon flash-muistista. Tämä ei ole välttämätöntä, mutta joskus voi RAM-muistista tulla uupelo.

... (rivit 48-54)
// Jos yritetään muuta kuin mifare tyyppistä muistia käyttää
  MFRC522::PICC_Type piccType = rfid.PICC_GetType(rfid.uid.sak);
  if (    piccType != MFRC522::PICC_TYPE_MIFARE_MINI
      &&  piccType != MFRC522::PICC_TYPE_MIFARE_1K
      &&  piccType != MFRC522::PICC_TYPE_MIFARE_4K) {
      Serial.println(F("Toimii vain MIFARE Classic tageilla!"));
      return;
  }
...

Kuten kommenttikin sen kertoo, loopin alussa tarkistetaan että yritetään käyttää oikean tyyppistä tagia.

... (rivit 56-73)
// luetaan ID. 
  for(byte i = 0; i < 4; i++)
  {
    kortin_ID[i] = rfid.uid.uidByte[i];
  }
  // Tarkistus: jos kyseessä on väärä ID niin mitään ei kirjoiteta.
  byte ok = 4;

  for(byte i = 0; i < 4; i++)
  {
    if(!(sallittu_ID[i] == kortin_ID[i]))
    {
      // jos vertailtavat eivät ole samat... 
      // Riittäisi silmukan lopetus yhteenkin väärään bittiin, mutta tehdään nyt
      // huvin vuoksi näin... 
      ok--;
    }
  }
...

Riveillä 56-73 luetaan tagin UID ja verrataan sitä riveillä 11-19 annettuihin arvoihin. Tällä tavalla voidaan varmistua, että kyseessä on juurikin se tagi, mihin kirjoitusoperaatio halutaan kohdistaa.

Huom! UID:n vertailu ei tagiin kirjoittamisen kannalta ole välttämätöntä, jos avain A on tiedossa. Tämä on vain yksi hyvin yksinkertainen ja "raaka" esimerkki, kuinka tageja voidaan käyttää.

... (rivit 79-80)
Serial.println(F("Autentikoidaan avaimella A..."));
    status = rfid.PCD_Authenticate(MFRC522::PICC_CMD_MF_AUTH_KEY_A, traileriblokki,&avain_A,&(rfid.uid));
... (rivi 90)
rfid.PICC_DumpMifareClassicSectorToSerial(&(rfid.uid), &avain_A, sektori);
...

Tagin muistiin autentikointi suoritetaan avaimella A. Jos käytettäisiin avainta B (jota ei voi käyttää oletuksena autentikointiin), olisi PCD_Authenticate() funktion ensimmäinen parametri PICC_CMD_MF_AUTH_KEY_B. Onnistuneen autentikoinnin jälkeen rivillä 90 luetaan sektorin 1 tiedot ja tulostetaan ne sarjaporttiin (tulostaa vain kyseisen sektorin).

 ... (rivit 93-101)
// Kirjoitetaan data sektoriin
    Serial.println(F("Datan sisältö:"));
    for(byte b = 0; b < 16;b++)
    {
      Serial.print(tiedot[b]);
    }
    Serial.println();
    Serial.println(F("Kirjoitetaan data..."));
    status = rfid.MIFARE_Write(blokkiosoite,tiedot,16);
...

Lopuksi tagiin kirjoitetaan ennalta määritetty tieto, mikä ensiksi tulostetaan sarjaporttiin informoimaan käyttäjää, että mitä tietoa kirjoitetaan.

Kun koodi kokonaisuudessaan toteutetaan, voidaan sitä oikean ID:n avaimella testata:

Sarjaporttiin tulostetut tiedot ja tietojen tarkistus ASCII taulukon avulla.

Lisää Arduino RFID koodeja?

MFRC522-kirjaston esimerkkejä kannattaa GitHubissa selailla ja niitä on loppujen lopuksi aika helppo yhdistellä toisiinsa myös. Enempää RFID-juttuja hutasussa ei ole toistaiseksi tulossa, mutta toivottavasti näistä koodeista ja selvityksistä suomenkielellä on edes jollekin apua. Palautetta voi antaa info-sivujen kautta ja suuremmista asiavirheistä olisi myös hyvä saada ilmoitusta, että saadaan sivuille asiat oikein esille.

Lähteitä ja linkkejä:
https://github.com/miguelbalboa/rfid/tree/master/examples
https://en.wikipedia.org/wiki/Radio-frequency_identification
https://fi.wikipedia.org/wiki/RFID
https://www.nfc-research.at/index.php@id=40.html
https://playground.arduino.cc/Learning/MFRC522/
https://randomnerdtutorials.com/security-access-using-mfrc522-rfid-reader-with-arduino/
https://www.idautomation.com/barcode-faq/rfid/
https://aksulit.com/rfid/
https://www.nedapidentification.com/insights/understanding-the-confusing-world-of-rfid-tags-and-readers-in-access-control/
https://learn.sparkfun.com/tutorials/rfid-basics/all
https://www.rfidcard.com/types-of-uid-rfid-card/
https://learn.adafruit.com/adafruit-pn532-rfid-nfc/mifare
https://www.nxp.com/docs/en/application-note/AN10927.pdf
https://www.nxp.com/docs/en/application-note/AN10833.pdf https://www.nxp.com/docs/en/data-sheet/MF1S50YYX_V1.pdf https://www.nxp.com/docs/en/data-sheet/MFRC522.pdf