Mit einem Nrf24 unterschiedliche Struct-Daten an mehrere Empfänger versenden

combie:
Wenn das men so einfach wäre....

Okay, mein Motto heißt zwar "Aufgeben ist auch keine Option" aber in diesem Fall definitiv "over and out" Ich beschäftige mich gerade mal ein dreiviertel Jahr mit Arduino und seine unendlichen Weiten.... und das nur nach Feierabend.Soviel am Stück gelesen, hab ich seit 40 Jahren nicht mehr. Und wenn ich ehrlich bin, übersteigt mein Projekt gerade wohl meinen Verstand. Eigendlich schade, aber wie heißt es so schön... einem alten Pferd kannste ja auch keine neuen Kunststücke mehr beibringen. :wink:

Ich möchte mich bei allen bedanken, die versucht haben für mich hier ein Lösungsweg zu finden. Leider war es nur schwere Kost für mich. Aber vielleicht denächst bei einem leichteren Projekt...es sei den, es fällt Hirn vom Himmel dann ich mach weiter.
LOB AN EUCH ALLE

Leg es nicht ganz weg. Mit jeder Erkenntnis (evtl. beim neuen Projekt) steigt die Wahrscheinlichkeit, dass es später doch noch wird.

Gruß Tommy

aber in diesem Fall definitiv "over and out"

Wenn die Lösung so nicht will, könnte man evtl. das Problem modifizieren.

Also nicht sofort die Flinte in den Sand stecken, oder den Kopf ins Korn werfen.

@ Tommy
im Moment ist meine motivation im Keller :frowning: , und da werden die NRF24 auch zu finden sein !!!
Vielleicht bin ich in ein paar Jahren soweit, um mich denen wieder anzunehmen. :sunglasses:

@Combie
Na ja, auf dem Weg war ich auch schon, halt die Namen weglassen und nur die nackten Zahlen übertragen.
Da würde ich bei 6 Spuren für Zeiten und Runden an die 30 Byte kommen.
Aber es sind eben nicht alle Daten die zur Verfügung stehen, und damit kann ich mich leider nur schwer trösten.

Benziner:
@Combie
Na ja, auf dem Weg war ich auch schon, halt die Namen weglassen und nur die nackten Zahlen übertragen.
Da würde ich bei 6 Spuren für Zeiten und Runden an die 30 Byte kommen.
Aber es sind eben nicht alle Daten die zur Verfügung stehen, und damit kann ich mich leider nur schwer trösten.

Anfangs sagtest du:

ich bin als blutjunger Anfänger
Angenommen, ich würde das glauben....

Dann sage ich dir:
Anfänger finden lustige Lösungen, aufgrund von lustigen Ideen.

Das ist natürlich einerseits gut!
Aber andererseits verstellt es auch den Blick für bessere Lösungen.

Das war die eine Seite der Geschichte!
Jetzt die andere:

Leider habe ich nicht verstanden, was du "wirklich" erreichen willst.
Auch das "Warum" und auch das "Wozu" liegt für mich im dunklen.
Das ganze übergeordnete Konzept liegt im dichten Nebel.

Das macht es mir unmöglich über Alternativen nachzudenken und damit auch das helfen.

Die dritte Seite:
Du kennst "rubber duck debugging"?

Nein?

Dann die Alternative:
Erkläre mir dein Problem, so oft und so lange, bis du selber verstanden hast, wie es geht.
Oder bis ich es verstanden habe.

Dies ist ein spekulativer Beitrag ;D

combie:
Das ganze übergeordnete Konzept liegt im dichten Nebel.
...
Erkläre mir dein Problem, ...

Es geht um eine Rennbahn und die Anzeige der zentral ermittelten Rundenzeiten an vier bis sechs Stellen.

Problem: Der zentrale Mega2560 hat keine sechs serielle Schnittstellen.

Lösung: Radio, denn ein Sender hat viele Empfänger.

