Serielle Daten (14 byte) lesen&verarbeiten - funkt. nur kurz, dann falsche Werte

Hallo zusammen,

ich komme bei meinem ersten Arduino Projekt nun nicht mehr so richtig weiter
und hoffe hier auf etwas Unterstützung =).
(Hardware Beratungs-Thread: Micro od. Mini Pro? + Display? zur Anzeige serieller RS232 Daten - Deutsch - Arduino Forum)

Folgende Hardware wird momentan genutzt:

  • Arduino UNO (Display wollte mit dem Micro Pro nicht wirklich laufen, daher kurzerhand den UNO geholt)
  • Waveshare 2,8" Touch TFT mit SPI Schnittstelle

Nochmal kurz worum es geht:
In meinem Auto befindet sich ein Zeitronix Datenlogger der auf einem RS232 Bus seine Daten rausschickt. Diese will ich abfangen und auf einem Display darstellen. Momentan sende ich die Daten per HTerm an den UNO.

Es werden IMMER 14 byte gesendet, die wie folgt aussehen:
00 01 02 D2 C8 00 00 00 FF 80 43 19 FE FF

Hierbei bleiben die ersten 3 byte, also 00, 01, 02 immer gleich. Die weiteren 11 Byte stellen
dann die Daten dar. Byte 4 ist Lambda, Byte 5+6 die Abgastemperatur (EGT), und Byte 12 User1 (bei mir Benzindruck).

Bevor ich nun das Programm und meine vorläufige GUI anhänge, erstmal das Problem:
Nach dem dauerhaften senden der Daten per Hterm (immer die oben genannten 14byte) werden paar Sekunden (1-3 ca.) die richtigen Werte angezeigt, dann fängt es an das die Werte hin und her springen. Fuel Pressure sollte bspw. 1,5 sein, springt dann jedoch auf 0,25 oder 10.
Irgendwie werden die Pakete nichtmehr in der richtigen Reihenfolge eingelesen.

Nun mal die Gui's:

Gui3: Wird nach dem anschalten für 3sec. angezeigt, und kann per Touch auf das obere drittel als dauerhaftes Bild gewählt werden:

Gui2: Anzeige von EGT und Fuel pressure:
(Umschalten zwischen Gui2/Gui1 durch drücken auf die unteren 2/3 des Bildschirms

Gui1: Azeige von EGT+Fuel pressure, sowie Min/Max von EGT/Fuel pressure/Lambda
(Min/Max zeigen immerhin mal die richtigen falschen Werte ^^)

Der Code befindet sich im nächsten Post, der Post hier wurde zu lang..

Zuletzt noch ein Bild aus HTerm:

Ich wäre um jeden Tipp dankbar und froh =)

So, hier ist nun mein Code:

//Zeitronix Packet format, bytes[]
//[0] always 0
//[1] always 1
//[2] always 2
//[3]  0 AFR
//[4]  1 EGT Low
//[5]  2 EGT High
//[6]  3 RPM Low
//[7]  4 RPM High
//[8]  5 MAP Low
//[9]  6 MAP High
//[10] 7 TPS
//[11] 8 USER1
//[12] 9 Config Register1
//[13]10 Config Register2
// 00 01 02 | D2 C8 00 00 00 FF 80 43 19 FE FF

// LCD
#define LCD_CS A3 
#define LCD_CD A2 
#define LCD_WR A1 
#define LCD_RD A0 
#define LCD_RESET A4 

// Touchscreen
#define XPT_CS  4
#define XPT_IRQ 255     
#define TS_LEFT 3900    
#define TS_RT   300     
#define TS_TOP  360
#define TS_BOT  3800

#include <SPI.h>          
#include "Adafruit_GFX.h" // Hardware-specific library
#include <HX8347D_kbv.h>
HX8347D_kbv tft;
#include <XPT2046_Touchscreen.h>
XPT2046_Touchscreen ts(XPT_CS, XPT_IRQ);

// Schriftarten
#include <Fonts/FreeSansBoldOblique18pt7b.h>
#include <Fonts/FreeSansBold9pt7b.h>
#include <Fonts/FreeSansBold18pt7b.h>

// Farben
#define BLACK       0x0000
#define GREEN       0x07E0 
#define LIGHTGREY   0xC618      
#define DARKGREY    0x7BEF      


