Go Down

Topic: Arduino Nano SIm800L Modul String setzen und vergleichen. (Read 558 times) previous topic - next topic

Serenifly

Das kann z.B. ein NewLine sein.
Ja. Unbedingt das. Die ganzen AT Kommandos werden mit einem CR + LF abgeschlossen. Darauf sollte man abfragen. Das CR kann man ignorieren und das LF als Endzeichen nehmen

Siehe Anleitung:
Code: [Select]

Commands are usually followed by a response that includes.
"<CR><LF><response><CR><LF>"

Wobei es das CR/LF am Anfang etwas komplizierter macht

GastAnfaenger0815

#16
Jul 20, 2019, 10:06 pm Last Edit: Jul 20, 2019, 10:07 pm by GastAnfaenger0815
Okay, ich komme da noch nicht so ganz hinter.

Wenn ich das Array char inhalt[160] = "";

so bestücke:
Code: [Select]
 while (count == 0) // Loop bis count nicht mehr gleich 0.
  {
    while (tcSerial.available() > 0)// Wenn dort Daten sind dann lese sie.
    {
      c = (char)tcSerial.read();
      if (fuesseCount >= 6 && punktCount == 0) //Zählt bis anzahl der füße erreicht.
      {
        inhalt[charCounter++] = c; // Schreibt jedes Zeichen einzellnd in das Char Array
      }
      inhalt[charCounter] = '\0';
      if (c == '"') fuesseCount++;  // Zählt ["]
      if (c == '.') punktCount++;   // Zählt [.]
      Serial.print(c);
      count++; // Erhöhe die Variable count um 1
    }
  }


Und mir dann charCounter seriel ausgeben lasse, dann steht da das charCounter auf 8 gesetzt wurde.
Obwohl Hallo1. nur 6 zeichen hat. Ich vermute, dass noch Enter mit in das Array geschrieben werden. Denn wenn ich bei:
inhalt[charCounter] = '0';
charCounter durch die Zahl 5 ersetze, erscheint nur hal, also 3 zeichen + die Null-Terminierung, aber es müssten ja eigentlich 4 zeichen + Null-Terminierung sein. Oder?

in der Seriellenausgabe sieht es wie folgt aus:

Code: [Select]
Bereit
AT+CMGF=1

OK
AT+CMGR=1

+CMGR: "REC READ","+4912345678910",,"19/07/20,21:41:06+08"
Hallo.

OK  
      
Hallo.    
8
Hallo.

Serenifly

Was willst du eigentlich genau auswerten? Es wird einfacher sein den kompletten String einzulesen und dann zu Parsen. Man kann z.B. mit strtok() an den Kommas teilen und dann mit einem die Teil-Strings weiterarbeiten. Oder mit strchr()/strrchr() nach einzelnen Zeichen suchen

GastAnfaenger0815

#18
Jul 20, 2019, 10:49 pm Last Edit: Jul 20, 2019, 10:51 pm by GastAnfaenger0815
Ich möchte die SMS die ich an das TC35 sende in das Array char inhalt[160] = "";
schreiben und dieses Array anschließend mit anderen Arrays vergleichen.
Wenn char inhalt[160] gleich dem Array char text1[] = "Hallo."; ist. Möchte ich eine Aktion ausführen. Mein Problem ist jetzt, dass das Array char inhalt[160] wohl erst noch mit einem "enter" beschrieben wird. Deswegen kann ich das nicht mit dem Array char text1[] vergleichen.

Im Moment wenn ich das array char inhalt[160] beschreibe schreibe ich da wohl eher
[
Enter
Hallo.
]

rein.

GastAnfaenger0815

#19
Jul 21, 2019, 02:13 am Last Edit: Jul 21, 2019, 08:40 pm by GastAnfaenger0815
Ich bin jetzt mit dem Auswerten von dem an den Modul gesendeten Nachrichten erst mal so zu frieden, nun würde ich mich daran versuchen den Code nicht blockierend zu schreiben. Wenn ich es richtig verstanden habe, wäre es mit der Funktion Millis(); mach bar. Doch da gestaltet sich für mich folgendes Problem, wenn ich es richtig verstanden habe müsste ich mit millis alles in if funktionen verschachteln. Gibt es da einfachere Möglichkeiten, die ich nicht sehe?

