Datenblöcke per Serial übertragen?

Hallo.

Nach einer sehr langen Pause beschäftige ich mich gerade wieder mit Arduino und co.

Da ich kein Anhaltspunkt habe wonach ich suchen muss, versuche ich mal zu erklären was ich möchte.

Ich würde gerne mehrere Werte als Block via Serial übertragen.

Agenommen ich lese mehrere werte ein

Wert1 = 0 // 0-255
Wert2 = 0 // 0-255
.
.
.
Wert10 = 0 // 0-255

Diese werte möchte ich nun am Stück nicht blockierend übertragen

Werte einlesen

Werte übertragen

Wenn Werte übertragen

Werte einlesen

Werte Übertragen

usw.

das ganze soll im Loop laufen ohne diesen zu blockieren.

Nur habe ich gerade keine Ahnung wo ich da genau ansetzen soll.

Gruß
Micha

manchmal muss man das SerialEvent noch im loop aufrufen.

manchmal muss man das SerialEvent noch im loop aufrufen.

Bei Software Serial, muss man da eine Extrarunde einlegen.
HardwareSerial implementiert das.

Da ich kein Anhaltspunkt habe wonach ich suchen muss,

Ich verwende für solche Zwecke, solange nicht etwas eklatantes dagegen spricht, den CmdMessenger.

Ist es immer eine feste Anzahl an Bytewerten? Wenn nicht, musst Du am Anfang halt die Anzahl übertragen.

Dann schaue Dir dazu mal Array und Serial.write an.

Gruß Tommy

Edit: Warum soll es unbedingt Serial sein? Evtl. wäre I2C eine Lösungsmöglichkeit.

combie:
Bei Software Serial, muss man da eine Extrarunde einlegen.
HardwareSerial implementiert das.

Ich habe es schon in einem Standardsketch aufrufen müssen, es wurde nicht wie im Tutorial beschrieben automatisch aufgerufen.

Tommy56:
Ist es immer eine feste Anzahl an Bytewerten? Wenn nicht, musst Du am Anfang halt die Anzahl übertragen.

Dann schaue Dir dazu mal Array und Serial.write an.

Gruß Tommy

Edit: Warum soll es unbedingt Serial sein? Evtl. wäre I2C eine Lösungsmöglichkeit.

ja es sind immer eine feste Anzahl an Bytes. Und ich möchte einfach 10 Bytes wie beschrieben übertragen.

byte var[10];


void setup() {

  
var[0] = 128;
var[1] = 12;
var[2] = 28;
var[3] = 8;
var[4] = 44;
var[5] = 22;
var[6] = 77;
var[7] = 88;
var[8] = 99;
var[9] = 33;
  
Serial.begin(9600);

}




void loop() {


Serial.write(var[0]);
//Serial.print(var[0]);

}

Soweit bin ich mal gekommen.
bei "write" kann ich im Monitor nur nen viereck sehen
bei "print" die eigentlich zahl.

Denke mal das ist aber normal so und das wenn am anderen Ende ein weiterer Arduino hängt das auch verwerten kann.

Nur wenn ich dann

Serial.write(var[0]);
.
.
.
Serial.write(var[9]);

übertrage wird dieser auch als block übertragen? Also wenn sich wärend der Übertragung var[7] ändert, wird dies berücksichtigt oder nicht bei der Übertragung?

I2C Fällt aus da ich Schlussendlich nicht an eine Arduino übertrage sondern an ein funkmodul das nur Serial kann.

Es gibt eine zweite Variante von write, bei der Du die Länge mit angeben kannst.

Serial.write(var,sizeof(var));

Gruß Tommy

Tommy56:
Es gibt eine zweite Variante von write, bei der Du die Länge mit angeben kannst.

Serial.write(var,sizeof(var));

Gruß Tommy

Okay.

Werde ich gleich mal testen, bzw erst mal nen testaufbau basteln.
Werde mich dann mit dem Ergebniss melden.

Dank und Gruß
Micha

Also wenn sich wärend der Übertragung var[7] ändert, wird dies berücksichtigt oder nicht bei der Übertragung?

Das nennt man einen "inkonsistenten Datensatz".
Sowas sollte man meiden, wie der Teufel das Weihwasser.

Übrigens:
Das eigentliche Problem ist nicht, irgendwelche Datenblöcke zu senden.
Sondern:
Der Empfänger muss diese Datenblöcke in einem endlosen Datenstrom identifizieren und analysieren.

Denn die Serielle, die kennt keine Blöcke.
Das Datenblock Konzept gibt es nur in deinem Kopf, nicht in der Seriellen.
Von daher musst du das mühsam in Software gießen.

combie:
Das nennt man einen "inkonsistenten Datensatz".
Sowas sollte man meiden, wie der Teufel das Weihwasser.

Übrigens:
Das eigentliche Problem ist nicht, irgendwelche Datenblöcke zu senden.
Sondern:
Der Empfänger muss diese Datenblöcke in einem endlosen Datenstrom identifizieren und analysieren.

