Zustandsautomat Geht nicht

Hallo,
ich habe hier einen Zustands automat der einen Befehl senden soll und dann 5 sekunden auf eine Antwort warten bevor er den nächsten sendet, dass klappt hin und wieder mal, ich führe exakt das gleiche script mehrmals aus und bekomme unterschiedliche cases nur beantwortet. Weiß jemand woran das liegt?

Code:

#include <SoftwareSerial.h>
#define SIM800_TX 8
#define SIM800_RX 9
SoftwareSerial mySerial(SIM800_TX, SIM800_RX);

int start = 0;
int zustand = 0;
unsigned long Millis;
unsigned long Intervall;
enum ZKom : byte { SENDEN, EMPFANGEN };
ZKom zustandKom = SENDEN;


#define ZEILENTRENNZEICHEN 13
char* receiveBuffer() {
  static char lineBuffer[40];
  static byte counter = 0;
  char c;
  if (mySerial.available() == 0) return NULL;
  if (counter == 0) memset(lineBuffer, 0, sizeof(lineBuffer));
  c = mySerial.read();
  if (c == ZEILENTRENNZEICHEN)
  {
    counter = 0;
    return lineBuffer;
  }
  else if (c >= 32)
  {
    lineBuffer[counter] = c;
    if (counter < sizeof(lineBuffer) - 2) counter++;
  }
  return NULL;
}

void setup() {

  Serial.begin(9600);
  while (!Serial);

  mySerial.begin(9600);
  while (!mySerial);

  Serial.println("Bereit");

}

void loop() {
  if (millis() - Millis >= Intervall) {
    zustandKom = SENDEN;
  }


  if (zustandKom == SENDEN) {
    if (start == 0) {
      zustand = Serial.read();
      if (zustand > 48 ) {
        start = 1;
        Serial.println(zustand);
      }
    }
    switch (zustand) {

      case 49:
        Serial.println("Case 1");
        while (!mySerial);
        mySerial.println("AT");
        zustand = 50;
        zustandKom = EMPFANGEN;
        Millis = millis();
        Intervall = 5000;
        break;

      case 50:
        Serial.println("Case 2");
        while (!mySerial);
        mySerial.println("AT+SAPBR=3,1,Contype,GPRS");
        zustand = 51;
        zustandKom = EMPFANGEN;
        Millis = millis();
        Intervall = 5000;
        break;

      case 51:
        Serial.println("Case 3");
        while (!mySerial);
        mySerial.println("AT+SAPBR=3,1,APN,web.vodafone.de");
        zustand = 52;
        zustandKom = EMPFANGEN;
        Millis = millis();
        Intervall = 5000;
        break;

      case 52:
        Serial.println("Case 4");
        while (!mySerial);
        mySerial.println("AT+SAPBR=3,1,USER,vodafone");
        zustand = 53;
        zustandKom = EMPFANGEN;
        Millis = millis();
        Intervall = 5000;
        break;

      case 53:
        Serial.println("Case 5");
        while (!mySerial);
        mySerial.println("AT+SAPBR=3,1,PWD,vodafone");
        zustand = 54;
        zustandKom = EMPFANGEN;
        Millis = millis();
        Intervall = 5000;
        break;

      case 54:
        Serial.println("Case 6");
        while (!mySerial);
        mySerial.println("AT+SAPBR=1,1");
        zustand = 55;
        zustandKom = EMPFANGEN;
        Millis = millis();
        Intervall = 5000;
        break;

      case 55:
        Serial.println("Case 7");
        while (!mySerial);
        mySerial.println("AT+SAPBR=2,1");
        zustand = 56;
        zustandKom = EMPFANGEN;
        Millis = millis();
        Intervall = 5000;
        break;

      case 56:
        Serial.println("Verbindung fertig");
        start = 0;
        break;

    }
  }

  if (zustandKom == EMPFANGEN) {
    char* text = receiveBuffer();
    if (text != NULL) {
      if (strcmp(text, "OK") == 0 ) {
        Serial.println(text);
        //zustandKom = SENDEN;
      } else if (strcmp(text, "ERROR") == 0 ) {
        Serial.println(text);
        //zustandKom = SENDEN;
      } else {
        Millis = millis();
        Intervall = 3000;
        Serial.println(text);
      }
    }
  }
}

Serieller Monitor 1:

Bereit

49

Case 1

Case 2

AT+SAPBR=3,1,Contype,GPRS



OK

Call Ready



SMS Ready
Case 3

Case 4

AT+SAPBR=3,1,USER,vodafone



OK



SMS Ready
Case 5

Case 6

AT+SAPBR=1,1



ERROR



SMS Ready

Case 7

Verbindung fertig

Serieller Monitor2:

Bereit

49

