UNO mit TC35 SMS-Problem bei bestimmten Abfragen am GSM Netzwerk

Hallo, ich spiele gerade mit einem Siemens TC35 SMS-Modul und einem UNO. Hierbei tritt ein Problem auf welches ich mir nicht so ganz richtig erklären kann.

In den beiden Funktionen unten möchte ich aus dem GSM-Netz den Netzbetreiber und die Signalstärke auslesen, sowie das noch vorhandene Restguthaben der Telefonkarte...
Die erste Funktion wird etwa alle 60sec. durchlaufen, die zweite 1xtäglich.

Problem dabei ist, wenn ich den void Guthaben mit in den Programmablauf einbringe, funktioniert der SMS Versand nicht mehr, und auch beim Aktualisieren der GSM-Daten (Netzbetreiber/Signal) gibt es immer wieder mal Probleme (Lesefehler). Ohne geht es einwandfrei.

meine Vermutung ist dass sich die Arrays irgendwie untereinander beeinflussen. Kann das sein?

Die beiden Funktionen erstellen lokale char's und die seriellen Daten zwischen zu speichern, die benötigten Werte werden dann an globale int's weitergegeben und weiterverarbeitet.

Wo liegt hier das Problem?
Danke und Gruß Stefan

void GSM_DATEN_HOLEN() {
  char NETZ[200]; //200speicher fuer Serielle Daten des GSM-Modules
  char SIGNAL[40];//40
  int Platz = 0; //Platz im char-Array

  //Einlesen ob mit Vodafone verbunden
  gsm.println("AT+CSQ"); //Abfrage des Netzes 

  while (gsm.available() > 0) {
    NETZ[Platz] = gsm.read();
    Platz++;
  }

  if (strstr(NETZ, "Vodafone")) { //schauen ob in den empfangenen Daten der Teile #Vodafone# enthalten ist, wenn ja Netzbetreiebr auf 1 setzen, ansonsten 0
    Netzbetreiber = 1;
  }

  else {
    Netzbetreiber = 0;
  }

  delay(2000);

  // Die Signalstaerke des Funknetzes einlesen
  Platz = 0;
  gsm.println("AT+COPS?"); //Abfrage der Signalqualitaet
  while (gsm.available() > 0) {
    SIGNAL[Platz] = gsm.read();
    Platz++;
  }

  // den Signal-string aufteilen und nur den Wert (der zweite im String) der die Feldstaerke enthaelt als int in  Signal uebertragen
  char *Wert; //Speicher fuer die Stringteile die ausgelesen wurden
  byte Pos = 1;
  Wert = strtok(SIGNAL, ", "); //den String nach Trenzeichen , und Leerzeichen durchsuchen und ausgeben, solange bis kpl. durchsucht
  while (Wert != NULL) {

    if (Pos == 2) {
      Signal = map(atoi(Wert), 0, 31, 0, 100) ; //den Wert von 0-31 auf 0-100 skalieren und an Signal uebergeben, mit atoi wird der Wert von char in int gewandelt!

      if (atoi(Wert) > 90) { //Wenn er erhaltenen Wert gr. 90 ist Signal auf 0 setzen, da das Signal nicht lesbar ist oder nicht verfuegbar
        Signal = 0;
      }

    }
    Pos++;
    // naechsten Abschnitt erstellen
    Wert = strtok(NULL, ", ");
  }

}

