Serial.read bei Nextion Display

Hallo zusammen,
Wenn die Nextion Displays etwas über serial verschicken, sind die letzten 3 byte immer mit 0xFF terminiert. Momentan nutze ich in meinem Programm folgende Funktion (aus dem Netz geklaut) um die vom Display gesendeten Daten auszulesen:

void recvWithEndMarker() {
    static byte index      = 0;
    char        endMarker  = 0xFF;
    char        rc;

    while (Serial.available() > 0 && nextionNewData == false) {
        rc = Serial.read();

        if (rc != endMarker) {
            nextionReceivedChars[index] = rc;
            index++;
            if (index >= nextionNumChars) {
                index = nextionNumChars - 1;
            }
        } else {
            nextionReceivedChars[index] = '\0';
            index                       = 0;
            nextionNewData              = true;
        }
    }
}

Funktioniert an sich ganz gut, außer wenn das Nextion 0xFF als Bestandteil der Daten schickt. Als Beispiel:

Dezimal 10 vom Display über serial -> 71 0A 00 00 00 FF FF FF -> kein Problem
Dezimal 511 vom Display über serial -> 71 FF 01 00 00 FF FF FF -> Problem, da nach FF nichts mehr eingelesen wird.

Lange Rede kurzer Sinn: wie kann ich es bewerkstelligen, die ganze Zeile einzulesen und nur die letzten 3 FF wegzuschneiden?

Vielen Dank schon mal :wink:

Lies Dir mal diese Diskussion durch.

Gruß Tommy

Z.B. so

const char nextionNumChars = 25;
char nextionReceivedChars[nextionNumChars]; // die Antwort ohne Endekennung
bool nextionNewData = false;  // true wenn Antwort komplett, muss nach Auswerten vom Aufrufer rückgesetzt werden

bool recvWithEndMarker(Stream& nextion) {
    static byte index      = 0;
    const char endMarker  = 0xFF;
    char  rc=0;

    while (nextion.available() && ! nextionNewData) {
        rc = nextion.read();
        nextionReceivedChars[index] = rc;
        if (index < nextionNumChars-1) index++;
    }
    if (rc != endMarker) return false; // not complete yet

    while (rc == endMarker) { // zurück vor den letzten endMarker
        index--;
        rc = nextionReceivedChars[index-1]; 
    } 
    nextionReceivedChars[index] = '\0';
    index  = 0;
    return (nextionNewData  = true);
}

ungetestet, kompiliert immerhin

Nachtrag:
Allerdings sollte man sicherheitshalber eine kleine Wartezeit drinhaben, nicht dass zufällig die letzten FF Teil einer Binärzahl sind und das Telegramm noch mitten im Empfangen steckt.

Und wer sagt, dass das Nextion Display an Serial hängt?

Danke für die Hilfe, leider bin ich noch nicht wirklich weiter gekommen, ich muss noch ein bisschen rumprobieren

Sorry, für die späte Antwort.

Versuche gerade selber eine Funktion zu schreiben, da mir der link bzw. der Code von euch leider nicht weiterhelfen. Kapiers einfach nicht :wink:

Da sämtliche Antworten vom Nextion eine feste Länge haben (mit Ausnahme von Strings) versuche ich gerade die Auswertung folgendermaßen zu erledigen:

void recvFromNextion() {
    static byte index     = 0;
    char        endMarker = 0xFF;
    char        rc;
    static bool headerRead = false;

    while (Serial.available() > 0 && !nextionNewData) {
        rc = Serial.read();
        if (!headerRead) {
            nextionReceivedChars[index] = rc;
            index++;
            headerRead = true;
        }
        if (headerRead) {
            if ((nextionReceivedChars[0] == 0x65) && (index <= 6)) {
                nextionReceivedChars[index] = rc;
                index++;
            } else if ((nextionReceivedChars[0] == 0x66) && (index <= 4)) {
                nextionReceivedChars[index] = rc;
                index++;
            } else if ((nextionReceivedChars[0] == 0x71) && (index <= 7)) {
                nextionReceivedChars[index] = rc;
                index++;
            } else if (nextionReceivedChars[0] == 0x70) {
                if (rc != endMarker) {
                    nextionReceivedChars[index] = rc;
                    index++;
                    if (index >= nextionNumChars) {
                        index = nextionNumChars - 1;
                    }
                } else {
                    nextionReceivedChars[index] = '\0';
                }
            } else {
                Serial.println(nextionReceivedChars[0]);
                nextionTerminate();
                Serial.println(nextionReceivedChars[1]);
                nextionTerminate();
                Serial.println(nextionReceivedChars[2]);
                nextionTerminate();
                Serial.println(index);
                nextionTerminate();
                index          = 0;
                nextionNewData = true;
                headerRead     = false;
            }
        }
    }
}