20:44:51.584 -> Case 1

20:44:51.584 -> AT

20:44:51.584 -> 

20:44:51.584 -> OK



20:44:52.285 -> +CPIN: READY



20:44:53.889 -> Call Ready



20:44:54.589 -> SMS Ready

Case 2

Case 3

AT+SAPBR=3,1,APN,web.vodafone.de

20:45:02.737 -> 

20:45:02.737 -> OK



SMS Ready

Case 4

Case 5

AT+SAPBR=3,1,PWD,vodafone

20:45:11.215 -> 

20:45:11.215 -> OK



20:45:11.548 -> SMS Ready

Case 6

Case 7

AT+SAPBR=2,1

20:45:19.636 -> 

20:45:19.636 -> +SAPBR: 1,3,"0.0.0.0"

20:45:19.724 -> 

20:45:19.724 -> OK



20:45:20.027 -> SMS Ready

Verbindung fertig

Du brauchst für das Warten einen eigenen Zustand. Im Moment wird das immer aufgerufen und ist immer wahr auch wenn du gar nicht Warten willst

Und sowas hier:

case 49:
case 50:

Du meinst eigentlich ASCII Zeichen. Dann verwende auch ASCII Zeichen und nicht die Zahlencodes. Das ist zwar das gleiche für den Compiler aber schlechter lesbar

Also einen Zustand der sagt wann das hier aktiv werden soll?

if (millis() - Millis >= Intervall) {
zustandKom = SENDEN;
}

Wie verwende ich hier ASCII Zeichen, und wo macht das ganze dann später beim ausführen von dem Script unterschiede?

Dann verwende auch ASCII Zeichen und nicht die Zahlencodes

Hypec:
Wie verwende ich hier ASCII Zeichen, ...

Z. B.

case 'A' ...

Gruß

Gregor

Also einen Zustand der sagt wann das hier aktiv werden soll?

Ja. So:

enum ZKom : byte { SENDEN, EMPFANGEN, WARTEN };

Oder vielleicht auch so:

enum ZKom : byte { SENDEN, EMPFANGEN, WARTEN_3000, WARTEN_5000 };

Hypec:
wo macht das ganze dann später beim ausführen von dem Script unterschiede?

Es macht keinen Unterschied, aber es ist besser lesbar.

Oke das muss dann aber ein anderer Zustand sein da ich so EMPFANGEN ja direkt wieder abbreche und in den Zustand WARTEN springe. Der eigentliche sinn von Warten ist ja aber das der Zustand EMPFANGEN solang wiederhollt wird bis das Intervall vergangen ist und dann der Zustand wieder Senden wird.
Vorstellung: SENDEN --> EMPFANGEN --> 5s EMPFANGEN --> SENDEN
So: SENDEN --> EMPFANGEN --> WARTEN --> SENDEN

Wieso willst du 5 Sekunden Empfangen? Das macht wenig Sinn. Du weißt doch genau was du als Antwort empfangen müsstest.

Oder geht es um das hier?

      zustand = Serial.read();

Ich dachte das war nur als Test da und dass das eigentlich voll automatisch ablaufen sollte. Selbst, wenn dann ist das ein anderes ganz "empfangen". Der Zustand EMPFANGEN ist dafür dar von dem SIM Modul zu lesen! Nicht vom seriellen Monitor.

Aber auch das geht wiederum über einen extra Zustand. Du musst nur mal deine Programm-Teile richtig trennen. Empfangen vom seriellen Monitor könnte man vielleicht auch immer tun. Es ist lediglich die Reaktion darauf die eventuell nicht sofort erfolgen kann

Also ich erzähle vielleicht mal alles das zustand = Serial.read(); ist momentan zu Testzwecken da und soll wenn das Programm Funktioniert durch ein zustand = 1; ersetzt werden welches Jede Stunde einmal das ausführt und dann Messdaten per http an einen Webserver senden soll.

Du weißt doch genau was du als Antwort empfangen müsstest.

Nein das ist mit dem Sim Modul etwas dumm da machmal auf den Befehl AT nur ein OK zurück kommt und manchmal ein OK … SMS Ready oder bei AT+SAPBR=2,1 kommt OK … und dann die IP zurück welche sich ja immer ändert.

Wo ist hier der Fehler das, dass Script nach case 1 aufhört zu laufen?

#include <SoftwareSerial.h>
#define SIM800_TX 8
#define SIM800_RX 9
SoftwareSerial mySerial(SIM800_TX, SIM800_RX);

int start = 0;
int zustand = 0;
unsigned long Millis;
unsigned long Intervall;
enum ZKom : byte { SENDEN, EMPFANGEN };
ZKom zustandKom = SENDEN;
enum War : byte { JA, NEIN };
War warten = NEIN;


