NEXTION Display: Serielle Schnittstelle abfragen ohne Library?

Hallo, kann mir jemand ein wenig erklären, wie ich eine Abfrage der Seriellen Schnittstelle aufbauen muss?

Es gibt hier einen Thread, wo das Thema vorkommt, aber ich würde es gerne noch einmal ganz von vorne erklärt bekommen:

Meine Überlegungen bisher:

ich muss nach Serial.available() fragen
wenn serielle Daten vorhanden, die Zeichenkette nach bestimmten Kriterien analysieren, um festzustellen, um welches NEXTION-Event es sich handelt, und nach der Abschluss-Sequenz Ausschau halten ( drei mal "0xff").

Konkret würde ich das Ganze gerne mit zwei unterschiedlichen Beispielen durchgehen:

  1. "Device automatically wakeup" - Event (0x86 0xff 0xff 0xff)

  2. Ein Touch-Event (Beispiel: 0x65 0x01 0x02 0x01 0xff 0xff 0xff
    Die Komponente "id=2" auf der Seite 1 hat ein Touch-Press-Event ausglöst)

Wie muss ich das angehen, dass ich den String entsprechend aufsplitte, um an die gewünschten Informationen zu kommen und danach wieder an der seriellen Schnittstelle auf das nächste event gewartet werden kann, ohne dass eines übersehen wird?

Und noch eine Frage dazu: verzögert die Abfrage nach Serial.available() meinen loop in irgendeiner Form, wenn kein serielles Event anliegt?

Wieso liest du dir den Beitrag nicht durch ?
Warum müssen wir das hier nochmal wiederholen ?

Du kannst doch alles wie beschrieben genau nachspielen und wenn dann konkrete Fragen auftauchen, werden wir die sicher auch behandeln können.

Wenn du den Sketch richtig aufbaust, wird deine Abfrage "Serial.available()" die Loop nur unwesentlich verzögern.

Hallo,

korrigiert mich bitte, wenn ich etwas übersehen habe, aber ich habe in dem erwähnten Thread nur an einer Stelle (im diesem Beitrag von SkobyMobil) eine Beschreibung für die Serial-Abfrage gefunden.

Ganz konkret geht es mir darum, wie ich sicher gehen kann, dass ich den Anfang der gewünschten Serial-Sequenz erwische und wie das Ende. Auch dazu habe ich einen Beitrag gefunden, allerdings wird hier ein einzelnes Zeichen als Start- bzw. End-Marker verwendet. Wie müsste ich eine Abfrage aufbauen um nach der Zeichenfolge " 0xff 0xff 0xff" als Endmarker zu suchen?

HotSystems:
Du kannst doch alles wie beschrieben genau nachspielen und wenn dann konkrete Fragen auftauchen, werden wir die sicher auch behandeln können.

Ich habe den seriellen Kram mal in eine Klasse gepackt, die auch das Nextion Format unterstützt.

Der Klassse wird eine Callback Funktion übergeben, die beim Empfang einer vollständigen Nachricht aufgerufen wird.

Da es auch binäre Nachrichten gibt, befindet sich die Länge der Nachricht in einem Byte vor der eigentlichen Nachricht,
um sie bei Bedarf auszuwerten.

Ein ganz einfaches Beispiel:

#include <WhandallSerial.h>  // https://github.com/whandall/WhandallSerial

// simple handler just prints some infos about the received line

void processLine(const char* buf) {
  Serial.print(F("len = "));
  Serial.print((uint8_t)buf[-1]);
  Serial.print(F(", strlen = "));
  Serial.println(strlen(buf));
  Serial.println(buf);
}

SSerial console(Serial, processLine); // used serial and handler

void setup() {
  Serial.begin(250000);
  console.begin(64, optTripleFF); // buffer size and options, maybe +optKeepDlm
}

void loop() {
  console.loop();    // collect chars and call handler for each line
}

