Forum: Mikrocontroller und Digitale Elektronik Probleme mit String


von P. F. (pfuhsy)


Lesenswert?

Hallo,

ich habe folgendes Problem. Ich hab die unten angegebene Funktion in 
mein µC geladen. Der Spricht über UART mit einem GSM-Modul. Diese 
Funktion wird aufgerufen, um einen Status des Moduls abzufragen. Doch 
komischerweise, bekomme nichts zurück (sehe ich über die vorletzte Zeile 
"putString(Rueckgabe)".
1
char *Status(char *AT_Befehl, char *Antwort, int TimeOut)
2
{
3
  char *Rueckgabe = NULL;
4
  int i = 0;
5
6
  Puffer_loeschen();              //Puffer löschen
7
  putString(AT_Befehl);            //AT-Befehl senden
8
  waitMs(TimeOut);              //etwas warten
9
10
  while(!(strstr (_buffer, Antwort)))      //falls vorhanden Antwort prüfen
11
  {
12
    waitMs(1000);              //etwas Zeit verbummeln beim warten
13
    
14
    //falls die Zeit überschritten wird, "Error" als Rückgabewert übertragen und
15
    //die Schleife vorzeitig beenden. Sonst kann es zu Endlosschleifen kommen.
16
    if (i>=10)     
17
    {
18
      Rueckgabe = "Error";        //"Error" zurückgeben, falls keine Antwort
19
      goto ende;              
20
    }
21
    i++;
22
  }
23
24
  Rueckgabe = strstr (_buffer, Antwort);    //Wert in Variable schreiben
25
  strcat(Rueckgabe, "\r\n");
26
  ende:                    //Sprungmarke für Vorzeitige Beendung
27
  Puffer_loeschen();              //Puffer löschen
28
  putString(Rueckgabe);            //zu Testzwecken
29
  return Rueckgabe;              //Antwort als Rückgabewert
30
}


Wenn ich testweise die Deklaration z.B. durch
1
char *Rueckgabe = "Hallo";
 ersetzte und die Zeile
1
Rueckgabe = strstr (_buffer, Antwort);
 auskommentiere, dann bekomme ich ein "Hallo" zurück. Ich weiß aber das 
die richtige Antwort beim µC ankommt, 1. beobachte alles über einen HT 
und 2. müsste er mir sonst ein "Error" aus der If-Anweisung senden. Ich 
vermutet, dass das Problem irgendwo in der Zeile
1
Rueckgabe = strstr (_buffer, Antwort);
 liegt. Ich komme aber gerade nicht weiter, hat jemand eine Idee ???

Gruss

von Peter II (Gast)


Lesenswert?

woher kommt _buffer überhaupt?

von P. F. (pfuhsy)


Lesenswert?

Das ist ein globaler Schreibpuffer
1
char _buffer[100];                //Globaler Schreibpuffer

von Klaus W. (mfgkw)


Lesenswert?

so ganz verstehe ich auch nicht, was es machen soll (weil der Rest vom 
Programm fehlt), aber ich glaube nicht, daß du das hier so machen 
willst:
1
  Rueckgabe = strstr (_buffer, Antwort);    //Wert in Variable schreiben
2
  strcat(Rueckgabe, "\r\n");

_buffer wird ja irgendwie eine globale Variable sein, die von irgendwo 
gefüllt wird (Interrupt? anderer Thread?).

Mit strstr bekommst du einen Zeiger in den Puffer, und mit
strcat() änderst du diesen Puffer!

PS: bist du sicher, daß der Puffer immer nullterminiert ist?
Irgendwann muß er ja mal verlängert werden, und möglicherweise
gleichzeitig suchst du darin (und verlässt dich auf die \0 am Ende).

von P. F. (pfuhsy)


Lesenswert?

So ganz habe ich das jetzt nicht verstanden. Hier ist das komplette 
Programm, vielleicht kann man das dann besser nachvollziehen.
1
#define F_CPU     3686400            //Taktfrquenz
2
#define BAUD    19200            //einstellte Baudrate
3
//------------------------
4
#define AT_Anrufen  "atd0160xxxxxxx;\r"    //AT-Befehl für einen Anruf
5
#define AT_Auflegen  "ath\r"            //AT-Befehl für das Auflegen
6
#define AT_Temp    "at+cmte?\r"        //AT-Befehl für Temperaturabfrage
7
#define AT_Signal  "at+csq\r"          //AT-Befehl für Signalstärke
8
#define AT_Guth    "atd*100#\r"        //AT-Befehl für Guthabenabfrage
9
#define Ant_Temp  "+CMTE:"          //Antwort für Temperatur
10
#define Ant_Guth  "+CUSD:"          //Antwort für Guthaben
11
#define Ant_Signal  "+CSQ:"            //Antwort für Singalstärke
12
//------------------------
13
#define LED_Alarm_An  PORTB |= (1 << PB0);  //Kontroll-LED an "Alarm ausgelöst"
14
#define LED_Alarm_Aus  PORTB &= ~(1 << PB0);  //Kontroll-LED aus "Alarm ausgelöst"
15
//------------------------
16
#include <avr\io.h>                //zur Deklaration der Ports
17
#include <ctype.h>                //zur Verwendung von toupper
18
#include <string.h>                //zur Stringverwendung
19
#include "D:\Programmieren\Mikrocontroller\AVR\Header\uart.h"
20
#include "D:\Programmieren\Mikrocontroller\AVR\Header\interrupt.h"
21
#include <avr/io.h>
22
//----------------------------------------------------------------------
23
char _buffer[100];                //Globaler Schreibpuffer
24
int _i = 0;                    //globale Laufvariable
25
//----------------------------------------------------------------------
26
//----------------------------------------------------------------------
27
void initPorts() 
28
{
29
  //Ports B.0/1 als Ausgänge deklarieren
30
  DDRB = (1<< PB0)|(1<<PB1); 
31
  //Ports D.2/3 als Eingänge deklarieren
32
  DDRD = (0<<PB2)|(0<<PB3);
33
  // PORTD = PULL-UP
34
  PORTD = 0x04;                            
35
}
36
void Puffer_loeschen()
37
{
38
  for (int i=0; i<100; i++)
39
  {
40
    _buffer[i] = 0;
41
  }
42
43
  _i = 0;
44
}
45
void Anrufen()
46
{
47
  Puffer_loeschen();              //Puffer löschen
48
  putString(AT_Anrufen);            //Anrufen
49
  waitMs(15000);                //Zeit abwarten
50
  putString(AT_Auflegen);            //Auflegen
51
  waitMs(15000);                //bis zum nächsten Alarm warten
52
  Puffer_loeschen();              //Puffer löschen
53
}
54
char *Status(char *AT_Befehl, char *Antwort, int TimeOut)
55
{
56
  char *Rueckgabe = NULL;
57
  int i = 0;
58
59
  Puffer_loeschen();              //Puffer löschen
60
  putString(AT_Befehl);            //AT-Befehl senden
61
  waitMs(TimeOut);              //etwas warten
62
63
  while(!(strstr (_buffer, Antwort)))      //falls vorhanden Antwort prüfen
64
  {
65
    waitMs(1000);              //etwas Zeit verbummeln beim warten
66
    
67
    //falls die Zeit überschritten wird, "Error" als Rückgabewert übertragen und
68
    //die Schleife vorzeitig beenden. Sonst kann es zu Endlosschleifen kommen.
69
    if (i>=10)     
70
    {
71
      Rueckgabe = "Error";        //"Error" zurückgeben, falls keine Antwort
72
      goto ende;              
73
    }
74
    i++;
75
  }
76
77
  Rueckgabe = strstr (_buffer, Antwort);    //Wert in Variable schreiben
78
  strcat(Rueckgabe, "\r\n");
79
  ende:                    //Sprungmarke für Vorzeitige Beendung
80
  Puffer_loeschen();              //Puffer löschen
81
  putString(Rueckgabe);            //zu Testzwecken
82
  return Rueckgabe;              //Antwort als Rückgabewert
83
}
84
ISR(USART_RXC_vect)               //USART, Rx Complete
85
{
86
  char data = 0;
87
  data = getChar();              //Zeichen holen
88
  _buffer[_i] = data;
89
  _i++;
90
  //data = toupper(data);            //in große Zeichen umwandeln
91
}
92
//----------------------------------------------------------------------
93
//----------------------------------------------------------------------
94
main()                      //Hauptschleife
95
{
96
  initPorts();
97
  initUART();
98
  initInterrupt();
99
100
  do
101
  {
102
    //Alarm ausgelöst
103
    if (!(PIND & (1 << PD2))) 
104
    {
105
      waitMs(1000);            //etwas Zeit verbummeln
106
      if (!(PIND & (1 << PD2)))      //Alarm steht immernoch an
107
      {
108
109
        LED_Alarm_An;          //Kontroll-LED an "Alarm ausgelöst"    
110
        //Anrufen();          //Anrufen
111
        LED_Alarm_Aus;          //Kontroll-LED aus "Alarm ausgelöst"
112
113
        Status(AT_Signal, Ant_Signal, 500);
114
        //Status(AT_Temp, Ant_Temp, 500);
115
        //Status(AT_Guth, Ant_Guth, 500);
116
      }
117
    }
118
119
    Puffer_loeschen();          //Wenn mit den Daten nichts gemacht wird, werden sie gelöscht
120
  }
121
  while (true);
122
}

...un die Header
1
Uart.h
2
//Taktfrequenz
3
#ifndef F_CPU 
4
  #define F_CPU 3686400
5
#endif
6
7
//Baudrate
8
#ifndef BAUD 
9
  #define BAUD 19200
10
#endif
11
12
//UART-Schnitstelle initialisieren
13
void initUART() {
14
    UBRRL = (F_CPU / BAUD - 16) / 16;       //Baudberchnnung
15
    UCSRB = (1<<RXEN)|(1<<TXEN)|(1<<RXCIE);    //Receiver/Transmitter/Receiver-Interrupt zulassen
16
    UCSRC = (1<<URSEL)|(1<<UCSZ1)|(1<<UCSZ0);  // Asynchron 8N1 
17
}
18
19
//Zeichen senden
20
void putChar(char data)  {
21
  while (!(UCSRA&32));          //warte bis UDR leer ist
22
  UDR = data;                //senden
23
}
24
25
//ganze Strings senden
26
void putString(char buffer[]) {
27
  for (int i=0 ; buffer[i] !=0 ; i++)
28
    putChar(buffer[i]);
29
}
30
31
//Zeichen empfangen
32
char getChar()                
33
{
34
  char data=0;
35
  while (!(UCSRA&128));           //warte bis RX-complete RXC UCSRA
36
  data=UDR;                 //empfangen
37
  return data;              //empfanges Zeichen übertragen
38
}
1
interrupt.h
2
//Interrupt initialisieren
3
#include <avr/interrupt.h>
4
5
void initInterrupt() {
6
  sei();                  // Interrupts zulassen
7
}

von Klaus W. (mfgkw)


Lesenswert?

_i und _buffer sind nicht volatile.

Abgesehen davon, daß die ISR nicht auf das Ende des Puffers achtet und 
bei Bedarf auch drüber rausschreibt.

So eine richtig schlüssige Vorgehensweise sehe ich nicht darin, kann 
aber auch an mir liegen...

von Klaus W. (mfgkw)


Lesenswert?

Seit wann stehen in C in einer Headerdatei Funktionsdefinitionen?
Das ist hier nicht das Problem, ist aber auch nicht gerade elegant.

von P. F. (pfuhsy)


Lesenswert?

Klaus Wachtler schrieb:
> _i und _buffer sind nicht volatile.

Würde das das Problem lösen ? Ich bin Anfänger und brauche etwas merh 
Input ?

> Seit wann stehen in C in einer Headerdatei Funktionsdefinitionen?

An den Feinschliff kann man noch arbeiten, da gebe ich dir recht. Nur 
ich versuch erstmal das eine Problem zu lösen bevor ich eine neues 
Baustelle aufmache.

von Klaus W. (mfgkw)


Lesenswert?

Peter F. schrieb:
> Würde das das Problem lösen ? Ich bin Anfänger und brauche etwas merh
> Input ?

Im Tutorial steht u.a. auch dazu vieles, was man nicht unbedingt jedem 
einzeln vorkauen muß.

von Klaus W. (mfgkw)


Lesenswert?

Peter F. schrieb:
> An den Feinschliff kann man noch arbeiten, da gebe ich dir recht. Nur
> ich versuch erstmal das eine Problem zu lösen bevor ich eine neues
> Baustelle aufmache.

Wenn ein Programm verworren ist, ist das kein Schönheitsfehler, sondern 
häufig die Ursachae dafür, die anderen Fehlerursachen nicht zu finden.

Ebenso wie man eine planvolle Vorgehensweise und die Doku nicht erst 
hinterher macht, dann kann man es sich auch sparen.

Zumal du nicht nur deine Zeit damit verschwendest.

von P. F. (pfuhsy)


Lesenswert?

Also ehrlich gesagt erdachte ich mir eine eventuelle schnelle Lösung des 
Problems und keine "Vorträge" über die Programmiervariante. Wenn dass 
das Problem ist, werde ich es natürlich ändern. Nur durch testen der 
einzelne Funktionsabschnitte, glaube ich immernoch dass das Problem bei 
der übergabe der Daten in die Variable "Rueckgabe" ist. Und die übergabe 
funktioniert ist ja schliesslich, sonst würde ich ein "Error" bekommen. 
Das habe ich auch mittel einen Suchstring getestet, der auf keinen Fall 
im Puffer sein kann.

von Klaus W. (mfgkw)


Lesenswert?

Die fehlenden volatile sind auf jeden Fall falsch.
Dabei ist schwer vorherzusagen, ob das das einzige Problem ist.

Also räumt man doch das schon mal zur Seite und sucht ggf. ohne
diese Fehler weiter.

Außerdem weiß ich jetzt ehrlich gesagt nicht, ob deine 
Fehlerbeschreibung noch zum letzten Programm passt.
Anrufen() wird ja gar nicht aufgerufen.
Kommt dann trotzdem etwas über die UART?

von P. F. (pfuhsy)


Lesenswert?

Klaus Wachtler schrieb:

> Außerdem weiß ich jetzt ehrlich gesagt nicht, ob deine
> Fehlerbeschreibung noch zum letzten Programm passt.

Wieso denn nicht ?

> Anrufen() wird ja gar nicht aufgerufen.

Das ist aus Testzwecken erstmal auskommentiert. Ich teste mmomentan nur 
die Funktion Status().

> Kommt dann trotzdem etwas über die UART?
Nein. Ist auskommentiert.

von P. F. (pfuhsy)


Lesenswert?

Klaus Wachtler schrieb:
> Die fehlenden volatile sind auf jeden Fall falsch.

Ich versuche die ins Programm zu bringen, doch aus dem Tutorial über 
volatile werde ich nicht wikrlich schlau.

von Peter II (Gast)


Lesenswert?

Klaus Wachtler schrieb:
> Die fehlenden volatile sind auf jeden Fall falsch.

bei i ja, aber _buffer würde ich es nicht verwenden. Die Adresse von 
buffer ändert sich nicht. Der inhalt kann kaum in einem Register 
speichert werden.

von P. F. (pfuhsy)


Lesenswert?

Peter II schrieb:
> Klaus Wachtler schrieb:
>> Die fehlenden volatile sind auf jeden Fall falsch.
>
> bei i ja, aber _buffer würde ich es nicht verwenden. Die Adresse von
> buffer ändert sich nicht. Der inhalt kann kaum in einem Register
> speichert werden.

OK. Geändert. Hilft aber nichts.

von Stefan E. (sternst)


Lesenswert?

Peter F. schrieb:
> glaube ich immernoch dass das Problem bei
> der übergabe der Daten in die Variable "Rueckgabe" ist.

Das Problem mit Rueckgabe wurde von Klaus Wachtler schon kurz 
angerissen, ist dann aber nicht weiter verfolgt worden (oder ich habe es 
übersehen).
1
  Rueckgabe = strstr (_buffer, Antwort);    //Wert in Variable schreiben
2
  strcat(Rueckgabe, "\r\n");
3
  ende:                    //Sprungmarke für Vorzeitige Beendung
4
  Puffer_loeschen();              //Puffer löschen
5
  putString(Rueckgabe);            //zu Testzwecken
6
  return Rueckgabe;              //Antwort als Rückgabewert
Der von strstr gelieferte Pointer zeigt auf die Fundstelle innerhalb 
von _buffer. Puffer_loeschen überschreibt _buffer komplett mit Nullen, 
und damit auch das, worauf Rueckgabe zeigt. Rueckgabe zeigt daher 
danach auf einen leerer String.

von P. F. (pfuhsy)


Lesenswert?

Stefan Ernst schrieb:
> Der von strstr gelieferte Pointer zeigt auf die Fundstelle
> innerhalb von _buffer. Puffer_loeschen überschreibt _buffer komplett
> mit Nullen, und damit auch das, worauf Rueckgabe zeigt. /Rueckgabe/
> zeigt daher danach auf einen leerer String.

Oh man, natürlich. Ich hab einmal zu wenig um die Ecke gedacht. Danke, 
jetzt funktioniert es.

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.