void Guthaben() {
  
  //Abfragen des Kontostandes der Guthabenkarte
  lcd.clear();
  lcd.print("lade GSM-Guthab.");


  char Daten[300]; //300
  int Stelle = 0; //Platz im char-Arry
  delay(500);
  gsm.println("AT+CUSD=1,\"*100#\""); //GSM-Code - Abfrage des Kontostand
  while (gsm.available() > 0) {
    Daten[Stelle] = gsm.read();
    Stelle++;
    if (Stelle > 299) { //Das Empfangsarry auf 299 Stellen begrenzen
      Stelle = 299;
    }
  }
  if (strstr(Daten, "Kontostand")) { //schauen ob in den empfangenen Daten der Teile #Kontostand:# enthalten ist, wenn ja sind die Daten gueltig und werden weiterverarbeitet
    char *Wert; //Speicher fuer die Stringteile die ausgelesen wurden
    byte Pos = 1;
    Wert = strtok(Daten, "; "); //den String nach Trenzeichen , und Leerzeichen durchsuchen und ausgeben, solange bis kpl. durchsucht
    while (Wert != NULL) {

      if (Pos == 3) { //der benoetigte Wert befindet sich an der 3ten Stelle in der Stringzerlegung
        EUR = (atof(Wert) * 100) + 1; //Berechnen der EUR Guthabens in EUR und an EUR-Variable uebergeben.
              }
      Pos++;
      // naechsten Abschnitt erstellen
      Wert = strtok(NULL, "; ");
    }

    lcd.clear();
    lcd.print("GSM-Guthaben: "); lcd.setCursor (0, 1); lcd.print(EUR / 100.0); lcd.print(" EUR");
    letzte_EUR = millis(); //speichern der letzten erfolgreichen Abfrage des Kontostandes
    delay(5000);

  }
  else {
    lcd.clear();
    lcd.print("GSM-Lesefehler!");
  }
  delay(1000);
  lcd.clear();

}

Es gibt keine voids! Void ist ein Datentyp.

Serial ist langsam. Du kannst nicht einfach eine while-Schleife machen und direkt alles einlesen. Sondern du musst eine Einlese-Funktion solange aufrufen bis das Endzeichen ankommt und dann melden dass du fertig eingelesen hast.

Oder wenigstens ein Delay zwischen dem Abesenden des Befehls und dem Einlesen machen. Damit Zeit ist für Senden + Befehlsverarbeitung + Empfangen

Ok werde zwischen Senden und Empfangen ein Delay einbauen und mich dann wieder melden.

Aber trotzdem gleich eine Frage, obige Funktionen werden nicht ständig durchlaufen, wenn ich den
Guthaben nicht mit im Programmablauf habe, also /* */, dann funktioniert ja alles, nur in dem Moment
wo die Guthabenfunktion mir hinzukommt geht der SMS Versand nicht mehr…

Könnte es evtl. auch ein Speicherüberlauf sein?

Die seriellen Daten werden zu GSM Modul übertragen, jedoch meldet es dann Error zurück, wenn die Guthaben-Funktion mit eingebaut ist… Die beiden Array’s sind aber doch nur “lokal” angelegt, also nur wenn die Funktion gerade aufgerufen wird, oder? Dann dürften Sie im restlichen Programmablauf, wenn die Funktion wieder verlassen wurde nicht mehr da sein, der Speicherplatz sollte also wieder frei sein.

Die beiden Funktionen werden auch nie aufgerufen, wenn eine SMS verschickt werden soll. Da ist mindestens 1 sec. dazwischen. an der (Software)Seriellen ist nur das TC35 angeschlossen.

zu der while-Schleife: Ich sende meine Daten an des TC-35, danach sollte ich etwas warten. Die Schleife wird dann solange durchlaufen, bis Serial nicht mehr verfügbar ist - also alles übertragen wurde. Ich gehe/ging eigentlich davon aus, dass ich mit dieser Schleife den gesamten Datenverkehr meiner Anforderung einlesen kann.

Hier in der zweiten Funktion hab ich das Array auf 300 Stellen begrenzt, da das TC35 Unmengen an Infos überträgt, die ich nicht benötige… das sollte doch so auch in Ordnung sein. Zumindest sollte mein Array[300] so auf keinen Fall überlaufen, auch wenn 1000 Zeichen gesendet werden?

