Software Serial Probleme

Hallo Community,

ich habe ein Problem mit meinem Code und komme nicht dahinter wie ich es lösen kann.
Folgender Aufbau:
Messwerte eines Linearschiebers (Schnittstelle RS-422) wird über einen RS422 to TLL Konverter im Arduino mittels Software.Serial eingelesen. Das Messergebnis wird dann für verschiedene Dinge genutzt. Die Werte kommen solange richtig an, bis ich:

  • In der Loop-Funktion das Display update
  • Ich einen Button gedrückt halte

Wenn ich z.B. das Display-update einbinde, kommen die nächsten 10 Werte falsch an (z.B. Prüfsumme falsch, oder STX nicht erkannt,...)

Scheinbar verliert die serielle Schnittstelle dann vorübergehend die Synchronisation?

Hier die Info über das Datenprotokoll des Linearschiebers:
02h STX
xxh ABS-Daten
xxh ABS-Daten
xxh ABS-Daten
xxh ABS-Daten
xxh ABS-Daten
xxh ABS-Daten
03h ETX
xxh BCC

1 Start Bit
8 Daten Bits
1 Stopp Bit
keine Parität

Die Blockprüfsumme ist ein "Exklusiv-Oder" aller Daten inklusive STX und ETX. Sämtliche Werte werden im ASCII-Format übertragen.

Vielleicht könnt ihr mir ja helfen.

Hier der Code:

#include <Adafruit_GFX.h>    // Adafruit Grafikbibliothek
#include <Adafruit_ST7735.h> // Adafruit ST7735-Bibliothek
#include <Arduino.h>
#include <OneButton.h>
#include <SoftwareSerial.h>
#include <SPI.h>

// Definieren der SoftwareSerial-Pins
const int rxPin = 3; // RX Pin
const int txPin = 2; // TX Pin

// Initialisieren der SoftwareSerial-Instanz
SoftwareSerial rs422(rxPin, txPin);


// TFT-Display-Pins
#define TFT_CS     10
#define TFT_RST    8
#define TFT_DC     9

#define REDLEDPin 5
#define GREENLEDPin 6

// Initialisieren des TFT-Displays
Adafruit_ST7735 tft = Adafruit_ST7735(TFT_CS, TFT_DC, TFT_RST);

// Knopf- und Relais-Pins
const int buttonPin1 = A0;
const int relayPin1 = 4;
const int buttonPin2 = A1;
const int relayPin2 = 7;
int AbsLength = 0;



OneButton button1(buttonPin1);
OneButton button2(buttonPin2);

// Variable zum Speichern der Linearschieberposition
int PosLEND = -200;
int sliderPosition = 0;
int PosL2ori = -150;
int PosL2 = PosL2ori; 
int PosL1 = -75;
int Pos0 = 0;
int PosR1 = 75;
int PosR2 = 150;
int PosR2ori = 150;
int PosREND = 200;
int sliderPositionCm = 0;
int toubleclick_tedection = 0;

void setup() {
  // Beginnen der Kommunikation mit dem Messgerät
  Serial.begin(9600);
  rs422.begin(9600);  // Initialize software
  // Initialisieren des TFT-Displays
  tft.initR(INITR_BLACKTAB); // Initialisierung für 1.44" und 1.8" TFT mit schwarzem Tab
  tft.fillScreen(ST7735_BLACK); // Hintergrundfarbe

  // Initialisieren der Knopf- und Relais-Pins
  pinMode(buttonPin1, INPUT);
  pinMode(relayPin1, OUTPUT);
  pinMode(buttonPin2, INPUT);
  pinMode(relayPin2, OUTPUT);

  // Initialisieren der LED Pins
  pinMode(REDLEDPin, OUTPUT);
  pinMode(GREENLEDPin, OUTPUT);

  // Relais initial ausschalten
  digitalWrite(relayPin1, LOW);
  digitalWrite(relayPin2, LOW);

  // LED initial ausschalten
  digitalWrite(REDLEDPin, HIGH);
  digitalWrite(GREENLEDPin, LOW);

  button1.attachClick(click1);
  button1.attachDoubleClick(doubleclick1);
  button1.attachLongPressStart(longPressStart1);
  button1.attachLongPressStop(longPressStop1);
  button1.attachDuringLongPress(longPress1);

  // link the button 2 functions.
  button2.attachClick(click2);
  button2.attachDoubleClick(doubleclick2);
  button2.attachLongPressStart(longPressStart2);
  button2.attachLongPressStop(longPressStop2);
  button2.attachDuringLongPress(longPress2);

    toubleclick_tedection = 0;
}