Sobald der erste char eingelesen wurde, weiß man um welches Datagram es sich handelt (sendme, get, currentID, usw) und je nach Typ wird eine fixe Anzahl an bytes eingelesen. Außer beim String (ID 0x70) hier wird auf den Endmarker 0xFF gewartet. Die Serial.prints im Unteren Bereich dienen momentan nur zu Versuchszwecken, und genau da habe ich momentan ein Problem:
Wenn ich den Code, so wie er hier steht ausführe, funktioniert alles an sich sehr gut, die einzelnen chars werden in das char-array nextionReceivedChars geschrieben. Allerdings haben nextionReceivedChars(0) und nextionReceivedChars(1) immer den selben Wert. Der Grund dafür ist mir klar, da bist zum ersten Schreiben nach headerRead kein neues Serial.read aufgerufen wird. Habe bereits versucht nach headerRead=true ein Serial.read() einzubauen und auch das erste index++ wegzulassen, aber sobald ich das mache, erhalte ich nur nach jedem Zweiten Durchlauf des Codes eine Ausgabe von Serial.print. Dieses Verhalten leuchtet mir gar nicht ein :confused:
recvFromNextion() wird im loop aufgerufen und nextionNewData wird nach der Verarbeitung der Daten zurückgesetzt.
Wo könnte hier das Problem liegen??

mfg
Mike

Hi

Was soll der Code wo machen?
Ein/zwei Kommentare wären hier doch schon was wert.

MfG

Sorry, hier mit ein paar Kommentaren

void recvFromNextion() {
    static byte index     = 0;       // Index für char array
    char        endMarker = 0xFF;    // Endmarker
    char        rc;                  // gelesener char
    static bool headerRead = false;  // 1 wenn erster Char (Header) gelesen wurde

    while (Serial.available() > 0 && !nextionNewData) {
        rc = Serial.read();  // Lesen von Serial
        if (!headerRead) {   // Wenn Header noch nicht gelesen wurde
            nextionReceivedChars[index] = rc; // Schreibe Header in Char Array Index 0
            index++;
            headerRead = true;
        }
        // Je nachdem welcher Header erhalten wurde, wird im nächsten Abschnitt entschieden wieviele Chars eingelesen werden sollen
        if (headerRead) {                                             // Wenn Header bereits gelesen wurde
            if ((nextionReceivedChars[0] == 0x65) && (index <= 6)) {  // Header = 0x65 (nextion Component ID), 7 Chars werden verarbeitet
                nextionReceivedChars[index] = rc;
                index++;
            } else if ((nextionReceivedChars[0] == 0x66) && (index <= 4)) {  // Header = 0x66 (nextion sendme), 5 Chars werden verarbeitet
                nextionReceivedChars[index] = rc;
                index++;
            } else if ((nextionReceivedChars[0] == 0x71) && (index <= 7)) {  // Header = 0x81 (nextion get numeric), 8 Chars werden verarbeitet
                nextionReceivedChars[index] = rc;
                index++;
            } else if (nextionReceivedChars[0] == 0x70) {  // Header = 0x70 (nextion get string), chars bis erreichen des endMarkers (0xFF) werden verarbeitet
                if (rc != endMarker) {
                    nextionReceivedChars[index] = rc;
                    index++;
                    if (index >= nextionNumChars) {  // Verhindert dass über die Array Grenze geschrieben wird
                        index = nextionNumChars - 1;
                    }
                } else {
                    nextionReceivedChars[index] = '\0';
                }
            } else {                                      // Wenn alle Chars eingelesen wurden oder Header unbekannt
                Serial.println(nextionReceivedChars[0]);  // Nur für Testzwecke
                nextionTerminate();                       // Nur für Testzwecke Schreibt 3x 0xFF an Nextion
                Serial.println(nextionReceivedChars[1]);  // Nur für Testzwecke
                nextionTerminate();                       // Nur für Testzwecke Schreibt 3x 0xFF an Nextion
                Serial.println(nextionReceivedChars[2]);  // Nur für Testzwecke
                nextionTerminate();                       // Nur für Testzwecke Schreibt 3x 0xFF an Nextion
                Serial.println(index);                    // Nur für Testzwecke
                nextionTerminate();                       // Nur für Testzwecke Schreibt 3x 0xFF an Nextion
                index          = 0;
                nextionNewData = true;  // wird in loop abgerufen, verarbeitung der Daten erfolgt wenn true, wird danach auf false gesetzt
                headerRead     = false;
            }
        }
    }
}