Denn die Serielle, die kennt keine Blöcke.
Das Datenblock Konzept gibt es nur in deinem Kopf, nicht in der Seriellen.
Von daher musst du das mühsam in Software gießen.

Hallo combie

Ja da hast wohl durch Erfahrung hell gesehen was wohl als nächste frage kommt. ^^

Aber zum "inkonsistenten Datensatz", wenn ich im folgenden Code übertrage dürfte es ja nicht zu dem problem kommen.

byte var[10];


int R0;
int R1;
int R2;
int R3;
int R4;
int R5;
int R6;
int R7;
int R8;
int R9;

byte R0M;
byte R1M;
byte R2M;
byte R3M;
byte R4M;
byte R5M;
byte R6M;
byte R7M;
byte R8M;
byte R9M;

void setup() {


  Serial.begin(9600);
  Serial1.begin(9600);

}


void loop() {

  R0 = analogRead(A0);
  R0M = map(R0, 0, 1024, 0, 255);

  R1 = analogRead(A1);
  R1M = map(R1, 0, 1024, 0, 255);

  R2 = analogRead(A2);
  R2M = map(R2, 0, 1024, 0, 255);

  R3 = analogRead(A3);
  R3M = map(R3, 0, 1024, 0, 255);

  R4 = analogRead(A4);
  R4M = map(R4, 0, 1024, 0, 255);

  R5 = analogRead(A5);
  R5M = map(R5, 0, 1024, 0, 255);

  R6 = analogRead(A6);
  R6M = map(R6, 0, 1024, 0, 255);

  R7 = analogRead(A7);
  R7M = map(R7, 0, 1024, 0, 255);

  R8 = analogRead(A8);
  R8M = map(R8, 0, 1024, 0, 255);

  R9 = analogRead(A9);
  R9M = map(R9, 0, 1024, 0, 255);


  var[0] = R0M;
  var[1] = R1M;
  var[2] = R2M;
  var[3] = R3M;
  var[4] = R4M;
  var[5] = R5M;
  var[6] = R6M;
  var[7] = R7M;
  var[8] = R8M;
  var[9] = R9M;

  Serial1.write(var, sizeof(var));
//Serial.println(var[0]);

}

Wenn ich die Daten nun empfangen möchte muss ich natürlich dann aus dem Datentrom wie du es gesagt hast meinen Datenblock raus fischen.

Hier gab es ja schon ein Bsp. mit Serial Event. Aber so wie ich den Code gelesen habe blockiert dieser dann mein Loop, bis er die Daten eingelesen hat oder?

Schuppeste:
https://www.arduino.cc/en/Tutorial/SerialEvent

manchmal muss man das SerialEvent noch im loop aufrufen.

zumal in dem Code nur auf eine Art Endzeichen geprüft wird.
Wenn ich das nicht falsch verstehe füllt der Code die Daten solange auf, bis das Endzeichen kommt, ungeachtet ob nun alle Bytes da sind oder nur die hälfte.

Gruß
Micha

Ja da hast wohl durch Erfahrung hell gesehen was wohl als nächste frage kommt. ^^

Natürlich!
Du musstest ja zwangsläufig auf das Problem "Parser" stoßen.

Aber zum "inkonsistenten Datensatz", wenn ich im folgenden Code übertrage dürfte es ja nicht zu dem problem kommen.

Natürlich nicht.
Allerdings blockiert der Code.
Und ein Parser ist damit überfordert, er kann einen solchen Datensatz nicht analysieren.

Du könntest natürlich auch Dein Array von 10 auf 12 Werte aufbohren und am Anfang ein Startbyte und am Ende ein Endebyte eintragen. Beides sollten Werte sein, die Du nicht als gültige Werte hast.

Außerdem hast Du geschrieben, dass Du nicht an einen Arduino, sondern an ein Funkmodul senden willst. Da brauchst Du ja keine Empfangsroutine, sondern musst Dich nach den Anforderungen des Funkmoduls richten.

Gruß Tommy

sondern musst Dich nach den Anforderungen des Funkmoduls richten.

Je, nach Bauart/Konfiguration, können solche Module durchaus transparent sein.
z.B. XBee oder HC-12

Pauschal:
Module, welche über eine Serielle kommunizieren, können das.
(Ausnahmen werden wie immer die Regel bestätigen, also keine Gewähr darauf)

Schuppeste:
Ich habe es schon in einem Standardsketch aufrufen müssen, es wurde nicht wie im Tutorial beschrieben automatisch aufgerufen.

Nur wenn dein Code blockierend geschrieben ist.

Denn:
In main() wird nach jedem loop() Durchlauf, die Serial Event Kette abgearbeitet.

Hier ein Auszug aus dem Arduino AVR Core:

int main(void)
{
	init();

	initVariant();

#if defined(USBCON)
	USBDevice.attach();
#endif
	
	setup();
    
	for (;;) {
		loop();
		if (serialEventRun) serialEventRun();
	}
        
	return 0;
}