void loop() {
  // Serial.print("Ready");
  // Linearschieberposition lesen, wenn Daten verfügbar sind
  button1.tick();
  button2.tick();
  if (rs422.available()) {
    digitalWrite(REDLEDPin, LOW);
    digitalWrite(GREENLEDPin, HIGH);
    sliderPosition = readLinearPosition();
    sliderPositionCm = sliderPosition/100;
    if (sliderPositionCm >= PosREND) {
        digitalWrite(relayPin1, LOW);
    }
    if (sliderPositionCm <= PosLEND) {
        digitalWrite(relayPin2, LOW);
    }
    Serial.print(sliderPositionCm);
    Serial.print('\n');
    Serial.println(toubleclick_tedection);
    Serial.print('\n');

    if (toubleclick_tedection == 0){
      if(sliderPositionCm == PosL2 || sliderPositionCm == PosL1 || sliderPositionCm == Pos0 || sliderPositionCm == PosR1 || sliderPositionCm == PosR2) {
        digitalWrite(relayPin1, LOW);
        digitalWrite(relayPin2, LOW);
      if (sliderPositionCm == Pos0) {
          PosL2 = -150;
          PosL1 = -75;
          Pos0 = 10000000;
          PosR1 = 75;
          PosR2 = 150;
      }
      if (sliderPositionCm == PosL2) {
          PosL2 = 1000000;
          PosL1 = -75;
          Pos0 = 0;
          PosR1 = 75;
          PosR2 = 150;
      }
      if (sliderPositionCm == PosL1) {
          PosL2 = -150;
          PosL1 = 10000000;
          Pos0 = 0;
          PosR1 = 75;
          PosR2 = 150;
      }
      if (sliderPositionCm == PosR1) {
          PosL2 = -150;
          PosL1 = -75;
          Pos0 = 0;
          PosR1 = 10000000;
          PosR2 = 150;
      }
      if (sliderPositionCm == PosR2) {
          PosL2 = -150;
          PosL1 = -75;
          Pos0 = 0;
          PosR1 = 75;
          PosR2 = 10000000;
      }
      }
    }
  if (toubleclick_tedection == 1 && sliderPositionCm == 0) {
          digitalWrite(relayPin1, LOW);
          digitalWrite(relayPin2, LOW);
          toubleclick_tedection = 0;
      }
  }
  // updateDisplay(sliderPositionCm);
}

void updateDisplay(int position) {
  // Berechnung der Balkenlänge basierend auf der Position des Linearschiebers
  int barLength = map(position, 0, 100, 0, tft.width()); // Angenommen, die maximale Position ist 100

  tft.fillRect(0, tft.height() / 2 - 10, barLength, 20, ST7735_GREEN); // Zeichnen des Balkens
  tft.fillRect(barLength, tft.height() / 2 - 10, tft.width() - barLength, 20, ST7735_BLACK); // Rest des Balkens löschen
   // Anzeigen des aktuellen Messwerts
  tft.setCursor(0, 0); // Setzt den Cursor in die obere linke Ecke
  tft.setTextColor(ST7735_WHITE);  // Setzt die Textfarbe
  tft.setTextSize(1); // Setzt die Textgröße
  tft.print("Position: ");
  tft.println(position); // Zeigt den aktuellen Messwert an
}


