SantyagoSantyago
Avatar

Witaj!
Blog archiwalny. Już niebawem nowy serwis!

YouTube RSS Facebook GitHub

Arduino poradnik

Wstęp

Teoria

Biblioteki

Komponenty

Czujniki i sensory

Rozwiązania i algorytmy

Narzędzia

Mikrokontrolery i Arduino IDE

Arduino i klony

Poradniki wideo

Reklama na Blogu

Najnowsze poradniki

Ostatnie komentarze

Ostatnie fotografie

polskie-gorypolskie-gorypolskie-gorypolskie-gorypolskie-gorypolskie-gorypolskie-gorypolskie-gorypolskie-gorywieliczka-szyb-danilowicza

Czytnik RFID/NFC NXP PN532

RFID (Radio-frequency identification) oraz NFC (Near Field Communication) to dwie bardzo zbliżone technologie bezprzewodowej komunikacji, które są używane praktycznie na każdym kroku w różnych dziedzinach naszego życia - od weryfikacji tożsamości, kontroli dostępu oraz systemach płatniczych. Technologia RFID po raz pierwszy została opatentowana w 1983 i była prekursorem szerzej dziś znanego NFC.

Czym dokładnie jest RFID?

RFID pozwala na jednokierunkową, bezprzewodową komunikację pomiędzy niezasilonym znacznikiem RFID, a zasilonym czytnikiem. Znaczniki takie mogą być skanowane nawet w odległości do 200 metrów, dzięki czemu mogą znaleźć zastosowanie nawet na lotniskach w celu monitorowania przemieszczjących się bagaży. RFID może operować w kilku zakresach częstotliwości radiowych, gdzie każda z nich posiada własne standardy i protokoły komunikacji.

Zakres czętotliwości Zasięg skanowania Standard
120 ± 150 kHz do 10 cm LF (Low Frequency)
13.56 MHz do 1 m HF (High Frequency)
433 MHz do 100 m UHF (Ultra High Frequency)
865 ± 868 MHz do 2 m UHF (Ultralight High Frequency)
902 ± 928 MHz do 2 m UHF (Ultralight High Frequency)
2450 ± 5800 MHz do 2 m Mikrowave
3.1 ± 10 GHz do 200 m Mikrowave

Przykładowe znaczniki RFID 125kHz

Czym zatem jest NFC?

Technologia NFC wykorzystuje (podobnie jak RFID HF) częstotliwość 13.56 MHz. W odróżnieniu jednak od RFID pozwala dodatkowo na dwustronną komunikację pomiędzy dwoma urządzeniami NFC, pozwalając na obsługę bardziej złożonycch interakcji, a także wymianę danych.

NFC zostało opracowane głównie w celu komunikacji na małe, bezpieczne odległości poniżej 20 cm. Takie cechy pozwalają na zastosowanie w telefonach komórkowych oraz przeprowadzania bezpiecznych transakcji bezgotówkowych. Ważna cechą NFC jest również możlwiość skanowania pojedynczego tagu w tym samym czasie. Typowa przepustowość NFC to 106 kbit/s, jednak potrafią uzyskać nawet transfery do 848 kbit/s.

Przykładowy znaczniki NFC 13,56 MHz / Mifare

Mifare jako bezdotykowy standard kart

W 1994 roku, firma Phillips opracowała  bezdotykowy standard karty zbliżeniowej Mifare, oferujący dodatkowe mechanizmy kontroli danych takie jak CRC, bit parzystości, czy nawet kodowanie. Karty w tym standardzie wyposażone są również w pamięć EEPROM o rozmiarze 8kbit, zorganizowanych w 16 sektorach, zawierających po 4 bloki pamięci o rozmiarze 16 bajtów. Standard Mifare pozwala także na ustawienie indywidualnych reguł dostępu do każdego bloku z osobna za pomocą kluczy dostępowych i bitów dotępu. Potrafią przechowywać informację do 10 lat oraz oferują 100 tysięcy cykli zapisu.

