RFID Karte lesen, solange vor Reader PN532

#include <SPI.h>
#include <Wire.h>
#include <Adafruit_PN532.h>


// If using the breakout with SPI, define the pins for SPI communication.
#define PN532_SCK (14)
#define PN532_MOSI (13)
#define PN532_SS (2)
#define PN532_MISO (12)



Adafruit_PN532 nfc(PN532_SCK, PN532_MISO, PN532_MOSI, PN532_SS);

void setup() {
  Serial.begin(115200);
  Serial.println("Hallo!");
  nfc.begin();
  Serial.println("Warte auf eine Karte ...");
}


void loop() {
  uint8_t success;
  uint8_t uid[] = { 0, 0, 0, 0, 0, 0, 0 };  // Buffer to store the returned UID
  uint8_t uidLength;                        // Length of the UID (4 or 7 bytes depending on ISO14443A card type)
  success = nfc.readPassiveTargetID(PN532_MIFARE_ISO14443A, uid, &uidLength);

  if (success) {
    String idcard = "";
    for (uint8_t i = 0; i < uidLength; i++) {
      idcard += (String)uid[i];
    }
    Serial.println("UID Hex_als_String: " + idcard);

    while (nfc.readPassiveTargetID(PN532_MIFARE_ISO14443A, &uid[0], &uidLength)) {
    }
    
    
  }
  else {
      return;
  }
}

Hallo zusammen,

als Neuling stehe ich etwas auf dem Schlauch. Folgendes möchte ich im ersten Schritt realisieren: RFID Karte/Tag wird von einem PN532 Reader erkannt und die UID in einem String gespeichert. Solange die Karte vor dem Lesegerät ist, soll dieses pausieren. Erst wenn die Karte weggenommen wird, soll das Lesegerät auf die nächste Karte warten. Bei meinem Code wird die Karte einmal erkannt. Danach reagiert das Lesegerät nicht mehr, ich kann keine neue Karte lesen und im Seriellen Monitor sehe ich nur die UID der letzten Karte. Was fehlt hier noch???

Nimm den Code aus den Beispiel. Der Funktioniert.

Der Reader "pausiert" zwar nicht in dem Beispiel. ABER der Reader erkenne dort ob eine neue Karte erkannt wird.

Gruß

Pucki

Nein.

Doch.

Der gibt die UID nur 1 x im s.Monitor aus. Wenn er sie neu lesen würde, würde die Anzeige scrollen. Halte ich aber eine andere Karte davor, gibt er die wieder aus.

success = nfc.readPassiveTargetID(PN532_MIFARE_ISO14443A, uid, &uidLength);

Dann hat success ja die UID.
Also muss man nur die Variable puffern und vergleichen obs eine neu gibt.

Das geht sogar ohne Beispiel.

Hier ist das schön und in DE dokumentiert.

ps. Ich mag das Modul. :wink:

Gruß

Pucki

Der Reader erkennt nicht, ob eine neue Karte erkannt wurde.
Er erkennt, ob eine Karte davor ist oder nicht.
Nimmst Du die Karte weg und hälst sie wieder davor, wird diese wieder ausgegeben.

Das ist richtig.

ABER lt. TO seinen Wunsch ist GENAU das was du sagst sein Wunsch.

Der Grund warum, der neu einliest ist aber das " success " geleert wird, weil er keine neuen /alte Werte liest.

Gruß

Pucki

Gut, dann sind wir uns ja einig, dass:

falsch ist.
Der Reader gibt jeden Wechsel Karte/Keine Karte mit der dann gefundenen ID zurück.

Nu zu:

Das habe ich auch so gelesen.
Und daher ist das Beispiel zwar ein Einstieg, aber nicht die Lösung.

Dazu muss die UID gespeichert werden und mit der (neu) gelesenen verglichen werden.
Nur wenn neue UID, dann wieder in den Ausgabemodus und diese dann abspeichern.

Richtig?
Aber das kann ja @cbollweg nochmal genau beschreiben.

Richtig.

Wir sind uns wieder einig. WOW. Tag rot am Kalender anmalen ich muss :wink:

Gruß

Pucki