Da ich mich mit NRF24 nicht auskenne, wäre meine Lösung: Viele RX an einen TX (ohne Rückkanal). Elektrisch würde ich das mit RS485 lösen, da ich mich vor den Störungen der Autos fürchten würde und viel RX an einem TX bei RS485 Teil der Busspezifikation ist.

So sieht mein spekulativer Blick auf dieses Projekt aus.

Ich hoffe, ich konnte den Nebel etwas lüften ::slight_smile:

Aha, ja...
Eine Rennbahn....

Immerhin!

Klar:

Wer Funk kennt, nimmt lieber Kabel!

Wobei ich mich frage:
Wozu der Mega, wenn die Daten doch vom PC kommen?
Was sind das für Anzeigen?

Wieso sind die Bezeichner im Programm so kryptisch benannt?

combie:
Wozu der Mega, wenn die Daten doch vom PC kommen?

Vermutlich um die Daten auf mehrere serielle Schnittstellen (UART) zu verteilen.

combie:
Was sind das für Anzeigen?

combie:
Wieso sind die Bezeichner im Programm so kryptisch benannt?

Die stammen aus dem Datenfluß:

BRZ:15,015;BRF:Paul Mustermann;BRS:4;AR1:0;RZ1:0,000;F1:Friedhelm Busch;AR2:0;RZ2:0,000;F2:Max Jägermeister;AR3:0;RZ3:0,000;F3:Paul Mustermann;AR4:0;RZ4:0,000;F4:Thorsten Hesse;

Ich rate mal:

BRZ: beste Rundenzeit
BRF: bester Fahrer
BRS: beste Spur
RZ1: Rundenzeit Spur 1
F1: Fahrer Spur 1

Alle Angaben ohne Gewähr ::slight_smile:

combie:
Wobei ich mich frage:
Wozu der Mega, wenn die Daten doch vom PC kommen?
Was sind das für Anzeigen?

Wieso sind die Bezeichner im Programm so kryptisch benannt?

Start:

los geht es dieses Jahr:

Erklärung der Inhalte:

elektrischer Aufbau Blockschema:

agmue:
Alle Angaben ohne Gewähr ::slight_smile:

Danke agmue :slight_smile: , besser hätte ich es auch nicht erklären können!
Du steckst aber auch schon, ganz tief drin.... Danke

combie:

Wer Funk kennt, nimmt lieber Kabel!

10 bis 15 Meter Kabel sollen auf der Länge auch sehr empfänglich sein :wink:

Und das Kabel wären zusätzliche stolperfallen....
Die Bahn ist mehrfach mit Scheibenkondensatoren ausgestattet, sollte funzen. Ein Mega mit 100 WsLeds läuft störungsfrei an der Bahn.

Benziner:
10 bis 15 Meter Kabel sollen auf der Länge auch sehr empfänglich sein :wink:

Darum RS485!

Benziner:
Und das Kabel wären zusätzliche stolperfallen…

Das ist schlecht.

Anfänger finden lustige Lösungen, aufgrund von lustigen Ideen.

Aus meinem “Erfahrungsschatz” könnte ich nur noch ESP32 beisteuern, da werden ganze HTML-Seiten übertragen, nicht nur ca. 200 Zeichen. Das wäre doch eine lustige Idee :grin:

Leider kann ich nur Stolperfallen oder lustige Ideen beisteuern, sorry.

agmue:
Darum RS485!

