Serielle Datenstring vom Computer im Adruino Mega einlesen und aufteilen

F1 als Vorbild, der Link ist anschaulich.

Ich bin dran.

Hallo xy Projekt,
Jetzt bin ich etwas verwirrt, meintest Du nicht die letzten Version mit den Tab`s???.
Mittlerweile gibt es unzählige Versionen auf meinem Rechner Deine / Meine aber löschen möchte ich sie nicht, den wenn ich mal Zeit bekomme..... woher auch immer :smiley:
Wollte ich das ganze von Entstehung bis heute mal nachvollziehen.

Die Spannung von 5 bis 30 Volt soll angezeigt werden können, obwohl nur zwischen 12 und 20 Volt gefahren wird aber die Netzteile könnten ja mal unabsichtlich zu hoch eingestellt werden.
Also nach meinem Urteilsvermögen reicht hier die Werte.

Nein nein, es soll recht einfach gehalten werden.....klingt zwar echt Interessant und ist verlockend.....aber nein.
Es lässt sich leider nicht mit der Impulselektronik kombinieren.
Also um das mal genauer zu erklären.....

Es handelt sich um eine Impulselektronik die über Fotowiderstände die Runden(zeiten) der einzelnen Spuren via Timestamp an den Renncomputer sendet. Dieser wertet sie aus errechnet daraus die Rundenzeiten und gibt diese in bekannter Form seriell wieder aus.

An dieser Impulselektronik gibt es ebenfalls 5 Stück Potenzialfreie Ausgänge für eine Startampel.Diese sind gekoppelt an die Startprozedur bei einem Rennstart.
Das heißt, wenn ich am Renncomputer das Rennen starte, sind die Fahrspuren Stromlos und erhalten erst nach Ablauf der Startampel ihren Strom. Während des Startvorgangs werden alle 5 Ausgänge geschaltet und gehen nach und nach aus. Aber dieses Modi kann ich in der Software noch wie folgt ändern:

4 x Rot nach und nach aus, ist 4`te aus folgt 1x Grün
Hier sehe die Möglichkeiten den Ampel-Empfänger und deren WS annähernd der F1 leuchten zu lassen.

Von daher, einfach ist manchmal besser :wink:
Und versprochen "Hoch und Heilig" was anders kommt nicht mehr....in die Tüte.

