Probleme mit Siemens TC35

Guten Abend liebe Arduino Gemeinde,

benötige bitte eure Hilfe bezüglich eines Siemens TC35 GSM Modul...

Kurz zur Story, habe mir auf ebay vor zwei Wochen ein GSM "Shield" bestellt, mit dem Verkaufstitel TC35... nur das waren SIM900 Module mit Asia branding. Also keine Funktion... kurzerhand habe ich mir ein wirkliches Siemens TC35 bestellt und heute bekommen.

Nach ein paar Stunden des testen bin ich langsam am Ende meiner Geduld.
Bekomme keine sauberere Serielle Verbidnung zusammen und kann keine SMS senden.

Egal welches Tutorial ich angewendet habe, es läuft alles auf einen misserfolg raus.

  1. Problem "Serielle Verbidnung"

In allen Tutorial wird angegeben, dass eine Command mittels Serial.print dem Modul übergeben wird.
Bei mir funktioniert das ganze nur mit Serial.write (lesen und Schreiben) Wenn ich Serial.print verwende, dann bekomme ich nur zahlen zurück. Wenn ich überhaupt eine Antwort bekomme...

  1. Problem "kein SMS versand"

Mit Serial.Wirte komme ich soweit, dass ich eine Antwort vom Modul bekomme.
AT -> Antwort OK usw... auch bei AT+CPIN? bekomme ich READY zurück (das war bei den SIM900A nicht der fall). Sobald ich eine SMS Versende will, hängt sich das ganze auch bzw. ich kann die Nachricht nicht beenden. Bekomme nach einer weile Error als Antwort. Kurz zu meinen Vorgenen...

  Serial1.write("AT+CMGF=1\r");
  delay(2000);
  Serial1.write("AT+CMGS=\"+43xxxxxxxxx\"\r");
  delay(2000);
  Serial1.write("Message From GSM");
  delay(2000); 
  Serial1.write(0x1A);

Serial1.write(0x1A); -> Statt beenden bleibt er einfach im SMS Body. Wenn ich das ganze manuel im Serial Monitor durchspielen möchten, komme ich nicht aus der SMS Message zeile raus (> text)

  1. Problem "Modul Anrufen"

Wenn ich versuche, dass Modul anzurufen, dann bekomme ich nur die Antwort das der Teilnehmer nicht erreichbar ist. Bei der Empfangsabfrage AT+CSQ? bekomme ich 20,99 als Antwort und wenn ich den Netzwerkstatutus abfrage mit at+creg? kommt als Antwort 0,1...

  1. Problem "Handy Anrufen"

Wenn ich vom Modul aus versuche mein Handy anzurufen, kommt als Antwort "NO CARRIER"...

Verwendete Hardware

- Siemens TC35 GSM Modul

  • Arduino MEGA 2560 (Hardware Serial nicht Softserial)
  • Arduino UNO (als Refernz)
  • Sim Karte A1 Österreich

Werde VM noch Test durchführen, mit einer Stromversorgung vom Labornetzteil.
Heute habe ich es über den 5V Ausgang des Arduinos versorgt.

Mein gesamtes Testprogramm

void setup() {
  Serial.begin(9600);
  Serial1.begin(9600);
  
  pinMode(7, OUTPUT);
  pinMode(8, INPUT);
  
  Serial.println("TC35 GSM Modul: ");
}

void loop() {  
  
  // Do AT commands
  if (digitalRead(8) == LOW){
    if (Serial.available()){
        Serial1.write(Serial.read());
    } 
  
    if (Serial1.available()){
      Serial.write(Serial1.read());
    }
  }

  // Sending SMS
  if (digitalRead(8) == HIGH){                               // On button press
  digitalWrite(7, HIGH);                                     // Turn LED on.

  Serial1.write("AT");                                      // Sends AT command to wake up cell phone
  Serial.write(Serial1.read());
  delay(2500);
  
  Serial1.write("AT+CMGF=1\r");                              // Puts phone into SMS mode 
  Serial.write(Serial1.read()); 
  delay(2500);                                               // Wait a second
  
  Serial1.write("AT+CMGS=\"+43xxxxxxxxxx\"");               // YOUR NUMBER HERE; Creates new message to number
  Serial.write(Serial1.read());
  delay(2500);
  
  Serial1.write("Sent from my Arduino");                    // Message contents
  Serial.write(Serial1.read());
  delay(2500);
  
  //Serial1.write(char(26));                              // (signals end of message)
  Serial1.write(0x1A);                                    // sends ctrl+z end of message
  Serial.write(Serial1.read());
  delay(2500);
  
  Serial1.write("AT+CMSS=1");                             // Sends message at index of 1
  Serial.write(Serial1.read());

  delay(2500);                                           // Give the phone time to send the SMS

  Serial.println("done..."); 
  delay(10000);
  }
 }