Nu ist das mit dem 24L01 nichts weiter als ein Kabel ohne Draht.
Er macht Point2Multipoint ohne ACK.
Die Daten werden fortlaufend (aus den Array's) :wink: gesendet und am Empfänger aufbereitet.
Prinzipiell könnte sogar der Stream genommen werden und nach jedem Ende des Feldes ( ; ) genau dieser Buffer auf die Antenne gelegt werden.
Nach dem Blockbild ist das wirklich das allerkleinste Übel.

Allerdings geht das hier zu weit für den, der andren Teil nicht mitbekommen hat.

my_xy_projekt:
Prinzipiell könnte sogar der Stream genommen werden und nach jedem Ende des Feldes ( ; ) genau dieser Buffer auf die Antenne gelegt werden.

Dieser Ansatz könnte erfolgversprechend sein :slight_smile:

Leider kenne ich NRF24 nicht, daher halte ich mich zurück.

my_xy_projekt:
Start:
https://forum.arduino.cc/index.php?topic=694542.0
los geht es dieses Jahr:
https://forum.arduino.cc/index.php?topic=694542.msg4922373#msg4922373

Erklärung der Inhalte:
https://forum.arduino.cc/index.php?topic=694542.msg4924472#msg4924472

elektrischer Aufbau Blockschema:
https://forum.arduino.cc/index.php?action=dlattach;topic=694542.0;attach=410846

Ah, ja....
Das ist also die Vorgeschichte....

Dann werde ich mich auch mal raushalten.

  1. Viele Köche verd.....
  2. Immer noch liegen viele Teile im Nebel, trotz aufmerksamen lesen

combie:
Dann werde ich mich auch mal raushalten.

Du kannst Dich entspannt zurücklehnen, denn my_xy_projekt hat die Übersicht und er hat einen Plan! könnte ein Zitat aus “Dr. Who” sein :slight_smile:

Ich werde ihn bei “divide et impera” unterstützen, soweit es mir möglich ist. Strukturen kommen da eher nicht vor, zumindest sehe ich derzeit keine.

Selbstverständlich werde ich keine Sekunde zögern, bei Bedarf Deinen psychologischen Rat einzuholen 8)

“Was bin ich wieder für ein Schelm!” Heinz Erhardt

agmue:
hat die Übersicht und er hat einen Plan!

Ersteres sollte der TO haben und letzteres ist wohl eher Wunschdenken :wink:

Der jenige der immer einen totsicheren Plan hatte: Egon Olsen.

@my_xy_projekt: Wenn man keinen Plan hat, sollte man jemanden kennen, der einen hat: Mich!

Anfänger finden lustige Lösungen, aufgrund von lustigen Ideen.

Ich hatte geschrieben: "Aus meinem 'Erfahrungsschatz' könnte ich nur noch ESP32 beisteuern, ... Das wäre doch eine lustige Idee :grin: "

Heute ist ja ein besonderes Datum, da wollte ich einen Scherz machen und habe mir mal ESP-NOW angesehen. Zu meiner Überraschung ist ein funktionierendes Programm draus geworden. Ich habe mich also selbst veräppelt.

Ausgabe beim Empfänger:

[sup][color=maroon]Bytes received: 204
x: 7
y: 16
t: BRZ:15,015;BRF:Paul Mustermann;BRS:4;AR1:0;RZ1:0,000;F1:Friedhelm Busch;AR2:0;RZ2:0,000;F2:Max Jägermeister;AR3:0;RZ3:0,000;F3:Paul Mustermann;AR4:0;RZ4:0,000;F4:Thorsten Hesse;

Bytes received: 204
x: 9
y: 18
t: BRZ:15,015;BRF:Paul Mustermann;BRS:4;AR1:0;RZ1:0,000;F1:Friedhelm Busch;AR2:0;RZ2:0,000;F2:Max Jägermeister;AR3:0;RZ3:0,000;F3:Paul Mustermann;AR4:0;RZ4:0,000;F4:Thorsten Hesse;[/color][/sup]

Die Variablen x und y sind nur Zufallszahlen, damit sich was ändert.

@Benziner: Würdest Du auf ESP32 umsteigen?

Quellenangabe:

Rui Santos
Complete project details at ESP-NOW with ESP32: Send Data to Multiple Boards (one-to-many) | Random Nerd Tutorials

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files.

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

Ich habe mal meine "lustige Idee" weitergeführt, um zu zeigen, wie eine Datenstruktur mittels ESP-NOW übertragen werden kann. Dabei habe ich mich selbstverständlich bei den bereits gezeigten Programmen zu diesem Projekt bedient.

Datenfluß: UNO (anstelle Renn-PC) → ESP-NOW-Sender → ESP-NOW-Empfänger → MAX7219-Anzeige für Spur 1

Ausgabe ESP-NOW Sender:

