Die Befehlsausgabe zum Display beschränkt sich auf simples ausgeben der "extern" zusammen gebastelten Kommandokette, eine weitere Funktion zum einfügen von z.B. ".txt=" in die Struktur halte ich nicht für sinnvoll.
In Richtung Display -> Controller verwende ich eine Struktur, die entsprechend gesendet werden muss:
Startbyte, Kommandobyte, Datenbytes, Endbyte.
Jeder weiß ja was der entsprechende Tastendruck bewirken soll und kann die entsprechenden Daten zusammenstellen.
Das Kommandobyte enthält entweder die aktuelle Seitennummer oder eine selbst definierte "externe" ID von 0x20 bis 0xFF, das sind 224 ID's, die bis zu 15 Byte Datenanhang haben können.
Das sollte für fast alle Anwendungen reichen.
Falls nicht wird der Bereich von 0x00 bis 0x31 als Seitennummer behandelt, der 127 Komponenten-ID's folgen können. Von diesen kann eine beliebige Anzahl als dual-state deklariert werden, die direkt im Bit 7 ihren Status senden.
Das Endbyte besteht aus 0xF und Anzahl gesendete Datenbytes.
AA C1 33 44 55 F3 ext. ID C1 drei Bytes 33 44 55
Kommando bzw. Page liegen als Byte (switch, case) vor, die Daten (max. 15 Byte) in einem Array.
Es gibt eine weitere Funktion, die direkt den "Wert" einer Komponente abfragt
(get page.component) und als int oder Liste (txt) ablegt.
Vielleicht hat jemand Interesse und testet mal mit.
Anzahl der Datenbytes nach dem 3 0xFF halte ich für ungünstig.
Welchen Vorteil soll Dein System gegenüber der normalen Kommunikation ohne Nextion-Lib bringen?
Wenn da jemand mit testen können soll, fehlt Deine Lib dazu.
Ich habe überhaupt keine lilablassblaue Verschimmerung wie deine Excel-Tabelle mit vorhanden Nextion-Projektdateien zusammenhängt.
In einem Nextion-Projekt werden üblicherweise im Nextion-Editor Objekte wie Labels, Buttons usw. definiert und diese Objekte kann mann dann über ihre Namen ansprechen.
Und wie hängen dann deine Bytefolgen damit zusammen?
Ich frage mich sogar ob du überhaupt ein Nextion-Display hast das du damit ansteuerst.
void ButtonStartRot() {
Serial2.print(F("b0.bco=63488")); // "b0" Bezeichner de Buttons ".bco" Eigenschaft backgroundcolor des Buttons
Serial2.print(F("\xFF\xFF\xFF")); // Sends 0xff 0xff 0xff, which tell the Nextion that it has a complete string of data
}
void ButtonStartWeiss() {
Serial2.print(F("b0.bco=65535"));
Serial2.print(F("\xFF\xFF\xFF")); // Sends 0xff 0xff 0xff, which tell the Nextion that it has a complete string of data
}
void ButtonStopRot() {
Serial2.print(F("b1.bco=63488"));
Serial2.print(F("\xFF\xFF\xFF")); // Sends 0xff 0xff 0xff, which tell the Nextion that it has a complete string of data
}
void ButtonStopWeiss() {
Serial2.print(F("b1.bco=65535"));
Serial2.print(F("\xFF\xFF\xFF")); // Sends 0xff 0xff 0xff, which tell the Nextion that it has a complete string of data
}
Er beendet den Inhalt mit 3 Mal 0xff, wie die normale Übertragung und sendet danach die Anzahl der Nutzbytes:
0xff,0xff,0xff,Anzahl
Ich meine die Nutzung des Nextion Instruction Set, da man meist sowieso nur wenige Funktionen braucht.
Dazu die universelle Empfangsroutine nach Whandall
// nach Whandall 05.09.2019 forum.arduino.cc
// https://forum.arduino.cc/t/nextion-component-id-trennen/609217/19
const byte bufferSize = 15;
uint8_t buffer[bufferSize];
void setup() {
Serial.begin(115200);
Serial2.begin(9600);
}
bool readNex(Stream &s) {
static uint8_t bIndex = 0;
bool allesDa = false;
if (s.available()) {
uint8_t inChar = s.read();
buffer[bIndex++] = inChar;
// 0x71 bei diesen Paketen können drei 0xFF Bestandteil des Pakets sein,
// also ergibt es nur Sinn auf die Delimiter hinter dem Wert zu testen
if (inChar == 0xFF && (bIndex >= (*buffer == 0x71 ? 8 : 3)) &&
buffer[bIndex - 2] == 0xFF && buffer[bIndex - 3] == 0xFF) {
allesDa = true;
} else {
allesDa = (bIndex == bufferSize);
}
}
if (allesDa) bIndex = 0; // Index zurücksetzen
return allesDa;
}
void loop() {
unsigned long varVomNextion =0;
bool fertig = readNex(Serial2);
if (fertig && buffer[0] == 0x71) { // Buffer[0] enthält das Kennbyte, nach dem die Auswertung erfolgen muss - hier numerische Daten
varVomNextion = buffer[1]+buffer[2]*256+buffer[3]*65536+buffer[4]*16777216;
Serial.println(varVomNextion);
}
}
Wie wird denn diese Anzahl verarbeitet wenn die Kennung "Ende des Strings" = 0xFF0xFF0XFF schon gesendet wurde?
Mit meinem Halbwissen würde ich jetzt vermuten, dass bytes die nach der Ende-Kennung gesendet werden als Beginn der nächsten Bytefolge interpretiert werden.
Die allseits bekannte Form mit dem Vorteil, dass die Kommandos (bis auf die drei FF am Ende) im Klartext lesbar sind, was m.E. die Fehlersuche doch sehr erleichtert
Den "Address mode", der offensichtlich besonders dann nützlich sein könnte, wenn mehrere Display an einer seriellen Verbindung hängen und jedes davon getrennt angesprochen werden soll (General Rules 19)
Und am Ende auch den "Protocol Reparse" - möglicherweise Voraussetzung für Deine Idee, weil Du die gesendeten Bytes auf dem Display selbst dekodieren kannst bzw. sogar musst (General Rules 20).
Es gibt nun wohl zwei Möglichkeiten:
eine Library auf der CPU (Arduino, ESP) setzt Deine Binärkommandos in normale Nextion-Instruktionen um. Dafür benötigt sie aber Kenntnis der UI-Konfiguration des Displays
Parser auf dem Display selbst
In beiden Fällen fehlen nötige Informationen. Ich persönlich bin bisher auch mit dem normalen Modus der Displayansteuerung, insbesondere wegen der Klartextkommandos, ganz gut gefahren und zufrieden.
Vielleicht habe ich es auch noch nicht ganz verstanden und wesentlicher Zweck sind nur die Rückmeldungen vom Display.
Damit ist das schon mal raus, da man da logischerweise nichts ändern kann.
Was macht die ?
Liest einen vom Display gesendeten little endian - Wert ein, von dem vorher noch ermittelt werden muss von wem er stammt.
Wovon ich rede:
D.h. ich lege fest was und wie gesendet wird gesendet wird wenn etwas gesendet werden soll.
simples praktisches Beispiel, ein Button schaltet eine Pumpe um (an/aus).
Der Button sendet AA B4 F0
case 0xB4:
-> alles was mit Pumpe umschalten zu tun hat
break;
Ich lese also nicht kompliziert irgendwelche Daten aus, sondern sende was genau benötigt wird dorthin wo es benötigt wird (eindeutige Zuordnung durch die "externe ID".
Damit kann man z.B. auf dem Display Daten verknüpfen und senden, die kompletten Einstellungsdaten einer Seite senden usw.
Genau das habe ich in #1 geschrieben, es geht ausschließlich um die Steuerung des Controllers.
Ich bin noch am basteln der *.hmi zu Demozwecken, dann stelle ich alles ein.
Man kann wie in meinem Beispiel gezeigt vom Microcontroller zum Display Befehle senden die zum Beispiel die Farbe eines Buttons ändern. Im Nextion-Editor gibt es eine Menge Eigenschaften die man durch Senden von Befehlen Microcontroller==>Display anders setzen kann.
void ButtonStartRot() {
Serial2.print(F("b0.bco=63488")); // "b0" Bezeichner de Buttons ".bco" Eigenschaft backgroundcolor des Buttons
Serial2.print(F("\xFF\xFF\xFF")); // Sends 0xff 0xff 0xff, which tell the Nextion that it has a complete string of data
}
Und für die Richtung Microcontroller ==> Display braucht man das dreifach 0xFF
Ok, ich hatte übersehen, dass es bei Dir nur 1 0xf sein soll. Sorry, mein Fehler.
Kannst Du garantieren, dass das 0xf nicht irgendwo als Inhalt auftaucht?
Dass die Länge nach dem Ende in meinen Augen unsinnig ist, bleibt aber bestehen.
Wenn Du meinen Text wirklich mal gelesen hättest wüsstest Du das es eben nicht das 0xF allein ist.
Wie hoch schätzt Du die Wahrscheinlichkeit, dass in den Daten ein 0xF mit exakt der Anzahl der bereits empfangenen Bytes codiert in den unteren vier Bit vorkommt?
Klar kann man die Bytezahl an den Anfang setzen, nur weiß der Mikrocontroller dann nicht wann Schluss ist. Wie hoch hättest Du den timeout denn gern?
Sorry, aber lies Dir mal meine Beiträge zum Thema Nextion durch.
Das ist falsch, den dann würde z.B. mein Debugger für das nextion instruction set auf dem Display nicht laufen können.
Nur macht es in Richtung Controller -> Display außer in zeitkritischen Anwendungen keinen Sinn den aktiven protocol reparse mode zu verwenden.
Okay, so langsam fange ich an zu verstehen was Du da treibst (jedenfalls glaube ich das ).
So auf die Schnelle und ohne Bewertung, nur erster Eindruck:
Du ersetzt einen zugegebenermaßen u.U. aufwendigen Parser auf dem Controller durch einen einfachen, generischen und durch Code auf dem Display für jede erforderliche Rückmeldung.
Muss ich mal in einer ruhigen Stunde genauer drüber nachdenken.
Hmm. Vielleicht sollte "auf Anfang" doch eine Chance bekommen können:
Controller empfängt erstes Byte (oder zweites, wenn 0xAA das Startbyte bleiben soll), maskiert das High Nibble aus und hat dann mit dem Low Nibble (ggf. einmal inkrementiert) gleich einen Zähler für den Rest der Übertragung. Wenn der auf 0 runtergezählt hat, ist fertig.
Anstatt kompliziert zu ermitteln was den auf dem Display gedrückt wurde meldet sich die Komponente mit ihrer ID (wenn sie denn etwas mitzuteilen hat ). Der Mikrocontroller "weiß" also sofort um was es geht und kann die entsprechende Routine anspringen.
Und anstatt anschließend kompliziert mit get page.component.(val,txt) alle Werte zusammen zu suchen werden sie eben gleich mitgeliefert.
Geht prinzipiell, widerspricht aber dem Grundgedanken der Funktionsweise des Displays, welches selbst komplizierte Berechnungen durchführen kann.
Warum sollte man aufwendig Daten vom Display lesen, bearbeiten und wieder zum Display schicken wenn dieses das alles selbst kann und sich selbst meldet wenn erforderlich?
Meine Kalenderdaten z.B. werden vom ESP einfach an das Display durchgereicht, diese stellt dann eigenständig die Termine von z.B. morgen 6:00 Biotonne Leerung auf heute Biotonne rausstellen um, generiert Alarme wenn erforderlich und was sonst noch so anfällt.
Der Timer der das handelt hat über 500 Codezeilen.
Warum so etwas verschwenden, daher werden die Datenbytes über eine eigene Funktion gelesen und auf dem Display kann eine Routine laufen die den Datenstrom generiert, sendet und dabei einfach mitzählt.
Steht die Anzahl vorn muss auf dem Display die Routine durchlaufen werden, alles zwischengespeichert werden (was schon wieder komplizierte Vorgänge erfordert), nachgezählt werden und kann erst dann gesendet werden.