Hi

Du prüfst in Deiner WHILE-Schleife, ob der Header bereits gesetzt ist.
Ja -> lese nachricht
Nein -> Lese Header (und setze Header auf 1).
DAS ist Dein Problem - Du machst Das genau anders herum - somit ist header IMMER 1, wenn Du an die 2.te IF kommst.
Also entweder die 2.te IF als ELSE (wird nur ausgeführt, wenn header schon gesetzt ist), oder die IFs umdrehen - wobei Du dann das Problem haben wirst, daß ein auf false zurück gesetzter header direkt den neuen header setzt.

Also

if (!header){
   //setze header
}else{
   //setze Nachricht/werte aus/beende Nachricht
}

So wird bei 'jedem Durchgang' ein neuer Wert eingelesen, der Header gesetzt, wenn zuvor nicht gesetzt war, sonst in die Nachricht geschrieben.

MfG

danke für den tipp, das hätte ich eigentlich auch bereits versucht. Allerdings bekomme ich dann nur nach jedem Zweiten Durchlauf des Codes (also wenn zwei mal vom Nextion etwas gesendet wird) eine Ausgabe und die sieht auch anders aus.
Wenn ich den Code wie vorhin gepostet verwende, bekomme ich folgende Ausgabe im Nextion Simulator. Als Beispiel hier, bei einem Seitenwechsel:
66 -> Header des Datagrams
66 -> Header des Datagrams
07 -> Seiten-Nr
35 -> Index als Zeichen "5"

Nutze ich statt dessen if/else, bekomme ich folgendes (wie gesagt nur nach jedem zweiten Durchlauf):
66 -> Header des Datagrams
07 -> Seiten-Nr
FF -> Terminate Char
35 -> Index als Zeichen "5" - Bis hier stimmt eigentlich alles
00 -> ?? möglicherweise Seitennummer auf die gewechselt wurde - Ab hier wirds merkwürdig
07
FF
31 -> Keine Ahnung wo das herkommt
FF
07
FF
31

Nextion sendet bei einem Seitenwechsel folgendes:
66 -> Header
07 -> Seiten-Nr
FF -> Terminator
FF -> Terminator
FF -> Terminator

Habs folgendermaßen gelöst:

