ESP32-Steuerung via Bluetooth - Programm hängt sich auf

Hallo zusammen,

ich baue gerade ein kleines Programm zusammen, welches über einen ESP32 einen Linearantrieb steuern soll. Die Steuerbefehle werden von einer selbstgeschriebenen App über Bluetooth gesendet.
Dabei sind die Befehle lediglich einzelne Ziffern, die vom ESP verarbeitet werden (bspw. command == 2 → Nullpunkt wird angefahren).
Das funktioniert soweit auch so wie es soll, nur habe ich bei command == 9 ein Problem. Dabei soll der Schlitten einen festen, vorher angegebenen Punkt anfahren. Der Ablauf sieht in etwa so aus: In der App klickt man auf den Button “Festpunktfahrt”, woraufhin die “9” übermittelt wird. Dann wird in dem entsprechenden Textfeld der gewünschte Wert eingegeben und mit dem Druck auf den Button “Fahrt starten” übergeben.
Allerdings hängt sich das Programm an der, im Code hervorgehobenen Stelle, auf. In ganz seltenen Fällen schafft es das Programm noch zur mit “!!” markierten Stelle, aber die Werte für “n” werden nie ausgegeben.
Der switch-case-Abschnitt ist direkt aus dem Forum entnommen und wandelt einen seriell ankommenden Wert in ein long int um und funktioniert sioliert auch wunderbar.
Nur nicht eingebettet in den restlichen Code.

#include "BluetoothSerial.h"

#if !defined(CONFIG_BT_ENABLED) || !defined(CONFIG_BLUEDROID_ENABLED)
#error Bluetooth is not enabled! Please run `make menuconfig` to and enable it
#endif

#define dirPin 33
#define stepPin 32
#define end_max 25
#define end_zero 26

BluetoothSerial SerialBT;

const char startOfNumberDelimiter = '<';
const char endOfNumberDelimiter   = '>';
String command;
char incomingChar;
String stopString = "";
long n;
byte flag = 0;
static long receivedNumber = 0;
static boolean negative = false;
byte c;


void setup ()
{
  Serial.begin (115200);
  SerialBT.begin("Sensormessung");
  pinMode(dirPin, OUTPUT);
  pinMode(stepPin, OUTPUT);
  pinMode(end_max, INPUT_PULLUP);
  pinMode(end_zero, INPUT_PULLUP);
}

void loop () {
  if ((SerialBT.available()) && (flag != 1)) {
    char incomingChar = SerialBT.read();
    if (incomingChar != '\n') {
      command += String(incomingChar);
    }
  }
  if (command != "") {
    Serial.print("command = ");
    Serial.println(command);
  }

  if (command == "2") {
    digitalWrite(dirPin, LOW);
    while (digitalRead(end_zero) == HIGH) {
      drive();
      if (SerialBT.available()) {
        char incomingChar = SerialBT.read();
        stopString = String(incomingChar);
        if (stopString == "8") {
          break;
        }
      }
    }
    flush_all();
  }

  if (command == "3") {
    digitalWrite(dirPin, LOW);
    while (digitalRead(end_max) == HIGH) {
      drive();
      if (SerialBT.available()) {
        char incomingChar = SerialBT.read();
        stopString = String(incomingChar);
        if (stopString == "8") {
          break;
        }
      }
    }
    flush_all();
  }


  if (command == "4") {
    digitalWrite(dirPin, LOW);
    while (digitalRead(end_max) == HIGH) {
      drive();
      if (SerialBT.available()) {
        char incomingChar = SerialBT.read();
        stopString = String(incomingChar);
        if (stopString == "5") {
          break;
        }
      }
    }
    flush_all();
  }


  if (command == "6") {
    digitalWrite(dirPin, HIGH);
    while (digitalRead(end_zero) == HIGH) {
      drive();
      if (SerialBT.available()) {
        char incomingChar = SerialBT.read();
        stopString = String(incomingChar);
        if (stopString == "7") {
          break;
        }
      }
    }
    flush_all();
  }



  if (command == "9") {
    while ((digitalRead(end_zero) == HIGH) && (digitalRead(end_max) == HIGH)) {
      SerialBT.flush();
      flag = 1;
      while (SerialBT.available ()) {
        Serial.println("!");
                                        //Ab hier keine Funktion mehr
        static long receivedNumber = 0;
        static boolean negative = false;

        byte c = SerialBT.read ();
        Serial.println("!!");
        switch (c)
        {

          case endOfNumberDelimiter:
            if (negative)
              n = (- receivedNumber);
            else
              n = (receivedNumber);
            Serial.print("n= ");
            Serial.println(n);
            break;

          case startOfNumberDelimiter:
            receivedNumber = 0;
            negative = false;
            break;

          case '0' ... '9':
            receivedNumber *= 10;
            receivedNumber += c - '0';
            break;

          case '-':
            negative = true;
            break;


        }
        if (n >= 0) {
          digitalWrite(dirPin, LOW);
        }
        else {
          digitalWrite(dirPin, HIGH);
          n = (-n);
        }
        for (int i = 0; i >= n; i++) {
          drive();
        }
        flag = 2;
      }
      if (flag == 2) {
        Serial.println("break");
        break;
      }
    }
    flush_all();
    flag = 0;
  }
  flush_all;
}

void flush_all() {
  Serial.flush();
  SerialBT.flush();
  command = "";
  stopString = "";
}

void drive() {
  digitalWrite(stepPin, HIGH);
  delayMicroseconds(1000);
  digitalWrite(stepPin, LOW);
  delayMicroseconds(1000);
}

Vermutlich ist es ein ganz dummer Fehler, den ich einfach nur übersehe.
Falls mir jemand dabei helfen könnte, wäre ich ihm sehr dankbar :slight_smile:

Wenn Du mit flush() den Buffer leerst und anschließend mit available() prüfst ob was im Puffer vorhanden ist, könnte es schon ein Logikproblem geben.

Abgesehen davon würde ich erst das vollständige Kommando auslesen und dann entsprechend reagieren!
Also ein char-Array oder meinetwegen auch einen String füllen, bis ein Linebreak kommt. Dann erst im switch den Zweig ausführen und die Parameter nach dem Kommando verwenden.

Weiterhin wäre mir es zu gefährlich nur in einem Zweig den Endschalter zu prüfen. Das würde ich ich loop() auf höchster Ebene machen! Wenn der Motor aktiv ist && der Endschalter high -> Immer stoppen.

Mit der Auslagerung von jedem case in eine eigene Funktion wird der Code auch deutlich übersichtlicher und weniger verschachtelt.

Danke für die Antwort.
Den flush() direkt hinter dem available habe ich nur als Versuch mal eingebracht. Vorher hatte ich das flush da nicht, und es gab das gleiche Fehlerbild.
Um die Kommandos selber habe ich mir keine Gedanken gemacht, weil die restlichen Befehle anstandslos ausgeführt wurden, aber ich werde es mir mal ansehen.
Und die Form ist, gelinde gesagt, noch verbesserungswürdig, das weiß ich.

This topic was automatically closed 120 days after the last reply. New replies are no longer allowed.