Hier eine Version die etwas mehr macht.

Eingaben auf Serial werden an Serial1 weitergegeben (als Nextion Nachricht),
eingehende Nachrichten werden als Dump dargestellt.

#include <WhandallSerial.h>  // https://github.com/whandall/WhandallSerial

// simple handler just prints some infos about the received line

void processLine(const char* buf) {
  Serial.print(F("len = "));
  Serial.print((uint8_t)buf[-1]);
  Serial.print(F(", strlen = "));
  Serial.println(strlen(buf));
  dump(buf, buf[-1]);
}

void processConsoleLine(const char* buf) {
  Serial1.print(buf);
  Serial1.write(0xFF);
  Serial1.write(0xFF);
  Serial1.write(0xFF);
}

SSerial console(Serial, processConsoleLine); // used serial and handler
SSerial nextionSerial(Serial1, processLine); // used serial and handler

void setup() {
  Serial.begin(250000);
  console.begin(64, optIgnoreLF); // buffer size and options
  Serial1.begin(115200);
  nextionSerial.begin(64, optTripleFF | optKeepDlm); // buffer size and options
}

void loop() {
  console.loop();         // collect chars and call handler for each line
  nextionSerial.loop();   // collect chars and call handler for each line
}

void dump(const void* ptr, int len) {
  const byte* adr = (const byte*) ptr;
  byte idx;
  if (len) {
    for (; len > 0; len -= 16, adr += 16) {
      for (idx = 0; (idx < 16) && (idx < len); idx++) {
        phByte(adr[idx]);
        Serial.write(' ');
      }
      Serial.write('\'');
      for (idx = 0; (idx < 16) && (idx < len); idx++) {
        Serial.write(adr[idx] < 0x20 ? '.' : adr[idx]);
      }
      Serial.write('\'');
      Serial.println();
    }
  }
}

void phByte(byte byt) {
  if (byt < 16) {
    Serial.write('0');
  }
  Serial.print(byt, HEX);
}

Ausbabe beim Einschalten des Displays:

len = 63, strlen = 0
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 '................'
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 '................'
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 '................'
00 00 00 00 00 00 00 00 00 00 00 00 FF FF FF '............⸮⸮⸮'
len = 4, strlen = 4
88 FF FF FF '⸮⸮⸮⸮'
len = 5, strlen = 1
66 00 FF FF FF 'f.⸮⸮⸮'

Es geht auch etwas hübscher:

#include <WhandallSerial.h>  // https://github.com/whandall/WhandallSerial

// simple handler just prints some infos about the received line

void processLine(const char* buf) {
  Serial.print(F("len = "));
  Serial.print((uint8_t)buf[-1]);
  Serial.print(F(", strlen = "));
  Serial.print(strlen(buf));
  Serial.print(F(", "));
  dump(buf, buf[-1]);
}

void processConsoleLine(const char* buf) {
  Serial.print(F("sent \""));
  Serial.print(buf);
  Serial.println(F("\""));
  Serial1.print(buf);
  Serial1.write(0xFF);
  Serial1.write(0xFF);
  Serial1.write(0xFF);
}

SSerial console(Serial, processConsoleLine); // used serial and handler
SSerial nextionSerial(Serial1, processLine); // used serial and handler

void setup() {
  Serial.begin(250000);
  console.begin(64, optIgnoreLF); // buffer size and options
  Serial1.begin(115200);
  nextionSerial.begin(64, optTripleFF | optKeepDlm); // buffer size and options
}

void loop() {
  console.loop();         // collect chars and call handler for each line
  nextionSerial.loop();   // collect chars and call handler for each line
}

