Rfid-Reader Auswertung - Neueinsteiger von Bascom kommt nicht weiter

Hallo Leute,
Ich habe mir mit dem Leonardo einen kleinen Rfid Reader zusammengebaut und komme an der Stelle der Auswertung der Tag´s nicht weiter. Wo habe ich den Denkfehler in der switch-case ?

#include <SoftwareSerial.h>

const byte codeLength = 14; //15 Zeichen gesammt da bei es bei 0 anfängt: Manufacturers code(2) + ID card number(10) + parity bits(3).
volatile long lastRead=0;
char code[codeLength];
int  val = 0;
int bytesread = 0;


SoftwareSerial RFID (11, 255);

void setup()
{
  Serial.begin(9600);
  while(!Serial)
    Serial.print ("Moin");
  RFID.begin(9600);
}

void loop()
{
  if (RFID.available())
  {
    lastRead = millis(); //Zeit des letzten bytes
    val = RFID.read();
    if((val == 10)||(val == 13)) //Wenn neue Zeil zb durch leseabbruch verschoben
    {
      bytesread=0;
    }
    else
    {
      code[bytesread] = val;
      bytesread++;
    }
  }


  if ((bytesread>0) && (millis()-lastRead>1000))//Wenn am lesen und zu lange kein byte empfangen = reset
  {
    bytesread = 0;
  }

  if(bytesread == codeLength) //Wenn alles empfangen
  {
    bytesread = 0;
    Serial.print("TAG code: ");   
    Serial.println(code);           
  }
  switch (code){
  case 05000604E2E5:
    Serial.print("Station 1");
    break;
  case 4F0088925E0B:
    Serial.print("Station 2");
    break;
  }
}

05000604E2E5 und 4F0088925E0B sind die mit dem Arduino ausgelesenen Codes der Tags.

Du kannst nicht auf strings switchen. Außerdem gehören String-Literale in Anführungszeichen:
"4F0088925E0B"

Dafür gibt es strcmp():
http://www.cplusplus.com/reference/cstring/strcmp/
Die Funktion gibt 0 zurück wenn die strings gleich sind.

if(strcmp(code, "05000604E2E5") == 0)

Außerdem solltest du beachten, dass C-strings Null-terminiert sind, und das Array daher eins größer als die sichtbaren Zeichen sein muss. Du solltest daher sicherheitshalber das machen (es geht vielleicht auch ohne, da der Vergleichs-String korrekt terminiert ist):
char code[codeLength + 1];
Weil es eine globale Variable ist, steht im letzten Index dann automatisch NULL

Das mit den Indices ist genau anders herum. Ein Array der Größe 14 geht von 0-13. Wenn dein Code 2+10+3 ist musst du codeLength auf 15 setzen. Obwohl die 3 Parity Bits anscheinend gar nicht übertragen oder ausgelesen werden. Dein Vergleichs-String ist 12 Zeichen lang.

So richtig wills nicht...
owei da muss ich ncoh reichlich dazulernen^^
In Bascom wars doch leichter.... werde morgen mal weiter schaun, die Müdigkeit schlägt zu.
Danke für die schnelle Antwort, wenigstens kommen keine Fehlermeldungen mehr, nur die Richtigen Codes erkennt er immer noch nicht, sprich die Ausgabe kommt nicht zu den jeweiligen Tags.

Du kannst den empfangenen Wert in eine Zahl umwandeln und diese dann mir Switch vergleichen.
Müßte mit atol() gehen (Habs nicht probiert darum bitte mit Vorsicht geniesen)
Grüße Uwe

Joschi1711:
Danke für die schnelle Antwort, wenigstens kommen keine Fehlermeldungen mehr, nur die Richtigen Codes erkennt er immer noch nicht, sprich die Ausgabe kommt nicht zu den jeweiligen Tags.

Kann es sein, dass Dein Reader z.B. einen 14-stelligen Code mit Hersteller-ID und/oder Prüfziffer sendet, Du aber versuchst, nur mit der 12-stelligen Karten-ID zu vergleichen?

Anbei mal ein Code zum Testen: Der gesendete Code wird eingelesen und in jedem Fall ausgegeben, entweder als "Valid" oder als "Invalid", zusammen mit der gelesenen Zeichenkette.

Wenn das nicht läuft, müßtest Du erstmal einen viel einfacheren Test-Sketch laufen lassen, der nur die Zeichen vom RFID-Reader liest und direkt auf dem Seriellen Monitor ausgibt, damit Du erstmal durchzählen kannst, wie viele Zeichen überhaupt gesendet werden.

