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 
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 
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 
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