NEXTION Display: Serielle Schnittstelle abfragen ohne Library?

Ok, ich habe jetzt mal Punkt1 von deinem letzten Post befolgt und die _P dort entfernt, wo der Compiler sie bemängelt hat. Jetzt bleibt im Moment noch ein Error, nämlich die Sache mit der dtostrf-Funktion:

WhandallNextion.cpp:1182:52: error: 'dtostrf' was not declared in this scope

Du hast gemeint, ich könnte das durch sprintf-Formatierung ersetzen.
Die betroffene Formatierung lautet in deinem Original:

set(dtostrf(value, 2 + nachkomma, nachkomma, buff));

die dtostrf habe ich verstanden, hoffe ich:
dtostrf([float],[Anzahl der gesamten Länge des umgewandelten String inkl. Dezimaltrennzeichen],[Anz. Nachkommastellen], buff)
stimmt das so?

soll ich diese Zeile in eine sprintf- Formatierung umwandeln? Wenn ja, kannst du bitte so nett sein und mir dabei helfen?

printf() ist eine alte und sehr weit verbreitete Standard Funktion. Da findest du endlos Anleitungen dazu. z.B.:

http://www.cplusplus.com/reference/cstdio/printf/

sprintf() geht genauso nur dass man in einen Puffer schreibt

ist

sprintf(buff, "%2 + nachkomma.nachkomma", value);

komplett daneben?

Ja, ziemlich.

Wenn dein Kompiler das Ersetzen der Präzisionsangabe durch einen Parameter unterstützt müsst das gehen:

sprintf(buff, "%.*f", nachkomma, value);

Leider geht das beim AVR gcc nicht.

The variable width or precision field (an asterisk * symbol) is not realized and will to abort the output.

Aber da kann man sich dann so behelfen:

char format[10];
int nachkomma = 2;
sprintf(format, "%%.%df", nachkomma);
sprintf(buff, format, value);

Danke!

wenn ich es mit

set(sprintf(buff, "%.*f", nachkomma, value));

probiere, kommt folgender error:

error: invalid conversion from 'int' to 'const char*' [-fpermissive]
set(sprintf(buff, "%.*f", nachkomma, value));

wenn ich deinen code ändere:

void NxText::set(float value, uint8_t nachkomma) {
  char buff[10] = "";
    
    char format[10];
int nachkomma = 2;
sprintf(format, "%%.%df", nachkomma);

    set(sprintf(buff, format, value));

}

sieht es so aus:
WhandallNextion.cpp:1184:5: error: declaration of 'int nachkomma' shadows a parameter
int nachkomma = 2;

^
/Arduino/libraries/WhandallNextion/src/WhandallNextion.cpp:1187:36: error: invalid conversion from 'int' to 'const char*' [-fpermissive]
set(sprintf(buff, format, value));

^
/Arduino/libraries/WhandallNextion/src/WhandallNextion.cpp:1176:6: error: initializing argument 1 of 'void NxText::set(const char*)' [-fpermissive]
void NxText::set(const char* txt) {

^

Sieht so aus als gäbe es da ein Problem mit der Parameterübergabe ins set(char*).
Zieh das mal auseinander:

sprintf(buff, format, value);
set(buff);

Warum hast du diesen

WhandallNextion.cpp:1184:5: error: declaration of 'int nachkomma' shadows a parameter
int nachkomma = 2;

Fehler jetzt da eingebaut?

Ok, sprintf() ist geklärt:-)

int nachkomma=2 war irrtümlich da...

Der Kompiler werkelt weiter und bleibt bei folgendem hängen:

Arduino/libraries/OUtility/src/OUtility.cpp: In function 'void fhAdr(const void*)':
/Arduino/libraries/OUtility/src/OUtility.cpp:729:20: error: cast from 'const void*' to 'uint16_t {aka short unsigned int}' loses precision [-fpermissive]
phByte(((uint16_t)adr)>>8);

^
/Arduino/libraries/OUtility/src/OUtility.cpp:730:19: error: cast from 'const void*' to 'uint16_t {aka short unsigned int}' loses precision [-fpermissive]
phByte((uint16_t)adr);

^

Bei dir sind Pointer 32 Bit lang, also musst du anders casten, shiften und natürlich auch mehr Bytes drucken.

Alternativ geht das natürlich auch via sprintf mit dem Format "%p".

Hm- nachdem der Kompiler die Überraschungen ja nur schrittweise ausspuckt, wäre meine Frage jetzt:

An wie vielen Stellen werde ich wohl anders anders casten, shiften und mehr Bytes drucken müssen? Und was ist sonst noch zu erwarten, nachdem das gelöst ist? Meinst du, da kommt noch viel??