Jedenfalls kannst Du nicht "Herstellercode+Karten-ID+Prüfziffer" oder "Karten-ID+Prüfziffer" einlesen und dann nur mit der "Karten-ID" (ohne Prüfziffer) vergleichen. Da müßte schon genau beachtet werden, was der Reader eigentlich sendet und womit dann verglichen wird.

Nachtrag: Beispiel-Sketch zum Auslesen von Readern, die 14-stellige Werte liefern:

#include <SoftwareSerial.h>

SoftwareSerial rfidSerial (11, -1); // RX, TX

void setup() {
  // put your setup code here, to run once:
  Serial.begin(9600);
  rfidSerial.begin(9600);
  Serial.println("Started");
}

void readRfid()
#define CODESIZE 14
{
  char readbuffer[CODESIZE+1]; // Lesepuffer 1 größer als Codelänge
  int count=0; // Zeichenzähler
  if (!rfidSerial.available()) return; // Nix zu tun, return
  // Code ab hier wird nur ausgeführt, wenn ein Zeichen empfangen wurde
  memset(readbuffer,0,sizeof(readbuffer)); // Lesepuffer löschen
  while (rfidSerial.available() && count<CODESIZE) 
  {
    readbuffer[count]=rfidSerial.read(); // Zeichen auslesen
    count++; // Zeichenzähler erhöhen
    delay(2); // 2 Millisekunden auf das nächste Zeichen warten
  }
  while (rfidSerial.available()) rfidSerial.read(); // ggf. abschließendes CR überlesen
  if (strcmp(readbuffer,"05001023556709")==0)
    Serial.print("Valid code ");
  else  
    Serial.print("Invalid code ");
  Serial.println(readbuffer);  
}

void loop() {
  readRfid();
}

Guten Morgen,
Danke für den Tip.
atol() bringt mir bei beide Tag´s den wert 0 , zumindest printed er ihn.

void loop()
{
  long int Co;
: 
ursprünglicher Code wie oben
:
if(bytesread == codeLength) //Wenn alles empfangen
  {
    bytesread = 0;
    Co = atol(code);
    
    
    //if(strcmp(code, "05000604E2E50") == 0)  Serial.print("Station 1");

    //if(strcmp(code, "4F0088925E0B0") == 0) Serial.print("Station 2");
    
    Serial.print(Co);   
    Serial.println(code);  


  }
}

@ jurs,
Ich habe die Tags erst ausgelesen und den Code (im Programm auch "code") anzeigen lassen, da wirft er genau diese Werte aus.
Abzüglich der Null am Ende , wenn ich das richtig verstehe.

genau dieser Vergleich funktioniert ja in Bascom, also sollten die Tag-Werte doch stimmen.

Joschi1711:
@ jurs,
Ich habe die Tags erst ausgelesen und den Code (im Programm auch "code") anzeigen lassen, da wirft er genau diese Werte aus.
Abzüglich der Null am Ende , wenn ich das richtig verstehe.

genau dieser Vergleich funktioniert ja in Bascom, also sollten die Tag-Werte doch stimmen.

Ich habe in meinem Beitrag oben nochmal einen Sketch zum Testen angehängt, teste mal damit!

Ansonsten teste mit diesem ganz einfachen Test-Sketch, was eigentlich im seriellen Monitor ankommt:

#include <SoftwareSerial.h>

SoftwareSerial rfidSerial (11, -1); // RX, TX

void setup() {
  // put your setup code here, to run once:
  Serial.begin(9600);
  rfidSerial.begin(9600);
  Serial.println("Started");
}

void loop() {
  if (rfidSerial.available()) Serial.write(rfidSerial.read());
}

Will so auch nicht funktionieren,
der spuck bei dem einem Tag 05000604E2E5 aus, und genau den Wert habe ich zum Vergleich im Programm,
kommt immer Invalid.

Muss erscht mal auf Arbeit, heute Abend gehts weiter ^^.

Joschi1711:
Will so auch nicht funktionieren,
der spuck bei dem einem Tag 05000604E2E5 aus, und genau den Wert habe ich zum Vergleich im Programm,
kommt immer Invalid.

Wenn Dein Reader 12-stellige Codes ausspuckt, dann mußt Du in meinem oben geposteten Code nicht nur den Vergleichscode anpassen, sondern auch die Codegröße durch Änderung der Definition auf:

#define CODESIZE 12