Erst einmal danke für die schnellen Antworten. Ich hole zu diesem Projekt mal etwas weiter aus. Es geht darum, dass in einem MakerSpace nur Benutzer Maschinen einschalten können, die in einem Googlesheet dafür mit Ihrer UID erfasst wurden. Die Maschine soll solange über ein Relais An geschaltet sein, wie sich sich eine Berechtigte Karte vor dem Reader befindet. Das Googlesheet erfasst dann die Anschalt und Abschaltzeit (wenn die Karte wieder entfernt wird). So grob lief das ganze eigentlich schon perfekt, nur das in dem MakerSpace mehrere unterschiedliche Kartentypen unterwegs sind. Also welche mit 4 Blöcken und welche mit 7 Blöcken. Deswegen wurden nicht alle Karten zuverlässig gelesen und ich habe mit verschiedenen Reader herumprobiert, bin aber zu der Erkenntnis gekommen, das der Fehler im Code liegen muss. Aus diesem Grund und weil ich das Ganze natürlich von Grund auf verstehen will, habe ich mich jetzt erst einmal um den Part des Auslesens der UID und der Speicherung in einem String entschieden. Die String Variable wird dann an das Googlesheet übergeben.

Naja.

Die erste Frage, die sich stellt ist. Sind alle Karten vom selben Typ.
Es gibt zwar jede Menge Typen, aber der PN532 kann, soweit ich weiß, nur 2 Arten Lesen.

Einmal die Mifare + dann aber mit andere Code die NFC-Typen also 2** . Wobei die Zahl die Speichergröße angibt.

Da beide Typen unterschiedlich sind muss der Code angepasst werden.

Bei den NFC-Beispielcode ist eine Tabelle die angibt, welche Karte welche Struktur hat.

Ich kann dir jetzt schon verraten, dass das kein leichtes Unterfangen wird.
Ich persönlich würde eher mich auf ein System einigen. Und dann die Karten neu ausgeben.
Das ist 1. ein prima Sicherheitsupdate, man weiß, wer nun eine Karte hat, und 2. sind dann alle Karten vom selben Typ. Was dein Problem gewaltig vereinfacht.

Schau dir in den Beispielen den Code für Mifare + den für NFC an, dann weißt du wovon ich rede.

Gruß

 Pucki

HA!
Ich habs geahnt, dass der Holzweg mit Nägeln gepflastert ist.
Du musst jetzt zwei Dinge realisieren:
a) Erkennung ob überhaupt eine Karte vorliegt
aa) Erkennung ob die Karte zugelassen ist.

Damit ist das Beispiel bedingt nutzbar.
Success wird nur erfüllt, wenn eine Karte erstmalig erkannt wird.
Um eine dauerhafte Erkennung zu starten müsste success neu gefüllt werden.
Ich lad mir die lib mal runter und denk bis morgen mal nach, wie man da am günstigsten ran kommt - vielleicht findet aber auch jemand anderes einen direkten Weg.

Das ist wie gesagt nur halb richtig.

Der PN532 (den roten den du hast) ist wenigstens Stressfrei in der Lage Mifare + NFC-Karten zu lesen.

Mit den RC522 (den blauen) habe ich es nicht geschaft NFC-Karten zu lesen. Soll angeblich gehen aber wie gesagt ich bin zu dööf dafür.

Ach und nur so nebenbei. Ich hoffe für dich das die Karten wenigstens auf derselben Frequenz laufen. Wenn nicht, gilt mein Rat Nr. 1 oben doppelt :wink:

Gruß

Pucki

Es sind wohl alles Mifare Karten mit 7 Blöcken, also 7 bytes (Mifare Ultralight), und 4 bytes (Mifare Classic) kann der Reader ja auch.

Wenn ich die Karten über die Beispiele in der LIB auslese, werden alle problemlos erkannt. Das Problem fängt wie gesagt beim übertragen in die Variable an, denke ich. :slight_smile:

Das ist doch einfach.

Setzt alt_success als globale Variable.

Wenn Success erkannt wird, dann mit alt_success vergleichen.

Bei JA nix tun (bzw. was anders)
bei nein, success mit der Datenbank vergleichen, und darauf reagieren und alt_success = success setzen.

Sobald die Karte weg ist, ist success = Nix und am löscht alt_success.

Wie oben schon geschrieben, das lesen der UNTERSCHIEDLICHEN Karten ist die Nuss die es zu knacken gilt.

Weshalb ich übrigens von Mifare auf NFC-215 umgestiegen bin. Die Teile sind preiswerter und mehr als eine Nr. muss ich nicht speichern. Der TO braucht ja nicht einmal das. :wink:

Gruß