Oprócz Mifare możemy wymienić również późniejszy standard Mifare Pro, w którym wykorzystano mikroprocesor z koprocesorem szyfrującym algorytmem 3DES. Obecnie najnowszym standarem Mifare jest ProX, który obsługuje infrastrukturę klucza publicznego PKI.

Przykładowa karta RFID 13.56 MHz / Mifare

Obecnie większość znaczników RFID jak i NFC pracujące w zakresie częstotliwości  13.56 MHz spełniają standard Mifare, oferując dodatkową pamięć EEPROM.

Cztnik NFC/RFID bazujący na PN532

Najlepszym do tej pory czytnikiem z jakim się spotkałem jest moduł PN532 v3 od Elchouse, który można u nas dostać już za 32,00 złotych. Moduł może pracować zarówno z napięciami TTL 5V jak i 3.3V wykorzystując jedną z trzech dostępnych magistrali I2C, SPI lub UART/HSU poprzez wygodny przełącznik umieszczony na płytce PCB. To co wyróżnia ten moduł od pozostałych, to bardzo małe wymiary wynoszące około 43mm x 41mm, antena poprowadzona na brzegach płytki oraz otwory montażowe, co pozwala na bardzo wygodne ulokowanie w ewnetualnej obudowie. W zależności od zastsowanych tagów zasięg operacyjny może mieścić się w przedziale nawet do 5...7cm.

Obsługiwane karty to: Mifare 1k, 4k, Ultralight, DesFire, ISO/IED 14443-4 (CD97BX, CD ligiht, Desfire, P5CN072), Innovision Jewel (IRT5001), FeliCa (RCS_860, RCS_854). Oprócz odczytywania znaczników, moduł pozwala również na komunikację z urządzeniami NFC - np.: telefonem komórkowym, a także wymianę danych między dwoma modułami w trybe P2P.

Domyślnie moduł jest ustawiony w trybie pracy UART, ale bez problemu możemy wybrać nas interesujący:

  ON KE
UART 0 0
I2C 1 0
SPI 0 1

Podłączenie modułu z Arduino za pomocą SPI

Aby przygotować moduł do pracy z interfejsem SPI przełączamy przełącznik ON w pozycję Off (0) oraz KE w pozycję On (1). Następnie wystarczy połączyć:

  • pin zasilania modułu VCC podłączamy do pinu 5V w Arduino,
  • pin masy GND modułu podłączamy dp pinu GND w Arduino,
  • pin SCK modułu podłączamy do 13 pinu cyfrowego w Arduino,
  • pin MISO modułu podłączamy do 12 pinu cyfrowego w Arduino,
  • pin MOSI modułu podłączamy do 11 pinu cyfrowego w Arduino,
  • pin SS modułu podłączamy do 10 pinu cyfrowego w Arduino,

Moduł skonfigurowany w trybie pracy SPI

Odczytywanie unikatowego identyfikatora