Was bedeutet "anders casten, shiften und natürlich auch mehr Bytes drucken" denn für mich genau? Was soll ich genau ändern?

Findest du nicht dass du jetzt mit dem Verlangen nach einem Grundkurs in Programmierung etwas über das Ziel hinausschießt?

void fhAdr(const void* adr) {
  phByte(((uint32_t)adr)>>24);
  phByte(((uint32_t)adr)>>16);
  phByte(((uint32_t)adr)>>8);
  phByte((uint32_t)adr);
  pBlAfter(':');
}

oder

void fhAdr(const void* adr) {
  char buff[11];
  sprintf(buff, "%p: ", adr);
  SerialUSB.print(buff);
}

Ich weiß nicht, ob ich übers Ziel schieße, weil ich meine eigene Frage nicht verstehe;-)
Glaub mir, ich weiß deine Bemühungen sehr zu schätzen, aber ich glaube, wir sollten es an diesem Punkt lieber lassen. Ich verstehe leider zu wenig von der Materie, um deine Tipps umzusetzten und habe die Befürchtung, dass da noch einige afragen dieser Art auftauchen würden, und selbst wenn ich einen Sketch zum Compilen bringe, hätteich immer noch Sorge, dass ich selbst ein paar Fehler in die alibrary eingebaut habe, sodass sie im Endeffekt instabiler läuft als die itead-Library.
Nochmals danke- ich finde, es war trotzdem nicht umsonst und sich ein paar Forumsteilnehmer Anregungen holen werden...

Na dann.

Ok, ich bin doch noch im Rennen - ich habe jetzt nämlich auf Teufel komm raus noch deinen Code eingefügt (ehrlich gesagt, ohne genau zu wissen, was ich tue), und siehe da - kein Error mehr. Weißt du, ich dachte nur, es werden bestimmt noch mehr neue Fehler auftauchen und ich wollte dich nicht mehr nerven. Nachdem der Sketch jetzt aber tatsächlich fertig kompiliert hat, werde ich mich doch ans Ausprobieren machen. Entschuldige, wenn ich so wankelmütig bin, aber ich bin einfach verunsichert, weil ich hier eigentlich in fremden Gewässern fische;-)

Gut so, wer aufgibt hat sofort verloren. :wink:

Aber ich will nicht auch noch als Motivationstrainer auftreten,
man sollte niemanden zu seinem Glück zwingen.

Ist ja schön dass du dich jetzt doch damit auseinandersetzen willst,
bisher war ich ja der einzige der das (und auch nur wenig) benutzt hat.

Eine Bitte hätte ich noch:

Du hast ja schon zwei Beispiele gebracht, aber es würde mir extrem helfen, wenn du einen Beispiel-Sketch schreiben könntest, der folgendes beinhaltet:
1.Ein Beispiel-Objekt, z.B. ein Num-Objekt
2.Ein Beispiel-Commando im Haupt-loop() zum Ändern einers Wertes in dem Objekt (z.b Hintergrundfarbe, oder auch den Zahlenwert selbst)
3. Ein Beispiel zum Abfragen eines Wertes aus dem Objekt in eine Variable, die dann im Haupt-Loop zur Verfügung steht

Ich glaube, das würde mir helfen, den Code zu durchschauen. Es geht mir wirklich nicht darum, die Programmier-Arbeit auf dich abzuwälzen, es wäre einfach gut, ein möglichst simples und richtig implementiertes Beispiel zu haben, an dem ich mich entlangtasten kann. Ich habe derzeit sämtliche Files aus allen deinen Libraries geöffnet und seh grad vor lauter Bäumen den Wald nicht (welche Funktion macht was etc...). Daaaanke!

Beim Testen des Beispiels habe ich direkt einen Fehler entdeckt.

void NxNum::set(long value) {
  setAtt(pmsVal, value);
}

dort stand vorher pmsText, was natürlich nicht geht.

Ich habe ein Feld stdText (page 0, id 1) und stdNum (page 0, id 2) definiert,
beide mit "send component id" bei "Touch release event".
Der Beispielcode spielt in erster Line an dem Nummern Feld rum.

Der Kode setzt die Nummer auf die Zahl der abgelaufenen Sekunden seit Start.

Der Touch Event der Nummer löst ein get .val aus, das erschien mir als das Einfachste.

"c" zeigt die Debug-Ausgabeeinstellungen an, "c=0" schaltet alle aus, "c=-1" alle ein,
"c" schaltet einzelne Optionen um.

silent unterdrückt die Ausgabe von commandHandler.

#include <WhandallSerial.h>
#include <WhandallNextion.h>

void processCmd(const char* buf);

const char PROGMEM pmsEvt[] = "evt 0x";
const char PROGMEM pmsCntt[] = " cnt ";