Hier mein code:
Code: [Select]
//TC35 Siemens SMS Modul, erstes Testptrogramm.

#include <SoftwareSerial.h>
#define rxPin 9
#define txPin 8
SoftwareSerial tcSerial = SoftwareSerial(rxPin, txPin);
char text[] = "Es sind";
char nummer[] = "+4912345678910";
char inhalt[160] = "";
char c;
int fuesseCount = 0;
int punktCount = 0;
int charCounter = 0;
int count = 0;
char text1[] = "Hallo.";
int temperatur = 147;
uint32_t requestMillis = 0;
int16_t ConvWait = 1000;
//------------------------------------------------
void setup()
{
  pinMode(10, OUTPUT);
  tcSerial.begin(9600);
  Serial.begin(9600);
  //while (!Serial){}
  //tcSerial.begin(9600);
  digitalWrite(10, 0);
  delay(1000);
  digitalWrite(10, 1);
  delay(0000);
  Serial.println("Bereit");

}
//------------------------------------------------
void loop()
{
  LeseNachricht();
  if (strcmp(inhalt, text1) == 0)
  {
    Serial.println(inhalt);
    Serial.println("Sende diesen Text.");
    inhalt[charCounter] = '\0';
    NachrichtenLoeschen();
    Serial.println(charCounter);
    inhalt[0] = '\0';
    count = 0;
    SendeNachricht();
  }
  //Serial.println(inhalt);
  //ZeigeAusgabeModul();
  delay(5000);
}
//------------------------------------------------
void LeseNachricht()
{
  tcSerial.println("AT+CMGF=1"); // Setze Textmode auf 1
  delay(500);
  tcSerial.println("AT+CMGR=1"); // Lese erste Nachricht im Speicher SM
  delay(500);

  while (count == 0) // Loop bis count nicht mehr gleich 0.
  {
    charCounter = 0;
    fuesseCount = 0;
    punktCount = 0;
    while (tcSerial.available() > 0)// Wenn dort Daten sind dann lese sie.
    {
      c = (char)tcSerial.read();
      if (fuesseCount >= 6 && punktCount == 1) //Zählt bis anzahl der füße erreicht.
      {
        inhalt[charCounter++] = c; // Schreibt jedes Zeichen einzellnd in das Char Array
      }
      //inhalt[charCounter] = '\0';
      if (c == '"') fuesseCount++;  // Zählt ["]
      if (c == '.') punktCount++;   // Zählt [.]
      Serial.print(c);
      count++; // Erhöhe die Variable count um 1
    }
  }
  Serial.println(inhalt);
  Serial.println("hallo");
  NachrichtenLoeschen();
  //charCounter = 0;
  Serial.println(charCounter);
  count = 0;
}
//------------------------------------------------
void NachrichtenLoeschen()
{
  tcSerial.println("AT+CMGD=1"); // CMGD Löscht nachrichten.
  delay(1000);

}
//------------------------------------------------
void SendeNachricht()
{
  Serial.println("Sende Nachricht...");
  tcSerial.print("AT+CMGF=1\r"); // Setzt Textmode auf 1
  delay(1000);
  tcSerial.print("AT+CMGS=\""); // Setzt Nummer.
  tcSerial.print(nummer);
  tcSerial.print("\"\r");
  delay(1000);
  tcSerial.print(text);
  tcSerial.print(temperatur);
  delay(1000);
  tcSerial.print((char)26); // sendet CTRL+Z
  delay(1000);
}
//------------------------------------------------
void ZeigeAusgabeModul()
{
  while (tcSerial.available() > 0)
  {
    Serial.write(tcSerial.read());
  }
}
//------------------------------------------------
void Zeit()
{
  requestMillis = millis();
  if (millis() - requestMillis >= ConvWait)
  {


  }
}

Serenifly