Do obsługi modułu możemy skorzystać z gotowej biblioteki PN532, która należy rozpakować do katalogu naszych bibliotek w szkicowniku. Na rozgrzewkę spróbujemy odczytać unikatowy identyfikator znacznika RFID / NFC za pomocą poniższego programu. Biblioteka potrafi odczytać identyfikator kart w standardzie Mifare Classic (4 bajty) oraz Mifare Ultralight (7 bajtów).

  1. #include <SPI.h>
  2. #include <PN532_SPI.h>
  3. #include "PN532.h"
  4.  
  5. PN532_SPI pn532spi(SPI, 10);
  6. PN532 nfc(pn532spi);
  7.  
  8. void setup(void)
  9. {
  10.   // Inicjalizacja portu szeregowego
  11.   Serial.begin(115200);
  12.  
  13.   // Inicjalizacja czytnika NFC
  14.   nfc.begin();
  15.  
  16.   // Pobranie wersji firmware
  17.   uint32_t versiondata = nfc.getFirmwareVersion();
  18.  
  19.   // Jesli nie udalo sie pobrac, to nie jest to modul PN53x
  20.   if (!versiondata)
  21.   {
  22.     Serial.print("Nie odnaleziono modlu PN53x");
  23.     while(1);
  24.   }
  25.  
  26.   // Wyswietlenie wersji ukladu PN5xx
  27.   Serial.print("Znaleziono uklad PN5");
  28.   Serial.println((versiondata>>24) & 0xFF, HEX);
  29.  
  30.   // Wyswietlenie wersji firmware
  31.   Serial.print("Firmware: ");
  32.   Serial.print((versiondata>>16) & 0xFF, DEC);
  33.   Serial.print('.');
  34.   Serial.println((versiondata>>8) & 0xFF, DEC);
  35.  
  36.   // Konfiguracja modulu do odczytu znacznikow RFID
  37.   nfc.SAMConfig();
  38.  
  39.   Serial.println("Oczekiwanie na znacznik...");
  40. }
  41.  
  42. void loop(void)
  43. {
  44.   // Status
  45.   uint8_t success;                          
  46.  
  47.   // Bufor przechowujacy unikatowy identyfikator
  48.   uint8_t uid[] = { 0, 0, 0, 0, 0, 0, 0 };
  49.  
  50.   // Dlugosc unikatowego identyfikatora.
  51.   uint8_t uidLength;                        
  52.  
  53.   // Proba odczytania znacznika  
  54.   success = nfc.readPassiveTargetID(PN532_MIFARE_ISO14443A, uid, &uidLength);
  55.  
  56.   // Jesli sukces odczytu
  57.   if (success)
  58.   {
  59.     Serial.println();
  60.     Serial.println("Znaleziono znacznik ISO14443A");
  61.     
  62.     // wyswietlenie dlugosci unikatowego identyfikatora
  63.     Serial.print("  Dlugosc: ");
  64.     Serial.print(uidLength, DEC);
  65.     Serial.println("B");
  66.     
  67.     // wyswietlenie unikatowego identyfikatora
  68.     Serial.print("  UID: ");
  69.     nfc.PrintHex(uid, uidLength);
  70.  
  71.     // wyswietlenie typu znacznika
  72.     Serial.print("  TYP: ");
  73.     if (uidLength == 4)
  74.     {
  75.       Serial.println("Mifare Classic");
  76.     } else
  77.     if (uidLength == 7)
  78.     {   
  79.       Serial.println("Mifare Ultralight");
  80.     }
  81.   }
  82.  
  83.   delay(1000);
  84. }

Wynik dziłania programu

Dostęp do pamięci EEPROM w znacznikach Mifare

Jak wspomniałem wcześniej, znaczniki w tym standardzie wyposażone są w pamięć EEPROM o rozmiarze 8kbit. Pamięć ta zorganizowana jest w 16 sektorach, zawierających po 4 bloki pamięci o rozmiarze 16 bajtów. Teoretycznie więc mogą pomieścić 1 KB danych. W praktyce jest to jednak troszkę mniej, ponieważ każdy sektor posiada zarezerwowany jeden blok noszący nazwę Sector Trailer, który przechowuje informacje o kluczach dostępowych oraz ustawionych reguł dostępu (Access Bits) do tego sektora. Dodatkowo pierwszy sektor, oprócz Sector Trailer posiada blok producenta (Manfacturer Block) przechowujący unikatowy identyfikator znacznika oraz dane producenta.

Łatwo więc policzyć, że faktyczna ilość danych jaką możemy przechować wynosi:

(16 sektorów * 3 bloki) - 1 = 47 bloków danych

47 bloków danych * 16 bajtów = 752 bajty.

Cóż... filmu nie zapiszemy, ale taki rozmiar pozwala na przechowanie wielu cennych informacji - od wizytówek, czasów ostatniego skanowania czy ilości przeprowadzonych transakcji.  Jeśli ktoś zastanawiał się, w jaki sposób niektóre karty płatnicze pozwalają na zapamiętanie kwoty środków na koncie i ich wyświetlanie - już wie :)

Klucze A i B oraz bity dostępu (Access Bits)

