Zapis i odczyt danych na karty MIFARE
Jeżeli posiadamy czytnik kart RC522 oraz kilka tagów do niego możemy poza samym odczytem ich unikalnych identyfikatorów chcieć przechowywać na nich dane. W końcu posiadają one 1kb nieulotnej pamięci, która tylko czeka aż coś do niej wpiszemy.
Podłączenie czytnika
Czytnik należy podłączyć dokładnie w taki sam sposób jak opisany w tym lub tym artykule pamiętając o tym, żeby zasilanie 3.3V podłączyć do linii 3.3V (w przeciwnym wypadku spalimy czytnik), czyli:
- SDA – 10
- SCK – 13
- MOSI – 11
- MISO – 12
- GND – GND
- RST – 9
- 3.3V – 3.3V
Po lewej stronie są nazwy pinów opisane na czytniku kart, a po prawej te na Arduino.
Wymagane komponenty
Aby poprawnie komunikować się z czytnikiem kart musimy wyposażyć nasze Arduino IDE w bibliotekę RFID z GitHuba.
Szkic programu
Najpierw musimy załączyć niezbędne biblioteki:
#include <SPI.h> #include <MFRC522.h>
Kiedy Arduino już wie któych plików użyć możemy powiedzieć mu, aby utworzył globalny obiekt do komunikacji z czytnikiem:
#define RST_PIN 9 #define SS_PIN 10 MFRC522 mfrc522(SS_PIN, RST_PIN);
W funkcji setup() uruchamiamy port szeregowy oraz inicjujemy połączenie z czytnikiem:
void setup() { Serial.begin(9600); SPI.begin(); mfrc522.PCD_Init(); }
loop() póki co zostawimy pusty. Zaimplementujemy teraz funkcje saveData() oraz readData().
Uwaga! Te funkcje w implementacji są do siebie bardzo podobne. W normalnym programie nie powinniśmy kopiować i wklejać w kółko tego samego kodu, jednak w poniższym przykładzie zrobimy to aby pokazać jak niezależnie odczytać i zapisać dane z/do karty.
bool saveData() { if (!mfrc522.PICC_IsNewCardPresent()) { return false; } if (!mfrc522.PICC_ReadCardSerial()) { return false; } MFRC522::MIFARE_Key key; for (byte i = 0; i < 6; i++) key.keyByte[i] = 0xFF; byte block = 53; char buffer[16] = {0}; strcpy(buffer, "Tekst"); if(mfrc522.PCD_Authenticate(MFRC522::PICC_CMD_MF_AUTH_KEY_A, block, &key, &(mfrc522.uid)) != MFRC522::STATUS_OK) { return false; } if(mfrc522.MIFARE_Write(block, buffer, 16) != MFRC522::STATUS_OK) { return false; } mfrc522.PICC_HaltA(); mfrc522.PCD_StopCrypto1(); return true; }
Opis przebiegu funkcji:
- Sprawdzamy, czy jakaś karta została przyłożona do czytnika. Jeżeli nie to zwracamy fałsz (niepowodzenie)
- Odczytujemy UID karty w celu nawiązania dalszej komunikacji z tą konkretną kartą. Jeżeli to się nie powiedzie zwracamy fałsz.
- Teraz możemy przygotować dane do zapisania na kartę. Te dane to:
- klucz dostępu (domyślnie jest to 6 bajtów wypełnionych jedynkami)
- numer bloku (nie może to być blok 0, ani żaden podzielny przez 3 – modyfikacja bloku o numerze podzielnym przez 3 grozi nadpisaniem klucza autoryzacyjnego i utraceniem dostępu do bloku)
- bufor z danymi do zapisu wypełniony zerami
- Do bufora wklejamy tekst, który chcemy zapisać przez funkcję strcpy()
- Autoryzujemy się za pomocą naszego domyślnego klucza (jeżeli to się nie powiedzie to zwracamy fałsz)
- Zapisujemy dane na karę, w przypadku niepowodzenia standardowo zwracamy fałsz
- Kończymy komunikację z kartą
- Zwracamy prawdę (cały proces zapisu powiódł się)
Zobaczmy teraz funkcję służącą do odczytu danych. Są tu cztery ledwie widoczne na pierwszy rzut oka zmiany:
bool readData() { if (!mfrc522.PICC_IsNewCardPresent()) { return false; } if (!mfrc522.PICC_ReadCardSerial()) { return false; } MFRC522::MIFARE_Key key; for (byte i = 0; i < 6; i++) key.keyByte[i] = 0xFF; byte block = 53; byte len; char buffer[16] = {0}; if(mfrc522.PCD_Authenticate(MFRC522::PICC_CMD_MF_AUTH_KEY_A, block, &key, &(mfrc522.uid)) != MFRC522::STATUS_OK) { return false; } if(mfrc522.MIFARE_Read(block, buffer, &len) != MFRC522::STATUS_OK) { return false; } Serial.println(buffer); mfrc522.PICC_HaltA(); mfrc522.PCD_StopCrypto1(); return true; }
Pierwsza z nich to zamiana metody MIFARE_Write na MIFARE_Read. Jej ostatnim parametrem jest długość odczytanych danych z bloku (jako referencja), dlatego też musimy utworzyć sobie zmienną len, a następnie przekazać ją do metody przez operator dereferencji &. To była druga zmiana. Trzecia jest taka, że nie używamy funkcji strcpy, ponieważ to MIFARE_Read zapisze nam dane w buforze. Ostatnią zmianą jest dopisanie linijki
Serial.println(buffer);
w celu wypisania zawartości pamięci na port szeregowy.
Teraz na koniec funkcji setup dopiszmy
while(!saveData()); Serial.println("Data saved");
oraz zaimplementujmy loop():
void loop() { readData(); }
To, co właśnie zrobiliśmy oznacza, że nasze Arduino zaraz po włączeniu będzie oczekiwało na przyłożenie karty. Po pierwszym przyłożeniu karty od włączenia w bloku 53 zostanie zapisany ciąg „Tekst”. Każde kolejne przyłożenie karty będzie odczytywało zawartość owego 53 bloku i wypisywało to co w nim znajdzie na port szeregowy jako tekst.
W ten sposób możemy personalizować karty przykładowo zapisując na nich imię właściciela, jakiś identyfikator itp. dane.
Dodatkowo dane zapisane na karcie możemy odczytać za pomocą przykładowego szkicu dołączonego do biblioteki MFRC522 o nazwie DumpInfo. Po jego wgraniu i uruchomieniu portu szeregowego musimy przyłożyć kartę do czytnika i przytrzymać ją aż do momentu odczytania całej pamięci.
Chcę podłączyć rc522 do nodemcu v2. Niby znalazłem kilka tutoriali i raczej sobie poradzę. Ale chcę też podłączyć moduł kart pamięci sd (zamówiłem taki https://nettigo.pl/products/modul-czytnika-kart-sd), żeby na karcie zapisywać który identyfikator był używany z czytnikiem. Też znalazłem schematy połączeń. Ale nie znalazłem jak podłączyć oba te urządzenia do jednego nodemcu v2. Oba używają spi, a ja z tym nigdy nie miałem do czynienia. Ale to nie wszystko, bo do nodemcu mają być jeszcze podłączone urządzenie po i2c i muszą mi zostać wolne piny właśnie dla i2c (w nodemcu v2 i2c może działać na dowolnych pinach). No i jeszcze przydałby mi się jeden wolny pin na diodę.
Poradzicie coś jak to podłączyć?