Und nun zurück zum Thema, diese 5 Ausgänge würde ich dann gern auf die Pin`s 25 bis 30 legen und übertragen. Diese sind Zeitkritisch und würde diese gern wie die Spurdaten übertragen.

Die Spannungs und Temperaturwerte könnten z.B. mit der Zeit gesendet werden.
Nun kommt noch mal ein dickes Danke!!!

Hallo Agmue,
denkst Du dabei nur an die Stromaufnahme der Pixels ? oder hat es noch einen anderen Hintergrund?

Danke für Dein Angebot, die Ampel kommt zum Schluss dran. Es kann dann gut sein das ich dann auf Dein Angebot zurückkomme. Es ging mir erstmal darum das die Werte übertragen werden, was wir / Du :wink: hinterher daraus machen.....bin für alles offen.

Ja. Aber schau in das zip.
Die Dateien da drin haben das Datum 23.8.2021.
Da fehlt alles rund um das mit dem #define

Ok - ich mach heute Schluß.
Schau ich morgen mit meinem letzten Stand.

Bis denne.

Ja, bei mir sind das gemessene 10 mA bei Weiß, aber auch bei Rot, Grün und Blau alleine. Die Startampel hat auch nur Rot, Grün und Gelb, das sind auch nur 20 mA. Bei 23 Pixeln nicht so wirklich entscheidend.

Aber als Nächstes möchtest Du die Tribüne beleuchten oder ... und dann beklagst Du Dich bei mir, warum ich Dich nicht gleich auf die WS2815 hingewiesen habe.

Also schon mal vorneweg ein fröhliches "Siehste!" :joy:

Zu spät, Programm mit Startaufstellung, Countdown Einführungsrunde und Start-Countdown, teilweise mit verkürzten Zeiten:

// Startampel
#define DEBUG

#ifdef DEBUG
#define DEBUG_PRINT(x)    Serial.print (x)
#define DEBUG_PRINTLN(x)  Serial.println (x)
#else
#define DEBUG_PRINT(x)
#define DEBUG_PRINTLN(x)
#endif

const uint8_t hornPin = 13, startknopfPin = 2;

#include <Adafruit_NeoPixel.h>  // Einbinden der Bibliothekt zum ansteuern der WS2812 LEDs
const uint8_t numAmpel = 23;   // Anzahl der WS2815 LEDs
const uint8_t ledPin = 8;      // Pin für WS2812 LEDs
Adafruit_NeoPixel ampel(144, ledPin, NEO_GRB + NEO_KHZ800);
const uint32_t AUS =   0x000000;
const uint32_t ROT =   0xFF0000;
const uint32_t GRUEN = 0x00FF00;
const uint32_t GELB =  0x808000;

void setup()
{
  pinMode(hornPin, OUTPUT);
  pinMode(startknopfPin, INPUT_PULLUP);
  Serial.begin(9600);
  DEBUG_PRINTLN(F("\nProgrammstart..."));
  ampel.begin();
  delay(1);                                 // sonst stimmen bei mir die Farben nicht
  ampelanzeige(1, 1, 1, 1, 1, 1, 1, 1, 1);  // Lampentest
  delay(1000);
}// Ende Setup

void loop()
{
  startampel();
}

void ampelanzeige(bool aGe, bool aGr, bool aRo1, bool aRo2, bool aRo3, bool aRo4, bool aRo5, bool bGr, bool bRo)
{
  ampel.fill(AUS, 0, numAmpel);   // Löschen
  if (aGe)                        // Startampel Gelb
  {
    ampel.fill(GELB, 0, 5);
  }
  if (aGr)                        // Boxenausfahrt Grün
  {
    ampel.fill(GRUEN, 5, 5);
  }
  if (aRo1)                       // Startampel Reihe 1 Rot
  {
    ampel.fill(ROT, 10, 1);
    ampel.fill(ROT, 15, 1);
  }
  if (aRo2)                       // Startampel Reihe 2 Rot
  {
    ampel.fill(ROT, 11, 1);
    ampel.fill(ROT, 16, 1);
  }
  if (aRo3)                       // Startampel Reihe 3 Rot
  {
    ampel.fill(ROT, 12, 1);
    ampel.fill(ROT, 17, 1);
  }
  if (aRo4)                       // Startampel Reihe 4 Rot
  {
    ampel.fill(ROT, 13, 1);
    ampel.fill(ROT, 18, 1);
  }
  if (aRo5)                       // Startampel Reihe 5 Rot
  {
    ampel.fill(ROT, 14, 1);
    ampel.fill(ROT, 19, 1);
  }
  if (bGr)                        // Boxenausfahrt Grün
  {
    ampel.fill(GRUEN, 20, 1);
  }
  if (bRo)                        // Boxenausfahrt Rot
  {
    ampel.fill(ROT, 21, 2);
  }
  ampel.show();
}

void signalton(bool &merkerHorn)
{
  uint32_t jetzt = millis();
  static uint32_t vorhin;
  const uint32_t intervall = 500;  // in Millisekunden
  static bool hornAn = false;
  if (hornAn)
  {
    if (jetzt - vorhin >= intervall)
    {
      DEBUG_PRINT(millis()); DEBUG_PRINTLN(F("\tHorn aus."));
      digitalWrite(hornPin, LOW);
      merkerHorn = false;
      hornAn = false;
    }
  } else {
    DEBUG_PRINT(millis()); DEBUG_PRINTLN(F("\tHorn an."));
    digitalWrite(hornPin, HIGH);
    hornAn = true;
    vorhin = jetzt;
  }
}

void startampel()
{
  uint32_t jetzt = millis() / 100;  // Zeiteinheit ist Zehntelsekunde
  static uint32_t eben = jetzt, countdown = 0;
  static bool merkerHorn = false;
  static uint8_t schritt = 0;
  bool startknopf = !digitalRead(startknopfPin);
  
  if (jetzt != eben)
  {
    eben = jetzt;
    if (countdown) countdown--;
  }

  switch (schritt)
  {
    case 0:
      if (startknopf)
      {
        countdown = 450; //30 * 60 * 10UL;  // 30 Minuten
        DEBUG_PRINT(millis()); DEBUG_PRINTLN(F("\t30 Minuten bis zum Start in die Einführungsrunde, die Boxengasse ist geöffnet."));
        //          Ge Gr R1 R2 R3 R4 R5 Gr Ro
        ampelanzeige(0, 0, 0, 0, 0, 0, 0, 1, 0);
        schritt++;
      }
      break;
    case 1:
      if (countdown == 400) //17 * 60 * 10UL)
      {
        DEBUG_PRINT(millis()); DEBUG_PRINTLN(F("\t17 Minuten vor der Einführungsrunde ertönt ein Signalton."));
        merkerHorn = true;
        schritt++;
      }
      break;
    case 2:
      if (countdown == 350) //15 * 60 * 10UL)
      {
        DEBUG_PRINT(millis()); DEBUG_PRINTLN(F("\t5 Reihen: 15 Minuten bis zum Start in die Einführungsrunde, die Boxengasse ist geschlossen. Es ertönt ein Signalton."));
        //          Ge Gr R1 R2 R3 R4 R5 Gr Ro
        ampelanzeige(0, 0, 1, 1, 1, 1, 1, 0, 1);
        merkerHorn = true;
        schritt++;
      }
      break;
    case 3:
      if (countdown == 300) //10 * 60 * 10UL)
      {
        DEBUG_PRINT(millis()); DEBUG_PRINTLN(F("\t10 Minuten vor der Einführungsrunde blinken die roten Leuchten und der Signalton ertönt zweimal."));
        //          Ge Gr R1 R2 R3 R4 R5 Gr Ro
        ampelanzeige(0, 0, 0, 0, 0, 0, 0, 0, 1);
        merkerHorn = true;
        schritt++;
      }
      break;
    case 4:
      if (countdown == 300 - 10) //(10 * 60 * 10UL) - 10)
      {
        DEBUG_PRINT(millis()); DEBUG_PRINTLN(F("\tRote Leuchten an."));
        //          Ge Gr R1 R2 R3 R4 R5 Gr Ro
        ampelanzeige(0, 0, 1, 1, 1, 1, 1, 0, 1);
        schritt++;
      }
      break;
    case 5:
      if (countdown == 300 - 20) //(10 * 60 * 10UL) - 20)
      {
        DEBUG_PRINT(millis()); DEBUG_PRINTLN(F("\tRote Leuchten aus. Signalton an."));
        //          Ge Gr R1 R2 R3 R4 R5 Gr Ro
        ampelanzeige(0, 0, 0, 0, 0, 0, 0, 0, 1);
        merkerHorn = true;
        schritt++;
      }
      break;
    case 6:
      if (countdown == 300 - 30) //(10 * 60 * 10UL) - 30)
      {
        DEBUG_PRINT(millis()); DEBUG_PRINTLN(F("\tRote Leuchten an."));
        //          Ge Gr R1 R2 R3 R4 R5 Gr Ro
        ampelanzeige(0, 0, 1, 1, 1, 1, 1, 0, 1);
        schritt++;
      }
      break;
    case 7:
      if (countdown == 200) //5 * 60 * 10UL)
      {
        DEBUG_PRINT(millis()); DEBUG_PRINTLN(F("\t4 Reihen: 5 Minuten bis zum Start in die Einführungsrunde. Es ertönt ein Signalton."));
        //          Ge Gr R1 R2 R3 R4 R5 Gr Ro
        ampelanzeige(0, 0, 0, 1, 1, 1, 1, 0, 1);
        merkerHorn = true;
        schritt++;
      }
      break;
    case 8:
      if (countdown == 150) //3 * 60 * 10UL)
      {
        DEBUG_PRINT(millis()); DEBUG_PRINTLN(F("\t3 Reihen: 3 Minuten bis zum Start in die Einführungsrunde. Es ertönt ein Signalton."));
        //          Ge Gr R1 R2 R3 R4 R5 Gr Ro
        ampelanzeige(0, 0, 0, 0, 1, 1, 1, 0, 1);
        merkerHorn = true;
        schritt++;
      }
      break;
    case 9:
      if (countdown == 100) //1 * 60 * 10UL)
      {
        DEBUG_PRINT(millis()); DEBUG_PRINTLN(F("\t2 Reihen: 1 Minute bis zum Start in die Einführungsrunde. Es ertönt ein Signalton."));
        //          Ge Gr R1 R2 R3 R4 R5 Gr Ro
        ampelanzeige(0, 0, 0, 0, 0, 1, 1, 0, 1);
        merkerHorn = true;
        schritt++;
      }
      break;
    case 10:
      if (countdown == 50) //15 * 10UL)
      {
        DEBUG_PRINT(millis()); DEBUG_PRINTLN(F("\t1 Reihe: 15 Sekunden bis zum Start in die Einführungsrunde. Es ertönt ein Signalton."));
        //          Ge Gr R1 R2 R3 R4 R5 Gr Ro
        ampelanzeige(0, 0, 0, 0, 0, 0, 1, 0, 1);
        merkerHorn = true;
        schritt++;
      }
      break;
    case 11:
      if (countdown == 0)
      {
        DEBUG_PRINT(millis()); DEBUG_PRINTLN(F("\tMit dem Wechsel von roten auf grüne Leuchten ist die Einführungsrunde gestartet."));
        //          Ge Gr R1 R2 R3 R4 R5 Gr Ro
        ampelanzeige(0, 1, 0, 0, 0, 0, 0, 0, 1);
        schritt++;
      }
      break;
    case 12:
      if (startknopf)
      {
        countdown = 50;
        DEBUG_PRINT(millis()); DEBUG_PRINTLN(F("\t1 Reihe: 5 Sekunden bis zur Startfreigabe, alle Fahrzeuge sind in Position, die Boxengasse ist geschlossen."));
        //          Ge Gr R1 R2 R3 R4 R5 Gr Ro
        ampelanzeige(0, 0, 1, 0, 0, 0, 0, 0, 1);
        schritt++;
      }
      break;
    case 13:
      if (countdown == 40)
      {
        DEBUG_PRINT(millis()); DEBUG_PRINTLN(F("\t2 Reihen: 4 Sekunden bis zur Startfreigabe."));
        //          Ge Gr R1 R2 R3 R4 R5 Gr Ro
        ampelanzeige(0, 0, 1, 1, 0, 0, 0, 0, 1);
        schritt++;
      }
      break;
    case 14:
      if (countdown == 30)
      {
        DEBUG_PRINT(millis()); DEBUG_PRINTLN(F("\t3 Reihen: 3 Sekunden bis zur Startfreigabe."));
        //          Ge Gr R1 R2 R3 R4 R5 Gr Ro
        ampelanzeige(0, 0, 1, 1, 1, 0, 0, 0, 1);
        schritt++;
      }
      break;
    case 15:
      if (countdown == 20)
      {
        DEBUG_PRINT(millis()); DEBUG_PRINTLN(F("\t4 Reihen: 2 Sekunden bis zur Startfreigabe."));
        //          Ge Gr R1 R2 R3 R4 R5 Gr Ro
        ampelanzeige(0, 0, 1, 1, 1, 1, 0, 0, 1);
        schritt++;
      }
      break;
    case 16:
      if (countdown == 10)
      {
        //          Ge Gr R1 R2 R3 R4 R5 Gr Ro
        ampelanzeige(0, 0, 1, 1, 1, 1, 1, 0, 1);
        countdown = random(2, 31);  // 0,2 bis 3 Sekunden Zufall
        DEBUG_PRINT(millis()); DEBUG_PRINT(F("\t5 Reihen: ")); DEBUG_PRINT(countdown / 10.0); DEBUG_PRINTLN(F(" Sekunden bis zur Startfreigabe."));
        schritt++;
      }
      break;
    case 17:
      if (countdown == 0)
      {
        //          Ge Gr R1 R2 R3 R4 R5 Gr Ro
        ampelanzeige(0, 0, 0, 0, 0, 0, 0, 0, 1);
        DEBUG_PRINT(millis()); DEBUG_PRINTLN(F("\tStart!"));
        schritt++;
      }
      break;
    case 18:
      if (startknopf)
      {
        //          Ge Gr R1 R2 R3 R4 R5 Gr Ro
        ampelanzeige(0, 0, 0, 0, 0, 0, 0, 1, 0);
        DEBUG_PRINT(millis()); DEBUG_PRINTLN(F("\tNach dem Passieren des letzten Fahrzeuges wird die Boxengasse auf Grün geschaltet und freigegeben."));
        schritt++;
      }
      break;
  }
  if (merkerHorn) signalton(merkerHorn);
}

Eventuell kann man das ja anpassen :thinking:

War das nicht später als Du / wir es nicht schon wieder alles vereint hatten?
Bei ist diese die letzte mit einzelnen Tab`s