#define ZEILENTRENNZEICHEN 13
char* receiveBuffer() {
  static char lineBuffer[40];
  static byte counter = 0;
  char c;
  if (mySerial.available() == 0) return NULL;
  if (counter == 0) memset(lineBuffer, 0, sizeof(lineBuffer));
  c = mySerial.read();
  if (c == ZEILENTRENNZEICHEN)
  {
    counter = 0;
    return lineBuffer;
  }
  else if (c >= 32)
  {
    lineBuffer[counter] = c;
    if (counter < sizeof(lineBuffer) - 2) counter++;
  }
  return NULL;
}

void setup() {

  Serial.begin(9600);
  while (!Serial);

  mySerial.begin(9600);
  while (!mySerial);

  Serial.println("Bereit");

}

void loop() {
  if (warten == JA) {
    Millis = millis();
    Intervall = 5000;
    if (millis() - Millis >= Intervall) {
      warten = NEIN;
      zustandKom = SENDEN;
      Serial.println(zustandKom);
    }
  }



  if (zustandKom == SENDEN) {
    if (start == 0) {
      zustand = Serial.read();
      if (zustand > 48 ) {
        start = 1;
        Serial.println(zustand);
      }
    }
    switch (zustand) {

      case 49:
        Serial.println("Case 1");
        while (!mySerial);
        mySerial.println("AT");
        zustand = 50;
        zustandKom = EMPFANGEN;
        warten = JA;
        break;

      case 50:
        Serial.println("Case 2");
        while (!mySerial);
        mySerial.println("AT+SAPBR=3,1,Contype,GPRS");
        zustand = 51;
        zustandKom = EMPFANGEN;
        warten = JA;
        break;

      case 51:
        Serial.println("Case 3");
        while (!mySerial);
        mySerial.println("AT+SAPBR=3,1,APN,web.vodafone.de");
        zustand = 52;
        zustandKom = EMPFANGEN;
        warten = JA;
        break;

      case 52:
        Serial.println("Case 4");
        while (!mySerial);
        mySerial.println("AT+SAPBR=3,1,USER,vodafone");
        zustand = 53;
        zustandKom = EMPFANGEN;
        warten = JA;
        break;

      case 53:
        Serial.println("Case 5");
        while (!mySerial);
        mySerial.println("AT+SAPBR=3,1,PWD,vodafone");
        zustand = 54;
        zustandKom = EMPFANGEN;
        warten = JA;
        break;

      case 54:
        Serial.println("Case 6");
        while (!mySerial);
        mySerial.println("AT+SAPBR=1,1");
        zustand = 55;
        zustandKom = EMPFANGEN;
        warten = JA;
        break;

      case 55:
        Serial.println("Case 7");
        while (!mySerial);
        mySerial.println("AT+SAPBR=2,1");
        zustand = 56;
        zustandKom = EMPFANGEN;
        warten = JA;
        break;

      case 56:
        Serial.println("Verbindung fertig");
        start = 0;
        break;

    }
  }

  if (zustandKom == EMPFANGEN) {
    char* text = receiveBuffer();
    if (text != NULL) {
      if (strcmp(text, "OK") == 0 ) {
        Serial.println(text);
        //zustandKom = SENDEN;
      } else if (strcmp(text, "ERROR") == 0 ) {
        Serial.println(text);
        //zustandKom = SENDEN;
      } else {
        Millis = millis();
        Intervall = 3000;
        Serial.println(text);
      }
    }
  }
}

Dann trenne erst mal deine Zustände richtig. Empfangen von SIM Modul ist wie gesagt etwas anderes als deine Test-Kommandos zu empfangen.

Nein das ist mit dem Sim Modul etwas dumm da machmal auf den Befehl AT nur ein OK zurück kommt und manchmal ein OK … SMS Ready oder bei AT+SAPBR=2,1 kommt OK … und dann die IP zurück welche sich ja immer ändert.

Ich habe im PDF Dokument nachsehen und da gibt es “SMS Ready” nur als Antwort auf “Module is powered on and SMS”. Nicht als Antwort auf ein Kommando

Das heißt aber auch dass es Nachrichten gibt die außerhalb der der Senden <-> Empfangen Routine kommen…
Nennt sich auch sehr passend “Unsolicited Result Code”. Mhh…

Auf AT+SAPBR=2,1 sollte laut Datenblatt die IP folgen und danach OK.

Wo empfange ich den die test Kommandos die Sende ich ja.

Das heißt aber auch dass es Nachrichten gibt die außerhalb der der Senden <-> Empfangen Routine kommen…
Nennt sich auch sehr passend “Unsolicited Result Code”.

Also habe ich das richtig verstanden das ich auf die nicht warten muss und nur das OK brauche?