Zobaczmy dokładniej jak wygląda struktura każdego bloku Sector Trailer:

  • Pierwsze sześć bajtów (0-5) przechowuje klucz dostępowy "A"
  • Kolejne cztery bajty (6-9) przechowują informacje o ustawionych bitach dostępu do wszystkich czterech bloków pamięci w sektorze z osobna (również do Sector Trailer). Każdy blok w sektorze może posiadać inne reguły dostępu. Ostatni zaś, czwarty bajt (9) nie jest wykorzystywany
  • Ostatnie sześć bajtów (10-15) przechowuje opcjonalny, drugi klucz "B"

W świeżo zakupionych znacznikach RFID oraz NFC zarówno klucz "A" jak i klucz "B" posiada wartość 0xFFFFFFFFFFFF.  Za pomocą tych kluczy uzyskujemy prawa odczytu i/lub zapisu do poszczególnych bloków w sektorze.

Bity dostępu fabrycznie ustawione są w następujący sposób (0xFF0780):

  • Klucz "A" nie jest możliwy do odczytania (ale wiemy jaką ma fabrycznie ustawioną wartość)
  • Klucz "B" jest możliwy do odczytania i jest ustawiony jako 0xFFFFFFFFFFFF
  • Klucz "B" nie jest używany do żadnych operacji na blokach pamięci
  • Za pomocą klucza "A" możemy wykonywać dowolne operacje - zapisywać i odczytywać dane, ustawiać własne klucze oraz modyfikować bity dostępu.

Odczyt z bloku pamięci

Zgodnie z organizacją pamięci, rozmieszczenie bloków w sektorach będzie następujące:

Blok Sektor Typ bloku
0 0 Manufacturer Block
1 0 Data Block
2 0 Data Block
3 0 Sector Trailer (0)
4 1 Data Block
5 1 Data Block
6 1 Data Block
7 1 Sector Trailer (1)
.... .... ....