Pucki

Nein.
Da nur Mifare gelesen werden, kannst Du auch in einem 7byte-array die 4byte-Variante abspeichern.

@cbollweg trenne Dich von String.
Chararray ist viel einfacher zu händeln.

Da war ich am Tippen als die Info kam :frowning:

Gruß

Pucki

Und bedeutend sinnvoller bei UID

Gruß

Pucki

#include <SPI.h>
#include <Wire.h>
#include <PN532.h>
#include <PN532_SPI.h>
#include <ESP8266WiFi.h>
#include <WiFiClientSecureAxTLS.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>

// If using the breakout with SPI, define the pins for SPI communication.
PN532_SPI pn532spi(SPI, 2);
PN532 nfc(pn532spi);

#define BUZZ_PIN D8
#define GATE_PIN D3

#define SCREEN_WIDTH 128  // OLED display width, in pixels
#define SCREEN_HEIGHT 32  // OLED display height, in pixels
// Declaration for an SSD1306 display connected to I2C (SDA, SCL pins)
#define OLED_RESET -1  // Reset pin # (or -1 if sharing Arduino reset pin)
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);

const char* host = "script.google.com";
const int httpsPort = 443;
const char* fingerprint = "46 B2 C3 44 9C 59 09 8B 01 B6 F8 BD 4C FB 00 74 91 2F EF F6";  // for https


//***********Things to change*******************
const char* ssid = "*****************";                                                              
const char* password = "*************";                                                            
String GOOGLE_SCRIPT_ID = "AKfycbyNJyCjyqBRDul36nhpc1k1hpDuHxjzio2-VvbKyOxzv7fUBwgF99w2D6vFMcp7Np1d";  // Replace by your GAS service id
const String unitName = "Hafven_Makerspace";                                                           // any name without spaces and special characters
//***********Things to change*******************
uint64_t openGateMillis = 0;
WiFiClientSecure client;

void setup() {

  pinMode(GATE_PIN, OUTPUT);
  
  digitalWrite(GATE_PIN, LOW);
  

  Serial.begin(9600);


  WiFi.mode(WIFI_STA);
  WiFi.begin(ssid, password);

  Serial.println("Started");
  Serial.print("Connecting");
  while (WiFi.status() != WL_CONNECTED) {
    delay(1000);
    Serial.print(".");
  }

  Serial.println("Hallo!");
  nfc.begin();

  uint32_t versiondata = nfc.getFirmwareVersion();
  if (!versiondata) {
    Serial.print("Didn't find PN53x board");
    while (10)
      ;  // halt
  }
  // Got ok data, print it out!
  Serial.print("Gefundener Chip PN5");
  Serial.println((versiondata >> 24) & 0xFF, HEX);
  Serial.print("Firmware ver. ");
  Serial.print((versiondata >> 16) & 0xFF, DEC);
  Serial.print('.');
  Serial.println((versiondata >> 8) & 0xFF, DEC);
  // configure board to read RFID tags
  nfc.setPassiveActivationRetries(0xFF);  // for example
  nfc.SAMConfig();

  Serial.println("Warte auf eine Karte ...");

  display.begin(SSD1306_SWITCHCAPVCC, 0x3C);
  delay(2000);
  display.clearDisplay();
  display.setTextColor(WHITE);
  display.setTextSize(1);
  display.setCursor(0, 10);
  display.print("Karte bitte");
  display.display();
}

void HandleDataFromGoogle(String data) {
  int ind = data.indexOf(":");
  String access = data.substring(0, ind);
  int nextInd = data.indexOf(":", ind + 1);
  String name = data.substring(ind + 1, nextInd);
  String text = data.substring(nextInd + 1, data.length());

  Serial.println(name);
  if (access == "-1") {
    Serial.print(" " + String("denied"));
  } else if (access == "any") {
    Serial.print(" " + String("go in"));
    OpenGate();
  } else if (access == "fridge") {
    Serial.print(" " + String("take it"));
    OpenGate();
  }
}

void OpenGate() {
  //openGateMillis = millis()+4000;
  digitalWrite(GATE_PIN, HIGH);
}