while (gsm.available() > 0) { //also hier durchlaufe ich solange gesendet wird
Daten[Stelle] = gsm.read(); //nächstes Zeichen einlesen und in Stelle 0-299 speichern
Stelle++;
if (Stelle > 299) { //und her begrenze ich auf 300 Zeichen im Array auch wenn wesentlich mehr gesendet
wurden
Stelle = 299;
}

Danke für die Antwort…

Der sendet doch nicht hunderte Zeichen ohne dass mal ein Endzeichen kommt, oder? Sowie ich das in Erinnerung habe sind die Zeilen mit CR + LF (o.ä.) abgeschlossen. Siehe Anleitung. Dann kann man das Zeilenweise einlesen.

Wie gesagt, die Art wie du das einliest ist viel zu primitiv. Zeilenweises Einlesen ist dringend nötig. Man könnte darüber hinaus auch eine Zustandsmaschine bauen die zwischen Kommando Senden und Antwort Empfangen umschaltet.

Speicher könnte ein Problem, sein da du damit recht verschwenderisch umgehst. So landen String Konstanten nicht im RAM:

.print(F("String im Flash"));

Geht überall mit print()/println()

OK, ich werde mich abends ranmachen das Ganze etwas umzuschreiben,
die print's mache ich in Flash, obwohl der gesamte Code eigentlich nicht all zu groß ist.

Als Empfangsarray mache ich nur noch ein globales, in welchem ich die empfangenen Daten zwischenspeichere. Mach der Auswertung benötige ich die seriellen Daten nicht mehr und lösche Sie mir memset( , , ).
Die nächsten seriellen Daten schreibe ich dann wieder in das gleiche Array. So benötige ich nicht in einer Funktion gleichzeitig 2 Arrays, das könnte evtl. auch noch Speicherplatz sparen..

Mit dem seriellen Einlesen der Daten muss ich mal schauen wie ich das umbaue,
glaub aber es ist wirklich ein Speicherplatzproblem.......

Hier siehst du was als Antwort auf die Kommandos gesendet wird:
http://tc485.od.ua/docs/at_commands_tc35.pdf

In vielen Fällen ist es z.B. "OK".

Hier eine Funktion um serielle Daten nicht-blockierend und zeilenweise einzulesen:

Man ruft readSerial() immer wieder auf und wenn ein CR oder LF empfangen wurde bekommt man true zurück. Am besten legt man darüber dann wie gesagt eine Zustandsmaschine. So weiß man immer was man was gerade los ist. Mögliche Fehlermeldungen muss man dann aber auch abfragen!

Auswertung benötige ich die seriellen Daten nicht mehr und lösche Sie mir memset( , , ).

Das ist nicht falsch, aber auch nicht unbedingt nötig. C Strings sind sowieso Null-terminiert. Wenn man also nach dem Einlesen an die letzte Stelle NULL schreibt spielt das was dahinter steht keine Rolle.

Hallo,

hab den Code jetzt etwas überarbeitet, jedoch an der “Seriellen Kommunikation” nichts verändert, die muss so eigentlich funktionieren, zumindest geht er, wenn ich über einen anderen Uno Seriell mit dem PC kommuniziere, das funktioniert alles richtig.

Speicherproblem sollte es auch keines sein, belegt nur 23% RAM, alles Print’s sind in (F( ) geschrieben.

Problem bleibt gleich. Auf dem LCD werden Netzbetreiber/Signalstärke/Guthaben angezeigt, jedoch funktioniert dann der SMS Versand nicht mehr.

nach langer suche jetzt folgendes Ergebnis:

wenn ich im void Guthaben() nachfolgend ausklammere

gsm.println("AT+CUSD=1,\"*100#\""); //GSM-Code - Abfrage des Kontostand
  while (gsm.available() > 0) {
    Daten[Stelle] = gsm.read();
    Stelle++;
    if (Stelle > 299) { //Das Empfangsarry auf 299 Stellen begrenzen
      Stelle = 299;
    }
  }

funktioniert die Guthabenabfrage natürlich nicht mehr, allerdings dafür der SMS Versand wieder einwandfrei.

Es muss irgendwas mit dem gsm.println(“AT+CUSD=1,_"*100#_”"); zu tun haben!

Kann es sein, dass dieses Kommando mehr als nur das Guthaben überträgt??? , auf dem Seriellen Monitor ist mir aufgefallen, dass hier zum Beispiel steht:

Ich Guthaben beträgt : 5.00 EUR.
Bitte wählen Sie:
1: Auflanden
2: …
3: …
4: … usw.

mein Verdacht ist, das TC35 wartet auf ein Kommando, was ich weiter machen möchte???
da ich diese nicht sende, wartet er einfach bis was kommt.

Was irgendwann kommt ist dann die Aufforderung gsmSerial.println(“AT+CMGF=1”); also eine SMS in Textmode zu senden.

Da er offensichtlich noch auf den Empfang einer Ziffer wartet (also der Auswahl oben) kann er mit dem empfangenem “A” nichts anfangen und bricht ab? Die restlichen seriellen Daten wie Rufnummer und Text werden dann nicht mehr richtig verarbeitet, daher kein SMS Versand.

Ist das evtl. der Grund / die Lösung meines Problems???