[sup][color=maroon]BRZ:15,015;BRF:Paul Mustermann;BRS:3;AR1:0;RZ1:5,866;F1:Friedhelm Busch;AR2:0;RZ2:0,000;F2:Max Jägermeister;AR3:0;RZ3:15,015;F3:Paul Mustermann;AR4:0;RZ4:0,000;F4:Thorsten Hesse;
BRS: 3 BRZ: 15 - 15 BRF: Paul Mustermann
AR1: 0 RZ1: 5 - 866 F1: Friedhelm Busch
AR2: 0 RZ2: 0 - 0 F2: Max Jägermeister
AR3: 0 RZ3: 15 - 15 F3: Paul Mustermann
AR4: 0 RZ4: 0 - 0 F4: Thorsten Hesse
Sent with success

Packet to: 8c:aa:b5:8c:1c:20 send status: Delivery Success[/color][/sup]

Ausgabe ESP-NOW Empfänger:

[sup][color=maroon]Bytes received: 160

BRS: 3 BRZ: 15 - 15 BRF: Paul Mustermann
AR1: 0 RZ1: 5 - 866 F1: Friedhelm Busch
AR2: 0 RZ2: 0 - 0 F2: Max Jägermeister
AR3: 0 RZ3: 15 - 15 F3: Paul Mustermann
AR4: 0 RZ4: 0 - 0 F4: Thorsten Hesse[/color][/sup]

Programm ESP-NOW Sender:

#include <esp_now.h>
#include <WiFi.h>
/* verwendet wird Hardware Serial2
 ESP32 UART2 RX = GPIO16
 ESP32 UART2 TX = GPIO17
 */

// REPLACE WITH YOUR ESP RECEIVER'S MAC ADDRESS
uint8_t broadcastAddress1[] = {0x8C, 0xAA, 0xB5, 0x8C, 0x1C, 0x20};
//uint8_t broadcastAddress2[] = {0xFF, , , , , };
//uint8_t broadcastAddress3[] = {0xFF, , , , , };

// Variablen für die zu versendenen Daten
const byte MAXZEICHEN = 26;
const byte SPUREN = 4;
bool ausgabe = false;     // Wartet auf Vollständigkeit

struct renn_struct {
  uint16_t BRZvk;
  uint16_t BRZnk;
  char BRF[MAXZEICHEN];
  byte BRS;
  // Spuren
  uint16_t AR[SPUREN];
  uint16_t RZvk[SPUREN];
  uint16_t RZnk[SPUREN];
  char F[SPUREN][MAXZEICHEN];
} myData;

void readSerial() {
  const int breakTimeRead = 500;       // Abbruchzeit in ms
  char readChar;                       // Einzelnes Zeichen
  static byte x = 0;                   // Position im Array
  static char buf[30] = {0};           // Zwischenspeicher

  unsigned long lastmillis = millis(); // Startzeit merken...
  while (Serial2.available() > 0 && millis() - lastmillis < breakTimeRead) {
    readChar = Serial2.read();         // Einlesen
    Serial.print(readChar);
    if (readChar == ';') {             // Feldende
      teileBuf(buf);                   // Übergeben zum teilen
      x = 0;                           // Position im Array rücksetzen
    } else {
      if (!isControl(readChar)) {      // Zeichen ist kein Steuierzeichen
        buf[x] = readChar;             // Dann aufnehmen
        if (x < 29) x++;               // neue Position setzen
        buf[x] = '\0';                 // CharArray abschliessen
      }
    }
  }
}