// Variablen deklarieren
int Gui1=0;
int Gui2=0;
int Gui3=1;

// Zeitronix Variablen Deklarieren: 
int gotPacket = 0;
char packet[11];
//EGT
byte EGT;
int EGTold=150;
int EGTnew=150;
int EGTminNew=800;
int EGTmaxNew=0;
int EGTminOld=800;
int EGTmaxOld=0;
//Fuel pressure
byte FuelPr;
double FuPnew=2;
double FuPold=2;
double FuPminNew=5;
double FuPmaxNew=0;
double FuPminOld=5;
double FuPmaxOld=0;
//Lambda/AFR
byte Lambda;
double Lda;
double LdaminNew=2;
double LdamaxNew=0;
double LdaminOld=2;
double LdamaxOld=0;

// Funktionen definieren
void GUI1(void);
void GUI2(void);
void GUI3(void);

//*******************************
//*******************************

void setup() 
{
    Serial.begin(9600);
    tft.begin();
    ts.begin(); 
                 
    // Startup Sequenz 3 Sekunden
    GUI3();
    delay(3000); //3000
    GUI2();
    Gui2=1;
    Gui3=0;
}

//*********************************
//*********************************

// Start GUI
void GUI3()
{
    tft.setFont(&FreeSansBoldOblique18pt7b);
    tft.setTextSize(1);
    tft.fillScreen(WHITE);
    tft.fillRect(3,3,50,314,RED);
    tft.fillRect(55,3,70,314,DARKGREY); 
    tft.fillRect(127,3,110,314,BLACK);
    tft.setCursor(20,300);
    tft.setTextColor(WHITE);
    tft.println("Audi Sport");
}

// GUI EGT+ FuP+ Min/Max
void GUI1()
{
    tft.setFont(&FreeSansBold18pt7b);
    tft.setTextSize(1);
    tft.fillRect(0,0,240,160,BLACK);
    tft.fillRect(0,160,240,320,DARKGREY);    
    
    tft.setCursor(5, 50);
    tft.setTextColor(GREEN); 
    tft.println("EGT:"); 
    tft.setCursor(5, 130);
    tft.setTextColor(GREEN);
    tft.println("FuP:");
    
    tft.setFont(&FreeSansBold9pt7b);
    tft.setCursor(5, 220);
    tft.setTextColor(GREEN);
    tft.println("EGT:");   
    tft.setCursor(5, 260);
    tft.setTextColor(GREEN); 
    tft.println("FuP:");  
    tft.setCursor(5, 300);
    tft.setTextColor(GREEN);
    tft.println("Lda:");
    tft.setFont(&FreeSansBold9pt7b);
    tft.setCursor(90, 175);
    tft.setTextColor(GREEN);
    tft.println("Min:          Max:");
}

// GUI EGT+FuP
void GUI2()
{
    tft.setFont(&FreeSansBold18pt7b);
    tft.fillScreen(BLACK);
    
    tft.setCursor(80, 50);
    tft.setTextColor(RED);
    tft.println("EGT:");
    tft.setCursor(60, 200);
    tft.setTextColor(ORANGE); 
    tft.println("Fuel pr.:");    
}

//*************************************************************
//*************************************************************

// Zeitronix Datenverarbeitung
void getZeitronixPacket(char* packetpointer)
{
  gotPacket = 0;
  
  char buffer[32] = {0xF}; // 32 bytes buffer um Startsequenz zu finden "0x00 0x01 0x02"
    for (int i=0; i<32; i++){
      Serial.readBytes(&buffer[i],1);
      if (i > 1 && buffer[i] == 2 && buffer[i-1] == 1 && buffer[i-2] == 0) {
            //gotPacket = 1;
            Serial.readBytes(packetpointer,11);
            gotPacket = 1;
  
      return;         
      }
    }
}

//*************************************************************
//*************************************************************