void dump(const void* ptr, int len) {
  const byte* adr = (const byte*) ptr;
  byte idx;
  if (len) {
    for (; len > 0; len -= 16, adr += 16) {
      for (idx = 0; (idx < 16) && (idx < len); idx++) {
        phByte(adr[idx]);
        Serial.write(' ');
      }
      Serial.write('"');
      for (idx = 0; (idx < 16) && (idx < len); idx++) {
        Serial.write(adr[idx] < 0x20 ? '.' : adr[idx]);
      }
      Serial.write('"');
      Serial.println();
    }
  }
}

void phByte(byte byt) {
  if (byt < 16) {
    Serial.write('0');
  }
  Serial.print(byt, HEX);
}
sent "get bkcmd"
len = 8, strlen = 2, 71 03 00 00 00 FF FF FF "q....⸮⸮⸮"
sent "page 1"
len = 4, strlen = 4, 01 FF FF FF ".⸮⸮⸮"
len = 5, strlen = 5, 66 01 FF FF FF "f.⸮⸮⸮"
sent "page 0"
len = 4, strlen = 4, 01 FF FF FF ".⸮⸮⸮"
len = 5, strlen = 1, 66 00 FF FF FF "f.⸮⸮⸮"

Hallo,

habe zwar kein Nextion, schau mir aber deinen Code immer gern an um zu schauen wie du das aufbaust. :slight_smile:
Danke.

Die Klasse ist ja durchaus auch ohne Nextion praktisch. :slight_smile:

Ich vermisse irgendeine Reaktion des Threaderstellers.

Hallo,

damit wird man hin und wieder leben müssen. Allerdings halte ich es so, sofern ich mir es merken kann, dass diese Leute dann von mir keine Hilfe mehr bekommen. Es gibt auch paar wenige die fangen einen Thread an und eröffnen einen neuen mit fast dem gleichen Problem. Ohne den alten in irgendeiner Form "abzuschließen".

Doc_Arduino:
sofern ich mir es merken kann, dass diese Leute dann von mir keine Hilfe mehr bekommen.

Vier Buchstaben kann ich mir merken.

Ich verlasse mich da lieber auf eine Liste der User, deren Fragen ich nicht beantworte, als auf mein Gedächtnis.

Gruß Tommy

Hi

Das habe ich schon bei eBay-Verkäufern angefangen ... da man als Käufer Da keine 'Schnitte' hat, sind die oberen Zeilen meiner Tabellenkalkulation für die 'etwas anderen' Verkäufer reserviert.

Aber eigentlich habt Ihr ja recht - hier müsste man wirklich rigoros bleiben und sich vor jedem Posten die 'üblichen Verdächtigen' aussortieren.

Befürchte nur: Dafür bin ich dann wohl doch zu faul :confused:

MfG

@ Whandall
Danke vielmals für deine klasse Klasse und entschuldige bitte die späte Reaktion. Ich habe einen recht aufreibenden Job, Familie und Weihnachten, und bin erst jetzt wieder dazu gekommen, eure Antworten genauer unter die Lupe zu nehmen...

Deine Klasse löst eigentlich genau mein Problem. Ich habe zeitgleich auch noch eine Antwort im Nextion-Forum bekommen, und zwar mit einer Lösung, die die Abfrage des wakeup- bzw sleep-Events direkt in der Nextion Library ermöglicht. Falls es jemanden interessiert:

https://nextion.itead.cc/forums/topic/arduino-related-question/#post-21322

Ich werde mal ein wenig testen und schauen, was sich für meine Zwecke am besten eignet....

Ich halte die Nextion Library für sehr schlecht geschrieben und benutze sie nicht.

Hahi:
entschuldige bitte die späte Reaktion. Ich habe einen recht aufreibenden Job, Familie und Weihnachten,
und bin erst jetzt wieder dazu gekommen, eure Antworten genauer unter die Lupe zu nehmen...

Lahme Ausrede :wink: ,

die Zeit reichte immerhin eine neue Frage zu starten ehe man sich um die Antworten der letzten kümmert.

Hahi:
Hallo,

