diff --git a/sketches/TestSerial/TestSerial.h b/sketches/TestSerial/TestSerial.h
new file mode 100644
index 0000000000000000000000000000000000000000..32a8a2c221d37e0b5c3730c94f524c636d03acbe
--- /dev/null
+++ b/sketches/TestSerial/TestSerial.h
@@ -0,0 +1,42 @@
+//-----------------------------------------------------------------------------
+// Thema:   Social Manufacturing Network / Development Environment
+// Datei:   TestSerial.h
+// Editor:  Robert Patzke
+// URI/URL: www.mfp-portal.de
+//-----------------------------------------------------------------------------
+// Lizenz:  CC-BY-SA  (wikipedia: Creative Commons)
+//
+
+#ifndef TestSerial_h
+#define TestSerial_h
+
+#include "Arduino.h"
+
+#include "environment.h"
+#include "LoopCheck.h"
+#include "StateMachine.h"
+#include "Monitor.h"
+#include "nRF52840SerE.h"
+#include "ComRingBuf.h"
+
+#define TmpVerMsg "Version 20230923-10 "
+
+#ifdef DebugTerminal
+// ****************************************************************************
+// Z u s t a n d s m a s c h i n e
+// ****************************************************************************
+//
+
+void smInit();
+void smCheckJobs();
+void smCheckMemory();
+void smTestSerMem();
+void smCheckRB();
+void smPutCharRB();
+void smReadPtrRB();
+void smGetCntIntSer();
+void smReadAllRB();
+#endif
+
+
+#endif // TestSerial_h
diff --git a/sketches/TestSerial/TestSerial.ino b/sketches/TestSerial/TestSerial.ino
new file mode 100644
index 0000000000000000000000000000000000000000..57eb0a0bac893542efcf3b734c62768fba3350c4
--- /dev/null
+++ b/sketches/TestSerial/TestSerial.ino
@@ -0,0 +1,458 @@
+// =============================================================================
+// Testprogramm für serielle Schnittstellen (eigene Treiber)
+// =============================================================================
+//
+
+#include "TestSerial.h"
+
+char *StartMsg =
+{
+    "%@TestSerial "
+    TmpVerMsg
+};
+
+LoopCheck     lc;
+// Eine statische Instanz der Klasse LoopCheck
+// Darüber wird das Zeitverhalten gesteuert (Software-Timer) und geprüft
+
+#ifdef DebugTerminal
+Monitor       mon(modeEcho | modeNl,0,&lc);
+// Eine statische Instanz (mit Konstruktordaten) der Klasse Monitor
+// Darüber wird mit (direkten) Terminals (z.B. VT100) kommuniziert
+// Unter Linux werden hier GtkTerm (siehe Internet) und
+// ArduinoMonTerm (eigene Entwicklung mit grafischen Wertanzeigen) eingesetzt.
+// Das in den IDEs integrierte Terminal ist dafür meistens nicht geeignet,
+// weil damit keine direkte Kommunikation (getipptes Zeichen sofort gesendet)
+// möglich ist.
+// ----- Parameter ------------------------------------------------------------
+// <mode Echo>  Alle eintreffenden Zeichen werden sofort zurückgesendet
+// <mode NL>    Vor der Ausgabe des Prompt (M>) erfolgt CR/LF
+// <0>          Für Speicherzugriffe wird von 32 Bit ARM ausgegangen
+// <&lc>        Für Zeitüberwachungen und entsprechende statistische Daten
+//              greift die Monitor-Instanz auf die LoopCheck-Instanz zu
+
+char *infoThis =
+{
+    "DHE TestSerial Version 1.0.0\r\n"
+    "c0  Abschalten der periodischen Meldung\r\n"
+    "c1  Prüfen der Speicheradressen\r\n"
+    "c2  Testen der Ringpuffer und seriellen Schnittstellen\r\n"
+    //"c3  Steuern/Analysieren der Messwerterfassung\r\n"
+    //"c4  Testen von Peripheriezugriffen\r\n"
+    //"c5  Temporäre lokale Tests\r\n"
+};
+
+#endif
+
+#ifdef DebugTerminal
+#define smCycleTime 5
+void smInit();  // Vorwärtsreferenz auf die weiter unten definierte Funktion
+StateMachine  sm(smInit, NULL, smCycleTime);
+// Eine statische Instanz für die Zustandsmaschine, die hier für allgemeine
+// Steuerungen, Überwachungen und zum Debugging verwendet wird
+// ----- Parameter ------------------------------------------------------------
+// <smInit>       Der zuerst aufgerufene Zustand (Funktion). Weitere Zustände
+//                werden in den weiteren Zustandsfunktionen eingesetzt.
+// <NULL>         Hier kann eine weitere Zustandsfunktion angegeben werden,
+//                die dann grundsätzlich vor dem Verzweigen in einen Zustand
+//                aufgerufen wird.
+// <smCycleTime>  Die Zukluszeit (Takt) der Zustandsmaschine in Millisekunden
+#endif
+
+
+SerParams     tty1Params, tty2Params;
+// ----------------------------------------------------------------------------
+nRF52840SerE  tty1,tty2;
+// ----------------------------------------------------------------------------
+// Eine statische Instanz der Klasse nRF52840SerE (UARTE)
+// Darüber werden die seriellen Schnittstellen (UARTE0 und UARTE1) des
+// nRF52840 bedient.
+// Die Parameter werden in einer Struktur <SerParams> über die Funktion
+// <begin(...)> gesetzt.
+
+#define       sndBufSize  256
+byte          sndBuffer1[sndBufSize];
+byte          sndBuffer2[sndBufSize];
+#define       recBufSize  256
+byte          recBuffer1[recBufSize];
+byte          recBuffer2[recBufSize];
+
+// ----------------------------------------------------------------------------
+ComRingBuf    crb1,crb2;
+// ----------------------------------------------------------------------------
+// Eine statische Instanz der Klasse <ComRingBuf>
+// Damit wird ein Ringpuffer aufgebaut, der eine serielle Schnittstelle bedient.
+// Der Speicher muss extra eingerichtet und mit der Funktion
+//  <setWriteBuffer(sndBufSize, sndBuffer)> übergeben werden.
+// Die Klasse für die serielle Schnittstelle muss von <IntrfSerial> abgeleitet
+// sein, die Instanz wird mit der Funktion <begin(...)> übergeben.
+
+
+void setup()
+{
+#if defined(DebugTerminal)
+  #if defined(ArduinoMonTerm)
+    mon.config(6);    // 6 Anzeigekanäle, die von ArduinoMonTerm aufgebaut werden
+
+    for(int i = 0; i < 6; i++)
+    {
+      if(i < 3)
+        mon.config(i+1,'C',16000,-16000,NULL);    // Kanalnummer, Typ, Maxwert, Minwert
+      else
+        mon.config(i+1,'C',4000,-4000,NULL);
+    }
+  #endif
+  mon.setInfo(infoThis);
+#endif
+
+  // Initialisierung von serieller Schnittstelle 1 und Ringpuffer 1
+  // --------------------------------------------------------------------------
+  tty1Params.inst    = SerCom1;       // Instanzindex der Schnittstelle (0,1)
+  tty1Params.rxdPort = 1;             // Nummer des IO-Port mit RxD-Pin
+  tty1Params.rxdPin  = 10;            // Nummer des RxD-Pin am Port
+  tty1Params.txdPort = 1;             // Nummer des IO-Port mit TxD-Pin
+  tty1Params.txdPin  = 3;             // Nummer des TxD-Pin am Port
+  tty1Params.speed   = Baud115200;    // Enumerator für Bitrate
+  tty1Params.type    = stStd;         // Standard-RS232
+
+  tty1.begin(&tty1Params, (IntrfBuf *) &crb1);
+  // Übergeben von Parametern und Referenz auf Ringpufferverwaltung
+  // für die Übergabe empfangener Zeichen
+
+  crb1.setWriteBuffer(sndBufSize, sndBuffer1);
+  crb1.setReadBuffer(recBufSize, recBuffer1);
+  // Speicher an Ringpufferverwaltung übergeben
+
+  crb1.begin((IntrfSerial *) &tty1);
+  // Referenz auf Schnittstelle an Ringpufferverwaltung
+  // für die Übergabe zu sendender Zeichen
+
+  tty1.startSend();     // Sendebetrieb aktivieren
+  tty1.startRec();      // Empfangsbetrieb aktivieren
+
+  // Initialisierung von serieller Schnittstelle 2 und Ringpuffer 2
+  // --------------------------------------------------------------------------
+  tty2Params.inst    = SerCom2;       // Instanzindex der Schnittstelle (0,1)
+  tty2Params.rxdPort = 1;             // Nummer des IO-Port mit RxD-Pin
+  tty2Params.rxdPin  = 11;            // Nummer des RxD-Pin am Port
+  tty2Params.txdPort = 1;             // Nummer des IO-Port mit TxD-Pin
+  tty2Params.txdPin  = 12;            // Nummer des TxD-Pin am Port
+  tty2Params.speed   = Baud115200;    // Enumerator für Bitrate
+  tty2Params.type    = stStd;         // Standard-RS232
+
+  tty2.begin(&tty2Params, (IntrfBuf *) &crb2);
+  // Übergeben von Parametern und Referenz auf Ringpufferverwaltung
+  // für die Übergabe empfangener Zeichen
+
+  crb2.setWriteBuffer(sndBufSize, sndBuffer2);
+  crb2.setReadBuffer(recBufSize, recBuffer2);
+  // Speicher an Ringpufferverwaltung übergeben
+
+  crb2.begin((IntrfSerial *) &tty2);
+  // Referenz auf Schnittstelle an Ringpufferverwaltung
+  // für die Übergabe zu sendender Zeichen
+
+  tty2.startSend();     // Sendebetrieb aktivieren
+  tty2.startRec();      // Empfangsbetrieb aktivieren
+}
+
+#ifdef DebugTerminal
+char  runView[4] = {'|','/','-','\\'};
+int   runViewIdx = 0;
+#endif
+
+void loop()
+{
+  lc.begin();
+  // --------------------------------------------------------------------------
+
+#ifdef DebugTerminal
+  // Der Monitor wird ständig aufgerufen und stellt damit eine grundsätzliche
+  // Belastung dar. Das ist für die Entwicklung auch vorgesehen.
+  // Es entsteht dadurch eine Reserve für den produktiven Einsatz.
+  //
+  mon.run();
+#endif
+
+#ifdef DebugTerminal
+  // Alle 5 Millisekunden wird die Zustandsmaschine für
+  // betriebliche Abläufe aufgerufen
+  //
+  if(lc.timerMilli(lcTimer4, smCycleTime, 0))
+  {
+    sm.run();
+  }
+
+  // Jede halbe Sekunde erfolgt die Ausgabe der Version
+  //
+  if(lc.timerMilli(lcTimer5, 500, 0))
+  {
+    if(!mon.cFlag[0])
+    {
+      mon.print(StartMsg);
+      mon.cprintcr(runView[runViewIdx]);
+      runViewIdx++;
+      if(runViewIdx > 3) runViewIdx = 0;
+    }
+  }
+#endif
+  // --------------------------------------------------------------------------
+  lc.end();
+}
+
+#ifdef DebugTerminal
+// ****************************************************************************
+// Z u s t a n d s m a s c h i n e  (für Monitor-Ergänzung)
+// ****************************************************************************
+//
+
+dword       debDword;
+byte        tmpByteArray[256];
+int         tmpInt;
+
+
+void smInit()
+{
+  sm.enter(smCheckJobs);
+}
+
+// ----------------------------------------------------------------------------
+// Abfrage der Monitorschalter
+// ----------------------------------------------------------------------------
+//
+char  tmpOut[256];
+char  charOut[2];
+
+
+void smCheckJobs()
+{
+  if(mon.cFlag[1] && !mon.busy)
+    sm.enter(smCheckMemory);
+  else if(mon.cFlag[2] && !mon.busy)
+    sm.enter(smCheckRB);
+/*  else if(mon.cFlag[3] && !mon.busy)
+    sm.enter(sm);
+  else if(mon.cFlag[4] && !mon.busy)
+    sm.enter(sm);
+  else if(mon.cFlag[5] && !mon.busy)
+    sm.enter(sm);
+  */
+}
+
+// ----------------------------------------------------------------------------
+// Testen der Speicherzugriffe (Datenstruktur)
+// ----------------------------------------------------------------------------
+//
+
+void smCheckMemory()
+{
+  if(sm.firstEnter())
+  {
+    mon.print((char *) "Speichertest ");
+    mon.lastKeyIn = ':';
+  }
+
+  if(mon.lastKeyIn == ':') return;
+
+  charOut[0] = mon.lastKeyIn;
+  charOut[1] = '\0';
+  mon.println(charOut);
+
+  if(mon.lastKeyIn == '0' || mon.lastKeyIn == ' ')
+  {
+    mon.cFlag[1] = false;
+    mon.print((char *) "-- Schleifenabbruch - drücke Enter");
+    sm.enter(smCheckJobs);
+  }
+  else if(mon.lastKeyIn == 'S' || mon.lastKeyIn == 's')
+  {
+    mon.println();
+    sm.enter(smTestSerMem);
+  }
+  mon.lastKeyIn = ':';
+  sm.resetEnter();
+}
+
+
+void smTestSerMem()
+{
+  nrfSerPtr perMem = NULL;
+
+  dword res1 = (dword) &perMem->EVENTS_ENDRX;
+  dword res2 = (dword) &perMem->INTEN;
+  dword res3 = (dword) &perMem->EVENTS_ERROR;
+  dword res4 = (dword) &perMem->ENABLE;
+  dword res5 = (dword) &perMem->BAUDRATE;
+  dword res6 = (dword) &perMem->RXD_AMOUNT;
+  dword res7 = (dword) &perMem->CONFIG;
+
+  sprintf(tmpOut,"%X %X %X %X %X %X %X",res1,res2,res3,res4,res5,res6,res7);
+  mon.println(tmpOut);
+  sm.enter(smCheckMemory);
+}
+
+
+// ----------------------------------------------------------------------------
+// Testen der Ringpuffer
+// ----------------------------------------------------------------------------
+//
+
+char *smCheckRBHelp =
+{
+    "A   Zeichen in P1 eingeben\r\n"
+    "B   Zeichen in P2 eingeben\r\n"
+    "I   Anzahl der Interrupts anzeigen\r\n"
+    "R   Inhalte der Empfangspuffer auslesen\r\n"
+    "Z   Zeiger/Index der Ringpuffer anzeigen\r\n"
+};
+
+void smCheckRB()
+{
+  if(sm.firstEnter())
+  {
+    mon.print((char *) "Testen der Ringpuffer und seriellen Schnittstellen ");
+    mon.lastKeyIn = ':';
+  }
+
+  if(mon.lastKeyIn == ':') return;
+
+  charOut[0] = mon.lastKeyIn;
+  charOut[1] = '\0';
+  mon.println(charOut);
+
+  if(mon.lastKeyIn == 'A' || mon.lastKeyIn == 'a')
+  {
+    sm.userVar = 1;
+    sm.enter(smPutCharRB);
+  }
+  else if(mon.lastKeyIn == 'B' || mon.lastKeyIn == 'b')
+  {
+    sm.userVar = 2;
+    sm.enter(smPutCharRB);
+  }
+  else if(mon.lastKeyIn == 'I' || mon.lastKeyIn == 'i')
+  {
+    sm.userVar = 1;
+    sm.enter(smGetCntIntSer);
+  }
+  else if(mon.lastKeyIn == 'R' || mon.lastKeyIn == 'r')
+  {
+    sm.userVar = 1;
+    sm.enter(smReadAllRB);
+  }
+  else if(mon.lastKeyIn == 'Z' || mon.lastKeyIn == 'z')
+  {
+    sm.userVar = 1;
+    sm.enter(smReadPtrRB);
+  }
+  else if(mon.lastKeyIn == '0' || mon.lastKeyIn == ' ')
+  {
+    mon.cFlag[2] = false;
+    mon.print((char *) "-- Schleifenabbruch - drücke Enter");
+    sm.enter(smCheckJobs);
+  }
+  else if(mon.lastKeyIn == 'H' || mon.lastKeyIn == 'h' || mon.lastKeyIn == '?')
+  {
+    mon.print(smCheckRBHelp);
+  }
+  mon.lastKeyIn = ':';
+  sm.resetEnter();
+}
+
+void smPutCharRB()
+{
+  int retv;
+
+  if(sm.firstEnter())
+  {
+    mon.print((char *) "Zeichen eingeben für Puffer ");
+    mon.print(sm.userVar);
+    mon.print((char *) " ");
+    mon.lastKeyIn = ':';
+  }
+  if(mon.lastKeyIn == ':') return;
+
+  mon.cprint(mon.lastKeyIn);
+  if(sm.userVar == 1)
+    retv = crb1.putChr(mon.lastKeyIn);
+  else
+    retv = crb2.putChr(mon.lastKeyIn);
+  mon.println(retv);
+  mon.lastKeyIn = ':';
+  sm.enter(smCheckRB);
+}
+
+void smReadPtrRB()
+{
+  ComRingBuf::DbBufValues bv;
+
+  mon.print((char *) "Instanz [");
+  mon.print(sm.userVar);
+  mon.print((char *) "]: Indizes RbIn=");
+  if(sm.userVar == 1)
+    crb1.dbGetBufValues(&bv);
+  else
+    crb2.dbGetBufValues(&bv);
+  mon.print(bv.rbRdIdx);
+  mon.print((char *) " RbOut=");
+  mon.print(bv.rbWrIdx);
+
+  mon.print((char *) " TbIn=");
+  mon.print(bv.tbRdIdx);
+
+  mon.print((char *) " TbOut=");
+  mon.println(bv.tbWrIdx);
+
+  if(sm.userVar == 2)
+  {
+    mon.lastKeyIn = ':';
+    sm.enter(smCheckRB);
+  }
+  else
+    sm.userVar++;
+}
+
+void smGetCntIntSer()
+{
+  int cnt1, cnt2;
+
+  cnt1 = tty1.getIrqCount();
+  cnt2 = tty2.getIrqCount();
+  mon.print((char *) "Interrupts Ser1=");
+  mon.print(cnt1);
+  mon.print((char *) " Ser2=");
+  mon.println(cnt2);
+  mon.lastKeyIn = ':';
+  sm.enter(smCheckRB);
+}
+
+unsigned char tmpCharBuf[32];
+
+void smReadAllRB()
+{
+  int nrIn;
+
+  if(sm.userVar == 1)
+  {
+    nrIn = crb1.getAll(tmpCharBuf);
+    mon.print((char *) "In(1)={");
+  }
+  else
+  {
+    nrIn = crb2.getAll(tmpCharBuf);
+    mon.print((char *) "In(2)={");
+  }
+  if(nrIn > 32) nrIn = 32;
+  mon.print(tmpCharBuf,nrIn,',');
+  mon.cprintln('}');
+  if(sm.userVar == 2)
+  {
+    mon.lastKeyIn = ':';
+    sm.enter(smCheckRB);
+  }
+  else
+    sm.userVar++;
+}
+
+#endif // DebugTerminal
+