Tommy56:
Du könntest natürlich auch Dein Array von 10 auf 12 Werte aufbohren und am Anfang ein Startbyte und am Ende ein Endebyte eintragen. Beides sollten Werte sein, die Du nicht als gültige Werte hast.

Außerdem hast Du geschrieben, dass Du nicht an einen Arduino, sondern an ein Funkmodul senden willst. Da brauchst Du ja keine Empfangsroutine, sondern musst Dich nach den Anforderungen des Funkmoduls richten.

Gruß Tommy

stimmt in dem Moment habe ich da einfach nicht weit genug gedacht. War wohl nen kleiner Overload bei mir Kopf.

So noch mal tief Luft geholt.

Arduino -> Funkmodul -> Funkmodul -> Arduino

Also Ja ich brauch eine Empfangsroutine.

Entschuldige meine zwischenzeitliche Verwirrung.

Das mit dem Startbyte und Endbyte könnte ein Problem werden. Da ich mir gedacht habe die DEZ Werte von 0 -255 zu nutzen.

Nur wenn ich nun ein Startbyte und Endbyte nutze, würden ja Zahlen wegfallen. Sagen wir mal 254 und 255.
Sprich könnte ich als Nutzdaten nur 0 - 253 nutzen.

Bzw. würde es Sinn machen wenn ich nur ein Startbyte (255) und dann die folgenden 10Bytes einlese und dann das einlesen beende?

Und wie würde man sowas realisieren?

Ja, das würde auch gehen. Nehmen wir mal die 255 als Startbyte. Ungetestet als Anregung:

byte werte[10]; // die gelesenen 10 Byte
// im loop

if (lesen()) {
  // mache was mit den Daten
}


liefert true, wenn 255 als Startbyte +10 Byte gelesen wurden
bool lesen() {
static bool imLesen = false;
static byte idx = 0;
byte c;
  if (!Serial.available()) return false;
  c = Serial.read();
  if (!imLesen && c == 255) {
    imLesen = true;
    idx = 0;
 }
  else {
    werte[idx++] = c;
    if (idx > 9) {
      imLesen = false;
      return true;
    }
     else return false; 
  }
}

Gruß Tommy

Du meinst sicher

if (lesen()) {
  // mache was mit den Daten
}

lesen allein ist nur die Adresse der Funktion, die ist immer !=0 und damit true
C / C++ erlaubt viel, auch viel Unsinn.

Du hast Recht. Ich habe es korrigiert.

Gruß Tommy

Also erstmal vielen dank für die Hilfe.

Ich habe den Empfangs Code mal für mein Mega angepasst und er empfängt auch nun Daten, nur scheint dort etwas nicht zu passen.

Sende Code

byte var[11];


void setup() {


  Serial.begin(9600);
  Serial1.begin(9600);

}


void loop() {

  var[0] = 255;
  var[1] = 100;
  var[2] = 110;
  var[3] = 120;
  var[4] = 130;
  var[5] = 140;
  var[6] = 150;
  var[7] = 160;
  var[8] = 170;
  var[9] = 180;
  var[10] = 190;


  Serial1.write(var, sizeof(var));
//Serial.println(var[0]);

}

Empfangs Code

byte werte[10]; // die gelesenen 10 Byte

void setup() {


  Serial.begin(9600);
  Serial1.begin(9600);

}



// im loop

void loop() {
  if (lesen()) {
    Serial.println(werte[0]);
    Serial.println(werte[1]);
    Serial.println(werte[2]);
    Serial.println(werte[3]);
    Serial.println(werte[4]);
    Serial.println(werte[5]);
    Serial.println(werte[6]);
    Serial.println(werte[7]);
    Serial.println(werte[8]);
    Serial.println(werte[9]);
  }
}

//liefert true, wenn 255 als Startbyte +10 Byte gelesen wurden
bool lesen() {
  static bool imLesen = false;
  static byte idx = 0;
  byte c;
  if (!Serial1.available()) return false;
  c = Serial1.read();
  if (!imLesen && c == 255) {
    imLesen = true;
    idx = 0;
  }
  else {
    werte[idx++] = c;
    if (idx > 9) {
      imLesen = false;
      return true;
    }
    else return false;
  }
}

Serieller Monitor

100
110
120
150
100
160
170
180
190
255
100
110
120
150
100
160

Im Empfang sind über längere Zeit alle Daten vorhanden aber nicht in der richtigen Reihenfolge.
Was mich wundert ist das die 255 auch in der Ausgabe auftaucht, was sie ja nicht sollte, sofern ich den Code richtig verstanden habe (das was ich davon verstanden habe).

Oder ist mir beim Umsetzen ein Fehler unterlaufen?

Baue Dir mal ein paar serielle Ausgaben (c, idx) in die lesen-Funktion, um zu schauen, was wo passiert.

Gruß Tommy