ich möchte eine Variable global definieren, sodass sie auch innerhalb unterschiedlicher funktionen verwendbar ist.

Whandall:
Ich halte die Nextion Library für sehr schlecht geschrieben und benutze sie nicht.

@Weil ich das schon an mehreren Stellen gehört habe, würde mich nur interessieren, was die Kritikpunkte an der Library sind? Prinzipiell finde ich es auch besser, solch relativ einfache Dinge selbst neu zu programmieren, als eine dubiose Library zu verwenden, die nur am Verständnis vorbeiführt und teilweise vermutlich zu aufgebläht, an vielerlei Punkten aber auch zu unflexibel und klein ist.

Trotzdem muss ich sagen, dass die Library für mich in einem anderen Projekt garnicht schlecht funktioniert hat und ich gerade am überlegen bin, ob ich das neue Projekt jetzt ohne Library schreiben soll. Ich frage mich: Warum nicht bei der Library bleiben, wenns ganz gut klappt damit? Gibt es versteckte Programmfehler, die mir unter Umständen grobe Schwierigkeiten einhandeln können, von denen ich als Laie nur nichts verstehe?
Ich muss einfach ganz nüchtern berücksichtigen, dass mich das Neu-Erarbeiten ohne Library vermutlich nicht wenig Zeit kosten würde, vor allem, wenn ich sicher gehen möchte, das die Programmierung verlässlich ist und keine Fehler enthält.

Whandall:
Lahme Ausrede :wink: ,

die Zeit reichte immerhin eine neue Frage zu starten ehe man sich um die Antworten der letzten kümmert.

Naja, die neue Frage entstand durch den besagten Thread im Nextion-FOrum, den ich zeitgleich mit diesem Thread eröffnet hatte. Ich wollte mal klären, ob die Lösung dieses Problems innerhalb der Nextion-Library mal prinzipiell ein gangbarer Weg ist, ehe ich hier weitermache. Abgesehen davon ist das Forum ja nicht nur für mich da, eure Antworten sind auf jeden Fall sehr hilfreich, egal ob ich jetzt meinen bescheidenen Senf dazu gebe oder nicht;-) . Auf jeden Fall nochmals danke!!

Ein Beispiel von miserablem Kode (String für einen AVR Arduino)

uint16_t NexText::getText(char *buffer, uint16_t len)
{
    String cmd;
    cmd += "get ";
    cmd += getObjName();
    cmd += ".txt";
    sendCommand(cmd.c_str());
    return recvRetString(buffer,len);
}

bool NexText::setText(const char *buffer)
{
    String cmd;
    cmd += getObjName();
    cmd += ".txt=\"";
    cmd += buffer;
    cmd += "\"";
    sendCommand(cmd.c_str());
    return recvRetCommandFinished();    
}

Keine Verwendung des F() Macros, keine Möglichkeit Feldnamen in PROGMEM zu legen.

Blockierende Kommunikation, Verwendung von goto ohne Not:

uint16_t recvRetString(char *buffer, uint16_t len, uint32_t timeout)
{
    uint16_t ret = 0;
    bool str_start_flag = false;
    uint8_t cnt_0xff = 0;
    String temp = String("");
    uint8_t c = 0;
    long start;

    if (!buffer || len == 0)
    {
        goto __return;
    }
    
    start = millis();
    while (millis() - start <= timeout)
    {
        while (nexSerial.available())
        {
            c = nexSerial.read();
            if (str_start_flag)
            {
                if (0xFF == c)
                {
                    cnt_0xff++;                    
                    if (cnt_0xff >= 3)
                    {
                        break;
                    }
                }
                else
                {
                    temp += (char)c;
                }
            }
            else if (NEX_RET_STRING_HEAD == c)
            {
                str_start_flag = true;
            }
        }
        
        if (cnt_0xff >= 3)
        {
            break;
        }
    }

    ret = temp.length();
    ret = ret > len ? len : ret;
    strncpy(buffer, temp.c_str(), ret);
    
__return:

    dbSerialPrint("recvRetString[");
    dbSerialPrint(temp.length());
    dbSerialPrint(",");
    dbSerialPrint(temp);
    dbSerialPrintln("]");

    return ret;
}

