eingelesenen Sring richtig identifizieren

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:

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

char CR = 13;

definiert habe probiert er an der stelle irgendwas zu rechnen oder so..

Danke für eure antworten!!

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.

THX for your fast reply...

But it is still not working.. I tried every combination.. "Neustart" ; "Neustart\r" ; "Neustart\r\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.

Das ist Schwachsinn:

(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.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:

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:

Hi,

the whole code is:

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

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

mal direkt ausprobieren!

Hey Serenifly,

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

MfG Stefan

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.

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?

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:

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:

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

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

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

int strcmp(const char *s1, const char *s2);
/* 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 :wink:

Das geht so wahrscheinlich nicht. Er hat so wie es aussieht einen String der mit "MISSED_CALL" anfängt.

Man braucht also strncmp():

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

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

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

Gruß

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.

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. :slight_smile:

Danke und Gruß!

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 :slight_smile:
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.

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.

Ok nur nochmal zum Verständnis. Ich bekomme ein "NULL" zurück wenn im String nichts gefunden wird. Wenn was gefunden wird, steht der Zeiger dann auf dem Anfang des Strings oder auf dem Anfang der "Telefonnummer" die ja eh mit einer "0" beginnt.?
Das würde dann bedeuten das ich die "0" am Anfang der Nummer nicht mitsuchen dürfte. Weißt du was ich meine?

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 smiley

Macht nix, ich bringe mich meist eh selbst durcheinander. XD

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.

Ok, braucht mehr RAM, hab ich verstanden, der Rest übersteigt mein Wissensstand :cold_sweat:
Das Gute ist das ich nicht eine Lib brauche da alles nur über AT-Befehle läuft. Also RAM hab ich noch genug, aber danke für den Tipp!
Eigentlich geht es nur darum das bei einem Anruf von meiner Nummer die GPS Daten abgerufen werden und zusammen mit der Akku Spannung per SMS an mein Handy gesendet werden.

Scherheinz:
Wenn was gefunden wird, steht der Zeiger dann auf dem Anfang des Strings oder auf dem Anfang der "Telefonnummer" die ja eh mit einer "0" beginnt.?

Der Zeiger zeigt auf den Anfang des gesuchten Strings in dem Arrays das du durchsuchst. z.B.:

char str[] = "123456789";
char* ptr = strstr(str, "45");

ptr zeigt danach auf die '4' in str. Wenn du Serial.println(ptr) machst kommt "456789" raus.

Das würde dann bedeuten das ich die "0" am Anfang der Nummer nicht mitsuchen dürfte.

Nein. NULL != '0'

NULL ist wirklich 0 in ASCII. '0' ist 48:

Außerdem ist das ein Zeiger. Das ist eine 16 Bit Variable die die Adresse einer Speicherzelle enthält. Mit dem Inhalt des Speichers hat das erst mal nichts zu tun. Die bekommst einen Zeiger zurück der 0 ist. Nicht einen Zeiger auf eine Speicherzelle in der 0 steht.

In dem Beispiel oben ist ptr die Adresse und *ptr ist der Inhalt. Das hier würde die '4' überschreiben:

char str[] = "123456789";
char* ptr = strchr(str, '4');     //Zeiger auf '4', d.h. die Adresse der Speicherzelle in der die '4' steht
*ptr = '1';       //'4' mit '1' ersetzen

ptr = '4' würde die Adresse selbst auf '4', d.h. auf 52, setzten. Das wäre ein schlimmer Fehler

Oder wenn man den Rest des String abschneiden möchte:

char str[] = "123456789";
char* ptr = strstr(str, "45");
*(ptr + strlen("45")) = 0;      //Inhalt der Adresse die von ptr + Stringlänge adressiert wird auf 0 setzen

Strings sind NULL-terminiert. Das heißt die Bearbeitung wird beendet wenn NULL/0/'\0' auftritt. Man könnte also den Anfang von "45" suchen und dann die Länge von "45" (2) auf den Zeiger addieren. Der Zeiger zeigt dann auf die '6'. Diese Adresse dereferenziert man (mit dem Stern) und schreibt 0 rein (nicht '0'!).
Wenn man dann str ausgibt kommt "12345" heraus.

NULL ist wirklich 0 in ASCII. '0' ist 48:
http://www.ascii-code.com/

Schande über mein Haupt!!

Alles klar jetzt hab ich es geschnallt! Das ist ja cool, dann kann ich mir ja jeden String zurechtschneiden wie ich ihn gerade brauch.
Vielen Dank nochmal!!

Gruß