Auch da gilt: werte das eigentliche Ende der Nachricht aus. Du bekommst am Anfang und am Ende ein CR + LF. Frage auf das LF ab. Nach dem zweiten LF ist Ende. Dann weißt du dass du fertig bist. Da nach dem Senden eine zeitlang zu warten ist völlig unnötig. Außerdem hängt diese Zeit von der Baudrate und der Anzahl der Zeichen ab und ist damit nicht konstant

Dann kann man bei jedem loop() Durchlauf abfragen ob was im seriellen Eingangspuffer ist. Wenn ja liest man das Zeichen aus. Wenn nein macht man nichts oder was anderes.
Hier ist ein einfaches Programm um was vom seriellen Monitor einzulesen bis ein LF kommt:
https://forum.arduino.cc/index.php?topic=622530.msg4217397#msg4217397

readLine() ist das relevante. Was in loop() steht ist größtenteils Auswertung. Da ist bei dir anders.
Und nicht von der while() Schleife verwirren lassen. i.d.R. wenn nichts blockiert wird nur ein Zeichen pro Aufruf ausgelesen. Deshalb muss man die Funktion in loop() ständig aufrufen


Man kann auch noch einen Zustands-Automaten bauen und zwischen Senden und Empfangen umschalten. Und dann nur Abfragen ob was da ist wenn man vorher was gesendet hat


Allgemein:
Verwende globale Variablen nur wenn wirklich nötig. Ansonsten lokale. Außerdem werden globale Variablen automatisch mit 0 initialisiert

GastAnfaenger0815

Das mit den Globalen und Lokalen Variablen ist mir völlig fremd. Ich weiß, dass ich noch folgendes machen könnte, nur als Beispiel

:
Code: [Select]

void LeseNachricht(char inhalt[160] = "", char c, int charCounter, int punktCount, int fuesseCount)