Delay() in der zentralen Kommunikation

void nexLoop(NexTouch *nex_listen_list[])
{
    static uint8_t __buffer[10];
    
    uint16_t i;
    uint8_t c;  
    
    while (nexSerial.available() > 0)
    {   
        delay(10);
        c = nexSerial.read();
        
        if (NEX_RET_EVENT_TOUCH_HEAD == c)
        {
            if (nexSerial.available() >= 6)
            {
                __buffer[0] = c;  
                for (i = 1; i < 7; i++)
                {
                    __buffer[i] = nexSerial.read();
                }
                __buffer[i] = 0x00;
                
                if (0xFF == __buffer[4] && 0xFF == __buffer[5] && 0xFF == __buffer[6])
                {
                    NexTouch::iterate(nex_listen_list, __buffer[1], __buffer[2], (int32_t)__buffer[3]);
                }
                
            }
        }
    }
}

Verwendung von sprintf für eine triviale Formatierung

bool NexWaveform::addValue(uint8_t ch, uint8_t number)
{
    char buf[15] = {0};
    
    if (ch > 3)
    {
        return false;
    }
    
    sprintf(buf, "add %u,%u,%u", getObjCid(), ch, number);

    sendCommand(buf);
    return true;
}

Es ist nicht schwer es besser zu machen.

Ich habe damit mal angefangen, ich hänge es dir mal als Anhang an.
Die Dokumentation ist leider sehr rudimentär.

Ein Beispiel für diese Library

#include <WhandallSerial.h>
#include <WhandallNextion.h>
const unsigned int millisPerTick = 50;
const unsigned int ticksPerSecond = 1000 / millisPerTick;

void processCmd(const char* buf);

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

// Main-0: datum-1, uhrzeit-2, wtag-4, msg1-8, msg2-9, msg3-14, btCat1-12, btCat2-13, (ticker-3, va0-5, va1-6, va2-7), nbGarden-10, nbNetw-11
// Garden-1: actGarden-3, nbMain-1, nbNetw-2
// Network-2: actAll-3, nbMain-1, nbGarden-2

const char pmsDatum[] PROGMEM = "datum";
const char pmsUhrzeit[] PROGMEM = "uhrzeit";
const char pmsWtag[] PROGMEM = "wtag";
const char pmsMsg1[] PROGMEM = "msg1";
const char pmsMsg2[] PROGMEM = "msg2";
const char pmsMsg3[] PROGMEM = "msg3";
const char pmsCat1[] PROGMEM = "btCat1";
const char pmsCat2[] PROGMEM = "btCat2";
const char pmsAGarden[] PROGMEM = "actGarden";
const char pmsAAll[] PROGMEM = "actAll";

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

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

void pReasonT(nxReason reason, NxText* which) {
  pReasonX(reason, (NxObject*)which);
}
void pReasonN(nxReason reason, NxNum* which) {
  pReasonX(reason, (NxObject*)which);
}
void pReasonX(nxReason reason, NxObject* which) {
  Serial.print(FPM(which->name()));
  Serial.write(' ');
  pNxReason(reason);
  Serial.println();
}
void catAction(nxReason reason, NxNum* which) {
  pReasonX(reason, which);
  if (reason == up) {
    which->get();
  } else if (reason == retNum) {
    Serial.print(FPM(which->name()));
    Serial.print(FPM(pmsEquals));
    Serial.println(which->accNumResult());
  }
}