void loop()
{
//Zeitronix*************************************************************  
   if (Serial.available()){
   getZeitronixPacket(packet);}

    if (gotPacket == 1) 
    {
        EGT = packet[2]*256 + packet [1];
        EGTnew = EGT*2;
        
        FuelPr = packet[8];  
        FuPnew = ((2.5*(FuelPr/50.0))-1.25+1.5); // bar=2,5*V-1.25 // V=Wert in Volt; 0 bar = 0,5V
        
        Lambda = packet[0];
        Lda = Lambda/10.0/14.7;   
      
//Zeitronix**Min/Max***********************************************************  
        if (EGT<EGTminNew) {EGTminNew=EGTnew;}
        if (EGT>EGTmaxNew) {EGTmaxNew=EGTnew;}
        if (FuPnew<FuPminNew) {FuPminNew=FuPnew;}
        if (FuPnew>FuPmaxNew) {FuPmaxNew=FuPnew;}
        if (Lda<LdaminNew) {LdaminNew=Lda;}
        if (Lda>LdamaxNew) {LdamaxNew=Lda;}
      }

//Touch+Gui*************************************************************

    if (ts.touched()) 
    {
      TS_Point p = ts.getPoint(); //XPT_2046_touchscreen returns in Landscape
      uint16_t y = map(p.y, TS_TOP, TS_BOT, 0, tft.height());
      uint16_t x = map(p.x, TS_LEFT, TS_RT, 0, tft.width());
      uint16_t w = tft.width() - 100;
      uint16_t h = tft.height() - 110;

       if ((x>50) && y && Gui1==0)
       { Gui1=1;
         Gui2=0; 
         Gui3=0;
         GUI1(); }
       else if ((x>50) && y && Gui2==0)
       { Gui1=0;
         Gui2=1;
         Gui3=0; 
         GUI2(); }
       else if  ((x<50) && y )
       { Gui1=0;
         Gui2=0; 
         Gui3=1;
         GUI3(); }
      }

// GUI EGT+ FuP+ Min/Max
    if (Gui1 ==1)
    {
      tft.setFont();
      tft.setTextSize(5);

      tft.setCursor(130, 20);
      tft.setTextColor(GREEN,BLACK);
      tft.println(EGTnew); 

      tft.setCursor(110, 100);
      tft.setTextColor(GREEN,BLACK);
      tft.println(FuPnew); 

      tft.setFont(&FreeSansBold18pt7b);
      tft.setTextSize(1);
      if (EGTminNew < EGTminOld) {tft.setCursor(80, 220);  tft.setTextColor(DARKGREY); tft.println(EGTminOld); tft.setTextColor(GREEN); tft.setCursor(80, 220);  tft.println(EGTminNew);}
          else {tft.setCursor(80, 220);  tft.println(EGTminOld);}
      if (EGTmaxNew > EGTmaxOld) {tft.setCursor(170, 220); tft.setTextColor(DARKGREY); tft.println(EGTmaxOld); tft.setTextColor(GREEN); tft.setCursor(170, 220); tft.println(EGTmaxNew);}
          else {tft.setCursor(170, 220);  tft.println(EGTmaxOld);}
      if (FuPminNew < FuPminOld) {tft.setCursor(70, 260);  tft.setTextColor(DARKGREY); tft.println(FuPminOld); tft.setTextColor(GREEN); tft.setCursor(70, 260);  tft.println(FuPminNew);}
          else {tft.setCursor(70, 260);  tft.println(FuPminOld);}
      if (FuPmaxNew > FuPmaxOld) {tft.setCursor(160, 260); tft.setTextColor(DARKGREY); tft.println(FuPmaxOld); tft.setTextColor(GREEN); tft.setCursor(160, 260); tft.println(FuPmaxNew);}
          else {tft.setCursor(160, 260); tft.println(FuPmaxOld);}
      if (LdaminNew < LdaminOld) {tft.setCursor(70, 300);  tft.setTextColor(DARKGREY); tft.println(LdaminOld); tft.setTextColor(GREEN); tft.setCursor(70, 300);  tft.println(LdaminNew);}
          else {tft.setCursor(70, 300);  tft.println(LdaminOld);}
      if (LdamaxNew > LdamaxOld) {tft.setCursor(160, 300); tft.setTextColor(DARKGREY); tft.println(LdamaxOld); tft.setTextColor(GREEN); tft.setCursor(160, 300); tft.println(LdamaxNew);} 
          else {tft.setCursor(160, 300); tft.println(LdamaxOld);}   
    }
    
// GUI EGT+ FuP  
    else if (Gui2 ==1)
    {  
      tft.setFont();
      tft.setTextSize(10);
      
      tft.setCursor(25, 80);
      tft.setTextColor(RED,BLACK);  
      tft.println(EGTnew);

      tft.setCursor(30, 230);
      tft.setTextColor(ORANGE,BLACK);
      tft.println(FuPnew); 
     }
       
//  Old = New
    EGTold=EGTnew;
    FuPold=FuPnew;
    EGTminOld=EGTminNew;
    EGTmaxOld=EGTmaxNew;
    FuPminOld=FuPminNew;
    FuPmaxOld=FuPmaxNew;
    LdaminOld=LdaminNew;
    LdamaxOld=LdamaxNew;
}