Mein Code ist so wie ich ihn oben gepostet habe für Reader, die einen 14-stelligen Code liefern (2 Zeichen Hersteller-ID plus 12 Zeichen Tag-ID = 14 lesbare Zeichen plus ggf. ein unsichtbares CR als Zeilenende-Steuerzeichen).

Wenn es auch damit nicht hinhaut, dann lasse mal ein Datenblatt zum Reader rüberwachsen, was Du da eigentlich für Hardware hast:
Manche Reader betten gesendete Codes in spezielle Steuerzeichen ein (STX= Start Text, ETX= End Text), in dem Fall wird natürlich eine Leseroutine benötigt, die (im Optimalfall) exakt auf diese Steuerzeichen reagiert oder (notfalls) wenigstens die Steuerzeichen überliest, statt sie in den Vergleichs-String für die Codeprüfung einzulesen.

uwefed:
Müßte mit atol() gehen (Habs nicht probiert darum bitte mit Vorsicht geniesen)

atol() geht nur mit reinen Dezimal-Zahlen. Nicht mit Hex.

long test = atol("1AA") liefert 1

So Feierabend und weiter gehts hier,
Also zum Lesegerät: Hier mal das Datenblatt http://www.kibuck.com/RDM630-Spec.pdf
Der Code besteht demnach aus 10ASCII Data Characteren.

Joschi1711:
So Feierabend und weiter gehts hier,
Also zum Lesegerät: Hier mal das Datenblatt For Sale Domain: kibuck.com
Der Code besteht demnach aus 10ASCII Data Characteren.

Falls Du nicht das Wiegand-Interface aktiviert hast, das etwas anderes sendet, kommen über Serial von Deinem Modul insgesamt 14 Zeichen, davon 2 Steuerzeichen und 12 lesbare Zeichen, und zwar:

02 - STX (Steuerzeichen "Start of Text", unsichtbar im seriellen Monitor)
Kartennummer - 10 Zeichen
Prüfnummer - 2 Zeichen
03 - ETX (Steuerzeichen "End of Text", unsichtbar im seriellen Monitor)

Dazu kannst Du meinen Code verwenden, wenn Du die Anzahl der Zeichen auf 12 im Code setzt und die beiden Steuerzeichen am Anfang und am Ende des Codes überliest.

#include <SoftwareSerial.h>

SoftwareSerial rfidSerial (11, -1); // RX, TX

void setup() {
  // put your setup code here, to run once:
  Serial.begin(9600);
  rfidSerial.begin(9600);
  Serial.println("Started");
}

void readRfid()
#define CODESIZE 12
{
  char readbuffer[CODESIZE+1]; // Lesepuffer 1 größer als Codelänge
  int count=0; // Zeichenzähler
  if (!rfidSerial.available()) return; // Nix zu tun, return
  // Code ab hier wird nur ausgeführt, wenn ein Zeichen empfangen wurde
  memset(readbuffer,0,sizeof(readbuffer)); // Lesepuffer löschen
  while (rfidSerial.available() && count<CODESIZE) 
  {
    char c=rfidSerial.read(); // Zeichen auslesen
    if (c>=32)
    {
      readbuffer[count]=c;
      count++; // Zeichenzähler erhöhen
    }  
    delay(2); // 2 Millisekunden auf das nächste Zeichen warten
  }
  while (rfidSerial.available()) rfidSerial.read(); // ggf. abschließendes CR überlesen
  if (strcmp(readbuffer,"050010235567")==0)
    Serial.print("Valid code ");
  else  
    Serial.print("Invalid code ");
  Serial.println(readbuffer);  
}

void loop() {
  readRfid();
}

Das sollte hinhauen, aber ich kann es bei mir nicht testen.

Allerdings ist in dem Fall, dass wie bei Deinem Reader jeder Code mit einem eindeutigen Startcode beginnt, auch ein viel einfacherer Einlesecode möglich als bei meinem Code, der eigentlich für Reader mit anderem Sendeprotokoll vorgesehen ist, ohne speziellen Startcode vor der eigentlichen Kartennummer.

Ok jetzt zeigt er Invalid und Valid an, langsam kommen wir der Sache näher,
nur wie überlese ich die letzten Zeichen?
bei 4F0088925E0B ist glaube ich die Kartennummer 4F0088925E
also die letzten beiden Zeichen müssen wech.

strncmp():
http://www.cplusplus.com/reference/cstring/strncmp/

Hat einen zusätzlichen Parameter für die Anzahl der zu vergleichenden Zeichen