NxText nxDate(0,  1, pmsDatum, pReasonT);
NxText nxTime(0,  2, pmsUhrzeit, pReasonT);
NxText nxWtag(0,  4, pmsWtag, pReasonT);
NxText nxMsg1(0,  8, pmsMsg1, pReasonT);
NxText nxMsg2(0,  9, pmsMsg2, pReasonT);
NxText nxMsg3(0, 14, pmsMsg3, pReasonT);
NxNum  nxCat1(0, 12, pmsCat1, catAction);
NxNum  nxCat2(0, 13, pmsCat2, catAction);
NxText nxAGar(1,  3, pmsAGarden, pReasonT);
NxText nxAAll(2,  3, pmsAAll, pReasonT);

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

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

void loop() {
  con.loop();
  Nxi.loop();
}

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 {
      Serial.println(F("pass to Nextion"));
    }
  } else if (!NxObject::prControl.command('c', buf)) {
    bool doClosingNewline = false;
    switch (*buf) {
      case 'v':
        Serial.println(AF(announce));
        break;
      default:
        Serial.print(F("Unknown CMD '"));
        Serial.print(buf);
        Serial.println(F("'"));
        Serial.print(F("try v or !"));
        doClosingNewline = true;
    }
    if (doClosingNewline) {
      Serial.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);
        Serial.write(' ');
        tou.print();
        Serial.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) {
  hPtr = hPtr;
  pNxReason(reason);
  switch (reason) {
    case done:
      break;
    case error:
      Serial.write(',');
      Serial.write(' ');
      NxObject::printCurrError();
      break;
    case retNum:
      Serial.write(' ');
      Serial.print(((MsgNumData*)hPtr)->value);
      break;
    case retStr:
      Serial.write(' ');
      ((MsgStrData*)hPtr)->pText();
      break;
    default:
      Serial.write(' ');
      Serial.print(FPM(pmsUnex));
      break;
  }
  Serial.println();
}

WhandallNextion.zip (1020 KB)

Whandall:
Ich habe damit mal angefangen, ich hänge es dir mal als Anhang an.
Die Dokumentation ist leider sehr rudimentär.

Waahhnsinn, ich bin begeistert! Deine Library müsste doch die Original-Library schnell verdrängen? Liegt das nur an der rudimentären Doku?
Soweit ich das jetzt gesehen habe, ist doch eh alles umgesetzt, was man so braucht, oder? Nur weil Du geschrieben hast, du hättest damit "angefangen" - sieht mir eigentlich recht vollständig aus. Ist die Library in dem einen oder anderern projekt im Einsatz? Würdest du sagen, der Code ist weitestgehend getestet? ich kann das nicht so beurteilen...

Ich habe die Funktionen alle mal angetestet, es ist aber durchaus möglich dass sich noch der ein oder andere Fehler im Kode verbirgt.

Es fehlt die Dokumentation, speziell die der inneren Struktur, des inneren Aufbaus.

So eine Library offiziell zur Verfügung zu stellen, führt zu einem Haufen von Hilferufen,
ich weiss nicht ob ich das in dem Maße möchte.

Du kannst ja mal versuchen ob du damit klar kommst oder ob noch irgendetwas fehlt
(QRCode gab es noch nicht als ich das schrieb), von den Funktionen her sollte mein Kode
mindestens so mächtig sein wie das Original.

Die gigantische Größe des Anhangs entsteht durch die generierten Hilfeseiten, speziell auch die in Latex,
der eigentliche Kode ist nicht so wild.

Ich hätte noch zwei Fragen, bevor ich mich ans Ausprobieren mache:

  1. Das mit den Hilferufen verstehe ich gut. Kannst du dir trotzdem vorstellen, die eine oder andere Frage zu beantworten, wenn es zum allgemeinen Verständnis deiner Library beiträgt? Ich fürchte nämlich, dass ich es nicht ganz alleine schaffen werde...

  2. Das ganze sollte auch auf einer ARM-Plattform funktionieren, oder? Ich hab ein custom pcb, das auf der Architektur des Arduino Due aufbaut...