float readLinearPosition() {
    if (rs422.available()) {
        if (rs422.read() == 0x02) { // Beginn bei STX
            char data[6];
            char bcc = 0x02;

            for (int i = 0; i < 6; i++) {
                while (!rs422.available());
                data[i] = rs422.read();
                bcc ^= data[i];
            }

            while (!rs422.available());
            char etx = rs422.read();
            bcc ^= etx;

            while (!rs422.available());
            char receivedBcc = rs422.read();

            if (receivedBcc == bcc) {
                return parsePosition(data);
            } else {
                Serial.println("Fehler in der Blockprüfsumme!");
                digitalWrite(REDLEDPin, HIGH);
                digitalWrite(GREENLEDPin, LOW);
                rs422.end();
                delay(1000);
                rs422.begin(9600);
                return -1.0;
            }
        }
    }
    return -1.0;
}

float parsePosition(char* data) {
    int multiplier = 1;
    float position = 0;

    for (int i = 5; i >= 0; i--) { // Umkehrung der Schleife für die korrekte Berechnung
        if (data[i] >= '0' && data[i] <= '9') {
            position += (data[i] - '0') * multiplier;
            multiplier *= 10;
        } else {
            Serial.print("Ungültiges Zeichen in den Daten: ");
            Serial.println(data[i]);
            return -1.0;
        }
    }
    return (position+32765-9125);
}

void click1() {
  Serial.println("Button 1 click.");
  int TurnOffFunction = 0;
     if (digitalRead(relayPin2) == LOW && digitalRead(relayPin1) == HIGH && sliderPositionCm <= PosR2) {
    digitalWrite(relayPin1, LOW); // Relais ausschalten
    TurnOffFunction = 1;
    }
   if (digitalRead(relayPin2) == LOW && TurnOffFunction == 0 && sliderPositionCm <= PosR2) {
    digitalWrite(relayPin1, HIGH); // Relais einschalten
    }
}  // click1

void click2() {
  Serial.println("Button 2 click.");
  int TurnOffFunction = 0;
   if (digitalRead(relayPin1) == LOW && digitalRead(relayPin2) == HIGH && sliderPositionCm >= PosL2ori) {
    digitalWrite(relayPin2, LOW); // Relais einschalten
    TurnOffFunction = 1;
   }
   if (digitalRead(relayPin1) == LOW && TurnOffFunction == 0 && sliderPositionCm >= PosL2ori) {
    digitalWrite(relayPin2, HIGH); // Relais einschalten
    }
}  // click2


// This function will be called when the button1 was pressed 2 times in a short timeframe.
void doubleclick1() {
  Serial.println("Button 1 doubleclick.");
  toubleclick_tedection = 1;
     if (digitalRead(relayPin2) == LOW && sliderPositionCm > 0) {
        digitalWrite(relayPin1, HIGH); // Relais einschalten
     }
     if (digitalRead(relayPin1) == LOW && sliderPositionCm < 0) {
        digitalWrite(relayPin2, HIGH); // Relais einschalten
    }
}  // doubleclick1


void doubleclick2() {
  Serial.println("Button 2 doubleclick.");
    toubleclick_tedection = 1;
     if (digitalRead(relayPin2) == LOW && sliderPositionCm > 0) {
        digitalWrite(relayPin1, HIGH); // Relais einschalten
     }
     if (digitalRead(relayPin1) == LOW && sliderPositionCm < 0) {
        digitalWrite(relayPin2, HIGH); // Relais einschalten
    }
}  // doubleclick2

// This function will be called once, when the button1 is pressed for a long time.
void longPressStart1() {
  Serial.println("Button 1 longPress start");
  if (digitalRead(relayPin2) == LOW && sliderPositionCm <= PosR2) {
    digitalWrite(relayPin1, HIGH); // Relais einschalten
  }
}  // longPressStart1

// This function will be called once, when the button1 is released after beeing pressed for a long time.
void longPressStop1() {
  Serial.println("Button 1 longPress stop");
  digitalWrite(relayPin1, LOW); // Relais ausschalten
}