void teileBuf(char *buf) {                    // Teilt den Puffer
  char *c;                                    // Zwischenspeicher
  c = strtok(buf, ":");                       // Übernehme bis Trennzeichen 1

  if (!strncmp(c, "BRZ", 3)) {                // Feldname
    myData.BRZvk = atoi(strtok(NULL, ","));   // Erste Zahl - Trenner ist ,
    myData.BRZnk = atoi(strtok(NULL, ","));   // zweite Zahl
  }
  else if (!strncmp(c, "BRF", 3)) {           // Feldname
    strcpy(myData.BRF, strtok(NULL, ":"));    // Fahrername - Trenner ist :
  }
  else if (!strncmp(c, "BRS", 3)) {           // Feldname
    myData.BRS = atoi(strtok(NULL, ":"));     // Zahl
  }
  else if (!strncmp(c, "AR", 2)) {
    int x = c[2] - 49;
    myData.AR[x] = atoi(strtok(NULL, ":"));
  }
  else if (!strncmp(c, "RZ", 2)) {
    int x = c[2] - 49;
    myData.RZvk[x] = atoi(strtok(NULL, ","));
    myData.RZnk[x] = atoi(strtok(NULL, ","));
  }
  else if (!strncmp(c, "F", 1)) {
    int x = c[1] - 49;
    strcpy(myData.F[x], strtok(NULL, ":"));
    if (x == SPUREN - 1) {                    // Datensatz endet mit Fahrername 4 / Array endet mit 3(!)
      ausgabe = true;                  // Freigabe für SerMon
    }
  }
  memset(buf, 0, 30);
}

void serMon() {
  if (ausgabe) { // Wenn Ausgabe frei
    Serial.println();
    Serial.print("BRS: ");  Serial.print(myData.BRS);
    Serial.print(" BRZ: "); Serial.print(myData.BRZvk); Serial.print(" - "); Serial.print(myData.BRZnk);
    Serial.print(" BRF: "); Serial.println(myData.BRF);

    for (int j = 0; j < SPUREN; j++) {
      Serial.print("AR"); Serial.print(j + 1); Serial.print(": "); Serial.print (myData.AR[j]);
      Serial.print(" RZ"); Serial.print(j + 1); Serial.print(": "); Serial.print(myData.RZvk[j]); Serial.print(" - "); Serial.print(myData.RZnk[j]);
      Serial.print(" F"); Serial.print(j + 1); Serial.print(": "); Serial.println(myData.F[j]);
    }
  }
}

void senden() {
  if (ausgabe) {  // Wenn Ausgabe frei
    ausgabe = false;
    esp_err_t result = esp_now_send(0, (uint8_t *) &myData, sizeof(renn_struct));
    Serial.println(result == ESP_OK ? "Sent with success" : "Error sending the data");
    Serial.println();
  }
}

// callback when data is sent
void OnDataSent(const uint8_t *mac_addr, esp_now_send_status_t status) {
  char macStr[18];
  Serial.print("Packet to: ");
  // Copies the sender mac address to a string
  snprintf(macStr, sizeof(macStr), "%02x:%02x:%02x:%02x:%02x:%02x",
           mac_addr[0], mac_addr[1], mac_addr[2], mac_addr[3], mac_addr[4], mac_addr[5]);
  Serial.print(macStr);
  Serial.print(" send status:\t");
  Serial.println(status == ESP_NOW_SEND_SUCCESS ? "Delivery Success" : "Delivery Fail");
}

void setup() {
  Serial.begin(115200);
  Serial2.begin(9600); // zum Empfang der Daten; UNO anstelle PC
  delay(1000);
  Serial.println("Start ESP-NOW sender");

  WiFi.mode(WIFI_STA);

  if (esp_now_init() != ESP_OK) {
    Serial.println("Error initializing ESP-NOW");
    return;
  }

  esp_now_register_send_cb(OnDataSent);

  // register peer
  esp_now_peer_info_t peerInfo;
  peerInfo.channel = 0;
  peerInfo.encrypt = false;
  // register first peer
  memcpy(peerInfo.peer_addr, broadcastAddress1, 6);
  if (esp_now_add_peer(&peerInfo) != ESP_OK) {
    Serial.println("Failed to add peer");
    return;
  }
  /*
    // register second peer
    memcpy(peerInfo.peer_addr, broadcastAddress2, 6);
    if (esp_now_add_peer(&peerInfo) != ESP_OK){
    Serial.println("Failed to add peer");
    return;
    }
    /// register third peer
    memcpy(peerInfo.peer_addr, broadcastAddress3, 6);
    if (esp_now_add_peer(&peerInfo) != ESP_OK){
    Serial.println("Failed to add peer");
    return;
    }
  */
}