const char pmsNumber[] PROGMEM = "stdNum";
const char pmsText[] PROGMEM = "stdText";

const char pmsEquals[] PROGMEM = " = ";
const char pmsPage0[] PROGMEM = "page 0";
const char pmsBkcmd3[] PROGMEM = "bkcmd=3";

SSerial con(dbSerial, processCmd);
SSerial Nxi(NexSerial, NxObject::inHandler);

void pReasonT(nxReason reason, NxText* which) {
  pReasonX(reason, which);
}
void pReasonN(nxReason reason, NxNum* which) {
  pReasonX(reason, which);
}
void pReasonX(nxReason reason, NxObject* which) {
  dbSerial.print(FPM(which->name()));
  dbSerial.write(' ');
  pNxReason(reason);
  dbSerial.println();
}

bool silent = false;
bool newNumbersValue;
int32_t numbersValue;

void numAction(nxReason reason, NxNum* which) {
  if (reason != done) {
    pReasonX(reason, which);
  }
  if (reason == up) {
    which->get();
  } else if (reason == retNum) {
    newNumbersValue = true;
    numbersValue = which->accNumResult();
  }
}

NxText nxTxt(0, 1, pmsText, pReasonT);
NxNum  nxNum(0, 2, pmsNumber, numAction);

const char announce[] PROGMEM = "Mini Example";


void setup() {
  dbSerial.begin(250000);
  NexSerial.begin(115200);
  con.begin(64);
  Nxi.begin(64, optTripleFF | optKeepDlm);
  NxObject::setGlobalHandler(pagePosHandler, commandHandler);
  NxObject::prControl.fromEEProm();
  dbSerial.println(AF(announce));
  NexCommand_P(pmsBkcmd3);
  NexCommand_P(pmsPage0);
}

void loop() {
  static uint32_t lastIncrement;
  static int32_t numValue;
  uint32_t topLoop = millis();
  con.loop();
  Nxi.loop();
  if (topLoop - lastIncrement >= 1000) {
    lastIncrement = topLoop;
    nxNum.set(++numValue);
  }
  if (newNumbersValue) {
    newNumbersValue = false;
    dbSerial.print(F("stdNum hat den Wert "));
    dbSerial.print(numbersValue);
    dbSerial.println(F(" an das Hauptprogramm abgegeben"));
  }

}

void withOneByte(const char* buf, void (*alAction)(uint8_t)) {
  (*alAction)((uint8_t)strtol(++buf, NULL, 0));
}

void withAdrLenPrefix(const char* buf, void (*alAction)(const uint8_t*, int, const char*), const char* pfx = NULL) {
  int len = 16;
  char* satis;
  uint8_t* res = (uint8_t*)strtol(++buf, &satis, 0);
  if (*satis == ',' || *satis == ' ') {
    len = (int)strtol(++satis, &satis, 0);
  }
  (*alAction)(res, len, pfx);
}

void withAdrLenPrefixLong(const char* buf, void (*alAction)(unsigned long, int, const char*), const char* pfx = NULL) {
  int len;
  char* satis;
  unsigned long res = strtoul(++buf, &satis, 0);
  if (*satis == ',' || *satis == ' ') {
    len = (int)strtol(++satis, &satis, 0);
  } else {
    len = 16;
  }
  (*alAction)(res, len, pfx);
}

void processCmd(const char* buf) {
  if (*buf == '!') {
    if (*++buf) {
      NexCommand(buf);
    } else {
      dbSerial.println(F("pass to Nextion"));
    }
  } else if (!NxObject::prControl.command('c', buf)) {
    bool doClosingNewline = false;
    switch (*buf) {
      case 'v':
        dbSerial.println(AF(announce));
        break;
      default:
        dbSerial.print(F("Unknown CMD '"));
        dbSerial.print(buf);
        dbSerial.println(F("'"));
        dbSerial.print(F("try v or !"));
        doClosingNewline = true;
    }
    if (doClosingNewline) {
      dbSerial.println();
    }
  }
}

void pagePosHandler(nxReason reason, const void* hPtr) {
  hPtr = hPtr;
  switch (reason) {
    case pageChange:
    case pageRefresh:
      break;
    case unhandledId:
      {
        MsgTouch& tou = *(MsgTouch*)hPtr;
        pNxReason(reason);
        dbSerial.write(' ');
        tou.print();
        dbSerial.println();
      }
      break;
    case transReady:
      break;
    case transDone:
      break;
    case down:
    case up:
    case done:
    case error:
    case retNum:
    case retStr:
    case downPos:
    case upPos:
    case downSleepPos:
    case upSleepPos:
    case sleep:
    case wakeUp:
    case reseted:
    case launched:
    case upgraded:
    default:
      break;
  }
}