Den Teil "// Zeitronix Datenverarbeitung" habe ich aus einem bereits existierenden Projekt abgeschaut, nachdem ich mich jetzt einige Wochen eingearbeitet habe kann ich meinen Fehler dennoch nicht finden..

Wenn es funktioniert werde ich sicher noch einiges optimieren, auch mit den Datentypen etc,
allerdings wollte ich erstmal die generelle Funktion sicherstellen.

Mich macht Deine Einstellung Send on Enter stutzig. Stelle dort mal ein.

Nur so ein Gedanke.

Danke für den Tipp, ich sende jedoch normal immer mit .
Ich habe dummerweise den Screenshot nach weiterem rumprobieren erstellt und nicht drauf geachtet
es zurück zu stellen...

Wenn Du uns falsche Angaben zuspielst, können wir nur falsche Schlüsse ziehen.

Gruß Tommy

Ich tippe auf die serielle Einleseroutine

void getZeitronixPacket(char* packetpointer)
{
  gotPacket = 0;
  
  char buffer[32] = {0xF}; // 32 bytes buffer um Startsequenz zu finden "0x00 0x01 0x02"
  for (int i=0; i<32; i++)
  {
    Serial.readBytes(&buffer[i],1);

Das gefällt mir nicht.

Was glaubst Du, was = {0xF} hinter der buffer-Deklaration macht?

Serial.readBytes() hat einen Timeout. Dann zählst Du zwar Deinen Index weiter, hast aber kein Byte in den buffer oder den packetpointer bekommen.

Ich würde als minimale Verbesserung die Verwendung von Serial.available() empfehlen und da, wo es nur um ein Byte geht, das auch als Einzelbyte lesen.

  buffer[i] = Serial.readByte();

Das Timing scheint mir etwas wacklig und das Auffinden der Startsequenz ist m.E. eher etwas für eine StateMachine als für "wir versuchen mal 32 Byte".

Je nachdem, wie oft die Daten kommen, evtl. ein Ringbuffer

Nee, kein Ringpuffer. Er hört ja nach 32 Byte auf.
Aber die 11 Byte Nutzdaten in den anderen Puffer (packetpointer) - wenn die nicht rechtzeitig kommen, gibt es Datenmüll.

Das verstehe ich nicht:

  • Arduino UNO (Display wollte mit dem Micro Pro nicht wirklich laufen, daher kurzerhand den UNO geholt)

Der UNO und MICRO PRO sind nicht so sehr verschieden daß es einen Grund gebe daß das Display nicht funktionieren sollte. Der MICRO PRO hat die SPI schnittstelle nur auf dem SPI Stecker.

if (Serial.available()){
   getZeitronixPacket(packet);}
...
void getZeitronixPacket(char* packetpointer)
{
  gotPacket = 0;
  
  char buffer[32] = {0xF}; // 32 bytes buffer um Startsequenz zu finden "0x00 0x01 0x02"
    for (int i=0; i<32; i++){
      Serial.readBytes(&buffer[i],1);
      if (i > 1 && buffer[i] == 2 && buffer[i-1] == 1 && buffer[i-2] == 0) {
            //gotPacket = 1;
            Serial.readBytes(packetpointer,11);
            gotPacket = 1;
  
      return;        
      }
    }
}

Wenn ich den Sketch richtig verstehe dann wird sobald wenigstens 1 Zeichen im Eingangsbuffer der seriellen Schnittstelle 32 Zeichen ausgelesen und kontrolliert ob die Startfrequenz im Buffer ist.

Sollte nicht kontrolliert werden ob wirklich 32 Byte gelesen werden können ?
Wieso denn 32 byte und nicht 14?

Grüße Uwe

(deleted)

ich würde da logisch in zwei Status denken:

Status: auf_start_sequenz_warten

  • das einkommenden byte in den Buffer kopieren
  • Wenn
    das 0. nicht 00 -> Ergebnis wegwerfen, neu beginnen
    index>=1 und das 1. nicht 01 -> Ergebnis wegwerfen, index = 0, neu beginnen
    index>=2 und das 2. nicht 02 -> Ergebnis wegwerfen, index = 0, neu beginnen
  • sonst index um 1 erhöhen.

Status: einlesen

  • die restlichen 11 bytes einlesen

Außerdem rächt sich imho jetzt die Beschränkung auf eine serielle Schnittstelle. Wie willst du da jetzt vernünftig debuggen, wenn du nicht siehst was dein Programm macht.

Nutze wenigstens das Display zum debuggen, oder mach dir einen separaten Sketch mit soft-serial zum testen deiner Lese routine. Wenn das fehlerfrei klappt, mach mit dem originalen Sketch weiter.

Peter-CAD-HST:
ich habe für mein Projekt das Beispiel "Serial Event example" aus dem IDE schnell an meine Start/Stop/Zeit-Bedingungen anpassen können.

Diese einfachen Beispiele sind in richtigen Programmen zum Teil kaum zu gebrauchen. Besser ist man denkt selbst darüber nach wie sich die serielle Schnittstelle zeitlich verhält

(deleted)

Tommy56:
Wenn Du uns falsche Angaben zuspielst, können wir nur falsche Schlüsse ziehen.

Da gebe ich dir Recht, war mein Fehler und natürlich nicht absichtlich, entschuldige!
Dennoch danke für deinen Beitrag.

wno158:
Was glaubst Du, was = {0xF} hinter der buffer-Deklaration macht?

Der Buffer wird mit lauter 1en/F aufgefüllt, so verstehe ich das zumindest.
Habe es auch mal mit 0 probiert, da mir das komisch vorkam, hat aber nichts geändert.

Serial.readBytes() hat einen Timeout. Dann zählst Du zwar Deinen Index weiter, hast aber kein Byte in den buffer oder den packetpointer bekommen.

Ich würde als minimale Verbesserung die Verwendung von Serial.available() empfehlen und da, wo es nur um ein Byte geht, das auch als Einzelbyte lesen.

Die ersten 3 Bytes will ich ja nicht in den packetpointer bekommen. Die darauffolgenden
müssten doch dann aus dem buffer in den packetpointer verschoben werden, oder nicht?

uwefed:
Das verstehe ich nicht:Der UNO und MICRO PRO sind nicht so sehr verschieden daß es einen Grund gebe daß das Display nicht funktionieren sollte. Der MICRO PRO hat die SPI schnittstelle nur auf dem SPI Stecker.

Ja gebe ich dir recht, aber das war alles komplett Neu für mich, ich wusste nichtmal
ob das Display funktioniert. Da ich schon sehr viel probiert hatte, habe ich erstmal den weg
gewählt mir den UNO zu holen, der Micro Pro wird bestimmt eine andere Bestimmung
bekommen, oder ich versuche es nochmals mit ihm =)

Wenn ich den Sketch richtig verstehe dann wird sobald wenigstens 1 Zeichen im Eingangsbuffer der seriellen Schnittstelle 32 Zeichen ausgelesen und kontrolliert ob die Startfrequenz im Buffer ist.

Sollte nicht kontrolliert werden ob wirklich 32 Byte gelesen werden können ?
Wieso denn 32 byte und nicht 14?

Wie gesagt, diesen Teil habe ich aus einem anderen Projekt abgeschaut, dort wird anschließend
aber alles einfach nur auf eine SD Karte geloggt. Habe es ebenfalls mit 14byte probiert, was
auch nicht zum Erfolg geführt hat.

noiasca:
Außerdem rächt sich imho jetzt die Beschränkung auf eine serielle Schnittstelle. Wie willst du da jetzt vernünftig debuggen, wenn du nicht siehst was dein Programm macht.

Nutze wenigstens das Display zum debuggen, oder mach dir einen separaten Sketch mit soft-serial zum testen deiner Lese routine. Wenn das fehlerfrei klappt, mach mit dem originalen Sketch weiter.

Vielen Dank für den Denkanstoß, ich werde es mal in der Art versuchen.
Mit dem debuggen hast du natürlich recht, 9600er Baud sollte per Softserial ja laufen.

Vielen Dank für alle übrigen Beiträge.
Ich vermute schon, es wird darauf hinauslaufen die Einleseroutine neu zu entwerfen,
so scheint das wohl nicht wirklich zu klappen.

Ah ja - entschuldige, dass ich da eine kleine Falle aufgebaut habe.
Du solltest noch etwas über Arrays lesen.

Ein F hat gefehlt, Du schreibst vier 0-Bits und vier Einsen (00001111b) - und es sollen ja alle Elemente initialisiert werden:

char buffer[32] = {0xFF, 0xFF, ... /* hier noch weitere 30 0xFF einfügen */};

So mache ich das allerdings nicht, sondern in etwa so:

char buffer[32];

void setup(){
  memset(buffer, 0xFF, 32);
}

Und was die zweite Anmerkung angeht:
Du könntest selbstverständlich mit

buffer[i] = Serial.readByte();

Deinen Startsequenz-Erkennungsbuffer befüllen und dann später mit

Serial.readBytes(packetpointer,11);

den Paketpuffer füllen. Da muss nix kopiert werden.

Ich vermute schon, es wird darauf hinauslaufen die Einleseroutine neu zu entwerfen

Ja, das denke ich auch. noiasca hat ja skizziert, wie das aussehen könnte.

Gruß Walter

wno158:
Ah ja - entschuldige, dass ich da eine kleine Falle aufgebaut habe.
Du solltest noch etwas über Arrays lesen.

Kein Problem, so lernt man ja. Aber du hast recht, ich muss mich in vielen belangen
noch einlesen. Ich habe zwar in meiner Technikerschule etwas C# programmiert,
aber das war nicht besonders tiefgehend und mit serieller Datenverarbeitung
schon gleich gar nicht.

Der generelle Ablauf den noiasca beschrieben hat, ist für mich nachvollziehbar und logisch.
Mir schwirren auch immer wieder Ideen durch den Kopf, aber irgendwie ist dann alles ineinander verschachtelt, und es klappt nicht wirklich.
Habe etwas rum probiert mit if/else und switch case, allerdings momentan nicht besonders erfolgreich. Ein Konstrukt hat immerhin mal die 3 Startbyte erkannt, ist dann aber tlw durcheinander gekommen, und hat die darauffolgenden bytes nicht eingelesen, das ganze sah auch nicht besonders toll aus duckundweg.

Um das ganze villeicht etwas mehr zu verstehen habe ich mich dann mal an diese Beispiele gehalten: Serial Input Basics - updated - Introductory Tutorials - Arduino Forum
Genau genommen: Example 6 - Program to receive binary data

void loop() {
    recvBytesWithStartEndMarkers();
    showNewData();
}

void recvBytesWithStartEndMarkers() {
    static boolean recvInProgress = false;
    static byte ndx = 0;
    byte startMarker = 0x01;
    byte endMarker = 0xFE;
    byte rb;
   

    while (Serial.available() > 0 && newData == false) {
        rb = Serial.read();

        if (recvInProgress == true) {
            if (rb != endMarker) {
                receivedBytes[ndx] = rb;
                ndx++;
                if (ndx >= numBytes) {
                    ndx = numBytes - 1;
                }
            }
            else {
                receivedBytes[ndx] = '\0'; // terminate the string
                recvInProgress = false;
                numReceived = ndx;  // save the number for use when printing
                ndx = 0;
                newData = true;
            }
        }

        else if (rb == startMarker) {
            recvInProgress = true;
        }
    }
}

void showNewData() {
    if (newData == true) {

  ...... hier kommt dann meine Datenverarbeitung....

Hier gab es natürlich nicht viel zu ändern, aber immerhin konnte ich so mal sehen das es anständig klappt.
Das ganze funktioniert so natürlich leider nicht, da ich ein Start und Stopbyte genommen habe:
00 01 02 D2 C8 00 00 00 FF 80 43 19 FE FF
Als Startbyte habe ich 01 gewählt und als Stopbyte FE. Diese sollten später zwar auch gleich bleiben, jedoch werden andere bytes diesen Wert durchlaufen, daher leider nicht praktikabel.

Würde die Möglichkeit bestehen das Beispiel auf meine Anforderungen abzuändern, oder macht es dann doch mehr Sinn alles neu zu entwerfen?

Ich komme leider gerade nicht wirklich weiter, mir fehlt einfach die Praxis und Erfahrung in diesem Bereich.

edit: Vermutlich könnte ich FE FF am Ende als Stopbytes nehmen. Die dürften sich in meinem fall nicht ändern.

Eine Endekennung brauchst Du nicht unbedingt, denn die Anzahl Nutzbytes nach den drei Anfangsbytes ist ja immer 11.

Jetzt hast Du einen Apparat, der nur aufgrund eines Bytes den Zustand ändert.
Ich denke, dass es vielleicht hilfreich ist, mal ganz genau aufzuschreiben was da passieren soll.
Dann gießt es sich danach fast von allein in Code. Den kannst Du dann immer noch aufhübschen.

Schau mal:

Zustand	                    Empfangenes Byte   Bedingung                  nächster Zustand
-------------------------------------------------------------------------------------------------------
0  warte auf Startbyte0     0                  erstes Startbyte korrekt   1
                            alles außer 0      das war nicht der Anfang   0
1  warte auf Startbyte1     1                  zweites Startbyte korrekt  2
                            alles außer 1      das war wohl nix           0
2  warte auf Startbyte2     2                  zweites Startbyte korrekt  3  (Zähler auf 0 setzen)
                            alles außer 2      das war wohl nix           0
3  Datenempfang läuft       alles              Zähler < 11                3  (weiter empfangen) 
                                               Zähler >= 11               0  (Paket komplett, von vorn) 
-------------------------------------------------------------------------------------------------------

hier mit Check auf die ersten 3 und die letzten 2 Bytes

/*
    Serial Receive 
    0x00 0x01 0x02 0xD2 0xC8 0x00 0x00 0x00 0xFF 0x80 0x43 0x19 0xFE 0xFF

    3 Startbytes fix
    2 Endbytes fix
    14 bytes ingesamt fix

    by noiasca
    https://forum.arduino.cc/index.php?topic=682436
 */

const byte numChars = 32;
byte receivedChars[numChars];

boolean newData = false;

void setup() {
  Serial.begin(115200);
  Serial.println("<Arduino is ready>");
}

void loop() {
  recvWithStartEndMarkers();
  showNewData();
}

void recvWithStartEndMarkers() {
  static boolean recvInProgress = false;
  static byte ndx = 0;
  byte rc;
 
  while (Serial.available() > 0 && newData == false) {
    rc = Serial.read();
    

    if (recvInProgress == false && rc == 0)
    {
      memset(receivedChars, 0, numChars);
      ndx = 0;
      recvInProgress = true;
      receivedChars[ndx] = rc;
      Serial.println();
    }
    else if (recvInProgress)
    {
      ndx++;
      receivedChars[ndx] = rc;
    }
    Serial.print(rc, HEX); Serial.print(" ");

    if (recvInProgress && ndx == 1 && rc !=1)
    {
      Serial.println("\n reset 1");
      ndx = 0;
      recvInProgress = false;
    }

    if (recvInProgress && ndx == 2 && rc !=2)
    {
      Serial.println("\n reset 2");
      ndx = 0;
      recvInProgress = false;
    }
    if (recvInProgress && ndx == 12 && rc !=0xFE)
    {
      Serial.println("\n reset 12");
      ndx = 0;
      recvInProgress = false;
    }
    if (recvInProgress && ndx == 13 && rc !=0xFF)   
    {
      Serial.println("\n reset 13");
      ndx = 0;
      recvInProgress = false;
    }

    if (ndx >= 13)
    {
      ndx = 0;
      newData = true;
      recvInProgress = false;
    }
  }
}

void showNewData() {
  if (newData == true) {
    Serial.print("\nThis just in:");
    for (byte i = 0; i < 14; i++)
    {
      if (receivedChars[i] < 0x10) Serial.print("0");
      Serial.print (receivedChars[i], HEX);
      Serial.print(" ");
    }
    Serial.println();
    newData = false;
  }
}

kann man nun noch zusammenräumen und verkürzen, hab aber keine Lust mehr ^^

(deleted)