Dann ein gut Nächtle....

Bis dann und tausende Dankeschön`s

Niemals......
außer vielleicht das zu schnell bist.
Agmue, das kann man doch nicht in so kurzer Zeit mal eben programmieren.
Das glaub ich jetzt wirklich nicht, das ist echt der Wahnsinn.

Okay das mit den WS2815 halte ich mal im Hinterkopf.....
Vielleicht baut man ja eine Art Lauflicht rund um die Bahn....sind nur 36 Meter und dann wo sich das Auto befindet leuchtet es auf. :joy: :joy: :joy:

Aber das mit der Ampel, komme immer noch nicht drüber weg wie man so schnell sein kann.
:clap: :clap: :clap:

Danke Agmue, ich glaub ich werde es mal am We ausprobieren
Und natürlich auch Dir ein gut Nächtle

Eher wohl voreilig, paßt nicht so richtig.

In der Schrittkette ist das ja nur Kopieren und Einfügen, da schafft man viele Zeilen.

Ich sehe mich eher als Warteinweiler:

Pin für LED-Streifen und Taster mußt Du anpassen, ich habe mit einem UNO getestet. Der Taster hat drei Funktionen. Der Countdown zählt in Zehntelsekunden.

Anfänglich hatte ich die Funktion ampelanzeige() nicht mit drin, sondern habe alle LEDs direkt in der Schrittkette geschaltet. Anstelle von ampelanzeige(0, 0, 0, 0, 0, 0, 0, 1, 0); habe ich jetzt ampelanzeige(0b000000010); als speichersparendere Variante verwenden.

Mit einem globalen Merker für das Horn ist die zeitlich begrenzte Ansteuerung kein Problem, hier wollte ich aber bei lokalen Variablen bleiben. Lokalen statischen Merker in der Schrittkette setzen ist unproblematisch, aber man muß das Horn auch zeitgesteuert ausschalten und den Merker zurücksetzen. Daher gibt es eine Referenz und noch einen internen Merker. In der nächsten Version habe ich einen Byte-Wert verwendet.

// Startampel
#define DEBUG

#ifdef DEBUG
#define DEBUG_PRINT(x)    Serial.print (x)
#define DEBUG_PRINTLN(x)  Serial.println (x)
#else
#define DEBUG_PRINT(x)
#define DEBUG_PRINTLN(x)
#endif

const uint8_t hornPin = 13, startknopfPin = 2;

#include <Adafruit_NeoPixel.h>  // Einbinden der Bibliothekt zum ansteuern der WS2812 LEDs
const uint8_t numAmpel = 23;   // Anzahl der WS2815 LEDs
const uint8_t ledPin = 8;      // Pin für WS2812 LEDs
Adafruit_NeoPixel ampel(144, ledPin, NEO_GRB + NEO_KHZ800);
const uint32_t AUS =   0x000000;
const uint32_t ROT =   0xFF0000;
const uint32_t GRUEN = 0x00FF00;
const uint32_t GELB =  0x808000;

void setup()
{
  pinMode(hornPin, OUTPUT);
  pinMode(startknopfPin, INPUT_PULLUP);
  Serial.begin(9600);
  DEBUG_PRINTLN(F("\nProgrammstart..."));
  ampel.begin();
  delay(1);                                 // sonst stimmen bei mir die Farben nicht
  ampelanzeige(0b111111111);  // Lampentest
  delay(1000);
}// Ende Setup

void loop()
{
  startampel();
}

void ampelanzeige(const uint16_t leds)
{
  enum {bRo, bGr, aRo5, aRo4, aRo3, aRo2,  aRo1, aGr, aGe};
  ampel.fill(AUS, 0, numAmpel);   // Löschen
  if (bitRead(leds, aGe))         // Startampel Gelb
  {
    ampel.fill(GELB, 0, 5);
  }
  if (bitRead(leds, aGr))         // Boxenausfahrt Grün
  {
    ampel.fill(GRUEN, 5, 5);
  }
  if (bitRead(leds, aRo1))        // Startampel Reihe 1 Rot
  {
    ampel.fill(ROT, 10, 1);
    ampel.fill(ROT, 15, 1);
  }
  if (bitRead(leds, aRo2))        // Startampel Reihe 2 Rot
  {
    ampel.fill(ROT, 11, 1);
    ampel.fill(ROT, 16, 1);
  }
  if (bitRead(leds, aRo3))        // Startampel Reihe 3 Rot
  {
    ampel.fill(ROT, 12, 1);
    ampel.fill(ROT, 17, 1);
  }
  if (bitRead(leds, aRo4))        // Startampel Reihe 4 Rot
  {
    ampel.fill(ROT, 13, 1);
    ampel.fill(ROT, 18, 1);
  }
  if (bitRead(leds, aRo5))        // Startampel Reihe 5 Rot
  {
    ampel.fill(ROT, 14, 1);
    ampel.fill(ROT, 19, 1);
  }
  if (bitRead(leds, bGr))         // Boxenausfahrt Grün
  {
    ampel.fill(GRUEN, 20, 1);
  }
  if (bitRead(leds, bRo))         // Boxenausfahrt Rot
  {
    ampel.fill(ROT, 21, 2);
  }
  ampel.show();
}

void signalton(uint8_t &merkerHorn)  // 0: nix, 1: einschalten, 2: warten auf Ausschalten
{
  uint32_t jetzt = millis();
  static uint32_t vorhin;
  const uint32_t intervall = 500;  // in Millisekunden

  switch (merkerHorn)
  {
    case 1:  // Horn einschalten
      DEBUG_PRINT(millis()); DEBUG_PRINTLN(F("\tHorn an."));
      digitalWrite(hornPin, HIGH);
      merkerHorn = 2;
      vorhin = jetzt;
      break;
    case 2:  // Horn zeitgesteuert ausschalten
      if (jetzt - vorhin >= intervall)
      {
        DEBUG_PRINT(millis()); DEBUG_PRINTLN(F("\tHorn aus."));
        digitalWrite(hornPin, LOW);
        merkerHorn = 0;
      }
      break;
  }
}

void startampel()
{
  uint32_t jetzt = millis() / 100;  // Zeiteinheit ist Zehntelsekunde
  static uint32_t eben = jetzt, countdown = 0;
  static uint8_t merkerHorn = 0, schritt = 0;
  bool startknopf = !digitalRead(startknopfPin);

  if (jetzt != eben)
  {
    eben = jetzt;
    if (countdown) countdown--;
  }

  switch (schritt)
  {
    case 0:
      if (startknopf)
      {
        countdown = 450; //30 * 60 * 10UL;  // 30 Minuten
        DEBUG_PRINT(millis()); DEBUG_PRINTLN(F("\t30 Minuten bis zum Start in die Einführungsrunde, die Boxengasse ist geöffnet."));
        //             GGRRRRRGR
        //             er12345ro
        ampelanzeige(0b000000010);
        schritt++;
      }
      break;
    case 1:
      if (countdown == 400) //17 * 60 * 10UL)
      {
        DEBUG_PRINT(millis()); DEBUG_PRINTLN(F("\t17 Minuten vor der Einführungsrunde ertönt ein Signalton."));
        merkerHorn = 1;  // Horn einschalten
        schritt++;
      }
      break;
    case 2:
      if (countdown == 350) //15 * 60 * 10UL)
      {
        DEBUG_PRINT(millis()); DEBUG_PRINTLN(F("\t5 Reihen: 15 Minuten bis zum Start in die Einführungsrunde, die Boxengasse ist geschlossen. Es ertönt ein Signalton."));
        //             GGRRRRRGR
        //             er12345ro
        ampelanzeige(0b001111101);
        merkerHorn = 1;  // Horn einschalten
        schritt++;
      }
      break;
    case 3:
      if (countdown == 300) //10 * 60 * 10UL)
      {
        DEBUG_PRINT(millis()); DEBUG_PRINTLN(F("\t10 Minuten vor der Einführungsrunde blinken die roten Leuchten und der Signalton ertönt zweimal."));
        //             GGRRRRRGR
        //             er12345ro
        ampelanzeige(0b000000001);
        merkerHorn = 1;  // Horn einschalten
        schritt++;
      }
      break;
    case 4:
      if (countdown == 300 - 10) //(10 * 60 * 10UL) - 10)
      {
        DEBUG_PRINT(millis()); DEBUG_PRINTLN(F("\tRote Leuchten an."));
        //             GGRRRRRGR
        //             er12345ro
        ampelanzeige(0b001111101);
        schritt++;
      }
      break;
    case 5:
      if (countdown == 300 - 20) //(10 * 60 * 10UL) - 20)
      {
        DEBUG_PRINT(millis()); DEBUG_PRINTLN(F("\tRote Leuchten aus. Signalton an."));
        //             GGRRRRRGR
        //             er12345ro
        ampelanzeige(0b000000001);
        merkerHorn = 1;  // Horn einschalten
        schritt++;
      }
      break;
    case 6:
      if (countdown == 300 - 30) //(10 * 60 * 10UL) - 30)
      {
        DEBUG_PRINT(millis()); DEBUG_PRINTLN(F("\tRote Leuchten an."));
        //             GGRRRRRGR
        //             er12345ro
        ampelanzeige(0b001111101);
        schritt++;
      }
      break;
    case 7:
      if (countdown == 200) //5 * 60 * 10UL)
      {
        DEBUG_PRINT(millis()); DEBUG_PRINTLN(F("\t4 Reihen: 5 Minuten bis zum Start in die Einführungsrunde. Es ertönt ein Signalton."));
        //             GGRRRRRGR
        //             er12345ro
        ampelanzeige(0b000111101);
        merkerHorn = 1;  // Horn einschalten
        schritt++;
      }
      break;
    case 8:
      if (countdown == 150) //3 * 60 * 10UL)
      {
        DEBUG_PRINT(millis()); DEBUG_PRINTLN(F("\t3 Reihen: 3 Minuten bis zum Start in die Einführungsrunde. Es ertönt ein Signalton."));
        //             GGRRRRRGR
        //             er12345ro
        ampelanzeige(0b000011101);
        merkerHorn = 1;  // Horn einschalten
        schritt++;
      }
      break;
    case 9:
      if (countdown == 100) //1 * 60 * 10UL)
      {
        DEBUG_PRINT(millis()); DEBUG_PRINTLN(F("\t2 Reihen: 1 Minute bis zum Start in die Einführungsrunde. Es ertönt ein Signalton."));
        //             GGRRRRRGR
        //             er12345ro
        ampelanzeige(0b000001101);
        merkerHorn = 1;  // Horn einschalten
        schritt++;
      }
      break;
    case 10:
      if (countdown == 50) //15 * 10UL)
      {
        DEBUG_PRINT(millis()); DEBUG_PRINTLN(F("\t1 Reihe: 15 Sekunden bis zum Start in die Einführungsrunde. Es ertönt ein Signalton."));
        //             GGRRRRRGR
        //             er12345ro
        ampelanzeige(0b000000101);
        merkerHorn = 1;  // Horn einschalten
        schritt++;
      }
      break;
    case 11:
      if (countdown == 0)
      {
        DEBUG_PRINT(millis()); DEBUG_PRINTLN(F("\tMit dem Wechsel von roten auf grüne Leuchten ist die Einführungsrunde gestartet."));
        //             GGRRRRRGR
        //             er12345ro
        ampelanzeige(0b010000001);
        schritt++;
      }
      break;
    case 12:
      if (startknopf)
      {
        countdown = 50;
        DEBUG_PRINT(millis()); DEBUG_PRINTLN(F("\t1 Reihe: 5 Sekunden bis zur Startfreigabe, alle Fahrzeuge sind in Position, die Boxengasse ist geschlossen."));
        //             GGRRRRRGR
        //             er12345ro
        ampelanzeige(0b001000001);
        schritt++;
      }
      break;
    case 13:
      if (countdown == 40)
      {
        DEBUG_PRINT(millis()); DEBUG_PRINTLN(F("\t2 Reihen: 4 Sekunden bis zur Startfreigabe."));
        //             GGRRRRRGR
        //             er12345ro
        ampelanzeige(0b001100001);
        schritt++;
      }
      break;
    case 14:
      if (countdown == 30)
      {
        DEBUG_PRINT(millis()); DEBUG_PRINTLN(F("\t3 Reihen: 3 Sekunden bis zur Startfreigabe."));
        //             GGRRRRRGR
        //             er12345ro
        ampelanzeige(0b001110001);
        schritt++;
      }
      break;
    case 15:
      if (countdown == 20)
      {
        DEBUG_PRINT(millis()); DEBUG_PRINTLN(F("\t4 Reihen: 2 Sekunden bis zur Startfreigabe."));
        //             GGRRRRRGR
        //             er12345ro
        ampelanzeige(0b001111001);
        schritt++;
      }
      break;
    case 16:
      if (countdown == 10)
      {
        //             GGRRRRRGR
        //             er12345ro
        ampelanzeige(0b001111101);
        countdown = random(2, 31);  // 0,2 bis 3 Sekunden Zufall
        DEBUG_PRINT(millis()); DEBUG_PRINT(F("\t5 Reihen: ")); DEBUG_PRINT(countdown / 10.0); DEBUG_PRINTLN(F(" Sekunden bis zur Startfreigabe."));
        schritt++;
      }
      break;
    case 17:
      if (countdown == 0)
      {
        //             GGRRRRRGR
        //             er12345ro
        ampelanzeige(0b000000001);
        DEBUG_PRINT(millis()); DEBUG_PRINTLN(F("\tStart!"));
        schritt++;
      }
      break;
    case 18:
      if (startknopf)
      {
        //             GGRRRRRGR
        //             er12345ro
        ampelanzeige(0b000000010);
        DEBUG_PRINT(millis()); DEBUG_PRINTLN(F("\tNach dem Passieren des letzten Fahrzeuges wird die Boxengasse auf Grün geschaltet und freigegeben."));
        schritt++;
      }
      break;
  }
  if (merkerHorn) signalton(merkerHorn);
}

Viel Spaß am WE :blush:

Ich geh mal noch darauf ein.
A3 - A11 sind 9.
Und 25 - 30 sind 6.
:wink:

Hab mir mal Gedanken gemacht. Du hast nen Spannungsteiler? Dann darf ich davon ausgehen, das bei +5V am Analogpin mit 24V gerechnet wird?
Dann könnte man daraus ein map() machen.

Brauchst Du eine Nachkommastelle?
Wie oft brauchst Du den Wert an den Empfängern?
Wie genau muss der Wert zum Zeitpunkt des senden sein?
Wenn Du mittelst zwischen gemessenem und letztem gemessenen Wert, kann es etwas dauern bis das mittel dem (unveränderten) aktuellen Wert entspricht.
Beispiel:
vorher 12V - nachher 20V
(12+20)/2 = 16
(16+20)/2 = 18
(18+20)/2 = 19
(19+20)/2 = 19,5
... usw.
Das kann also ggfls. ne Handvoll Umläufe dauern...
Aber schon nach dem ersten siehst, das es nicht mehr passt.

Ansonsten dürfte das kein grosses Ding werden.
Die Behandlung kann sich an der Funktion sendFeld orientieren und dort sogar eingearbeitet werden.

Bei den Werten für die Ampel muss man sehen, ob man das als bool-array nimmt und dann sendet, wenn sich der Inhalt verändert hat.

Mal sehen, was mir am Wochenende einfällt.

Na denn...

So mein lieber...
Ich hab mal was fürs Senden.
Empfangen sollte dann fast genauso gehen.
Ich hab mir schon nen Kommentar-Tab gebaut :wink:
Na denn. Hier die Kommentare von heute:

Notizen - Pinbelegung - verwendete Sende-Kürzel
2, 4 - NRF-CS/CE
20, 21 - I2C
25 - 29 - DigitalIn für Ampelabfrage
A3 - A10 - AnalogIn Spannungswert Fahrspur (ansprechbar als 57 - 64)
44 - 46 - Taster

Wenn mit Buchstabe begonnen, gilt für alle Empfänger
T {unixtime} - Unixzeit an alle
A {Ampel} - Ampelstatus (5 Pins im Array)
C {Temperatur}- DHT22 Wert
Wenn mit Zahl begonnen, gilt für die Spurnummer
{spurnummer}F - Fahrername
{spurnummer}R - beste Runde
{spurnummer}Z - Rundenzeit
{spurnummer}V - Voltage

Änderungen 10.9.2021
Neu für Ampel und Voltage:
// Bahndaten

  const uint8_t voltagePin[] = {A3, A4, A5, A6, A7, A8, A9, A10};
  const uint8_t ampelPin[] = {25, 26, 27, 28, 29};
  bool ampel[sizeof(ampelPin)] = {false};
  uint8_t voltage[sizeof(voltagePin)+1] = {0};

im Setup:

  // Init AmpelPin
  for (uint8_t i = 0; i < sizeof(ampelPin); i++)
  {pinMode(ampelPin[i], INPUT);}

im loop

  leseVoltage();                           // liest an AnalogPins die Spannung der Spuren

neue Funktion:

  void leseVoltage()
  {
  for (uint8_t i = 0; i < sizeof(spuren); i++)
  {
    voltage[i] = (voltage[i] + map(analogRead(voltagePin[i - 1]), 0, 1023, 0, 240)) / 2;
  }

Änderungen für Voltage
In der Funktion
void sendFeld(const uint8_t spurNummer, const char feldName)
eingefügt:

      case 'V':                              // sendet Voltage
      sprintf(lokalBuf, "%uV %u", spurNummer, voltage[spurNummer]);
      break;

Die Funktion
void sendeBahn(const uint32_t sendTimer) // versendet ein Feld aus den gespeicherten Daten
Neue Variable:

    static uint32_t lastVoltageSend = 0;   // (Zeit-)Merker für den Versand der Voltagedaten

am Ende geändert und NEU eingefügt:

        case fahrer:                         // Fahrername
        if (millis() - lastFahrerSend > 1000)
        {
          sendFeld(spur, 'F');
          lastFahrerSend = millis();
        }
        break;
      case volt:
        if (millis() - lastVoltageSend > 2000)
        {
          sendFeld(spur, 'V');
          lastVoltageSend = millis();
        }
        spur++;
        if (spur >= spuren + 1)
        {
          spur = 0;
        }
        break;
    }
    feld++;
    if (feld > volt)
    {
      feld = runde;
    }
  }
  }

Nicht wundern, die ketzten beiden Klammern aus der Notiz stimmen so.
Und hier der Sender mit Voltage.

Er sendet Voltage als Byte - macht dann irgendwo am Empfänger 240 als oberste Grenze
Ich will, das Du am Empfänger den gesendeten Wert genau so auf dem SerMon darstellst.

Das "Nachkomma" bekommen wir dann hin.
Na dann.

// Benziner_Sender_Stand 10.09.2021
https://forum.arduino.cc/t/serielle-datenstring-vom-computer-im-adruino-mega-einlesen-und-aufteilen/664626/472?u=my_xy_projekt
// basiert auf Benziner_Sender_#174 erste Erweiterung aus #458 (Voltage)

//Uhr
#include <DS1307RTCB.h>                  // auf die TimeLibB angepasste 1307 von Paul Stoffregen
#include <TimeLibB.h>                    // auf deutsch umgeschriebene TimeLib von Paul Stoffregen

// Sender
#include <nRF24L01.h>
#include <RF24.h>
#include <printf.h>                      // für die nrf-Lib debug-Ausgabe erforderlich
RF24 radio(2, 4);                        // CE, CSN - MISO 50, MOSI 51, SCK 52
const uint8_t address[6] = "00001";      // Sender-Adresse

// Display
#include <LiquidCrystal_I2C.h>
LiquidCrystal_I2C lcd(0x27, 16, 2);

// Tasterelemente
const uint8_t tasterLinks = 45;
const uint8_t tasterRechts = 44;
const uint8_t tasterLinksLED = 47;
const uint8_t tasterRechtsLED = 46;
const uint32_t bounceTime = 100;          // hoeher gewaehlt auch wegen LCD-Geschwindigkeit
const uint32_t timeout = 30000;           // Zeit die ohne Tastendruck vergehen muss um einen Abbruch zu erzwingen

// Renndaten
const uint8_t spuren = 4;                 // Anzahl befahrener Spuren
const uint8_t charNum = 26;               // max Anzahl Zeichen (derzeit Fahrername (25+1))
const uint8_t maxPSize = 32;              // maximale Anzahl Zeichen, die mit einem Mal versandt werden können

//                                        // AR - RZ - F werden mehrere Datensätze
uint16_t AR[spuren + 1];                  // Runden in der Spur
uint16_t RZvk[spuren + 1];                // Rundenzeit Vorkomma in der Spur
uint16_t RZnk[spuren + 1];                // Rundenzeit Nachkomma in der Spur
char F[spuren + 1][charNum];              // Fahrername in der Spur

// Bahndaten
const uint8_t voltagePin[] = {A3, A4, A5, A6, A7, A8, A9, A10};
const uint8_t ampelPin[] = {25, 26, 27, 28, 29};
bool ampel[sizeof(ampelPin)] = {false};
uint8_t voltage[sizeof(voltagePin) + 1] = {0};


bool ausgabe = false;                     // Wartet auf Vollständigkeit

void setup()
{
  Serial.begin(115200);
  Serial.println(F("Start..."));
  Serial1.begin(19200);
  // Tasten
  pinMode(tasterLinks, INPUT_PULLUP);
  pinMode(tasterRechts, INPUT_PULLUP);
  // Uhr
  setSyncProvider(RTC.get);               // Festlegen der Zeituebergabe an timeLib
  // setSyncInterval(3000);               // default festgelegt: 5000 ms
  Serial.print("Keine ");
  Serial.println("RTC gefunden");
  // Init AmpelPin
  for (uint8_t i = 0; i < sizeof(ampelPin); i++)
  {pinMode(ampelPin[i], INPUT);}
  // Display
  lcd.begin();
  lcd.backlight();
  lcd.clear();
  // Sender
  printf_begin();                          // muss fuer debugging rein
  pinMode(53, OUTPUT);                     // verhindert den SPI-SlaveMode
  radio.begin();                           // Start der 2,4 GHz Wireless Kommunikation
  radio.enableDynamicPayloads();
  radio.setPALevel(RF24_PA_MIN);           // Leistung des NRF(MAX,HIGH,LOW,MIN)
  radio.setDataRate(RF24_1MBPS);           // Setzen der Übertragungsgeschwindigkeit
  radio.setAutoAck(0);                     // Nicht auf Bestätigungsantwort warten
  radio.openWritingPipe(address);          // Setzen der Sendeadresse
  radio.stopListening();                   // Das angeschlossene Modul als Sender konfiguriert
  startBild();
  while (millis() < 2000)
  {
    sendeZeit(50);                         // Sendet die Zeit an alle Client
  }
  Serial.println(F("Let's go running..."));
}

void loop()
{
  leseBefehl();                            // anstelle eines Menu
  leseBahn();                              // liest fortlaufend vom Renncomputer ein
  leseVoltage();                           // liest an AnalogPins die Spannung der Spuren
  sendeBahn(5);                            // sende alle xx ms ein Datenfeld aus den Bahndaten
  sendeZeit(5000);                         // sende alle xx ms die Uhrzeit
  // serMon();
}

void leseAmpel()
{
  bool ampelTemp[sizeof(spuren)] = {0};      // temporäre Variable
  char sendAmpel[10] = {0};                // Für Übergabe
  for (uint8_t i = sizeof(ampelPin); i > 1 ; i--)
  {
    ampelTemp[i] = digitalRead(ampelPin[i]); // liest den Zustand der Pin ein
  }
  // hier vergleiche ist das gelesene mit dem bekannten
  // nur wenn ungleich, dann senden
  if (memcmp(ampelTemp, ampel, sizeof(ampelTemp)) != 0)
  {
    memcpy(ampel, ampelTemp, sizeof(ampel));
    //sprintf(sendAmpel, "A %i", (uint16_t)ampel);   // Datenpaket zusammenstellen
    //  sendData(&ampel);
    Serial.print(F("Sende Ampel: ")); Serial.println(sendAmpel);
  }
}

void leseVoltage()
{
  for (uint8_t i = 0; i < sizeof(spuren); i++)
  {
    voltage[i] = (voltage[i] + map(analogRead(voltagePin[i - 1]), 0, 1023, 0, 240)) / 2;
  }
}

void sendeBahn(const uint32_t sendTimer)   // versendet ein Feld aus den gespeicherten Daten
// sendTimer: Zeit in ms - in welchen Abständen die Funktion ein(!) Feld sendet
// Ein Umlauf: Anzahl Spuren(5) * Felder je Spur(3) * Zeit(5ms) ca. 75ms
{
  static uint32_t lastMillis = 0;          // Merker für letzte Sendung
  if (millis() - lastMillis > sendTimer)   //
  {
    enum {runde, zeit, fahrer, volt};      // was soll versandt werden
    static uint32_t lastFahrerSend = 0;    // (Zeit-)Merker für den Versand eines Fahrernamen
    static uint32_t lastVoltageSend = 0;   // (Zeit-)Merker für den Versand der Voltagedaten
    static uint8_t feld = runde;           // Merker Welches Feld versandt wird
    static uint8_t spur = 0;               // aus welcher Spur
    lastMillis = millis();
    switch (feld)
    {
      case runde:                          // sende Rundennummer
        sendFeld(spur, 'R');
        break;
      case zeit:                           // Rundenzeit
        sendFeld(spur, 'Z');
        break;
      case fahrer:                         // Fahrername
        if (millis() - lastFahrerSend > 1000)
        {
          sendFeld(spur, 'F');
          lastFahrerSend = millis();
        }
        break;
      case volt:
        if (millis() - lastVoltageSend > 2000)
        {
          sendFeld(spur, 'V');
          lastVoltageSend = millis();
        }
        spur++;
        if (spur >= spuren + 1)
        {
          spur = 0;
        }
        break;
    }
    feld++;
    if (feld > volt)
    {
      feld = runde;
    }
  }
}
void sendFeld(const uint8_t spurNummer, const char feldName)
{
  char lokalBuf[maxPSize] = {0};
  switch (feldName)
  {
    case 'F':                              // sendet Fahrernamen
      sprintf(lokalBuf, "%uF %s", spurNummer, F[spurNummer]);
      break;
    case 'R':                              // sendet Rundennummer / Beste Spurnummer
      sprintf(lokalBuf, "%uR %u", spurNummer, AR[spurNummer]);
      break;
    case 'Z':                              // sendet Rundenzeit
      sprintf(lokalBuf, "%uZ %u %u", spurNummer, RZvk[spurNummer], RZnk[spurNummer]);
      break;
    case 'V':                              // sendet Voltage
      sprintf(lokalBuf, "%uV %u", spurNummer, voltage[spurNummer]);
      break;
  }
  if (strlen(lokalBuf) > 0)                // Nur wenn was im Puffer steht senden!
  {
    sendData(lokalBuf);
  }
}
void sendData(char *sendbuffer)
{
  radio.write(sendbuffer, strlen(sendbuffer));
  Serial.print(F("Daten gesendet: "));
  Serial.println(sendbuffer);
}
void sendeZeit(const uint32_t sendTimer)   // Versendet LokalZeit
{
  static uint32_t lastMillis = 0;          // Merker wann das letzte Mal
  if (millis() - lastMillis >= sendTimer)
  {
    char zeit[14] = {0};                   // Puffer
    lastMillis = millis();
    sprintf(zeit, "T %ld", now());         // Datenpaket zusammenstellen
    sendData(zeit);
    Serial.print(F("Sende Zeit: ")); Serial.println(zeit);
  }
}


void startBild()
{
  // ************ Anfang LCD Start-Anzeige ***********
  lcd.clear();
  lcd.setCursor(0, 0);
  lcd.print(F("Con V-12.0 modx"));
  lcd.setCursor(0, 1);
  lcd.print(F("  4-Spur    "));
  // *************Ende LCD Start-Anzeige *************
}

void serMon()
{
  const uint32_t intervall = 5000;
  serMon(intervall);
}

void serMon(const uint32_t intervall)
{
  static uint32_t lastmillis = 0;
  ausgabe = true;
  if (ausgabe == true && (millis() - lastmillis) > intervall) // Wenn Ausgabe frei
  {
    lastmillis += intervall;
    ausgabe = false;
    for (uint8_t i = 0 ; i <= spuren; i++)
    {
      if (!i)
        Serial.print("BRS");
      else
      {
        Serial.print("AR");
        Serial.print(i);
      }
      Serial.print(": ");
      Serial.print (AR[i]);
      if (!i)
        Serial.print(" BRZ");
      else
      {
        Serial.print(" RZ");
        Serial.print(i);
      }
      Serial.print(": ");
      Serial.print(RZvk[i]); Serial.print(" - "); Serial.print(RZnk[i]);
      if (!i)
        Serial.print(" BRF");
      else
      {
        Serial.print(" F");
        Serial.print(i);
      } Serial.print(": "); Serial.println(F[i]);
    }
    Serial.println();
  }
}
void leseBefehl()
{
  char readChar;                           // Einzelnes Zeichen
  static uint8_t x = 0;                    // Position im Array
  static char buf[charNum] = {0};          // Zwischenspeicher
  while (Serial.available() > 0 )
  {
    readChar = Serial.read();              // Einlesen
    Serial.print(readChar);
    if (!isControl(readChar))              // Zeichen ist kein Steuerzeichen ...
    {
      buf[x] = readChar;                   // ... dann aufnehmen ...
      x++;                                 // ... neue Position setzen
    }
    else                                   // ... ist Steuerzeichen
    {
      if (isLowerCase(buf[0]))             // erstes Zeichen Kleinbuchstabe? ...
      {
        sendData(buf);                     // ... verschicken ...
        memset(buf, 0, sizeof(buf));       // ... Puffer löschen und ...
        x = 0;                             // ... zurücksetzen
      }
    }
  }
}

void leseBahn()                            // Datensatz vom RennPC
{
  const bool serialdebug = false;
  const uint32_t breakTimeRead = 50;       // Abbruchzeit in ms
  char readChar;                           // Einzelnes Zeichen
  static uint8_t x = 0;                    // Position im Array
  static char buf[charNum] = {0};          // Zwischenspeicher
  uint32_t lastmillis = millis();          // Startzeit merken...
  while (Serial1.available() > 0 && millis() - lastmillis < breakTimeRead)
  {
    readChar = Serial1.read();             // Einlesen
    if (serialdebug) Serial.print(readChar);
    if (readChar == ';')                   // Feldende? ...
    {
      buf[x] = '\0';                       // ... CharArray abschliessen ...
      teileBuf(buf);                       // ... Übergeben zum teilen und senden ...
      x = 0;                               // ... Position im Array rücksetzen
    }
    else if (!isControl(readChar))         // Zeichen ist kein Steuerzeichen ...
    {
      buf[x] = readChar;                   // ... dann aufnehmen ...
      x++;                                 // ... neue Position setzen
    }
  }
}

void teileBuf(char *buf)                   // Teilt den (Feld)Puffer
{
  //  Serial.println(buf);
  static bool istGleich = true;            // Merker letzter/aktueller Wert gleich?
  char *c;                                 // Teilstring
  char lokalBuf[charNum] = {0};            // Zwischenspeicher für Vergleich (Zeichenkette) Array
  uint16_t lokalInt = 0;                   // Zwischenspeicher für Vergleich (Zahl) Array
  c = strtok(buf, ":");                    // Übernehme bis Trennzeichen 1
  //                                       // Beste Rundenzeit - Aufteilung kommentiert
  if (!strncmp(c, "BRZ", 3))               // Vergleich auf Feldname ...
  {
    lokalInt = atoi(strtok(NULL, ","));    // ... Erste Zahl - Trenner ist ,
    if (RZvk[0] != lokalInt)               // bisheriger Wert ist anders? ...
    {
      RZvk[0] = lokalInt;                  // ... dann setze den Wert ...
      istGleich = false;                   // ... merke, das neuer Wert gesetzt
    }
    lokalInt = atoi(strtok(NULL, ","));    // ... zweite Zahl ...
    if (RZnk[0] != lokalInt)               // ... wie vor
    {
      RZnk[0] = lokalInt;
      istGleich = false;
    }
    if (!istGleich)                        // Neue Daten bekommen? ...
    {
      sendFeld(0, 'Z');                    // ... sende Daten! ...
      istGleich = true;                    // ... setze Merker zurück
    }
  }
  else if (!strncmp(c, "BRF", 3))
  {
    strcpy(lokalBuf, strtok(NULL, ":"));   // Bester Fahrername
    if (F[0] != lokalBuf)                  // Inhalt geändert? ...
    {
      memcpy(F[0], lokalBuf, sizeof(lokalBuf)); // ... schreibe ins Array ...
      sendFeld(0, 'F');                         // ... sende Daten
    }
  }
  else if (!strncmp(c, "BRS", 3))
  {
    lokalInt = atoi(strtok(NULL, ":"));    // Beste Spur
    if (AR[0] != lokalInt)                 // Inhalt geändert? ...
    {
      AR[0] = lokalInt;                    // ... nehme Daten auf ...
      sendFeld(0, 'R');                    // ... sende Daten: Spur0 Runden
      istGleich = false;                   // ..
    }
  }
  else if (!strncmp(c, "AR", 2))           // Rundennummer
  {
    uint8_t s = c[2] - '0';                // ermittelt die Spur
    lokalInt = atoi(strtok(NULL, ":"));
    if (AR[s] != lokalInt)
    {
      AR[s] = lokalInt;
      sendFeld(s, 'R');
    }
  }
  else if (!strncmp(c, "RZ", 2))           // Rundenzeit
  {
    uint8_t s = c[2] - '0';
    lokalInt = atoi(strtok(NULL, ","));
    if (RZvk[s] != lokalInt)
    {
      RZvk[s] = lokalInt;
      istGleich = false;
    }
    lokalInt = atoi(strtok(NULL, ","));
    if (RZnk[s] != lokalInt)
    {
      RZnk[s] = lokalInt;
      istGleich = false;
    }
    if (!istGleich)
    {
      // ACHTUNG Nicht verrückt machen, der Fahrername für die Spur ist hier noch nicht ermittelt!
      // das sieht etwas komisch in der Ausgabe aus
      //      serMon(0);
      sendFeld(s, 'Z');
      istGleich = true;
    }
  }
  else if (!strncmp(c, "F", 1))            // Fahrer
  {
    uint8_t s = c[1] - '0';
    strcpy(lokalBuf, strtok(NULL, ":"));
    if (F[s] != lokalBuf)
    {
      memcpy(F[s], lokalBuf, sizeof(lokalBuf));
      sendFeld(s, 'F');
    }
  }
}

Trotzdem unglaublich, eine Idee so schnell in die Tat umzusetzen. Ich ziehe den Hut davor mit dem Wissen das Du das erst seit 5 Jahren(wenn ich mich recht erinnere) machst. Wenn ich sehe wie meine Entwicklung in den letzten Jahr war, zweifel ich an mir selbst.

Morgen baue ich das mal auf und dann schau ich mal was Du da schönes programmiert hast.
Freu mich drauf :smiley: :+1:

Ohh Gott wie peinlich....möchte in Boden versinken!!!

Mal, der Witz ist gut....ich glaube das machst Du pausenlos bei meinen Ideen. :wink:
Dankbar, ich Dir bin.

Ja, es werden 8 Spannungsteiler aber die +5 V an den Analogen ist bei 30 V.
Grund ist hierzu ist das die Labornetzteile 30 Volt liefern können, und für den Fall das einer mal an den Netzteilen spielt und auf 30 Volt stellt die Analogen eben nicht mehr wie 5V bekommen.

Nachkommastelle wäre schon schön weil einige fahren mit 14,5 V..... es würden 0,5 V Schritte reichen.Aber ich glaube das hilft nicht wirklich, oder?

Im Grunde würde es reichen wenn er sich am Konverter verändert hat, aber auf Hinsicht NoACK glaub ich nicht empfehlenswert.

Ist abhängig vom senden, um so weniger ich sende um so genauer müsste gesendet werden. Die Zeit spielt dabei nicht die große Rolle.

Ich weiß nicht ob ich jetzt richtig an die Sache ran gehe aber vielleicht inspiziert es ja :wink:
Wie wäre es wenn man nur eine Zahl für die Ampel übermittelt?
z.B.
0=alle 5 Lichter aus
1= 1 Licht an
2= 2 Lichter an usw.

So, wäre die Übermittlung kurz da nur eine Zahl gesendet werden müsste und der Empfänger könnte es wieder umsetzen....hat ja sonst nichts zu tun. :grinning_face_with_smiling_eyes:

Ein großes Danke mal wieder an Dich / Euch

Schade. Ganz doll schade.
Wenn ich max 24V habe, dann kann ich mit einem Byte auskommen.
Der ByteWert 249 entspräche dann 24,9V
Hm..
Na mal schauen.
Ist ja noch nicht Wochenende.

(Unsere beiden Postst waren zeitgleich :wink: ) - na dann...

Ist nur zum Schutz des kleinen..... :wink:
Nicht das er in Rauch aufgeht......

Ich bin grad am überlegen, ob ich das als Kaskade baue.
Der Eingang als uint16_t mappen von 0 - 30.
Das senden von 0-25 und wenn es drüber liegt einfach abschneiden.

Würde das reichen, wenn Du weisst, das mehr als 25V anliegen?
Nehmen wir an, das voltage jetzt uint16_t ist:

voltage[i] = (voltage[i] + map(analogRead(voltagePin[i - 1]), 0, 1023, 0, 300)) / 2;

if (voltage[i] > 250)
  voltage[i] = 251;

Denk mal drüber nach.
Weil 9 Byte (Bahnen) und zusätzlich Kennung passen in ein Paket (maxPayload=32). Es bräuchte keine Umläufe.

Hallo XY Projekt,
irgendwie habe ich das gestern nicht mitbekommen, war heute ganz erstaunt wie fleißig Du gestern warst. Nun kannst Du Dir ja vorstelle das ich damit erst mal wieder zurechtkommen muss. Gehöre dabei nicht gerade zu den schnellsten......

Nur als Info für mein Verständnis, war es Absicht nicht den letzten Stand von Sender zu nehmen?
Wenn ja, wirst Du Deine Gründe dafür haben und werde bestimmt später erfahren warum....oder ich weiß es dann selbst. Aber das glaube ich ehr nicht.

Das ist vollkommen ausreichend.

So, dann werde ich mich jetzt darangeben den Sender zum laufen zu bekommen....na und dann
versuche ich mal die Hausaufgabe zu bewerkstelligen.
Eine Verneigung vor Deinem Können und Deiner Außerordentlichen unermüdlichen Hilfe.

Hallo Agmue,
ich habe heute mal ein Nano mit einem 64er Block WS zusammengesteckt und Deinen Sketch ausprobiert. Gut durch den 64ér Block sind die Led´s nicht an Punkt und Stelle.
Bitte sei mir jetzt nicht böse wenn ich das vorerst zurückstelle, aber die Konvertor / Empfänger haben Vorrang. Und Multitasking in Sachen programmieren hab ich nicht drauf, muss mich da erst mal auf eins konzentrieren.

Euch allen ein gut Nächtle und immer schön Gesund bleiben.

Nö, nur keine Sorgen :slightly_smiling_face:

@my_xy_projekt
Ich hab mal was zum empfangen

// Verarbeitung
uint8_t temp = 21;                    // Temperatur wir noch vom Converter übermittelt
const uint8_t maxSpuren = 8;
uint16_t AR[maxSpuren + 1] = {0};
uint16_t RZvk[maxSpuren + 1] = {0};
uint16_t RZnk[maxSpuren + 1] = {0};
uint16_t Voltage[maxSpuren + 1] = {0}; // Spannung für die Spur
const uint8_t charNum = 26;           // Anzahl Buchstaben -1 für Fahrernamen
char Fahrer[maxSpuren + 1][charNum] = {0};


Die serielle Ausgabe habe ich wie folgt gelöst...

void displayKalender() // Start Anzeige
{
  if (minute() != minutealt)
  {
    minutealt = minute();
    char zeileAnzeige[16] = {0};
    memset(zeileAnzeige, 0, sizeof(zeileAnzeige - 1));
    sprintf(zeileAnzeige, "%s %02u.%02u.  %02u:%02u", dayShortStr(weekday()), day(), month(), hour(), minute());
    for (uint8_t i = 0; i < 7; i++)
        {
          Serial.print(F("Analogwert von Eingang "));
          Serial.print(i);
          Serial.print(F("="));
          Serial.println(Voltage[i])/10;
          
        }
    lcd.setCursor(0, 0);
    lcd.print(ver);
    lcd.setCursor(0, 1);
    lcd.print(zeileAnzeige);
    DEBUG_PRINTLN(zeileAnzeige);
  }
}// Ende Start-Tab

Wollte dann doch mal selbst versuchen die richtigen Werte zu senden....aber klappt noch nicht so...

void leseVoltage()
{
  //Aufbau nach https://mint-unt.de/mediapool/78/781152/data/Voltmeter.pdf  
  
  //for (uint8_t i = 0; i < sizeof(spuren); i++) **Warum hast Du das so gemacht ?**
  for (uint8_t i = 0; i < spuren; i++)
  {
    //voltage[i] = (voltage[i] + map(analogRead(voltagePin[i]), 0, 1023, 0, 240)) / 2;
    MesswertOut = (analogRead(voltagePin[0]))*5;
    MesswertIn = (MesswertOut /1023)/0.09 ;
    voltage[i]= MesswertIn *10 ;Um die Kommastelle mitzubekommen    
    
    //if (voltage[i] > 250)  voltage[i] = 251;
    Serial.print("Voltage ");
    Serial.print(i);
    Serial.print("= ");
    Serial.println(voltage[i]);
    Serial.println(MesswertOut);
    Serial.println(MesswertIn);
  }
}

Nun die Frage aller Fragen.....War ist mein Ansatz halbwegs richtig?

Sender_V33DCA.ino (15.3 KB)
Turm_Empfaenger_V70.5DCA.ino (46.7 KB)

Bitte, was geht nicht.
Was erwartest Du, was kommt ?

Ich muss wissen, wo ich was suchen muss.

Nun ich habe am A3 über den Spannungsteiler wie in ( https://mint-unt.de/mediapool/78/781152/data/Voltmeter.pdf beschrieben) eine 9V Block angeschlossen.

Da es nicht möglicht ist Floatzahlen in ein Array zu schreiben habe ich das Problem das ich für jede Spur zwei Float Variablen benötige. Ich wüsste nicht wie ich das Spuren abhängig hinbekommen soll. Möchte nicht unnötig Speicher verbraten :wink:

Wer behauptet das?

float fArr[6];

Gruß Tommy