Hallo,
ich hab mich mal mit dem Thema RFID beschäftigt. Die lib dazu ist ja ziemlich umständlich zu verwenden finde ich. Mein Wunsch war es eine komplette Struct zu verarbeiten und das mit möglichst beliebigen Inhalt und fast beliebiger Länge, letzlich ohne dabei über Sektoren und Blöcke nachdenken zu müssen. Natürlich hab ich mir bei der Gelegenheit einen Tag komplett zerschossen und bei einem zweiten ein paar Sektoren
Herausgekommen ist jetzt aber ein fast eigenständiger Tab für die IDE der sich so bei verschieden Sketchen nutzen lässt. In dem verwendeten Beispiel ist das lesen und schreiben etwas sinnfrei, es soll aber ja auch nur die Verwendung zeigen. Die Anwendung ist aber, wie ich finde einfach und man muss sich fast keinen Kopf mehr um Sektoren und Blöcke machen.
Ich hab das Beispiel jetzt mehrfach getestet , eventuell findet ja jemand noch einen Bug oder hat noch eine Idee für eine sinvolle Erweiterung.
Heinz
/* Beispielsketch: RFID Tag mit den Daten einer beliebigen Struct
lesen und schreiben
Mai.2021
*/
#include <SPI.h> //include the SPI bus library
#include <MFRC522.h> //include the RFID reader library
#define SS_PIN 10 //slave select pin
#define RST_PIN 9 //reset pin
MFRC522 mfrc522(SS_PIN, RST_PIN); // instatiate a MFRC522 reader object.
MFRC522::MIFARE_Key key; //create a MIFARE_Key struct named 'key', which will hold the card information
#define STARTBLOCK 8 // möglich ab 1 ab hier wird geschrieben
// Testdaten
struct data {
byte a ;
int b ;
int c;
float f;
char text[20];
};
data mydata;
void setup() {
// put your setup code here, to run once:
Serial.begin(115200);
anzeige(mydata);
SPI.begin();
mfrc522.PCD_Init();
Serial.println("Scan a MIFARE Classic card");
Serial.print(F("Länge der Struct ")); Serial.println(sizeof(data));
// Prepare the security key for the read and write functions.
for (byte i = 0; i < 6; i++) {
key.keyByte[i] = 0xFF; //keyByte is defined in the "MIFARE_Key" 'struct' definition in the .h file of the library
}
}
void loop() {
// put your main code here, to run repeatedly:
bool newcard = askForNewCard(); // Abfrage Tag erkannt
if (newcard) {
fuellen(mydata); // Daten in struct schreiben
anzeige(mydata); // die erst mal anzeigen
WriteStruct(STARTBLOCK, mydata); // auf RFID schreiben
loeschen(mydata); // struct löschen
ReadStruct(STARTBLOCK, mydata); // erneut lesen
anzeige(mydata); // anzeigen
}
resetForNewCard(newcard); // immer bearbeiten
}
// Daten in Struct löschen
void loeschen(data &d) {
Serial.println(F(" Daten löschen"));
d.a = 0; // daten zum teste löschen
d.b = 0;
d.c = 0;
d.f = 0;
strcpy(d.text, "");
}
// struct beschreiben
void fuellen (data &d) {
d.a ++; // daten zum testen schreiben und ändern
d.b +=10;
d.c = 1023;
d.f = 123.45;
strcpy (d.text, "einen Text nutzen");
}
// daten in Struct anzeigen
void anzeige(data d) {
Serial.println(F("Daten aus Struct anzeigen"));
Serial.println(d.a);
Serial.println(d.b);
Serial.println(d.c);
Serial.println(d.f);
Serial.println(d.text);
Serial.println();
}
Der Tab
/* Tab zur Nutzung von RFDI Tags MIFARE Classic card 1K
Als Tab zum Sketch hinzufügen
beinhaltet folgende Funktionen.
Datum Mai 2021
askForNewCard erkennt einen aufgelegten Tag
resetForNewCard bendet Verbindung zum Tag
readBlock einen Block lesen (im Wesentlichen aus der Lib)
writeBlock einen Block schreiben
readStruct liest gesamte Datenstruktur
writeStruct schreibt gesamte Datenstruct
Name der verwendeten Datenstrutur "data"
------------------------------------------------------------
*/
bool askForNewCard() {
// Abfrage neue Karte vorhanden
if ( ! mfrc522.PICC_IsNewCardPresent()) {
return (0);
}
// Karte auswählen
if ( ! mfrc522.PICC_ReadCardSerial())
{
return (0);
}
Serial.println("erkannt");
return (1); // Returncode 1 Karte vorhanden
}
// ------------- Reset für neue Karte------
void resetForNewCard(bool newcard) {
static bool done;
static uint32_t altzeit;
if (newcard == true) {
altzeit = millis();
done = false;
}
if (millis() - altzeit >= 5000UL && done == 0) {
Serial.println(F("bereit Karte auflegen"));
// Halt PICC
mfrc522.PICC_HaltA();
// Stop encryption on PCD
mfrc522.PCD_StopCrypto1();
done = true;
}
}
// ------------einen Block lesen---------------
/* diese Funktion hab ich im Netz gefunden
* beruht im Wesentlichen auf ein Beispiel aus der Lib
* es wird geprüft ob die Blocknummer zulässig ist.
*/
byte readBlock(int blockNumber, byte *arrayAddress) {
int largestModulo4Number = blockNumber / 4 * 4;
int trailerBlock = largestModulo4Number + 3; //determine trailer block for the sector
//authentication of the desired block for access
byte status = mfrc522.PCD_Authenticate(MFRC522::PICC_CMD_MF_AUTH_KEY_A, trailerBlock, &key, &(mfrc522.uid));
if (status != MFRC522::STATUS_OK) {
Serial.print("PCD_Authenticate() failed (read): ");
Serial.println(mfrc522.GetStatusCodeName(status));
return 3;//return "3" as error message
}
//reading a block
byte buffersize = 18;//we need to define a variable with the read buffer size, since the MIFARE_Read method below needs a pointer to the variable that contains the size...
status = mfrc522.MIFARE_Read(blockNumber, arrayAddress, &buffersize);//&buffersize is a pointer to the buffersize variable; MIFARE_Read requires a pointer instead of just a number
if (status != MFRC522::STATUS_OK) {
Serial.print("MIFARE_read() failed: ");
Serial.println(mfrc522.GetStatusCodeName(status));
return 4;//return "4" as error message
}
Serial.println("block was read");
return 0;
}
//-------------Write specific block------------------
/* diese Funktion hab ich irgendwo gefunden
* beruht im Wesentlichen auf ein Beispiel aus der Lib
* es wird geprüft ob die Blocknummer zulässig ist.
*/
byte writeBlock(int blockNumber, byte *arrayAddress) {
//this makes sure that we only write into data blocks. Every 4th block is a trailer block for the access/security info.
int largestModulo4Number = blockNumber / 4 * 4;
int trailerBlock = largestModulo4Number + 3; //determine trailer block for the sector
if (blockNumber > 2 && (blockNumber + 1) % 4 == 0) {
Serial.print(blockNumber);
Serial.println(" is a trailer block:");
return 2;
}
//Serial.print(blockNumber);
//Serial.println(" is a data block:");
//authentication of the desired block for access
byte status = mfrc522.PCD_Authenticate(MFRC522::PICC_CMD_MF_AUTH_KEY_A, trailerBlock, &key, &(mfrc522.uid));
if (status != MFRC522::STATUS_OK) {
Serial.print("PCD_Authenticate() failed: ");
Serial.println(mfrc522.GetStatusCodeName(status));
return 3;//return "3" as error message
}
//writing the block
status = mfrc522.MIFARE_Write(blockNumber, arrayAddress, 16);
if (status != MFRC522::STATUS_OK) {
Serial.print("MIFARE_Write() failed: ");
Serial.println(mfrc522.GetStatusCodeName(status));
return 4;//return "4" as error message
}
Serial.println("block was written");
return 0; // ohne fehler beenden
}
/* -------------Daten schreiben---------------------
* Parameter blocknr ist der erster Block der genutzt wird
* Struct wird komplett Bytweise in die Datenblöcke
* geschrieben. TrailerBlocks werden übersprungen
*/
void WriteStruct(byte blocknr, struct data d) {
byte block[16] = {0}; // datenblock für rfid
byte *tempbytes = (byte*)&d; // hier Name der Struct beachten
byte i = 0; // Pos im dataBlock
byte status = 0;
byte max = sizeof(data);
Serial.println(F("RFID schreiben"));
if (blocknr == 0) {
Serial.print(F("BlockNr 0 nicht erlaubt"));
}
for (byte dataPos = 1; dataPos < max; dataPos++) {
block[i] = tempbytes[dataPos - 1]; // byte aus Struct in dataBlock
i++;
if (dataPos % 16 == 0 || dataPos == max) { //
if (blocknr > 2 && (blocknr + 1) % 4 == 0) {
Serial.print(blocknr); Serial.println(F(" ist Trailerblock"));
blocknr++;
}
Serial.print(F("Block ")); Serial.println(blocknr );
for (byte i = 0; i <16; i++) { // ausgeben
Serial.print(block[i], HEX); Serial.print(" ");
}
Serial.println();
status = writeBlock(blocknr, block); // Block schreiben
if (status != 0) {
Serial.print(F("ReturnCode ")); Serial.println(status);
}
for (byte i = 0; i < 16; i++) {
block[i] = 0;
}
i = 0;
blocknr++;
if (blocknr > 62 ) {
Serial.println(F("Ende von RFID erreicht"));
}
}
}
}
/*------------------ Daten lesen---------------
* Parameter blocknr ist der erster Block der genutzt wird
* Struct wird komplett Bytweise aus den Blöcken gelesen.
* TrailerBlocks werden übersprungen
*/
void ReadStruct(byte blocknr, struct data &d) {// hier Name der Struct beachten
byte block[18] = {0}; // datenblock für rfid
byte *tempbytes = (byte*)&d;// hier Name der Struct beachten
byte bn = 0;
byte max = sizeof(data);
byte status = 0;
Serial.println(F("RFID lesen"));
for (int dataPos = 0; dataPos < max; dataPos++) {
if (dataPos == 0 || dataPos % 16 == 0) {
if (blocknr > 2 && (blocknr + 1) % 4 == 0) {
Serial.print(blocknr); Serial.println(F(" ist Trailerblock"));
blocknr++;
}
Serial.print(F("Block ")); Serial.println(blocknr );
status = readBlock(blocknr, block);
if (status != 0) {
Serial.print(F("ReturnCode ")); Serial.println(status);
}
for (byte i = 0; i < 16; i++) { // ausgeben
Serial.print(block[i], HEX); Serial.print(" ");
}
Serial.println();
blocknr++;
bn = 0;
}
tempbytes[dataPos] = block[bn];// Byte in struct schreiben
bn++;
}
}