const char pmsUnex[] PROGMEM = "unexpected";

void commandHandler(nxReason reason, const void* hPtr) {
  if (!silent) {
    pNxReason(reason);
    switch (reason) {
      case done:
        break;
      case error:
        dbSerial.write(',');
        dbSerial.write(' ');
        NxObject::printCurrError();
        break;
      case retNum:
        dbSerial.write(' ');
        dbSerial.print(((MsgNumData*)hPtr)->value);
        break;
      case retStr:
        dbSerial.write(' ');
        ((MsgStrData*)hPtr)->pText();
        break;
      default:
        dbSerial.write(' ');
        dbSerial.print(FPM(pmsUnex));
        break;
    }
    dbSerial.println();
  }
}

Ich habe jetzt den Fehler in der WhandallNextion.cpp korrigiert und ein Nextion-HMI mit std.Text mit der ID 1 auf page 0 und stdNum (ID 2 auf page 0) erstellt. Deinen Beispiel-Sketch konnte ich auch kompilieren, ich bekomme auch die debug-Ausgabe "Mini Example", mehr tut sich aber nicht (dbSerial ist richtigerweise bei mir auf SerialUSB eingestellt und funktioniert offensichtlich auch, NexSerial habe ich auf Serial1 gestellt und sollte so auch stimmen).
Was genau sollte ich im Serial Monitor sehen bzw. was sollte sich auf dem Display tun? Bei mir auf jeden Fall beides ohne Reaktion, auch wenn ich das Display am Num-Feld berühre...

Welche Debug Ausgaben hast du denn eingeschaltet?

Hast du "send component id" bei "Touch release event" aktiviert?

Whandall:
"c" zeigt die Debug-Ausgabeeinstellungen an, "c=0" schaltet alle aus, "c=-1" alle ein,
"c" schaltet einzelne Optionen um.

silent unterdrückt die Ausgabe von commandHandler.

Du initialisierst die Optionen nicht aus dem EEPROM (mangels Masse), damit starten die wohl immer mit 0, d.h. alle Ausgaben ausgeschaltet.

Was soll sich wohl auf dem Display tun, wenn eine Zahl jede Sekunde hochzählt?

Bei allen Optionen aktiviert sehe ich ich im seriellen Monitor

Mini Example
cmd: "bkcmd=3"
cmd: "page 0"
 in: RetCode: OK
 *C* done
done
 in: RetCode: OK
 *C* done
done
 sa: stdNum.val=1
 in: RetCode: OK
 *stdNum* done
 sa: stdNum.val=2
 in: RetCode: OK
 *stdNum* done
 sa: stdNum.val=3
 in: RetCode: OK
 *stdNum* done
 sa: stdNum.val=4
 in: RetCode: OK
 *stdNum* done
 in: Touch: page 0, id 2, release
 *stdNum* release
stdNum release
 ga: get stdNum.val
 in: number: 4
 *stdNum* Number retrieved
stdNum Number retrieved
stdNum hat den Wert 4 an das Hauptprogramm abgegeben
 sa: stdNum.val=5
 in: RetCode: OK
 *stdNum* done
 sa: stdNum.val=6
 in: RetCode: OK
 *stdNum* done
 sa: stdNum.val=7
 in: RetCode: OK
 *stdNum* done

Whandall:
Welche Debug Ausgaben hast du denn eingeschaltet?

Wo schalte ich "C=1" ein? In der Eingabe am Seriellen Monitor? Oder irgendwo im Code? Wenn ich das am seriellen Monitor eingebe, tut sich nichts.

Whandall:
Hast du "send component id" bei "Touch release event" aktiviert?

Ja, habe ich, aber so weit komme ich offensichtlich garnicht - ich habe gesehen, dass bei dir am seriellen Monitor auch die Kommandos

cmd: "bkcmd=3"
und
cmd: "page 0"
bestätigt werden.

Bei mir steht am Monitor nur:

Mini Example

Du hast das Nextion auf 115200 Baud konfiguriert?
Default wären 9600 glaube ich.

Im seriellen Monitor "c=-1" (kleines c gleich minus 1) eingeben.
Auch ein einfaches c (kleines c) sollte eine Ausgabe erzeugen.

Du kannst auch ein

NxObject::prControl.command('c', "c=-1");

vor dem

 NexCommand_P(pmsBkcmd3);

in setup einbauen.

Wenn vorher alle Ausgaben abgeschaltet sind, was erwartest du auch zu sehen?

Du kannst an der Konsole damit spielen, wenn du als erstes Zeichen ein '!' benutzt,
wird der Rest der Zeile an das Nextion geschickt.

"!get stdNum.val"
"!stdNum.val=1234567"
...