Go Down

Topic: eingelesenen Sring richtig identifizieren (Read 647 times) previous topic - next topic

Kornfeld

Hi

ich habe bis jetzt ein Programm, welches einen String seriell empfängt.

Der empfangene String im Buffer sieht wie folgt aus: "Neustart" +CR +LF.

ich möchte nun in einer if anweisung diesen (wenn er denn kommt) erkennen und einen weiteren Befehl senden.

Wie kann ich den String vollständig darstellen, so das er erkannt wird?

Ich habe es so probiert:

Code: [Select]


if(serialBuffer == "Neustart" + CR + LF)
  {
    Serial1.print(STX);
    Serial1.print(Eins);
    Serial1.print(Sechs);
    Serial1.print(Semi);
    Serial1.print(Semi);
    Serial1.print(D);
    Serial1.print(D);
    Serial1.print(ETX);
  }
 


also das es so nicht stimmen kann.. weiss ich selbst... sieht schon kurios aus.. bzw. da ich CR als
Code: [Select]
char CR = 13;
definiert habe probiert er an der stelle irgendwas zu rechnen oder so..

Danke für eure antworten!!

Peter_n

CR = '\r'
LF = '\n'

You can test for "Neustart\r\n".

To write a single character like CR or STX, it is easier to use the Serial.write() function.

Kornfeld

THX for your fast reply...

But it is still not working.. I tried every combination.. "Neustart" ; "Neustart\r" ; "Neustart\r\n"


Peter_n

You have to post the whole sketch. Or you can make a small test-sketch.
I don't know what "serialBuffer" is, and how it is filled.

Serenifly

#4
Jul 15, 2014, 11:37 am Last Edit: Jul 15, 2014, 12:29 pm by Serenifly Reason: 1
Das ist Schwachsinn:
Code: [Select]

(serialBuffer == "Neustart" + CR + LF)


Damit addierst du 10 + 13 auf die Adresse des Strings. Dann vergleichst du die zwei Zeiger. Die sind natürlich ungleich.

C Strings werden mit strcmp() verglichen:
http://www.c-howto.de/tutorial-strings-zeichenketten-stringfunktionen-vergleichen-strcmp.html
http://www.cplusplus.com/reference/cstring/strcmp/

Wenn die Funktion 0 zurück liefert sind die Strings gleich. Idealerweise nimmt man dann auf dem AVR noch strcmp_P() und das PSTR() Makro damit der Vergleichs-String kein RAM belegt:
Code: [Select]

if(strcmp_P(serialBuffer, PSTR("Neustart")) == 0)



Vorsicht übrigens wenn du den Code direkt von mir nimmst. Der speichert CR/LF nicht im Array ab. Entsprechend kannst du nicht abfragen ob die im String enthalten sind. Das sollte aber unnötig sein. Wenn du den Text hast, weißt du eigentlich ob es korrekt gesendet wurde. Ob da die Steuerzeichen mit drin sind oder nicht, ist egal. Daher einfach auf "Neustart" vergleichen, ohne die Steuerzeichen. Damit sparst du dir den Aufwand das Programm anzupassen und es funktioniert genauso.

Ansonsten diese Tabelle wie man Sonderzeichen wie CR und LF in einem String Literal schreibt:
http://en.wikipedia.org/wiki/Escape_sequences_in_C#Table_of_escape_sequences

Kornfeld

Hi,

the whole code is:

Code: [Select]
char Null = 48;
char Eins = 49;
char Zwei = 50;
char Drei = 51;
char Vier = 52;
char Fuenf = 53;
char Sechs = 54;
char Sieben = 55;
char Acht = 56;
char Neun = 57;
char A = 65;
char B = 66;
char C = 67;
char D = 68;
char CR = 13;
char LF = 10;
char Semi = 59;
char STX = 2;
char ETX = 3;


const int SERIAL_BUFFER_SIZE = 81;
char serialBuffer[SERIAL_BUFFER_SIZE];

void setup(){
  Serial.begin(4800);
  Serial1.begin(4800);
}

void loop()
{
   if(readSerial())
       processSerial();
}

bool readSerial()
{
static unsigned int index;

if(Serial.available() > 0)
{
char c = Serial.read();

        if(c >= 32 && index < SERIAL_BUFFER_SIZE - 1)
{
serialBuffer[index++] = c;
}
                else if(c == '\r')
{
serialBuffer[index] = '\0';
index = 0;
return true;
}
}
return false;
}

void processSerial()
{
  if(serialBuffer == "Neustart\r\n")
  {
    Serial1.print(STX);
    Serial1.print(Eins);
    Serial1.print(Sechs);
    Serial1.print(Semi);
    Serial1.print(Semi);
    Serial1.print(D);
    Serial1.print(D);
    Serial1.print(ETX);
  }
 
}