void longPressStart2() {
  Serial.println("Button 2 longPress start");
  if (digitalRead(relayPin1) == LOW && sliderPositionCm >= PosL2) {
    digitalWrite(relayPin2, HIGH); // Relais einschalten
  }
}  // longPressStart1

// This function will be called once, when the button1 is released after beeing pressed for a long time.
void longPressStop2() {
  Serial.println("Button 1 longPress stop");
  digitalWrite(relayPin2, LOW); // Relais ausschalten
}


// This function will be called often, while the button1 is pressed for a long time.
void longPress1() {
  Serial.println("Button 1 longPress...");
}  // longPress1

// ... and the same for button 2:


void longPress2() {
  Serial.println("Button 2 longPress...");
}  // longPress2

Hier die Ausgabe vom Serial Monitor wenn ich in der Loop die Funktion Displayupdate hinzufüge:
-47
-47
-47
-47
-47
0
0
0
0
0
0
0
Fehler in der Blockprüfsumme!
0
0
0
-47
-47
usw.

Wenn ich das Displayupdate in der Loop-Funktion nicht einbinde (und auch einen der Taster nicht gedrückt halte - aslo so wie im eingefügten Code) kommt das richtige Ergebnis. Auch click oder dopelklick haben keinen negativen Einfluss:
-47
-47
-47
-47
-47
-47
usw.

Mir kommt es so vor, als würde der Buffer überlaufen, will euch aber auch nicht auf die falsche Fährte locken. Jedenfalls hoffe ich ihr könnt mir helfen. Bin mit meinem Latein am Ende.

LG
Chris

mir wären da zu viele harte for und while schleifen in deiner Leseroutine.

Lies den Soft-Serial nebenläufig ein - so wie in den Serial Input Basics beschrieben:

Versuche es mal so:

float readLinearPosition() {
  char readByte = 0;
  if (rs422.available()) {
    while (rs422.available() && readByte != 0x02) {
      readByte = rs422.read();
    }
    if (readByte == 0x02) { // Beginn bei STX
      char data[6];
      char bcc = 0x02;

      for (int i = 0; i < 6; i++) {
        while (!rs422.available());
        data[i] = rs422.read();
        bcc ^= data[i];
      }

      while (!rs422.available());
      char etx = rs422.read();
      bcc ^= etx;

      while (!rs422.available());
      char receivedBcc = rs422.read();

      if (receivedBcc == bcc) {
        return parsePosition(data);
      } else {
        Serial.println("Fehler in der Blockprüfsumme!");
        digitalWrite(REDLEDPin, HIGH);
        digitalWrite(GREENLEDPin, LOW);
        return -1.0;
      }
    } else {
      Serial.println("STX nicht gefunden");
    }
  }
  return -1.0;
}

Vielen Dank wwerner.

es kommen zwar noch Fehler vor, aber es läuft geschmeidiger:
Fehler in der Blockprüfsumme!

0

0

Fehler in der Blockprüfsumme!

0

0

-78

0

-78

0

-78

0

Ja, mir auch. Vielen Dank für den Link. Lese ich mir später durch.

Hier der aktuelle Status (Mit code von wwerner).

Youtube Link

Rote LED zeigt Kommunikationsfehler. Tritt doch noch häufig auf...

Achja, Display zeigt die Werte an hat aber noch ein "grafikproblem" -Bin noch nicht dazugekommen mich darum zu kümmern. Interessant ist, dass das Display bei Klick auf den Reset button funktioniert...

Hier die Funktion ohne Display update:
Youtube Link

Wie @noiasca schon geschrieben: Mach die ganzen For und while raus. Lese einzelne Bytes bis die STX findest. Dann lese einzelne Bytes in einen Buffer bist du ETX findest. Dann werte den Buffer aus. Auch das close, delay und begin muss raus.

Roger.

Ist das Problem mit dem Display auch bekannt?

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