void loop() {
  readSerial();
  serMon();
  senden();
}

Programm ESP-NOW Empfänger:

#include <esp_now.h>
#include <WiFi.h>
#include <Adafruit_GFX.h>
#include <SPI.h>
#include <Max72xxPanel.h>
/*
  MAX7219 - ESP32
  GND - GND
  VDD - 3,3V
  CLK - 18 (VSPI CLK)
  DIN - 23 (VSPI MOSI)
  CS -   5 (VSPI CS0)
*/
const byte pinCS = 5; // Attach CS=5, DIN=23, CLK=18
const byte numberOfHorizontalDisplays = 4;
const byte numberOfVerticalDisplays = 1;
Max72xxPanel matrix = Max72xxPanel(pinCS, numberOfHorizontalDisplays, numberOfVerticalDisplays);

//Must match the sender structure
const byte MAXZEICHEN = 26;
const byte SPUREN = 4;

struct renn_struct {
  uint16_t BRZvk;
  uint16_t BRZnk;
  char BRF[MAXZEICHEN];
  byte BRS;
  // Spuren
  uint16_t AR[SPUREN];
  uint16_t RZvk[SPUREN];
  uint16_t RZnk[SPUREN];
  char F[SPUREN][MAXZEICHEN];
} myData;

void serMon() {
  Serial.println();
  Serial.print("BRS: ");  Serial.print(myData.BRS);
  Serial.print(" BRZ: "); Serial.print(myData.BRZvk); Serial.print(" - "); Serial.print(myData.BRZnk);
  Serial.print(" BRF: "); Serial.println(myData.BRF);

  for (int j = 0; j < SPUREN; j++) {
    Serial.print("AR"); Serial.print(j + 1); Serial.print(": "); Serial.print (myData.AR[j]);
    Serial.print(" RZ"); Serial.print(j + 1); Serial.print(": "); Serial.print(myData.RZvk[j]); Serial.print(" - "); Serial.print(myData.RZnk[j]);
    Serial.print(" F"); Serial.print(j + 1); Serial.print(": "); Serial.println(myData.F[j]);
  }
  Serial.println();
}

//callback function that will be executed when data is received
void OnDataRecv(const uint8_t * mac, const uint8_t *incomingData, int len) {
  memcpy(&myData, incomingData, sizeof(myData));
  Serial.print("Bytes received: ");
  Serial.println(len);
  ausgabeRZ(myData.RZvk[0], myData.RZnk[0]);
  serMon();
}

void ausgabeRZ(const int vk, const int nk)
{
  matrix.fillScreen(LOW);
  if (vk < 10) {
    matrix.setCursor(6, 0);
  } else {
    matrix.setCursor(0, 0);
  }
  matrix.print(vk);
  matrix.drawPixel(12, 6, HIGH);
  matrix.drawPixel(12, 7, HIGH);
  matrix.setCursor(14, 0);
  if (nk < 100) {
    matrix.print("0");
  }
  if (nk < 10) {
    matrix.print("0");
  }
  matrix.print(nk);
  matrix.write();
}

void setup() {
  matrix.setIntensity(2); // Use a value between 0 and 15 for brightness
  matrix.setRotation(0, 1);    // The first display is position upside down
  matrix.setRotation(1, 1);    // The first display is position upside down
  matrix.setRotation(2, 1);    // The first display is position upside down
  matrix.setRotation(3, 1);    // The first display is position upside down
  matrix.setTextSize(0);
  matrix.setCursor(1, 0);
  matrix.print("-----");
  matrix.write();
  delay(500);
  //Initialize Serial Monitor
  Serial.begin(115200);
  Serial.println("Start ESP-NOW receiver");
  Serial.print("ESP Board MAC Address:  ");
  Serial.println(WiFi.macAddress());
  //Set device as a Wi-Fi Station
  WiFi.mode(WIFI_STA);

  //Init ESP-NOW
  if (esp_now_init() != ESP_OK) {
    Serial.println("Error initializing ESP-NOW");
    return;
  }

  // Once ESPNow is successfully Init, we will register for recv CB to
  // get recv packer info
  esp_now_register_recv_cb(OnDataRecv);
}