@serinifly ja das es absoluter schwachsinn das hab selbst ich schon irgendwo gesehen... ich werde das mit dem
Code: [Select]
if(strcmp_P(serialBuffer, PSTR("Neustart")) == 0)
mal direkt ausprobieren!

Kornfeld

Hey Serenifly,

du hast mal wieder auf anhieb absolut recht!! Danke dir für deine schnelle und vor allem gute Hilfe!!

MfG Stefan

Scherheinz

Hallo!
Ich kram das hier mal aus weil ich ein ähnliches Problem habe. Ich benutze ein GSM Shield und bekomme Meldungen wenn z.b. ein Anruf eingeht. Und zwar ein "RING" für jedes Klingeln und wenn ich auflege "MISSED_CALL......."  Ich möchte nun bei einem Anruf eine Funktion starten was auch soweit funktioniert solange ich auf das Wort "RING" warte.
Code: [Select]

if(strcmp_P(serialBuffer, PSTR("RING")) == 0)


Ich würde aber gern erst reagieren wenn wieder aufgelegt wurde und auch nur bei einer bestimmten Nummer, ich weiß aber nicht wie ich das rausgefiltert bekomme. Hat kann mir da jemand helfen?



Serenifly

#8
Jul 25, 2014, 06:49 pm Last Edit: Jul 25, 2014, 06:53 pm by Serenifly Reason: 1
es gibt noch strncmp():
http://www.cplusplus.com/reference/cstring/strncmp/
Damit vergleichst du die ersten n Zeichen. Damit könntest du abfragen ob der String mit "MISSED_CALL" anfängt.

Was auch reichen würde ist strstr():
http://www.cplusplus.com/reference/cstring/strstr/
Das sucht zwar den kompletten String durch, aber hier macht das keinen Unterschied

Gibt es auch beide mit der _P Version.

Um die Nummer zu bekommen kann man das z.B. das machen:
Code: [Select]

char str[] = "MISSED_CALL 00:00AM 0123456789";

char* ptr = strtok(str, " ");
ptr = strtok(NULL, " ");
ptr = strtok(NULL, " ");

Danach zeigt ptr auf die '0' in der Nummer am Ende. Also den Rest des Strings. Und dann kann man wieder mit strcmp(ptr, ...) auf einen String vergleichen. Oder auch Serial.println(ptr) machen.

Alternativ geht in diesem Fall auch strchr() statt strtok(), da der gesuchte String am Ende steht:
Code: [Select]

char* ptr = strchr(str, ' ');
ptr = strchr(ptr + 1, ' ');
ptr++;

Gleiches Ergebnis wie oben.

Der Unterschied ist das strtok() einen Zeiger auf das nächste Token (Teil-String liefert) und den Teil-String terminiert, während strchr() einen Zeiger auf das Leerzeichen selbst liefert. Deshalb muss man nochmal 1 drauf addieren.


Oder am besten gleich strrchr() (r = reverse):
Code: [Select]

char* ptr = strrchr(str, ' ');
ptr++;

Das durchsucht den String von hinten, wodurch man nur einen Aufruf braucht :)

sschultewolter

#9
Jul 25, 2014, 06:54 pm Last Edit: Jul 25, 2014, 06:58 pm by sschultewolter Reason: 1
http://openbook.galileocomputing.de/c_von_a_bis_z/011_c_arrays_013.htm#mjd148b11ca58a4e84fc80121d3c99dbdf

Code: [Select]
int strcmp(const char *s1, const char *s2);


Code: [Select]

/* strcmp.c */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

void String_Vergleich(char s1[], char s2[]) {
  int ret = strcmp (s1, s2);
  if(ret == 0)
     printf("%s == %s\n", s1, s2);
  else
     printf("%s %c %s\n",s1,( (ret < 0) ?'<' :'>'), s2);
}

int main(void) {
  char str1[] = "aaa";
  char str2[] = "aab";
  char str3[] = "abb";

  String_Vergleich(str1, str2);
  String_Vergleich(str1, str3);
  String_Vergleich(str3, str2);
  String_Vergleich(str1, str1);
  return EXIT_SUCCESS;
}


Verstehe jetzt nicht richtig, was du genau vorhast, was du machen kannst,

str1 entspricht deinem RING, oder MISSED_CALL, welches du einliest.
strArray1[MAX_NUMMERN] entspricht einer liste von Telefonnummern

