Hallo
Ich arbeite an einem Projekt mit RFID per RS485.
Ich erhalte vom RFID Empfänger folgenden String: 3% 3UA 0107777C80 J
Wobei 3% die Adresse des Empfängers repräsentiert (Adr 53) und 0107777C80 die ID des Tags.
Nun soll die ID mit der Adresse verglichen werden und wenn es die richtige ID zur Adresse ist einen Event
auslösen. (Zb. Einen UDP Befehl senden oder RS232 String senden, oder ganz simpel eine Lampe für
5sek auf Grün leuchten lassen.)
Kann mir da jemand einen Tip geben was ich dafür benötige? Und wie das Programmier technisch am
einfachsten umzusetzen wäre? Ich habe mindestens 30 RFID Empfänger am laufen und ebensoviele
Tags.
Vielen Dank
thomas
Hallo Thomas,
Hier mein Vorschlag:
Stelle zuerst sicher, dass die Daten "vertrauenswürdig sind. Ob dies eine Checksumme ist, oder ob du dies für unnötig erachtest ist alles dir überalles, aber dies muss unser Ausgangspunkt sein.
Ist dies gegeben solltest du ja wissen, an welcher Stelle dieses Strings, welcher ja nichts anderes als ein Array ist, sich welche Daten befinden. Dann kannst du einfach über ein Switch/case Statement, jenachdem ob ID und Adresse zusammenpassen, eine Routine aufrufen.
Gruss
Felix
Das funktioniert, wenn du im Serial Monitor ein LF/newline als Endzeichen sendest (und nur dann!!). Kann man im Code aber auch auf andere Endzeichen umstellen (END_CHAR Konstante):
const int READ_BUFFER_SIZE = 30; //muss groß genug für längsten String + 1 sein
char serialBuffer[READ_BUFFER_SIZE];
const char END_CHAR = '\n'; //Endzeichen. Hier nur ASCII-Steuerzeichen
void setup()
{
Serial.begin(9600);
}
void loop()
{
if (readSerial(Serial))
{
parseSerial();
}
}
void parseSerial()
{
Serial.print(F("String: ")); Serial.println(serialBuffer);
unsigned int adr = atoi(strtok(serialBuffer, " ")); //erstes Token in Integer wandeln
strtok(NULL, " "); //zweites Token verarbeiten, aber nichts damit machen
char* id = strtok(NULL, " "); //Zeiger auf drittes Token
Serial.print(F("Adresse: ")); Serial.println(adr);
Serial.print(F("Id:")); Serial.println(id);;
//id vergleichen. Das geht nicht mit == !!
if (strcasecmp_P(id, PSTR("0107777C80")) == 0) //liefert bei Gleichheit 0. Ignoriert Groß-/Kleinschreibung
Serial.println(F("Id richtig"));
else
Serial.println(F("Id falsch"));
}
bool readSerial(Stream& stream)
{
static byte index;
while (stream.available())
{
char c = stream.read();
if (c >= 32 && index < READ_BUFFER_SIZE - 1)
{
serialBuffer[index++] = c;
}
else if (c == END_CHAR && index > 0)
{
serialBuffer[index] = '\0';
index = 0;
return true;
}
}
return false;
}
Das hier:
53 3UA 0107777C80
Liefert:
String: 53 3UA 0107777C80
Adresse: 53
Id:0107777C80
Id richtig
Die Adresse wird in einen Integer gewandelt und kann einfach mit == verglichen werrden. Die ID lässt man aufgrund der Größe besser als String. Dafür braucht man dann eine Funktion aus der strcmp() Familie zum Vergleich
Wobei mir nicht ganz klar ist wie du von 3% auf 53 kommst. Tip-Fehler?
Hallo zusammen
Erstmal vielen Dank für die Antworten.
Die Daten sind vertrauenswürdig da es sich in einem geschlossenem System befindet. Auch die Checksumme ist nicht wirklich relevant. Wichtig ist nur die Adresse des Empfängers und die ID des Tags.
Das projekt geht um einen Tisch auf dem man ein Skelett zusammenbaut und der Benutzer über die Richtige oder falsche Position ein Visuelles und Akustisches Feedback erhält.
Habt ihr mir noch einen Tip welches Arduinomodell für meinen Fall am besten geeignet wäre? mit Rs 485 schnittstelle und der Möglichkeit der ausgabe über Gpio oder Relais.
@ Serenifly nein ist kein Tipfehler. Aber ich habe auch gestaunt über die Adresenzusammenstellung.
Ich werde noch beim Vertrieb nachfragen (IDTRONIC, R-OEM-LF-M800-485
125 kHz OEM RFID Module) denn auch aus dem Manual werde ich nicht ganz schlau wie das zusammengesetzt wird.
Zur Info:
Each terminal has an address included between 001 and 255; in the multipoint communication the address of the terminal is defined by 2 ASCII digits, both included between '0' and '?' (between 30 and 3f hexadecimal) in case of selecting.
In case of polling the first digit is the same as per the first selecting digit, while the second can be obtained by changing the dozens (from 3 to 2) of the second selecting digit.
For example the selecting address of the terminal 53 is “35” (33, 35 hexadecimal). The related polling address is “3%” (33,25 hexadecimal).
In case of global selecting the 2 address digits will be "``" (60,60 hexadecimal).
Vielen Dank
Thomas
Ok, die nehmen wohl alle ASCII Zeichen als gültige Ziffer. Etwas seltsam, aber ok.
Dann wandele das an der Stelle nicht per atoi() in einen Integer, sondern mach auch einen Vergleich mit einem String wie bei der ID.
Also sowas in der Art:
char* adr = strtok(serialBuffer, " ");
if (strcmp_P(adr, PSTR("3%")) == 0)
{
}
Hier nimmt man besser nicht strcasecmp(), da man evtl. zwischen Groß- und Kleinbuchstaben unterscheiden muss
Das normale strcmp() würde es bei dem kurzen String auch tun:
if (strcmp(adr, "3%") == 0)
{
}
Belegt nur 3 Byte RAM mehr
Wobei man das wohl auch irgendwie in eine richtige Zahl umrechnen kann. So richtig verstehe ich das aber auch nicht.
Wäre für zwei feste Zeichen nicht ein Zeichenvergleich sparsamer und auch schneller?
if (adr[0] == '3' && adr[1] == '%') {
}
Geht natürlich auch, aber so extrem optimieren muss man da nicht.
Einen Vergleichs-String zu haben hätte den Vorteil, dass man ihn global als Makro oder Konstante definieren kann.
Statt der Konstanten könnte man natürlich genauso einen globalen Array benutzen, da würde man dann sogar die abschließende '\0' sparen.
const char muster[2] = {'3', '%'};
if (adr[0] == muster[0] && adr[1] == muster[1]) {
}
Hm, diese Optimierungen beim Vergleichen sind ja ganz nett, aber da scheint ein anderer Flaschenhals zu sein.
Verstehe ich das richtig, dass da 30 von diesen Empfängern an einer RS485 hängen ? Für verschiedene Positionen auf dem Tisch ?
Ich hab mal in die Anleitung geschaut, die arbeiten standardmäßig mit 19200 Baud, möglich sind maximal 38400.
Wenn der Master der Reihe nach 30 Clients pollt dauert das natürlich seine Zeit.
Die Empfänger haben auch einen Eventmodus, aber wie verhindert man dann bei RS485, dass mehrere Clients gleichzeitig senden. Das ist ja kein CAN, wo die Hardware Kollisionen vermeidet.