void loop() {}

Während meiner Ausbildung habe ich gerne DDR-Bücher gelesen, die eine Einführung enthielten, warum dieses Buch für den Sozialismus der DDR von Nutzen sei. In Erinnerung daran möchte ich das auch mal auf dieses Thema bezogen tun.

Da die NRF24 des Themenstellers wohl wieder aus dem Keller hervorgeholt werden, ich aber keine NRF24 habe, versuche ich die Situation mit der Beschränkung auf wenige Bytes (NRF24 maximal 32) mittels ESP-NOW nachzustellen. Ob es sich um ein sinnvolles Unterfangen handelt, weiß man erst, wenn man ESP-NOW auf NRF24 umgestellt bekommen hat.

Der Aufbau entspricht #25 und #26, nur die Software von ESP-NOW-Sender und -Empfänger ändert sich.

Übertragene Zeichen:

BRZ:15,015;BRF:Paul Mustermann;BRS:4;AR1:0;RZ1:0,000;F1:Friedhelm Busch;AR2:0;RZ2:0,000;F2:Max Jägermeister;AR3:0;RZ3:0,000;F3:Paul Mustermann;AR4:0;RZ4:0,000;F4:Thorsten Hesse;

Grundsätzlich könnte man Teilzeichenketten von Semikolon zu Semikolon bilden und diese übertragen. Da es aber durchaus sinnvoll erscheint, die Zeichenkette vor dem Doppelpunkt in ein Byte zu komprimieren, und dieses Thema ja das Wort “Struktur” enthält, wandle ich im ESP-NOW-Sender eine Teilzeichenkette in eine Struktur aus einem Byte und einer Zeichenkette um. Die Struktur wird zum ESP-NOW-Empfänger übertragen und dort interpretiert. RZ1 (=0x21) wird auf dem Display angezeigt.

Zur Veranschaulichung zeigt der serielle Monitor viele Informationen an.

ESP-NOW-Sender:

#include <esp_now.h>
#include <WiFi.h>
/* verwendet wird Hardware Serial2
  ESP32 UART2 RX = GPIO16
  ESP32 UART2 TX = GPIO17
*/

// REPLACE WITH YOUR ESP RECEIVER'S MAC ADDRESS
uint8_t broadcastAddress1[] = {0x8C, 0xAA, 0xB5, 0x8C, 0x1C, 0x20};
//uint8_t broadcastAddress2[] = {0xFF, , , , , };
//uint8_t broadcastAddress3[] = {0xFF, , , , , };

// Variablen für die zu versendenen Daten
const byte MAXZEICHEN = 26;
const byte SPUREN = 4;
bool ausgabe = false;     // Wartet auf Vollständigkeit

struct renn_struct {
  uint8_t bed;             // Bedeutung des nachfolgenden Textes
  char txt[MAXZEICHEN];    // Text
} myData;

void readSerial() {
  char readChar;                       // Einzelnes Zeichen
  static byte pos = 0;                 // Position im Array
  static char buf[MAXZEICHEN] = {0};   // Zwischenspeicher

  while (Serial2.available() > 0) {
    readChar = Serial2.read();         // Einlesen
    //Serial.print(readChar);
    if (readChar == ';') {             // Feldende
      //Serial.println();
      teileBuf(buf);                   // Übergeben zum teilen
      pos = 0;                         // Position im Array rücksetzen
    } else {
      if (!isControl(readChar)) {      // Zeichen ist kein Steuierzeichen
        buf[pos] = readChar;           // Dann aufnehmen
        if (pos < MAXZEICHEN - 1) pos++;           // neue Position setzen (geändert 18.4.21)
        buf[pos] = '\0';               // CharArray abschliessen
      }
    }
  }
}