if(strcmp(str1, "MISSED_CALL") {
     for(int i = 0; i < INDEX; i++) if (strcmp(strArray1) // do something
}

Du musst natürlich dann auch entsprechend deine Telefonnummer auslesen und in ein einzelnen String kopieren.

Du kannst aber auch mit strpbrk() arbeiten, ebenfalls in dem Link. Dann kannst du einmal nach MISSED_CALL oder RING suchen und entsprechend eine Variable setzen. Des weiteren kannst du auch nach einer Telefonnummer dann suchen. Macht es evtl. ein bisschen einfacher.

Wenn mir keiner zuvor kommt, kann ich dir nachher einen kleinen Beispielcode geben.


Edit: Mist, Serenfly war schneller ;)
Keinen technischen Support über PN!

Serenifly

#10
Jul 25, 2014, 06:58 pm Last Edit: Jul 25, 2014, 07:01 pm by Serenifly Reason: 1
Das geht so wahrscheinlich nicht. Er hat so wie es aussieht einen String der mit "MISSED_CALL" anfängt.

Man braucht also strncmp():
Code: [Select]

if(strncmp_P(str, PSTR("MISSED_CALL"), 11) == 0)
{
}


Man kann die Länge des Strings mit strlen_P() bestimmen. Ist aber unnötig.


strpbrk() ist noch ne Option, ja. Wobei das eigentlich nur eine Variation von strchr() ist, mit der man nach mehreren Zeichen suchen kann. Was hier nicht nötig ist. Da gibt es zig Möglichkeiten. Man könnte auch per Hand drüber iterieren :)

In diesem Fall würde ich zu strrchr() raten, da der gesuchte String am Ende steht :)

Scherheinz

danke ihr zwei!! Das sind ja mehr Möglichkeiten als ich wollte  8)
Werde morgen mit dem Durchtesten anfangen, melde mich dann wieder!

Gruß

Serenifly

#12
Jul 25, 2014, 09:34 pm Last Edit: Jul 26, 2014, 09:48 am by Serenifly Reason: 1
Um das klar zu machen. Du musst zwei verschiedene Sachen machen:

1.) Testen ob der Teil-String "MISSED_CALL" enthalten ist. Das geht mit strncmp() (String n Compare) oder strstr() (String String). Am saubersten ersteres.

2.)  Wenn ja, den Teil-String der Telefon-Nummer suchen. Da diese unbekannt ist, geht man im String einfach zwei Leerzeichen nach rechts. Das geht mit strtok() (String Tokenizer), strchr() (String Character) oder hier am einfachsten mit strrchr() (String Reverse Character).
Mit diesem Zeiger aud den Teil-String kann man dann wieder strcmp() mit der Nummer machen.


Man könnte eigentlich auch gleich mit strstr() überprüfen ob die gewünschte Nummer irgendwo im String enthalten ist. Das ist aber irgendwie nicht schön. Und so könnte man noch andere Sachen machen. Mit strtok() könnte ma z.B. auch die Anrufzeit ausgeben.

Scherheinz

danke für den Tipp! Hatte es eben einfach mal mit strstr() und strcmp_P() probiert und es hat auf Anhieb funktionert. Bei Gelegenheit teste ich noch die anderen Funktionen aus.  :)

Danke und Gruß!


Serenifly

#14
Jul 26, 2014, 08:19 pm Last Edit: Jul 26, 2014, 09:41 pm by Serenifly Reason: 1
Wenn du die Telefon-Nummer gleich mit strstr() suchst, braucht du sie nicht noch mal zusätzlich mit strcmp() zu vergleichen. strstr() gibt dir NULL zurück wenn der String nicht drin ist und einen Zeiger auf den Anfang des Strings wenn ja. Wenn du also etwas anderes als einen NULL-Zeiger hast, dann weißt du dass der String enthalten ist und braucht ihn nicht nochmal zu vergleichen.

Der Unterschied ist folgender: str(n)cmp() fängt immer am Anfang des Strings an zu suchen und wenn der String nicht gleich am Anfang steht gilt er als nicht vorhanden. strstr() sucht überall im String.

Da hatte ich wohl etwas zuweit ausgeholt. Dass man strstr() auch gleich für die Telefon-Nummer nehmen könnte ist mir erst später gedämmert :)
Je nachdem was man genau will, kann es aber auch aber vielleicht auch sinnvoll sein erst mal nach "MISSED_CALL" zu suchen.


Es gibt übrigens auch strstr_P(). Genauso gibt es _P Versionen für eigentlich alle anderen String Funktionen denen man einen festen Vergleichs-String übergibt. Die _P Versionen funktionieren im Prinzip genauso, aber man übergibt halt das String Literal per PSTR() Makro als PROGMEM Konstante, damit es kein RAM belegt.
Das ist nicht immer essentiell, aber man verschwendet auch schnell mehrere hundert Bytes RAM wenn man das nicht macht. Wenn man dann noch RAM-intensive Libs verwendet, kann das problematisch werden.

Go Up