Forum: Compiler & IDEs Problem mit Funktion bei GSM-Modul über USART


von Bene J. (terfagter)


Lesenswert?

Hallo zusammen,

Ich habe eine Funktion geschrieben, die die Signalstärke eines 
GSM-Moduls auswertet. Das ganze funktioniert über AT-Befehle.
Ich sende dem Modul AT+CSQ<ENTER> und das Modul antwortet mit (z.B.) 
+CSQ: 13,99 wobei 13 die endscheidende Zahl ist, die ich benötige. Meine 
Funktion funktioniert beim ersten Durchlauf wunderbar, beim zweiten 
Durchlauf bleibt die Funktion bei while(!(0 == ukbhit2())); am Anfang 
der Funktion hängen.
Also sendet das Modul nichts mehr zurück beim zweiten Durchlauf! Wenn 
ich die AT-Befehle aber über ein Terminal an das GSM-Modul sende, kriege 
ich immer eine Antwort, auch wenn ich jede Sekunde sende. In meiner 
main() rufe ich die Funktion nur alle 3 sec auf. Also Zeit genug sollte 
das Modul haben, also liegt es nicht am Modul.
1
/*************************************************************************
2
Function: GsmSignalAbrufen()
3
Purpose:  Fragt die Signalstärke des GSM-Moduls ab.
4
Input:    none
5
Returns:  Status 0...1 schlechter Empfang, 11...31 guter Empfang, 99 nicht feststellbar
6
**************************************************************************/
7
char gsmtemp2[3];
8
char *GsmSignalAbrufen(void)
9
{
10
  uint8_t i=0;
11
  char gsmzeichen;
12
  char gsmsatz[20];
13
  char gsmtemp[9];
14
    
15
16
  _delay_ms(100);
17
  
18
  uputs2("AT+CSQ\r\n");              //Eingabe AT-Befehl
19
  uputs0("3. Schritt\n");
20
  while(!(0 == ukbhit2()));
21
  uputs0("4. Schritt\n");
22
  while (ugetchar2() != 10);            //Erste Zeile bis Linefeed (\r\n) einlesen und verwerfen
23
  do                        // Kompletten Datensatz empfangen
24
  {
25
    gsmzeichen = ugetchar2();          // Zeichen von USART einlesen
26
    gsmsatz[i] = gsmzeichen;          // Zeichenkette erweitern
27
    i++;
28
  } while (gsmzeichen != 10);          // Zeilende v. Datensatz erkennen
29
    
30
  strncpy(gsmtemp, gsmsatz, 8);          //Die ersten 8 Zeichen des Strings kopieren
31
  gsmtemp[8] = '\0';  
32
  strrev(gsmtemp);                //String umdrehen
33
  strncpy(gsmtemp2, gsmtemp, 2);          //Die ersten 2 Zeichen des Strings kopieren
34
  gsmtemp2[2] = '\0';                
35
  strrev(gsmtemp2);                //String wieder umdrehen
36
    
37
  if(!(0 == ukbhit2()))              //Dritte Zeile anholen und verwerfen
38
    while (ugetchar2() != 10);
39
  
40
  return gsmtemp2;
41
}

Woran könnte das liegen? Schonmal vielen Dank für eure Hilfe.

von Bene J. (terfagter)


Lesenswert?

Noch zusätzlich:
Ich habe keine Datenflußkontrolle aktiv.
Auch delay-Schleifen an verschiedensten Stellen in der Funktion, ergaben 
keine Besserung.
Wieso sendet das Modul nichts zurück, aber mit einem Terminal schon?!?

von Stefan E. (sternst)


Lesenswert?

Unabhängig von deinem eigentlichen Problem (dazu müsste man nämlich mal 
wissen, welchen USART-Code du überhaupt verwendest, damit man mal weiß, 
was ukbhit2 überhaupt macht, oder machen soll):

1
  strncpy(gsmtemp, gsmsatz, 8);          //Die ersten 8 Zeichen des Strings kopieren
2
  gsmtemp[8] = '\0';  
3
  strrev(gsmtemp);                //String umdrehen
4
  strncpy(gsmtemp2, gsmtemp, 2);          //Die ersten 2 Zeichen des Strings kopieren
5
  gsmtemp2[2] = '\0';                
6
  strrev(gsmtemp2);