void recvFromNextion() {
    static byte index     = 0;       // Index for Char Array
    char        endMarker = 0xFF;    // Endmarker
    char        rc;                  // incoming char
    static bool headerRead = false;  // 1 when first char (header) was read
    static bool stringComplete;// 1 when incoming string is read until endMarker
    static byte maxIndex = 0; // max expected bytes according to header

    while (Serial.available() > 0 && !nextionNewData) {
        rc = Serial.read();                   
        if (!headerRead) {                     // When header isn't read yet
            nextionReceivedChars[index] = rc;  // Write header in char arry index 0
            headerRead = true;
        }
        // maxIndex is set in the next section according to header
        if (headerRead) {  // When header is already read
            switch (nextionReceivedChars[0]) {
                // Header containing 4 Bytes
                case 0x00:  // Invalid Instruction
                case 0x02:  // Invalid Component ID
                case 0x03:  // Invalid Page ID
                case 0x04:  // Invalid Picture ID
                case 0x05:  // Invalid Font ID
                case 0x06:  // Invalid File Operation
                case 0x09:  // Invalid CRC
                case 0x11:  // Invalid Baud rate Setting
                case 0x12:  // Invalid Waveform ID or Channel #
                case 0x1A:  // Invalid Variable name or attribute
                case 0x1B:  // Invalid Variable Operation
                case 0x1C:  // Assignment failed to assign
                case 0x1D:  // EEPROM Operation failed
                case 0x1E:  // Invalid Quantity of Parameters
                case 0x1F:  // IO Operation failed
                case 0x20:  // Escape Character Invalid
                case 0x23:  // Variable name too long
                case 0x24:  // Serial Buffer Overflow
                case 0x86:  // Auto Entered Sleep Mode
                case 0x87:  // Auto Wake from Sleep
                case 0x88:  // Nextion Ready
                case 0x89:  // Start microSD Upgrade
                case 0xFD:  // Transparent Data Finished
                case 0xFE:  // Transparent Data Ready
                    maxIndex = 2;
                    break;

                // Header containing 5 Bytes
                case 0x66:  // Current Page Number (from sendme), byte2 = PageNr
                    maxIndex = 3;
                    break;

                // Header containing 7 Bytes
                case 0x65:  // Touch Event (from send Component ID), 2=PageNr, 3=ID, 4=event
                    maxIndex = 5;
                    break;

                // Header containing 8 Bytes
                case 0x71:  // Numeric Data Enclosed (from get of numeric values)
                    maxIndex = 6;
                    break;

                // Header containing 9 Bytes
                case 0x67:  // Touch Coordinate (awake), 2+3=x coord, 4+5=y coord, 6=event
                case 0x68:  // Touch Coordinate (sleep), 2+3=x coord, 4+5=y coord, 6=event
                    maxIndex = 7;
                    break;

                // Header containg string
                case 0x70:
                    break;
            }
            if ((index <= maxIndex) && (nextionReceivedChars[0] != 0x70)) { // Execute only if incoming datagram is not a string
                nextionReceivedChars[index] = rc;
                index++;
            } else if (nextionReceivedChars[0] == 0x70 && !stringComplete) { // Execute if incoming datagram is a string
                if (rc != endMarker) {
                    nextionReceivedChars[index] = rc;
                    index++;
                    if (index >= nextionNumChars) {  // Prevent writing out of array bounds
                        index = nextionNumChars - 1;
                    }
                } else { // if endMarker has been found
                    nextionReceivedChars[index] = '\0';
                    stringComplete              = true;
                }
            } else {                                    // If all chars were read or header is unknown
                Serial.print(nextionReceivedChars[0]);  // ONLY FOR TESTING
                Serial.print(nextionReceivedChars[1]);  // ONLY FOR TESTING
                Serial.print(nextionReceivedChars[2]);  // ONLY FOR TESTING
                Serial.print(nextionReceivedChars[3]);  // ONLY FOR TESTING
                Serial.print(nextionReceivedChars[4]);  // ONLY FOR TESTING
                Serial.print(nextionReceivedChars[5]);  // ONLY FOR TESTING
                Serial.print(nextionReceivedChars[6]);  // ONLY FOR TESTING
                Serial.print(nextionReceivedChars[7]);  // ONLY FOR TESTING
                Serial.print(nextionReceivedChars[8]);  // ONLY FOR TESTING
                Serial.print(nextionReceivedChars[9]);  // ONLY FOR TESTING
                nextionTerminate();                     // ONLY FOR TESTING
                index          = 0;
                nextionNewData = true;  // is called in loop for further processing, gets FALSE when processing is finished
                headerRead     = false;
                stringComplete = false;
            }
        }
    }
}

Für sämtliche Datagramme (außer Strings) wird eine feste Anzahl an Bytes eingelesen. Bei Strings wird bis auf das erscheinen von 0xFF gewartet. Somit kann die Funktion für Numerische Werte und Texte verwendet werdeb