{
  tcSerial.println("AT+CMGF=1"); // Setze Textmode auf 1
  delay(500);
  tcSerial.println("AT+CMGR=1"); // Lese erste Nachricht im Speicher SM
  delay(500);

  while (count == 0) // Loop bis count nicht mehr gleich 0.
  {
   
    charCounter = 0;
    fuesseCount = 0;
    punktCount = 0;
    //inhalt[charCounter] = '\0';
    while (tcSerial.available() > 0)// Wenn dort Daten sind dann lese sie.
    {
      c = (char)tcSerial.read();
      if (fuesseCount >= 2 && punktCount == 1) //Zählt bis anzahl der füße erreicht.
      {
        inhalt[charCounter++] = c; // Schreibt jedes Zeichen einzellnd in das Char Array
      }
      inhalt[charCounter] = '\0';
      if (c == '\n') fuesseCount++;  // Zählt ["]
      if (c == '.') punktCount++;   // Zählt [.]
      Serial.print(c);
      count++; // Erhöhe die Variable count um 1
    }
  }
  NachrichtenLoeschen();
  count = 0;




Dann könnte ich auch im loop mit der Methode LeseNachricht:
Code: [Select]

void loop()
{
 LeseNachricht( hier alle Variablen befüllen.);
}


Aber da bin ich dann mit der Syntac komplett überfordert. Ich beschäftige mich jetzt auch zum ersten mal mit dem Thema Programmierung.

Aber nur Beispiele abzuarbeiten, ist nichts für mich. Ich brauche zum lernen immer ein reales Problem.

Mit dem warten nach dem Senden eines AT befehles an das Modul, hatte ich das eigentlich so verstanden, dass das Modul eine gewisse Zeit braucht um den Befehl zu verarbeiten. Was sich für mich bis jetzt auch so gezeigt hatte, denn wenn ich die Befehle zu schnell sende, dann macht das Modul nichts mehr und in der seriellen Ausgabe kommen nur komische Zeichen. Deswegen denke ich schon, dass ich da was mit Zeiten machen muss.

Serenifly

Quote
Mit dem warten nach dem Senden eines AT befehles an das Modul, hatte ich das eigentlich so verstanden, dass das Modul eine gewisse Zeit braucht um den Befehl zu verarbeiten
Ja. Und die Übertragung selbst dauert auch etwas. Du brauchst 1 / Baudrate * 10 Sekunden pro Zeichen. Im Vergleich zur Geschwindigkeit des Prozessors ist das schon eine Ewigkeit. Das ist der Grund weshalb das normal nicht in einer while-Schleife geht. Die würde ein Zeichen einlesen und dann sofort abbrechen weil das nächste noch unterwegs ist.

Das mit dem Delay ist daher nicht grundlegend falsch. Dadurch wartet man einfach und kann so sicher sein dass die komplette Nachricht da ist. Grob geht das. Aber wenn du nicht-blockierend arbeiten willst, muss man es anders machen. Das die Nachrichten mit einem Endzeichen abgeschlossen werden hat schon seinen Grund.
Hier man muss man halt noch beachten dass am Anfang auch CR+LF kommt. Das kann man aber ähnlich wie du es schon gemacht hast mitzählen

Quote
Was sich für mich bis jetzt auch so gezeigt hatte, denn wenn ich die Befehle zu schnell sende, dann macht das Modul nichts mehr und in der seriellen Ausgabe kommen nur komische Zeichen.
Auch deshalb die Anmerkung mit dem Zustands-Automaten. So dass man erst das nächste Kommando sendet wenn die Antwort des vorherigen abgearbeitet ist


Insgesamt ist das nicht das einfachste Anfänger-Projekt. Da muss man schon einige Feinheiten beachten. Auch wenn man sich etwas auskennt

GastAnfaenger0815

Ahh okay, also wenn ich dich richtig verstanden habe, könnte ich einfach die wie du schon sagtest LF mit

if ( c ==  '\n') LFZaehler++;

zählen und einfach jeden nächsten Schritt mit z.b.

if (LFZaehler == 0)

{
Tu das
}


if (LFZaehler == 1;

{
tu das
}

abarbeiten und den LFZaehler mit dem letzten Schritt wieder auf 0 setzen, oder?

Serenifly

Na, ja. Nicht ganz. Eine Antwort sieht laut Anleitung so aus:
<CR><LF>Text<CR><LF>

Das solltest du auch im seriellen Monitor sehen. Das CR macht da nichts, aber das LF erzeugt eine Leerzeile.
Du musst also die Linefeeds zählen und beim zweiten hast du das Ende.

GastAnfaenger0815

Vorausgesetzt ich habe dich jetzt richtig verstanden, habe ich hier jetzt ein kleinen testcode geschrieben.

Code: [Select]
// Software Serial test Sketch für TC35 SMS Modul.

#include <SoftwareSerial.h>
#define rxPin 9
#define txPin 8
SoftwareSerial tcSerial = SoftwareSerial(rxPin, txPin);

int counter = 0;

void setup()
{
  pinMode(10, OUTPUT);
  Serial.begin(9600);
  tcSerial.begin(9600);
  digitalWrite(10, 0);
  delay(1000);
  digitalWrite(10, 1);
  delay(500);
  tcSerial.print("AT+CMGF=1\r\n");
  delay(500);
  Serial.println("Bereit!");
}

void loop()
{
  while (tcSerial.available() > 0)
  {
    Serial.write(tcSerial.read());
    char c;
    c = (char)tcSerial.read();
    if (c == '\n') counter++;
    if (counter == 0)
    {
      tcSerial.println("AT+CMGR=1");
    }

  }
  Serial.println(counter);
  delay(5000);
}



Dazu kommt dann hier die Serielleausgabe am Monitor

Code: [Select]

3
3
3
3
3
3
3
3
3
3
3Bereit!
A+MF1
ERR
1
A+MR1A+MR1A+MR1
RO
2
2
2
2
2
2
2
2
2
2
2
2
2
2
2
2
2
2
2
2
2
2
2
2
2
2
2
2
2
2
2
2
2
2
2


Was mich hier jetzt noch mehr verwirrt als die Tatsache dass, das was ich ausprobieren wollte nicht zu funktionieren scheint, ist dass schon vor das verlassen des Setups in dem int counter wohl eine 3 drinne steht. Uns später eine 2 obwohl nirgendwo was subtrahiert wird.

Nun ja ich hatte da gehofft, so lange in der If funktion zu bleiben, bis eine Antwort von dem Modul zurück kommt. Aber es kommen wie davor auch ohne delay komische Zeichen irgendwas muss ich da noch startk missverstehen.




GastAnfaenger0815

#26
Jul 21, 2019, 10:32 pm Last Edit: Jul 21, 2019, 10:40 pm by GastAnfaenger0815
Das obere Phonemen scheint wohl andere Ursachen zu haben, die ich nicht mehr reproduziert bekomme.

Mit dem folgenden Code

Code: [Select]
// Software Serial test Sketch für TC35 SMS Modul.
#include <SoftwareSerial.h>
#define rxPin 9
#define txPin 8
SoftwareSerial tcSerial = SoftwareSerial(rxPin, txPin);
int Counter = 0;
int testCounter = 0;
void setup()
{
  pinMode(10, OUTPUT);
  Serial.begin(9600);
  tcSerial.begin(9600);
  digitalWrite(10, 0);
  delay(1000);
  digitalWrite(10, 1);
  delay(500);
  //tcSerial.print("AT+CMGF=1\r\n");
  delay(500);
  Serial.println("Bereit!");
  delay(5000);
}
void loop()
{
  if (Counter == 0 && testCounter == 0)
  {
    //tcSerial.println("AT+CMGR=1");
    tcSerial.println("AT+CMGF=1");
    //Serial.println("Okay...");
    testCounter++;
  }
  while (tcSerial.available() > 0)
  {
    Serial.write(tcSerial.read());
    char c;
    c = (char)tcSerial.read();
    if (c == '\n') Counter++;


  }
  Serial.println(Counter);
  delay(5000);
}


Sieht die Serielle Ausgabe nun so aus.

Code: [Select]
Bereit!
0
A+MF1
O
2
2
2
2
2
2
2
2
2

 

Wobei es bei dem gesendeten AT - Befehl so aussieht, als würde beim Senden des Befehls nun jedes zweite Zeichen fehlen.
Was auch erstmal egal wäre, da das "O" das Teil vom "OK" sein wird. Also wenn ich das so weiter führe könnte es funktionieren, es wäre allerdings nur nicht so schön. Und so macht es ja auch wenig Sinn für weiterführende Probleme / Anwendungen oder sonstiges, wenn ich nicht feststelle warum es so ist und es gegebenenfalls auch löse.




Hmm, wenn ich die Zeilen:
  Serial.println(Counter);
  delay(5000);

weg lasse, dann kommt alles normal bei dem Seriellen monitor.

Code: [Select]
Bereit!
AT+CMGF=1

OK


Kann mir das einer erklären? Ich verstehe nicht warum die Ausgabe im seriellen Monitor von mir außerhalb der Schleifen so eine Wirkung haben sollte.
Oder ist es wirklich weil nahe zu direkt im gleichen Moment wo die If bedingung wahr wird das dann meine Ausgabe dafür sorgt das die Daten ein bisschen zusammen gewürfelt werden?

Serenifly

Code: [Select]

  Serial.write(tcSerial.read());
    char c;
    c = (char)tcSerial.read();
    if (c == '\n') Counter++;

Das ist Unsinn. Damit liest du zwei Zeichen aus und eines wird zwar ausgegeben aber nicht überprüft

GastAnfaenger0815

#28
Jul 22, 2019, 09:30 am Last Edit: Jul 22, 2019, 09:31 am by GastAnfaenger0815
Also meinst du eher so:

Code: [Select]

Serial.write(tcSerial.read());
    char c;
    c =tcSerial.read();
    if (c == '\n') Counter++;



Also ohne (char) bei c=tcSerial.read(); sonst kann ich dir gar nicht mehr folgen.

Oder meinst du, dass ich mit

If (c =='\n') Counter++;

Den Counter um 2 erhöhen muss weil es im prinzip 2 zeichen sind?

Serenifly

Du machst zweimal read(). Da ist doch klar dass ja jedes zweite Zeichen anders behandelt wird

Go Up