Liebe grüße aus den Süden Österreichs :wink:

schon mal mit einem eigenen Netzteil getestet?

Es funktioniert :slight_smile:

Bei der Stromvergung* ist egal, ob diese über den Arduino (nur für Testzwecke) oder einem Labornetzteil läuft. Aber ich bin draufgekommen, dass die Wertkarte bzw. dieser Netzanbieter an meinen Standort nur eine schlecht Verbindung aufweißt. Und wenn sich die das Moduk ins Netz einwählen kann, dann nimmt es auch keine Befehle mehr entgegen.

*Das Modul bekommt dann im Rack einen eigenen Stromanschluss und wir dnicht über den Arduino versorgt.

Neustart -> Verbindungsaufbau -> keine Verbindung -> Modul down!

Habe einfach eine Karte eines anderen Betreibers genommen und schon war es Plug and Play :wink:
Auch funktioniert Serial.print.. habe aber noch keine Ahnug, was das wirklich passiert..

Wenn ich über den Seriellen Monitor des Arduino´s befehle geben möchte, funktioniert dies nur so:

if (Serial.available()){
    Serial1.write(Serial.read());
  } 
  
  if (Serial1.available()){
     Serial.write(Serial1.read());
  }

Wenn ich automatisierte Befehle vom Programm ausgeben möchte, funktioniert dies nur so:

Serial1.print("AT+CMGF=1\r"); 
delay(1000);  
Serial1.print("AT+CMGS=\"+43xxxxxxxxxxx\"\r");  
delay(1000);  
Serial1.println("Test Message.");  
Serial1.print("\r");  
delay(1000);  
Serial1.println((char)26);  
Serial1.println();  }

Tipp für andere unerfahrene mit diesem GSM Modulen:

AT+CPIN? -> Antwort Ready
AT+CSQ -> Antwort X,99

Dann funktioniert mal die Karte und es ist im Netz eingewählt :wink:

Jetzt habe ich nur mehr eine fragen, wie kann ich am Besten die Antwort des Modules verarbeiten.

Bsp.
LCD Menü -> test Siganal -> button start test
uC schreibt AT+CSQ ans Modul.
Antwort in Char / String geben, zerelgen und die Werte verarbeiten ???

Das Thema serielle Schnittstelle abfragen/auswerten wurde schon mehrfach hier erörtert und ist kein einfaches Thema.

Vor allem musst du darauf achten, dass du nichtblockierenden Code schreibst.

Die Suchfunktion ist dein Freund

PS: funktioniert dein Asia Modul nun auch?

Bezüglich Suchfunktion, die nutze ich schon seit zwei Wochen :wink:
Aber vermutlich nicht richtig :confused:

Das Asia modul ist für den Eimer, habe es an der Händler zurück gesendet und warte mum auf das Geld.

Also das mit dem Seriellen, bekomme es schon soweit hin, dass ich die Antwort in ein char array bekomme.
Nur noch das Array sauber zerlegen...

Auch funktioniert Serial.print.. habe aber noch keine Ahnug, was das wirklich passiert..
...
Wenn ich über den Seriellen Monitor des Arduino´s befehle geben möchte, funktioniert dies nur so:
...
Wenn ich automatisierte Befehle vom Programm ausgeben möchte, funktioniert dies nur so:

Von GSM weiß ich nix, aber ich spekuliere mal: Es könnte am Zeilenende liegen. Der Monitor sendet je nach Einstellung CR/LF oder LF oder nichts.
Serial1.write(Serial.read()); Hier findet eine 1:1 Übertragung statt.
Serial1.print("AT+CMGF=1\r"); Hier wird auch ein Zeilenende mitgeliefert.

Die Zeilenendeeinstellung beim Monitor, häufig in Beispielen nicht dokumentiert, hat mir schon ein paar Denkschleifen beschert.

Beim Zerlegen des Arrays findest Du eventuell mehr Unterstützung, wenn Du Beipiele zeigst, was im Array steht. Nicht jeder, der sich mit dem Zerlegen auskennt, hat auch ein GSM-Shield. :wink:

Serial1.print("AT+CMGF=1\r"); das \r wird benötigt für die Zeileneingabe bzw. quasi als enter. Damit er den Befehl empfängt und für einen neuenen befehl eine neue Zeile hat zum lesen -> mal meine Überlegung.

Mir geht es darum, das ganze zum Automatisieren. Das GSM Modul wird in meine Haussteuerung (Projekt kommt noch zur Präsentation :wink: integriert und sollte sich selbst Überwachen, an der Viso Zustände ausgeben
(Modul OK oder Fehler.... Qualität der Verbindung... usw...)

Mittels SMS möchte ich auch eine Anfrage an das Modul senden, wobei ich dann als Antwort die gewünschten Parameter bekomme (Passen die Alarme? Temperatur des Server bzw. Server Schrank? usw...)

Hier mal der Code, wie ich auf zwei arten die mittels "AT+CSQ" die Signalqualität und den Netzwerkstatus.

byte index = 0;
byte strength = 0;
byte conctGSM = 0;

char cmd;
char answer[20];
char inData[20];                                 
char inChar;                                     

void setup() {
  Serial.begin(9600);
  Serial1.begin(9600);
  
  Serial.println("Give Commdand: ");
}


void loop(){   

  cmd = Serial.read();
  
  // nethode für ablegen in Char / String 
  if (cmd == 'A'){
    Serial.println("Check Signal... method A");                                                                             
    Serial.println("");
    Serial1.print("AT+CSQ\r");
    delay(2000);                                   
  
    while(Serial1.available() != 0){                                                                
            inChar = Serial1.read();                   
            inData[index] = inChar;         
            index++;                               
            //inData[index] = '\0';               
    }
     Serial.print(inData);                              // char Array

     // strength = ???;                                // Signalstärke       0 - 31
     // conctGSM = ???;                                // Im Netz eingewählt 99

     index = 0;   
     Serial.flush();
     Serial1.flush();   
     Serial.println("\r"); 
  }
  
  // nethode für 1:1 übersetzung
  if (cmd == 'B'){
    Serial.println("Check Signal... method  B");                                    
    Serial.println("");
    Serial1.print("AT+CSQ\r");
    delay(2000);
  
    while(Serial1.available()!=0){  
        Serial.write(Serial1.read());
    }

    Serial.flush();
    Serial1.flush();   
    Serial.println("\r"); 
  }
}

AT+CSQ wird immer wieder Rückgegeben... das zweite +CSQ keine Ahnung woher das kommt... 10,99 sind die zwei werte, welche ist verarbeiten möchte. Die erste Zahl steht für die Signalqualität und die zweite (nur 0 oder 99) ob das Modul im Netz eingewählt ist. Hier die Ausgabe des Seriellen Monitors:

char inData[] = "+CSQ: 10,99";

if (strncmp(inData, "+CSQ:", 5) == 0)
{
  char* ptr = inData + 5;
  strength = atoi(strtok(ptr, ","));
  conctGSM = atoi(strtok(NULL, ","));
}

EDIT: das "int" bei den Variablen entfernt. Ist vielleicht logischer in Zusammenhang mit deinem Code wo die schon global deklariert sind

Wow, danke für die schnelle Antwort :slight_smile: :slight_smile: :slight_smile:

Leider scheint es irgendwo noch ein Probelm zu geben, es dürfte sich offset eingeschlichen haben.
Das bekomme ich bei zwei durchläufen raus:

Das mit char inData[] = "+CSQ: 10,99"; war übrigens auch nur zum Test. Aber ich nehme mal an das hast du verstanden.

Statt Screenshots kopiere mal was das Gerät sendet in Code-Tags. Also so dass man nur sieht was ankommt. Ohne deine Debug/Kontroll Ausgaben.

Aber sowie ich es gesehen habe geht es darum sowas zu Parsen:

+CSQ: 10,99
+CSQ: 9,99

Keine Ahnung wo da 13 herkommen soll

Also das ganze sieht so aus (wenn du das meinst)

AT+CSQ
+CSQ: 10,99
OK

Die Antwort wird in drei Zeilen bzw. mit zwei Zeilumbrüchen von Modul gegeben.
Das erstemal wiederholt er den Eingegebene Befehl. Das zweite ist die Aktion und das dritte ist die bestätung, dass es erfolgreich ausgeführt wurde.

Wenn ich den Befehl mittels

Serial1.print("AT+CSQ");
oder
Serial1.println("AT+CSQ");

bekomme ich statt OK ERROR

Sollte eigentlich gehen. Erst fragt man ab ob der String mit "+CSQ:" anfängt. Wenn ja, deklariert man einen Zeiger der auf den Anfang + 5 zeigt (d.h auf das Leerzeichen). strtok() teilt den String mit wiederholten Aufrufen in Tokens entlang des Kommas. Und die zwei Tokens werden mit atoi() in Integer konvertiert.

Danke mal für die Richtung und bisherige Unterstützung.
Bekomme es aber nicht hin... werde mich am WE einwenig mehr in die ganzen Char Array und String angelegenheiten einlesen und einwenig experimentieren :wink:

Poste dann hier weiter, ob ich zu einer Lösung gekommen bin.

Der großteil meiner Proleme sind aber bereits gelöst und der SMS Versand funktioniert :slight_smile:

Poste mal deinen Code wie du ihn hast. Dass der Parser an sich geht sieht man wenn man ihn per Hand mit Daten füttert. So mache ich das fast immer, bevor ich sowas auf echte Daten loslasse.

Eben z.B. char inData[] = "+CSQ: 10,99";
Wenn du das nochmal lokal in loop() oder einen anderen Code-Block schreibst, verdeckt das die globale Variable und wird dann statt dem String von Serial verwendet.

Hallo,

Sry die späte Antwort, war gestern schon im Bett und heute erst jetzt dazu gekommen.
Hier mal mein gesamter Code:

byte index = 0;
byte strength = 0;
byte conctGSM = 0;

char cmd;
char answer[20];
char inData[20];                                 
char inChar;                                     

void setup() {
  Serial.begin(9600);
  Serial1.begin(9600);
  
  Serial.println("Give Commdand: ");
}


void loop(){   

  cmd = Serial.read();
  
  // nethode für ablegen in Char / String 
  if (cmd == 'A'){
    Serial.println("Check Signal... method A");                                                                             
    Serial.println("");
    Serial1.print("AT+CSQ\r");
    delay(2000);                                   
  
    while(Serial1.available() != 0){                                                                
            inChar = Serial1.read();                   
            inData[index] = inChar;         
            index++;                               
            //inData[index] = '\0';               
    }
     Serial.print(inData);                              // char Array

     if (strncmp(inData, "+CSQ: ", 6) == 0)
      {
        char* ptr = inData + 6;
        strength = atoi(strtok(ptr,""));
        conctGSM = atoi(strtok(NULL, ","));
      }

     Serial.print(" Strenght: ");
     Serial.print(strength);
     Serial.print(" GSM: ");
     Serial.print(conctGSM);
      
     // strength = ???;                                // Signalstärke       0 - 31
     // conctGSM = ???;                                // Im Netz eingewählt 99

     index = 0;   
     Serial.flush();
     Serial1.flush();   
     Serial.println("\r"); 
  }
  
  // nethode für 1:1 übersetzung
  if (cmd == 'B'){
    Serial.println("Check Signal... method  B");                                    
    Serial.println("");
    Serial1.print("AT+CSQ\r");
    delay(2000);
  
    while(Serial1.available()!=0){  
        Serial.write(Serial1.read());
    }

    Serial.flush();
    Serial1.flush();   
    Serial.println("\r"); 
  }
}

Fehler:

strength = atoi(strtok(ptr,""));

Du willst beim Komma abtrennen!

Das Leerzeichen in die Abfrage einzubeziehen schadet nichts. Ist aber ich nicht unbedingt nötig. Und atoi() kann auch mit führenden Leerzeichen umgehen. Ist Geschmackssache ob man da +5 oder +6 macht.

Die Ausgabe auf Serial sollte man auch nur in dem Fall machen. Und nicht jedesmal wenn eine Zeile ankommt.

EDIT:
Oder eine Alternative die vielleicht etwas einfacher zu verstehen ist:

char* ptr = inData + 5;
int strength = atoi(ptr);
int conctGSM = atoi(strchr(ptr, ',') + 1);

strtok() ist bei zwei Zahlen nicht unbedingt nötig. Aber bei mehr ist es sehr praktisch, da die Funktion automatisch immer das nächste Token bearbeitet.

Ganz verstehen tue ich es noch nicht, ist für komplettes neuland. Habe noch recht wenig erfahrung und mich noch nie wirklich mit String's beschäftigt.

Ich habe das Bauchgefühl, dass die Ausgabe des Modules nicht ganz Sauber ist:

AT+CSQ
+CSQ: 10,99

OK

Bekomme im Char Array zeilenumbrüche mitgesendet.
Kann man in der Ausgabe die Zeilenumbrüche beeinflussen???
Also wenn er zeichen für zeichen ins Array hinzufügt, dass er den Zeilenumbruch ingnoriert?

Das zerlegen sieht nach wie vor so aus:

AT+CSQ

+CSQ: 11,99

OK
 Strenght: 0 GSM: 10

--- Alternativer Versuchs Gedanke ---

Also ich habe mal eine Alternative Auswertung Veruscht.
Und zwar bastel ich mir einfach die Zahlen aus dem Char Array wieder zusammen :wink:

   Serial.println("Check Signal... method C");                                                                             
    Serial.println("");
    Serial1.print("AT+CSQ\r");
    delay(2000);                                   
  
    while(Serial1.available() != 0){                                                                
            inChar = Serial1.read();                   
            inData[index] = inChar;         
            index++;                                            
    }
     Serial.print(inData);                              // char Array

    String strengthStr = ""
            + String (inData[15]) 
            + String (inData[16])
            ;
            
    String conctGSMStr = ""
            + String (inData[18]) 
            + String (inData[19])
            ;

    Serial.print("strength: ");
    Serial.print(strengthStr);
    Serial.print("  GSM: ");
    Serial.println(conctGSMStr);
    
    Serial.print(" ");

Und hier Antwort

AT+CSQ

+CSQ: 10,99

OK
strength: 10  GSM: 99

Wobei dies Absolut nicht zuverlässig ist :confused:
(Ist nur ein Versuch und finde ich selbst nicht sauber gelöst)

AT+CSQ

+CSQ: 9,99

OK
strength: 9,  GSM: 9

Mit der String Klasse wird alles nur schlimmer. Braucht man einfach nicht.

Du scheinst sowieso ein Problem beim Einlesen zu haben. Der Parser funktioniert! Es kann problematisch sein, dass du wirklich alle Zeichen abspeicherst. Die Steuerzeichen selbst sollte man eigentlich nicht abspeichern.

Probier mal das:

const int SERIAL_BUFFER_SIZE = 16;


char* read_serial()
{
  static byte index;
  static char serial_buffer[SERIAL_BUFFER_SIZE];

  while (Serial1.available())
  {
    char c = Serial1.read();

    if (c >= 32 && index < SERIAL_BUFFER_SIZE - 1)
    {
      serial_buffer[index++] = c;
    }
    else if (c == '\n')
    {
      serial_buffer[index] = '\0';
      index = 0;
    }
  }

  return serial_buffer;
}

Kann man dann so aufrufen:

char* str = serial_read();

Sehr ähnlich kann man die serielle Schnittstelle auch nicht-blockierend einlesen.

Da kann man auch abfragen ob in der Zeile überhaupt was steht (leer kann eine Zeile sein wenn nur CR/LF gesendet wurde):

if(*str)
{
}

bzw.

if(*str != '\0')
{
}

oder

if(str[0] != '\0')
{
}

Hallo,
Mich würde mal interessiern, ob das TC35 tatsächlich mit 5Volt Betriebsspannung auskommt? Ich habe schon mehrfach gelesen, das die Betriebsspannung 9 V. betragen muss und dabei einen recht hohen Strom (ca. 1 A) verbraucht.
Wo liegen denn da die tatsächlichen Werte?

ARG! Habe den Fehler. Hätte mir mal den Code etwas genauer ansehen sollen.

Er liest einfach alles was kommt in ein Array ein. Das ist Murks. Wenn man das zeilenweise bekommt, kann man es auch schön zeilenweise einlesen und jede Zeile für sich auswerten. Das ist auch was meine Parse Funktion erwartet hat. Dass der String am Anfang steht und nicht irgendwo in der Mitte. Das hatte ich übersehen. Dann passen die zwei Codes nicht zusammen.

Was ich in #17 geschrieben haben kann man als Notlösung verwenden. Aber man muss read_serial() mehrmals aufrufen. Einmal pro Zeile.

Besser macht man das sowieso nicht-blockierend mit einen Zustandsautomaten...