Forum: Compiler & IDEs Mega164 und GCC: strstr() funktioniert nicht in while schleife


von rufus357 (Gast)


Lesenswert?

Hallo,
habe folgendes Problem. In meinem Unterprogramm GSM_wait() funktioniert 
die strstr Routine erst beim 2. Aufruf des Unterprogramms.

hier mein Code.
1
/////////////////////////////////////////////////////////////////////////////
2
// uint8_t GSM_wait(uint8_t z_ms)
3
//
4
// Rückgabe = 1: GSM_Ret in GSM Antwort gefunden
5
/////////////////////////////////////////////////////////////////////////////
6
uint16_t GSM_wait(uint16_t z_ms)
7
{
8
  uint16_t status;
9
  status=0;
10
  while(!(strstr(uart_rx_buffer, GSM_ret)))
11
  {
12
    if(status > z_ms)    
13
    {
14
      break;  
15
    }
16
    status++;
17
    _delay_ms(1);
18
    wdt_reset();
19
  }
20
  return status;
21
}
22
23
//------------------------------------------------------------------------
24
// void Start_SIMCOM(void)
25
// 
26
//------------------------------------------------------------------------
27
void Start_SIMCOM(void)
28
{
29
  GSM_ON();    // GSM einschalten
30
  GSM_ret_clr();          //Vergleichsbuffer löschen
31
  strcpy(GSM_ret, "OK\r\n");  // neuen Vergleichsstring in Buffer schreiben
32
  uart_rx_buffer_clr();   // seriell Eingangsbuffer löschen
33
  strcpy(COMGSM,"ATE0\r");  // AT Befehl in Ausgabebuffer schreiben
34
  uart_puts(COMGSM);        // AT Befehl an GSM Modul senden
35
36
  temp0_16=GSM_wait(5000); //max 5 sek. auf antwort warten.

Nach Ablauf des Programm bis hier her, kann ich auf dem rs232 monitordie 
Antwort nach ca. 2-3 sek. sehen. Nach weiteren 2-3 sek. stoppt das 
Programm durch einen Breakpoint auf die 2.  "GSM_wait(5000)" Routine. 
Jetzt kann ich im SRAM den Returnstring vom GSM sehen und den 
Vergleichsstring in "GSM_ret". Wenn ich jetzt mit F10 ("Step over" im 
AVR Studio4 ) die GSM_wait() Routine durchlaufe, bringt der strstr() 
Vergleich sofort das korrekte Ergebnis. D.h. der Returnwert liefert 0, 
was bedeutet, dass der strstr() Aufruf den "GSM_ret" String im 
"uart_rx_buffer" gefunden hat.
1
  temp0_16=GSM_wait(5000);  // zweiter Aufruf nur zur Fehlersuche
2
  GSM_Wake_up();
 usw.

Wo liegt mein Fehler. Ich steh im Moment föllig hilflos da und würde 
mich auf eure Hilfe sehr freuen.

Gruß
rufus357

von rufus357 (Gast)


Lesenswert?

Hallo nochmal,

der Kopftext war im obigem Text nicht korrekt. Ändert nichts am 
Fehlverhalten, führt aber eventuell zu unnötiger Diskusion.
1
/////////////////////////////////////////////////////////////////////////////
2
// uint8_t GSM_wait(uint8_t z_ms)
3
//
4
// Rückgabe = Zeit in ca. ms bis string gelesenvergleich ok war. Sonst z_ms+1
5
/////////////////////////////////////////////////////////////////////////////

Gruß
rufus357

von Hel Fer (Gast)


Lesenswert?

rufus357 schrieb:
> D.h. der Returnwert liefert 0,
> was bedeutet, dass der strstr() Aufruf den "GSM_ret" String im
> "uart_rx_buffer" gefunden hat.


Das manual sagt aber was anderes:

     The strstr() function returns a pointer to the beginning of the
     substring, or NULL if the substring is not found. If s2 points to a
     string of zero length, the function returns s1.

von rufus357 (Gast)


Lesenswert?

Danke für deine schnelle Antwort Hel Fer.

Das seh ich auch so.
Um so mehr verwirrt das Verhalten der while Schleife mich.
In der Schleife wird in diesem Fall (z_ms = 5000) solange durchlaufen, 
bis GSM_ret in uart_rx_buffer gefunden, oder der Timeout Zähler (z_ms) 
überschritten wird. In meinem Fall liefert strstr() immer NULL, obwohl 
GSM_ret in uart_rx_buffer bereits nach max 2-3 sek. gefunden werden 
müsste.
Denn der Return Wert ist am Ende 5001. D. h. die while Schleife wurde 
durch den break in if() beendet.
1
  while(!(strstr(uart_rx_buffer, GSM_ret)))
2
  {
3
    if(status > z_ms)    
4
    {
5
      break;  
6
    }
7
    status++;
8
    _delay_ms(1);
9
    wdt_reset();
10
  }

oder ????

Gruß
rufus357

von Walter S. (avatar)


Lesenswert?

der Buffer wird ja wohl in einem Interrupt gefüllt,
da kannst du doch nicht gleichzeitig vergleichen??

von rufus357 (Gast)


Lesenswert?

Hallo Walter,

das stiimmt. Jedoch wird dieser vergleich im millisekunden Takt 
wiederholt. Der Puffer enthällt den kompletten String nach spätestens 3 
sek. Ich dachte das müsste so funktionieren, denn ich leere den Puffer 
ja zwischenzeitlich nicht.

Ist das nicht so???

Gruß
rufus357

von Walter S. (avatar)


Lesenswert?

vielleicht wird der String zu schnell wieder neu gefüllt dass du gar 
keine gelegenheit zum vergleich mit dem richtigen string hast.
Ich würde es erst mal sauber programmieren:
wenn der String da ist setzt du ein Flag, dann erst vergleichen und dann 
erst den string wieder freigeben.

von rufus357 (Gast)


Lesenswert?

Hallo Walter,
das kann nicht sein, da ich in meinem rs232 Monitor die Kommunikation 
sehe und auf mein AT-Befehl nur die erwartete Antwort 
"ATE0\r\n\r\nOK\r\n" zurück kommt

Der Ablauf ist so:

- "GSM_ret" löschen und den Vergleichsstring "OK\r\n" hinein schreiben.
- "uart_rx_buffer" löschen. (Platz für 160 char).
- "COMGSM" (Sendepuffer) mit AT-Befehl "ATE0\r" beschreiben.
- Inhalt "COMGSM" an GSM senden.
- mit Aufruf "GSM_wait(5000)" max 5 sek. warten, bis der Antwortstring 
angekommen ist.

Ich habe den Algorithmus der "GSM_wait" Routine zum Test direkt in mein 
Aufrufer Programm kopiert. Dort funktioniert der Algorithmus. Mein 
Zähler der den Rückgabewert enthält steht zuverlässig auf 122. D.h. nach 
ca. 122 ms wird der Vergleichstring gefunden.

Woran kann das liegen. Jetzt versteh ich gar nicht mehr. Liegt vieicht 
auch an der vorgerückten Zeit.

freundliche Grüße und eine gute Nacht
rufus357

von Karl H. (kbuchegg)


Lesenswert?

rufus357 schrieb:
> Hallo Walter,
>
> das stiimmt. Jedoch wird dieser vergleich im millisekunden Takt
> wiederholt. Der Puffer enthällt den kompletten String nach spätestens 3
> sek. Ich dachte das müsste so funktionieren, denn ich leere den Puffer
> ja zwischenzeitlich nicht.


Zeig mal deine Empfangsroutine.
Wenn du zwischendurch Stringfunktionen da drauf ansetzen willst, dann 
muss zu jedem Zeitpunkt, auch nach dem Empfang des nächsten Zeichens, 
gewährleistet sein, dass der String auch gültig ist ... sprich, dass er 
das obligatorische \0 Zeichen am Stringende hat. Ist das in deiner 
Empfansgroutine berücksichtigt?

von rufus357 (Gast)


Lesenswert?

Hallo Karl Heinz,

Danke für deinen Hinweis. Dieser hat mich auf einen anderen Denkfehler 
gebracht. Ich lösche den Puffer grundsätzlich durch das Beschreiben mit 
\0, bevor ich diesen verwende. Somit ist auf jeden Fall ein String 
Terminator am Ende des Strings. Zusätzlich frage ich das vom GSM Modul 
immer am Ende gesendete \n ab, um danach ein \0 anzuhängen.
1
 
2
ISR(USART0_RX_vect) 
3
{
4
    uint8_t data;
5
   
6
    // Daten auslesen, dadurch wird das Interruptflag gelöscht              
7
    data = UDR0;
8
  if (uart_rx_cnt<(uart_buffer_size-1))          // Ist Puffer nicht voll ? 
9
  {     
10
           // Daten in Puffer speichern
11
           // aber durch if() Pufferüberlauf vermeiden
12
    uart_rx_buffer[uart_rx_cnt]=data;          
13
    uart_rx_cnt++; // Zähler erhöhen
14
    if (data=='\n')
15
    {
16
      //ja, dann String terminieren
17
      //uart_rx_buffer[uart_rx_cnt]="\0";              
18
        }
19
  }
20
}

Der o. g. Denkfehler war das Abfragen von \n, denn der Antwortstring vom 
GSM Modul ist grundsätzlich "<CR><LF><response><CR><LF>". also habe ich 
die String Terminierung in der Eingangsrouting auskommentiert.
Doch mein Problem bleibt das selbe.

Ich habe die Warte Routine umgeschrieben in eine Routine ohne 
Aufrufparameter und den Wartezeitwert als Konstante festgelegt, was im 
normalfall keine Rolle spielt, dann funktioniert die strstr() Funktion. 
Kannst Du dir einen Reim darauf machen? Ich würde das gerne verstehen. 
Ich hänge die Warteroutine mal unten hin. Vileicht siehst Du mit Deiner, 
von mir sehr geschätzten Erfahrung, mein Fehler.

Auskommentiert = nicht funktionierender Programmteil
1
uint16_t GSM_wait(void/*uint16_t z_ms*/)
2
{
3
/*  uint16_t status;
4
  status=0;
5
  while(!(strstr(uart_rx_buffer, GSM_ret)))
6
  {
7
    if(status > z_ms)    
8
    {
9
      break;  
10
    }
11
    status++;
12
    _delay_ms(1);
13
    wdt_reset();
14
  }
15
*/
16
  temp0_16=0;
17
  while(!(strstr(uart_rx_buffer, GSM_ret)))
18
  {
19
    if(temp0_16 > 5000)    
20
    {
21
      break;  
22
    }
23
    temp0_16++;
24
    _delay_ms(1);
25
    wdt_reset();
26
  }
27
  return temp0_16;
28
}

Vielen Dank und Gruß
rufus357

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.