Wozu einfach, wenn es auch kompliziert geht, gell? ;-)
1
strncpy(gsmtmp2, gsmsatz+6, 2);
2
gsmtmp2[2] = '/0';

von Bene J. (terfagter)


Lesenswert?

Ah ok. Ist natürlich einfacher. Was dazu gelernt...

von Bene J. (terfagter)


Lesenswert?

Problem gelöst:
Ich habe bevor ich den AT-Befehl übergebe noch zwei kleine 
while-Schleifen hinzugefügt, die überprüfen ob Zeichen vorhanden sind 
und diese dann bis zum Zeilenende verwerfen.

Damit sieht meine Funktion so aus:
1
char gsmtmp[3];
2
char *GsmSignalAbrufen(void)
3
{
4
  uint8_t i=0;
5
  char gsmzeichen;
6
  char gsmsatz[20];
7
  
8
  while (!(0 == ukbhit2()))
9
    while (ugetchar2() != 10);
10
11
  uputs2("AT+CSQ\r\n");              //Eingabe AT-Befehl
12
  
13
  while (ugetchar2() != 10);            //Erste Zeile bis Linefeed (\r\n) einlesen und verwerfen
14
  do                        // Kompletten Datensatz empfangen
15
  {
16
    gsmzeichen = ugetchar2();          // Zeichen vo USART einlesen
17
    gsmsatz[i] = gsmzeichen;          // Zeichenkette erweitern
18
    i++;
19
  } while (gsmzeichen != 10);          // Zeilende v. Datensatz erkennen
20
    
21
  strncpy(gsmtmp, gsmsatz+6, 2);          //Benötigte Zahl in gsmtmp speichern
22
  gsmtmp[2] = '\0';                //Stringende manuell setzen
23
24
  return gsmtmp;
25
}

Kann ich die Funktion noch verbessern?

von gascht (Gast)


Lesenswert?

im grunde kann man einiges anders machen ...

weil man das modul ja auch  für andere befehle brauch
kann man  einige sachen verallgemeinern

zB das wegsenden als funktion ..
entweder mit timeout und verwerfen oder neu senden

von Andreas S. (Firma: Schweigstill IT) (schweigstill) Benutzerseite


Lesenswert?

Abgesehen von dem obigen Diskussionsgegenstand gibt es noch ein weiteres 
Problem mit dem aufgeführten Programmcode.

Die Startadresse des Arrays gsmtmp[] wird zurückgegeben. Leider handelt 
es sich dabei jedoch um eine lokale Variable, deren Gültigkeit mit dem 
Verlassen von GsmSignalAbrufen() endet. Zwar ist der zurückgegebene 
Zeiger gültig, jedoch zeigt er auf einen freigegebenen Speicherbereich. 
Das kann zwar gutgehen, da der Speicher nicht sofort gelöscht wird, 
muss es aber nicht. Sobald der Stack z.B. durch weitere Funktionsaufrufe 
wieder neu
belegt wird, werden auch die Daten überschrieben.

Es gibt mehrere Möglichkeiten, die obigen Probleme zu vermeiden:

1. Übergabe eines vorab definierten Puffers an GsmSignalAbrufen()

2. Anforderung von dynamischem Speicher innerhalb von GsmSignalAbrufen()
   und Freigabe nach Verarbeitung des Inhaltes. ACHTUNG: SEHR SCHLECHTER
   PROGRAMMIERSTIL, da äußerst fehlerträchtig.

3. Deklaration von gsmtmp[] als static-Variable. ACHTUNG: Mäßig
   schlechter Programmierstil, da hierbei implizit angenommen wird, dass
   die Adresse einer lokalen Variable auch außerhalb der Funktion
   wohldefiniert und konstant ist.

von Stefan E. (sternst)


Lesenswert?

Andreas Schweigstill schrieb:
> Die Startadresse des Arrays gsmtmp[] wird zurückgegeben. Leider handelt
> es sich dabei jedoch um eine lokale Variable

Schau nochmal genau hin.

von Andreas S. (Firma: Schweigstill IT) (schweigstill) Benutzerseite


Lesenswert?

Stefan Ernst schrieb:
> Schau nochmal genau hin.

Upps, da habe ich mich in der Tat verguckt. Ich war gedanklich noch bei 
gsmtemp2[] aus dem ersten Quelltext, wo jedoch auch alles richtig 
übergeben wird. :-(

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.