Go Down

Topic: Arduino verarbeiten von RS485 String (Read 1 time) previous topic - next topic

clerkgable

Hallo

Ich arbeite an einem Projekt mit RFID per RS485.

Ich erhalte vom RFID Empfänger folgenden String: <STX> 3% 3UA 0107777C80 <ETX> 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

Aresloom

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

Serenifly

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):

Code: [Select]

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:
Code: [Select]

53 3UA 0107777C80

Liefert:
Code: [Select]

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?

clerkgable

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


Serenifly

#4
Jul 07, 2016, 07:37 pm Last Edit: Jul 07, 2016, 07:41 pm by Serenifly
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:
Code: [Select]

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:
Code: [Select]

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.

Whandall

#5
Jul 07, 2016, 08:57 pm Last Edit: Jul 07, 2016, 09:08 pm by Whandall Reason: ein ' vergessen
Wäre für zwei feste Zeichen nicht ein Zeichenvergleich sparsamer und auch schneller?
Code: [Select]
if (adr[0] == '3' && adr[1] == '%') {
}
Ah, this is obviously some strange usage of the word 'safe' that I wasn't previously aware of. (D.Adams)

Serenifly

#6
Jul 07, 2016, 09:00 pm Last Edit: Jul 07, 2016, 09:01 pm by Serenifly
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.

Whandall

Statt der Konstanten könnte man natürlich genauso einen globalen Array benutzen, da würde man dann sogar die abschließende '\0' sparen.
Code: [Select]
const char muster[2] = {'3', '%'};

if (adr[0] == muster[0] && adr[1] == muster[1]) {
}
Ah, this is obviously some strange usage of the word 'safe' that I wasn't previously aware of. (D.Adams)

ArduFE

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.

Go Up