Dla przykładu odczytamy sobie zawartość bloku pamięci 4 w sektorze 1 oraz przynależny mu Sector Trailer (blok 7)

  1. #include <SPI.h>
  2. #include <PN532_SPI.h>
  3. #include "PN532.h"
  4.  
  5. PN532_SPI pn532spi(SPI, 10);
  6. PN532 nfc(pn532spi);
  7.  
  8. void setup(void)
  9. {
  10.   // Inicjalizacja portu szeregowego
  11.   Serial.begin(115200);
  12.  
  13.   // Inicjalizacja czytnika NFC
  14.   nfc.begin();
  15.  
  16.   // Pobranie wersji firmware
  17.   uint32_t versiondata = nfc.getFirmwareVersion();
  18.  
  19.   // Jesli nie udalo sie pobrac, to nie jest to modul PN53x
  20.   if (!versiondata)
  21.   {
  22.     Serial.print("Nie odnaleziono modlu PN53x");
  23.     while(1);
  24.   }
  25.  
  26.   // Wyswietlenie wersji ukladu PN5xx
  27.   Serial.print("Znaleziono uklad PN5");
  28.   Serial.println((versiondata>>24) & 0xFF, HEX);
  29.  
  30.   // Wyswietlenie wersji firmware
  31.   Serial.print("Firmware: ");
  32.   Serial.print((versiondata>>16) & 0xFF, DEC);
  33.   Serial.print('.');
  34.   Serial.println((versiondata>>8) & 0xFF, DEC);
  35.  
  36.   // Konfiguracja modulu do odczytu znacznikow RFID
  37.   nfc.SAMConfig();
  38.  
  39.   Serial.println("Oczekiwanie na znacznik...");
  40. }
  41.  
  42. void loop(void)
  43. {
  44.   // Status
  45.   uint8_t success;                          
  46.  
  47.   // Bufor przechowujacy unikatowy identyfikator
  48.   uint8_t uid[] = { 0, 0, 0, 0, 0, 0, 0 };
  49.  
  50.   // Dlugosc unikatowego identyfikatora.
  51.   uint8_t uidLength;                        
  52.  
  53.   // Proba odczytania znacznika  
  54.   success = nfc.readPassiveTargetID(PN532_MIFARE_ISO14443A, uid, &uidLength);
  55.  
  56.   // Jesli sukces odczytu
  57.   if (success)
  58.   {
  59.     Serial.println();
  60.     Serial.println("Znaleziono znacznik ISO14443A");
  61.     
  62.     // wyswietlenie dlugosci unikatowego identyfikatora
  63.     Serial.print("  Dlugosc: ");
  64.     Serial.print(uidLength, DEC);
  65.     Serial.println("B");
  66.     
  67.     // wyswietlenie unikatowego identyfikatora
  68.     Serial.print("  UID: ");
  69.     nfc.PrintHex(uid, uidLength);
  70.  
  71.     // wyswietlenie typu znacznika
  72.     Serial.print("  TYP: ");
  73.     if (uidLength == 4)
  74.     {
  75.       Serial.println("Mifare Classic");
  76.       Serial.println("");
  77.  
  78.       Serial.println("Proba autoryzacji za pomoca klucza A");
  79.       
  80.       // Klucz
  81.       uint8_t keya[6] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
  82.  
  83.       // Sektor 1:
  84.       // #7 - Sector Trailer
  85.       // #6 - Data Block
  86.       // #5 - Data Block
  87.       // #4 - Data Block
  88.       // Sektor 0:
  89.       // #3 - Sector Trailer
  90.       // #2 - Data Block
  91.       // #1 - Data Block
  92.       // #0 - Manufacturer Block
  93.       
  94.       // Proba uzyskania dostepu do Bloku #4 pamieci
  95.  
  96.       success = nfc.mifareclassic_AuthenticateBlock(uid, uidLength, 4, 0, keya);
  97.  
  98.       if (success)
  99.       {
  100.         Serial.println("Uzyskano dostep do bloku #4");
  101.     
  102.         uint8_t data[16];
  103.  
  104.         // Odczyt danych z bloku #4
  105.         success = nfc.mifareclassic_ReadDataBlock(4, data);
  106.  
  107.         if (success)
  108.         {
  109.           Serial.println("Zawartosc bloku #4:");
  110.           nfc.PrintHexChar(data, 16);
  111.           Serial.println("");
  112.           delay(1000);
  113.         } else
  114.         {
  115.           Serial.println("Nie mozna odczytac zawartosci bloku #4");     
  116.         }
  117.       } else
  118.       {
  119.         Serial.println("Nie mozna uzyskac dostepu do bloku #4");  
  120.       }
  121.     }
  122.   }
  123.  
  124.   delay(1000);
  125. }

Wynik działania dla odczytania bloku #4 (Data Block)

Wynik działania dla odczytania bloku #7 (Trailer Block dla Sektora 1)

Jak widzimy blok #4 jest cały pusty - jednak blok #7 powinien zawierać informacje dla sektora 1, takie jak: klucze A i B oraz ustawienia bitów dostępu. Klucz A oznaczyłem kolorem czerwonym, bity dostępu kolorem zielonym, natomiast niebieskim klucz B.

Wspomniałem wcześniej, że dla nowego znacznika RFID/NFC klucz A i klucz B to 0xFFFFFFFFFFFF. Dlaczego więc klucz A posiada wartość 0x000000000000? Dzieje się tak dlatego, ponieważ ustawione bity dostępu 0xFF0780 nie pozwalają na odczyt zawartości klucza A, maskując go zerami przed odczytaniem. Pozwalają natomiast na odczyt zawartości klucza B.

O ile klucz A i klucz B obowiązują w obrębie całego sektora, to bity dostępu można ustawić indywidualnie dla każdego bloku w sektorze z osobna.

UWAGA! Należy zwrócić szczególną uwagę na wartości bitów dostępu, jeśli zamierzamy modyfikować klucze oraz bity dostępu. Niewłaściwe ustawienie bitów dostępu może na stałe zablokować nam dostęp do całego sektora, bez możliwości cofnięcia zmiany. Należy też zapamiętać jakie ustawiliśmy nowe klucze.

Zapis do bloku pamięci