void teileBuf(char *buf) {                    // Teilt den Puffer
  Serial.print("buf: ");  Serial.println(buf);
  char *c;                                    // Zeiger innerhalb des Puffers
  c = strtok(buf, ":");                       // Übernehme bis Trennzeichen 1
  myData.bed = 0;
  
  if (!strncmp(c, "BRZ", 3)) {                // Feldname
    myData.bed = 0x10;  // BRZ
    strncpy(myData.txt, strtok(NULL, ":"), MAXZEICHEN);
  }
  else if (!strncmp(c, "BRF", 3)) {           // Feldname
    myData.bed = 0x20;  // BRF
    strncpy(myData.txt, strtok(NULL, ":"), MAXZEICHEN);
  }
  else if (!strncmp(c, "BRS", 3)) {           // Feldname
    myData.bed = 0x30;  // BRS
    strncpy(myData.txt, strtok(NULL, ":"), MAXZEICHEN);
  }
  else if (!strncmp(c, "AR", 2)) {            // Feldname
    myData.bed = 0x10 + (c[2] - '0');          // ARn
    strncpy(myData.txt, strtok(NULL, ":"), MAXZEICHEN);
  }
  else if (!strncmp(c, "RZ", 2)) {
    myData.bed = 0x20 + (c[2] - '0');          // RZn
    strncpy(myData.txt, strtok(NULL, ":"), MAXZEICHEN);
  }
  else if (!strncmp(c, "F", 1)) {
    myData.bed = 0x30 + (c[1] - '0');          // Fn
    strncpy(myData.txt, strtok(NULL, ":"), MAXZEICHEN);
  }
  serMon(c);
  senden();
  memset(buf, 0, MAXZEICHEN);
}

void serMon(char * c) {
    Serial.print("  c: ");  Serial.println(c);
    Serial.print("myData.bed: 0x");  Serial.println(myData.bed, HEX);
    Serial.print("myData.txt: ");  Serial.println(myData.txt);
}

void senden() {
    esp_err_t result = esp_now_send(0, (uint8_t *) &myData, sizeof(renn_struct));
    Serial.println(result == ESP_OK ? "Sent with success" : "Error sending the data");
}

// callback when data is sent
void OnDataSent(const uint8_t *mac_addr, esp_now_send_status_t status) {
  char macStr[18];
  Serial.print("Packet to: ");
  // Copies the sender mac address to a string
  snprintf(macStr, sizeof(macStr), "%02x:%02x:%02x:%02x:%02x:%02x",
           mac_addr[0], mac_addr[1], mac_addr[2], mac_addr[3], mac_addr[4], mac_addr[5]);
  Serial.print(macStr);
  Serial.print(" send status:\t");
  Serial.println(status == ESP_NOW_SEND_SUCCESS ? "Delivery Success" : "Delivery Fail");
}

void setup() {
  Serial.begin(115200);
  Serial2.begin(9600); // zum Empfang der Daten; UNO anstelle PC
  delay(1000);
  Serial.println("Start ESP-NOW sender");

  WiFi.mode(WIFI_STA);

  if (esp_now_init() != ESP_OK) {
    Serial.println("Error initializing ESP-NOW");
    return;
  }

  esp_now_register_send_cb(OnDataSent);

  // register peer
  esp_now_peer_info_t peerInfo;
  peerInfo.channel = 0;
  peerInfo.encrypt = false;
  // register first peer
  memcpy(peerInfo.peer_addr, broadcastAddress1, 6);
  if (esp_now_add_peer(&peerInfo) != ESP_OK) {
    Serial.println("Failed to add peer");
    return;
  }
  /*
    // register second peer
    memcpy(peerInfo.peer_addr, broadcastAddress2, 6);
    if (esp_now_add_peer(&peerInfo) != ESP_OK){
    Serial.println("Failed to add peer");
    return;
    }
    /// register third peer
    memcpy(peerInfo.peer_addr, broadcastAddress3, 6);
    if (esp_now_add_peer(&peerInfo) != ESP_OK){
    Serial.println("Failed to add peer");
    return;
    }
  */
}

void loop() {
  readSerial();
}

EDIT Zeile 40: MAXZEICHEN - 1