void CloseGate() {
  //openGateMillis = 0;
  digitalWrite(GATE_PIN, LOW);
}
void loop() {
  uint8_t success;
  uint8_t uid[] = { 0, 0, 0, 0, 0, 0, 0 };  // Buffer to store the returned UID
  uint8_t uidLength;                        // Length of the UID (4 or 7 bytes depending on ISO14443A card type)
  success = nfc.readPassiveTargetID(PN532_MIFARE_ISO14443A, uid, &uidLength);

  if (nfc.readPassiveTargetID(PN532_MIFARE_ISO14443A, uid, &uidLength)) {
    
    // Display some basic information about the card
    Serial.println("Found an ISO14443A card");
    Serial.print("  UID Length: ");Serial.print(uidLength, DEC);Serial.println(" bytes");
    Serial.print("  UID Value: ");
    nfc.PrintHex(uid, uidLength);
    Serial.println("");
    String idcard = "";
    for (uint8_t i=0; i < uidLength; i++) 
    {
      idcard += (String)uid[i];
    }
    Serial.println("UID Hex_als_String: "+idcard);



    
    display.clearDisplay();
    display.setTextColor(WHITE);
    display.setTextSize(1);
    display.setCursor(0, 10);
    display.print(idcard);
    display.display();
    String data = sendData("id=" + unitName + "&uid=" + idcard,NULL);
    HandleDataFromGoogle(data);

   while (nfc.readPassiveTargetID(PN532_MIFARE_ISO14443A, &uid[0], &uidLength)) {}
    
  }
  else 
  {
    
    CloseGate();
    String data = sendData("id=" + unitName + "&uid="+"Ende", NULL);
    while (!nfc.readPassiveTargetID(PN532_MIFARE_ISO14443A, &uid[0], &uidLength)) {
    display.clearDisplay();
    display.setTextColor(WHITE);
    display.setTextSize(1);
    display.setCursor(0, 10);
    display.print("Karte bitte");
    display.display();
    }
  }
}




String sendData(String params, char* domain) {
  //google scripts requires two get requests
  bool needRedir = false;
  if (domain == NULL) {
    domain = (char*)host;
    needRedir = true;
    params = "/macros/s/" + GOOGLE_SCRIPT_ID + "/exec?" + params;
  }

  Serial.println(*domain);
  String result = "";
  client.setInsecure();
  Serial.print("connecting to ");
  Serial.println(host);
  if (!client.connect(host, httpsPort)) {
    Serial.println("connection failed");
    return "";
  }

  if (client.verify(fingerprint, domain)) {
  }

  Serial.print("requesting URL: ");
  Serial.println(params);

  client.print(String("GET ") + params + " HTTP/1.1\r\n" + "Host: " + domain + "\r\n" + "Connection: close\r\n\r\n");

  Serial.println("request sent");
  while (client.connected()) {

    String line = client.readStringUntil('\n');
    //Serial.println(line);
    //delay(500);
    if (needRedir) {

      int ind = line.indexOf("/macros/echo?user");
      if (ind > 0) {
            Serial.println(line);
        line = line.substring(ind);
        ind = line.lastIndexOf("\r");
        line = line.substring(0, ind);
         Serial.println(line);
        result = line;
      }
    }

    if (line == "\r") {
      Serial.println("headers received");
      break;
    }
  }
  while (client.available()) {
    String line = client.readStringUntil('\n');
    if (!needRedir)
      if (line.length() > 5)
        result = line;
    // Serial.println(line);
  }

  if (needRedir)
    return sendData(result, "script.googleusercontent.com");

  else
    return result;
}

Ich habe mal meinen kompletten code hier aufgezeigt. Eigentlich funktioniert er so, wie er soll. Eigentlich!!! Wenn eine Karte mit 4 bytes vor dem Reader liegt, wird die UID erkannt, übermittelt, geprüft, bei positiver Rückmeldung wird das Relais geschaltet und solange die Karte vor dem Reader ist, passiert nichts. Das soll auch so sein. Nehme ich die Karte weg, schaltet das Relais aus. Soweit alles gut. Mach ich das gleiche mit einer Karte mit 7 bytes, wird die uid korrekt erkannt, das Relais schaltet, allerdings hält der Loop nicht an. D.h. das relais wird immer wieder an und aus geschaltet. Warum also stopt der loop bei einer 4 bytes Karte und bei einer 7 bytes Karte nicht?

Das liegt an der kombination Karte und Initialisierung des Kartenleser
Produktiv musst du mit beiden Situationen umgehen können weil du verschiedene Karten hast.
Also sowohl dass die Karte nur einmal gelesen wird,
wie auch, dass sie immer wieder gelesen wird.