W kolejnym przykładzie zapiszemy do bloku 4 następujące dane "www.jarzebski.pl" oraz zmienimy klucze dostępowe A i B, pozostawiając domyślne ustawienia bitów dostępu 0xFF0780.

  1. #include <SPI.h>
  2. #include <PN532_SPI.h>
  3. #include "PN532.h"
  4.  
  5. PN532_SPI pn532spi(SPI, 10);
  6. PN532 nfc(pn532spi);
  7.  
  8. void setup(void)
  9. {
  10.   // Inicjalizacja portu szeregowego
  11.   Serial.begin(115200);
  12.  
  13.   // Inicjalizacja czytnika NFC
  14.   nfc.begin();
  15.  
  16.   // Pobranie wersji firmware
  17.   uint32_t versiondata = nfc.getFirmwareVersion();
  18.  
  19.   // Jesli nie udalo sie pobrac, to nie jest to modul PN53x
  20.   if (!versiondata)
  21.   {
  22.     Serial.print("Nie odnaleziono modlu PN53x");
  23.     while(1);
  24.   }
  25.  
  26.   // Wyswietlenie wersji ukladu PN5xx
  27.   Serial.print("Znaleziono uklad PN5");
  28.   Serial.println((versiondata>>24) @amp@ 0xFF, HEX);
  29.  
  30.   // Wyswietlenie wersji firmware
  31.   Serial.print("Firmware: ");
  32.   Serial.print((versiondata>>16) @amp@ 0xFF, DEC);
  33.   Serial.print('.');
  34.   Serial.println((versiondata>>8) @amp@ 0xFF, DEC);
  35.  
  36.   // Konfiguracja modulu do odczytu znacznikow RFID
  37.   nfc.SAMConfig();
  38.  
  39.   Serial.println("Oczekiwanie na znacznik...");
  40. }
  41.  
  42. void loop(void)
  43. {
  44.   // Status
  45.   uint8_t success;                          
  46.  
  47.   // Bufor przechowujacy unikatowy identyfikator
  48.   uint8_t uid[] = { 0, 0, 0, 0, 0, 0, 0 };
  49.  
  50.   // Dlugosc unikatowego identyfikatora.
  51.   uint8_t uidLength;                        
  52.  
  53.   // Proba odczytania znacznika  
  54.   success = nfc.readPassiveTargetID(PN532_MIFARE_ISO14443A, uid, &uidLength);
  55.  
  56.   // Jesli sukces odczytu
  57.   if (success)
  58.   {
  59.     Serial.println();
  60.     Serial.println("Znaleziono znacznik ISO14443A");
  61.     
  62.     // wyswietlenie dlugosci unikatowego identyfikatora
  63.     Serial.print("  Dlugosc: ");
  64.     Serial.print(uidLength, DEC);
  65.     Serial.println("B");
  66.     
  67.     // wyswietlenie unikatowego identyfikatora
  68.     Serial.print("  UID: ");
  69.     nfc.PrintHex(uid, uidLength);
  70.  
  71.     // wyswietlenie typu znacznika
  72.     Serial.print("  TYP: ");
  73.     if (uidLength == 4)
  74.     {
  75.       Serial.println("Mifare Classic");
  76.       Serial.println("");
  77.  
  78.       Serial.println("Proba autoryzacji za pomoca klucza A");
  79.       
  80.       // Klucz
  81.       uint8_t keya[6] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
  82.  
  83.       success = nfc.mifareclassic_AuthenticateBlock(uid, uidLength, 4, 0, keya);
  84.  
  85.       if (success)
  86.       {
  87.         Serial.println("Uzyskano dostep do bloku #4 (oraz sektora 1)");
  88.  
  89.         // Dane do zapisu
  90.         uint8_t zapisz[16] = { 'w', 'w', 'w', ',', 'j', 'a', 'r', 'z', 'e', 'b', 's', 'k', 'i', '.', 'p', 'l' };
  91.         
  92.         // Zapisujemy dane do bloku 4
  93.         success = nfc.mifareclassic_WriteDataBlock (4, zapisz);
  94.         
  95.         if (success)
  96.         {
  97.           Serial.println("Zapisano dane do bloku #4");          
  98.         } else
  99.         {
  100.           Serial.println("Blad podczas zapisu danych bloku #4");          
  101.         }
  102.        
  103.         // Nowy Sector Trailer
  104.         uint8_t sectortrailer[16] = {
  105.           0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5// Klucz A
  106.           0xFF, 0x07, 0x80, 0x69,              // Bity dostepu
  107.           0xB0, 0xB1, 0xB2, 0xB3, 0xB4, 0xB5   // Klucz B
  108.         };        
  109.  
  110.         // Zapisujemy Sector Trailer do bloku 7
  111.         success = nfc.mifareclassic_WriteDataBlock (7, sectortrailer);
  112.  
  113.         if (success)
  114.         {
  115.           Serial.println("Zapisano nowe klucze i bity dostepu sektora 1 (#4 - #7)");          
  116.         } else
  117.         {
  118.           Serial.println("Blad podczas zapisu nowych kluczy i bitow dostepu do sektora 1 (#4 - #7)");          
  119.         }
  120.         
  121.       } else
  122.       {
  123.         Serial.println("Nie mozna uzyskac dostepu do bloku #4 (oraz sektora 1)");  
  124.       }
  125.     }
  126.   }
  127.  
  128.   delay(2000);
  129. }