Ich denke mal jetzt geht es ^^
Habe einfach den CODESIZE auf 10 gesetzt und er spuckt die richtigen Kartennummern aus und vergleicht diese auch richtig.
Zum Sinn der ganzen Geschicht sei noch gesagt:
Das ganze wird ein Handscanner und die Tags sind an verschiedenen Stationen angebracht.
Diese Stationen sollen abgelaufen werden, an jeder Station wird beim erkennen des Tags die Position der nächsten ausgegeben.
sind an der letzten Station alle Tags eingelesen, bekommt man einen Code angezeigt, der zum "Entschärfen einer weiteren elektr. Bastelei benötigt wird.
Wer es nicht kennt, das Spiel nennt sich Geocaching ^^
Einen Reader mit dieser Funktion ist dort schon im Einsatz, doch der ist sehr unzuverlässig.

  1. Bascom geschrieben auf nem 4313, da passt nich viel rein
  2. Rfid Bausatz von Pollin, der sehr unsauber verarbeitet ist und einige Fehler im Aufbau enthält.

also bauen wir den ganzen Spass mit nem Arduino Micro.

Wenns fertig ist würde ich den Code auch hier reinsetzen, wenn jurs nichts dagegen hat, das ich seinen Codeanteil verwende???.

Ja, das geht auch. Aber nur wegen dieser Zeile:
while (rfidSerial.available()) rfidSerial.read();

Damit werden am Ende der Übertragung die restlichen Zeichen aus dem Empfangspuffer entfernt. Wenn das nicht wäre, würde er das Ende des gesendeten Strings als Anfang des nächsten interpretieren. :slight_smile:

Sei noch gesagt:
Das ist meine erster Kontakt mit nem Arduino und folglich mit diesem Forum hier.
Und ich muss sagen, sehr angenehm, wie man hier als Anfänger behandelt wird.
Das habe ich diese Wochen in einem anderen Forum (Linuxforum) ganz anders erlebt, da wird man gleich mal angemotzt von wegen die gesamten Grundlagen zu lernen.
Das finde ich für eine Bastelei etwas übertrieben.
Daher meinen Dank an die Poster und Antworter hier :slight_smile:

Joschi1711:
Habe einfach den CODESIZE auf 10 gesetzt und er spuckt die richtigen Kartennummern aus und vergleicht diese auch richtig.

Wenn Du die Prüfziffer des Rfid-Tags nicht überprüfst, ist es theoretisch möglich, dass eine falsche Kartennummer falsch gelesen wird und dabei der richtige Code herauskommt. Da es um keine sicherheitsrelavanten Prüfungen geht, möchtest Du die Gültigkeit der Prüfziffer offenbar auf Lücke setzen?

Joschi1711:
Wenns fertig ist würde ich den Code auch hier reinsetzen, wenn jurs nichts dagegen hat, das ich seinen Codeanteil verwende???.

Meinetwegen, keine Einwände. Allerdings wie gesagt: Für Deinen Readertyp mit dem speziellen Startcode-Zeichen ist prinzipiell auch ein einfacherer Einlesecode möglich, allerdings funktioniert dieser Code ganau so gut, belegt aber wohl ein paar Bytes mehr im Flash-Speicher als minimal notwendig wäre.

Wenn Du den Rfid-Code nicht von einer HardwareSerial Schnittstelle des Boards liest sondern von einer per Software emulierten SoftSerial, dann würde ich allerdings die standardmäßige SoftwareSerial Library rausschmeißen und stattdessen die "AltSoftSerial" Library verwenden. Die mitgelieferte SoftwareSerial ist nämlich extrem auf Naht genäht, der traue ich nicht wirklich über den Weg, z.B. wenn Deine Gerätschaften im Außenbereich zum Einsatz kommen sollen, mit stark schwankenden Temperaturen etc. Nicht, dass Dein Gerät im Hochsommer oder im Winter bei starkem Frost mit der SoftwareSerial Datenfehler produziert, wenn die Taktfrequenz des Arduino stärker von den nominellen 16 MHz abweicht als bei Zimmertemperatur.

Theoretisch brauche ich doch die SoftSerial im Einsatz dann gar nicht, da die Ausgabe über nen 2*16 LCD erfolgt?
habe ich das richtig verstanden, das ich bei Leonardo die Rx/Tx pins verwenden kann, wenn ich den USB port nicht benötige?

Ja und was wäre denn die einfachere Variante die Tags auszulesen?