mikrocontroller.net

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


Autor: Bene Jan (terfagter)
Datum:

Bewertung
0 lesenswert
nicht 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.
/*************************************************************************
Function: GsmSignalAbrufen()
Purpose:  Fragt die Signalstärke des GSM-Moduls ab.
Input:    none
Returns:  Status 0...1 schlechter Empfang, 11...31 guter Empfang, 99 nicht feststellbar
**************************************************************************/
char gsmtemp2[3];
char *GsmSignalAbrufen(void)
{
  uint8_t i=0;
  char gsmzeichen;
  char gsmsatz[20];
  char gsmtemp[9];
    

  _delay_ms(100);
  
  uputs2("AT+CSQ\r\n");              //Eingabe AT-Befehl
  uputs0("3. Schritt\n");
  while(!(0 == ukbhit2()));
  uputs0("4. Schritt\n");
  while (ugetchar2() != 10);            //Erste Zeile bis Linefeed (\r\n) einlesen und verwerfen
  do                        // Kompletten Datensatz empfangen
  {
    gsmzeichen = ugetchar2();          // Zeichen von USART einlesen
    gsmsatz[i] = gsmzeichen;          // Zeichenkette erweitern
    i++;
  } while (gsmzeichen != 10);          // Zeilende v. Datensatz erkennen
    
  strncpy(gsmtemp, gsmsatz, 8);          //Die ersten 8 Zeichen des Strings kopieren
  gsmtemp[8] = '\0';  
  strrev(gsmtemp);                //String umdrehen
  strncpy(gsmtemp2, gsmtemp, 2);          //Die ersten 2 Zeichen des Strings kopieren
  gsmtemp2[2] = '\0';                
  strrev(gsmtemp2);                //String wieder umdrehen
    
  if(!(0 == ukbhit2()))              //Dritte Zeile anholen und verwerfen
    while (ugetchar2() != 10);
  
  return gsmtemp2;
}


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

Autor: Bene Jan (terfagter)
Datum:

Bewertung
0 lesenswert
nicht 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?!?

Autor: Stefan Ernst (sternst)
Datum:

Bewertung
0 lesenswert
nicht 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):

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

Autor: Bene Jan (terfagter)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ah ok. Ist natürlich einfacher. Was dazu gelernt...

Autor: Bene Jan (terfagter)
Datum:

Bewertung
0 lesenswert
nicht 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:
char gsmtmp[3];
char *GsmSignalAbrufen(void)
{
  uint8_t i=0;
  char gsmzeichen;
  char gsmsatz[20];
  
  while (!(0 == ukbhit2()))
    while (ugetchar2() != 10);

  uputs2("AT+CSQ\r\n");              //Eingabe AT-Befehl
  
  while (ugetchar2() != 10);            //Erste Zeile bis Linefeed (\r\n) einlesen und verwerfen
  do                        // Kompletten Datensatz empfangen
  {
    gsmzeichen = ugetchar2();          // Zeichen vo USART einlesen
    gsmsatz[i] = gsmzeichen;          // Zeichenkette erweitern
    i++;
  } while (gsmzeichen != 10);          // Zeilende v. Datensatz erkennen
    
  strncpy(gsmtmp, gsmsatz+6, 2);          //Benötigte Zahl in gsmtmp speichern
  gsmtmp[2] = '\0';                //Stringende manuell setzen

  return gsmtmp;
}


Kann ich die Funktion noch verbessern?

Autor: gascht (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Andreas Schweigstill (Firma: Schweigstill IT) (schweigstill) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Stefan Ernst (sternst)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Andreas Schweigstill (Firma: Schweigstill IT) (schweigstill) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht 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. :-(

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.