Wynik działania programu

Jak widzimy zapis danych i zmiana kluczy zakończyła się powodzeniem, jednak już za drugim razem procedura się nie powiodła, ponieważ zmieniliśmy klucze dostępowe. Odczytamy zatem jeszcze raz blok 4 i 7, ale za pomocą nowego klucza 0xA0A1A2A3A4A5. Wykorzystamy do tego program z poprzedniego rozdziału, ale zmieniając klucz dostępowy na taki, jaki ustawiliśmy.

  1. uint8_t keya[6] = { 0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5 };

Nowa zawartość bloku #4 (Data Block)

Nowa zawartość bloku #7 (Trailer Block)

Wybór magistrali I2C lub UART/HSU

Jak wspomniałem wcześniej moduł może pracować nie tylko na magistrali SPI, ale również I2C i HSU/UART. W tym celu musimy jednynie zmienić fragment kodu odpowiedzialny za ładowanei odpowiednich biblitek.

Zmiast:

  1. #include <SPI.h>
  2. #include <PN532_SPI.h>
  3. #include "PN532.h"
  4.  
  5. PN532_SPI pn532spi(SPI, 10);
  6. PN532 nfc(pn532spi);

wpisujemy dla UART:

  1. #include <PN532_HSU.h>
  2. #include <PN532.h>
  3.  
  4. PN532_HSU pn532hsu(Serial);
  5. PN532 nfc(pn532hsu);

lub dla I2C:

  1. #include <Wire.h>
  2. #include <PN532_I2C.h>
  3. #include <PN532.h>
  4.  
  5. PN532_I2C pn532i2c(Wire);
  6. PN532 nfc(pn532i2c);

UWAGA!

Jeśli z jakiegoś powdu, Arduino nie będzie w stanie wykryć modułu po magistrali I2C, należy sprawdzić odpowiednie ustawienie przełącznika oraz zmienić w pliku biblioteki PN532.h linię 203:

uint8_t pn532_packetbuffer[255];

na

uint8_t pn532_packetbuffer[64];

Zaawansowane ustawienia bitów dostępu

Własne ustawienia bitów dostępu pozwalają na określenie bardziej precyzyjnych reguł. Nowe fabrycznie znaczniki nie korzystają z klucza B, a ustawienia dla wszystkich bloków w sektorze są jednakowe. Jednak poprawne ustawienie tych bitów to "być, albo nie być" do poprawnego działania, gdzie drobny błąd może nam trwale zablokować dostęp nie tylko do wybranego sektora, ale również całej pamięci EEPROM.

Z myślą dla śmiałków przygotowałem specjalny kalkulator bitów dostępu. Za jego pomocą, możemy aktywować oba klucze oraz precyzyjnie określić reguły dostępu każdego bloku z osobna z wykorzystaniem jednego lub dwóch kluczy.

Kalkulator znajdziecie pod poniższym adresem:

https://www.jarzebski.pl/arduino/narzedzia/bity-dostepu-do-pamieci-kart-mifare.html

Reklama

Komentarze Komentarze
Avatar 1
Brii Linux x86_64 / Opera 9.80
04 March 2014 - 12:59 Warszawa

Jestem pod wrażeniem - czekam na kolejne artykuły :)

Avatar 2
Korneliusz Linux x86_64 / Mozilla Firefox 27.0
04 March 2014 - 20:59 Bytom

A dzięki!

Avatar 1
Maciek Windows / Mozilla Firefox 47.0
13 June 2016 - 21:55 Żywiec

Witam,
na wstepie musze przyznac ze bardzo pomocny i swietnie napisany artykul, mam pytanie (jestem poczatkujacy) do grona bardziej doswiadczonych osob w powyzszej tematyce. interesuje mnie komunikacja miedzy dwoma modulami

zestaw1: uC+clrc663 <-> zestaw2: uC+pn512,

jak zaczac i jak to mozna ugryzc ? na co zwrocic uwage ?
z gory dziekuje za info.

Pozdrawiam

Avatar 2
Korneliusz Linux Ubuntu / Mozilla Firefox 49.0
23 September 2016 - 19:57 Bytom

W jakim celu miałyby się komunikować? Możliwości jest kilka od UART, po I2c, a na bezprzewodowej transmisji włącznie

Avatar 1
ElectroFunx Windows / Mozilla Firefox 48.0
28 August 2016 - 00:47 Wrocław

Witam,
wie Pan może czy da się przy użyciu HSU ustawić tak rejestry w PN532 aby bez pinów IRQ PN532 był w stanie sam nadawać gdy znajdzie jakiś tag?

Avatar 1
Darek Windows / Safari 537.36
21 April 2017 - 21:29 Łódź

Bardzo dobre wyjaśnienie o co w tym wszystkim chodzi :-)

Niestety ja poległem na próbie autoryzacji przy użyciu kilku kluczy w miejscu:
uint8_t keya[6] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
Nie potrafię sobie z tym poradzić, bardzo byłbym wdzięczny za pomoc

Avatar 1
Darek Windows / Safari 537.36
28 April 2017 - 21:43 Łódź

Pomogło dorzucenie do void loop-a używanych prze zemnie kluczy :-)
Teraz zastanawiam się jak uzyskać z nfc.PrintHexChar(data, 16); tylko wartość DEC. Pomoże ktoś ?

Avatar 1
Darek Windows / Safari 537.36
06 May 2017 - 21:43 Łódź

Gdyby ktoś wiedział i pomogł jak przekazać do

uint8_t zapisz[16] = { \'w\', \'w\', \'w\', \',\', \'j\', \'a\', \'r\', \'z\', \'e\', \'b\', \'s\', \'k\', \'i\', \'.\', \'p\', \'l\' };

Input z konsoli był bym bardzo wdzięczny :-)

Mam tak ale nie działa :-(

while (Serial.available() == 0);

uint8_t zapisz[16] = { Serial.parseInt() };

Avatar 1
Piotr Windows / Mozilla Firefox 67.0
29 May 2019 - 00:24 Poznań

Napisałeś, że możliwa jest komunikacja przez nfc z telefonem, lecz nigdzie w internecie nie mogę tego znaleźć. Mógłbyś podpowiedzieć jak się za to zabrać?

Avatar 1
rysiek Linux Ubuntu / Mozilla Firefox 69.0
08 September 2019 - 07:54 Warszawa

Nie zauważyłem w przykładach zmiany wartości bitów dostępu. Ciągle jest to ten sam używany zestaw: FF0780. A przecież poprzez zmianę jego wartości uzyskujemy różne warunki dostępu do bloków poprzez wykorzystanie znajomości kluczy przy czym sama wartość klucza nie decyduje o dostępie.

Avatar 1
Paweł Nowak Windows 7 / Mozilla Firefox 71.0
01 January 2020 - 22:38 Brak informacji

Witam.
A jak odczytać karty DESFire? Proszę o link do przykładowego programu i z jakiej biblioteki skorzystać?