[SOLVED] Simulink Serial Receive funktioniert nicht

HI Leute,

ich verzweifel hier noch mit dem Arduino Framework für Simulink. Ich möchte auf Serial2 Daten am Arduino einlesen und diese im Scope anzeigen lassen. Das funktioniert aber leider mal so gar nicht.
Für Testzwecke schicke ich aktuell alle 5 Sekunden einen random INT32 Wert an den Atmega2560.
Was mit normalen Code auch einwandfrei funktioniert, klappt bei Simulink überhaupt nicht. Entweder gehen Datenverloren oder es wird nur Murks angezeigt.

Die Daten Sende ich als Bytes.
Quellcode zum Senden:

#include <Arduino.h>

#define RX1 16
#define TX1 17
#define RX2 12
#define TX2 13
// Beispiel um von Serial 1 auf Serial 2 zu senden | TX1 -> RX2

unsigned long timeDelay = 0;

void setup() {
  Serial.begin(115200);
  Serial1.begin(9600, SERIAL_8N1, RX1, TX1);
  Serial2.begin(9600, SERIAL_8N1, RX2, TX2);
}

int32_t randomVal(void) {
  // Zufällige 16-Bit-Werte generieren
  // Random-Werte von 0 bis 65534 (da der obere Grenzwert exklusiv ist)
  uint16_t lowerBits = random(0, 65535);

  // Kurze Verzögerung, um die Seed-Werte zu ändern und verschiedene Zufallszahlen in jedem Schleifendurchlauf zu erhalten
  delay(10);

  // Random-Werte von 0 bis 65534 (da der obere Grenzwert exklusiv ist)
  uint16_t upperBits = random(0, 65535); 

  // Kombinieren die beiden 16-Bit-Werte zu einem 32-Bit-Wert
  int32_t randomVal = (int32_t)upperBits << 16 | lowerBits;

  // Ausgabe des generierten Werts
  Serial.println("Generierter Wert: " + String(randomVal));

  return randomVal;
}


void receiveData(void) {
  //prüfe ob Buffer Serial 2 einen vollständigen Int32 Wert enthält
  if (Serial2.available() >= sizeof(int32_t)) {
    int32_t receiveVal;
    byte int32Buffer[sizeof(int32_t)];

    Serial2.readBytes(int32Buffer, sizeof(int32_t));

    receiveVal  = (int32_t) int32Buffer[0] << 24;
    receiveVal |= (int32_t) int32Buffer[1] << 16;
    receiveVal |= (int32_t) int32Buffer[2] << 8;
    receiveVal |= (int32_t) int32Buffer[3] << 0;           

    Serial.println("Empfangener Wert: " + String(receiveVal) + "\n");
  }
}

void transmitData(void) {
  if (millis() < timeDelay) return;

  // sende jede Sekunde einen Zufallswert
  timeDelay = millis() + 5000;

  int32_t val = randomVal();

  for (byte i = 0; i < sizeof(int32_t); i++) {
    // übertrage je 8 Bit des Int32 Werts -> Big Endian Reihenfolge
    byte transmitVal = val >> (32 - 8 * (i + 1));

    Serial.println("Gesendeter Wert: " + String(transmitVal));
    Serial1.write(transmitVal);
  }
}

void loop() {
  transmitData();
  receiveData();
}

Mein Serial Receive Block in Simulink sieht aktuell wie folgt aus:

Ich hab beobachtet, dass 4 Werte teilweise ankommen. Aber die muss man scheinbar noch irgendwie zusammensetzen. Aktuell ist im oberen Scope nur 0 zu sehen...

Hallo iphilbln1

Reden beide Anlagen mit der gleichen Baudrate ?

Ja.

ich habe mittlerweile herausgefunden, dass dieses Problem nur auftritt, wenn ich sehr schnell Daten sende. Aktuell bei alle 11ms tritt dieses Phänomen auf.

NACHTRAG:
Scheinbar ist es wirklich ein Timingproblem, denn wenn ich die Sampling Time sehr weit runtersetze gehen zwar immer noch Daten verloren, jedoch nicht mehr so viele. Continouse mode funktioniert nicht. Wieso ist mir noch unklar.
Geht das nicht irgendwie sauberer?

Wie viele Bits werden pro Sekunde versendet und passt die die Baurate dazu ?

Auch das passt.

t = 4*(8+2) Bits / 9600 Bits*s^-1 = 4,16ms

Wieso setzt du die denn runter? :scream: ich würd die intuitiv eher hoch setzen damit dein "rechenzyklus" ja deutlich langsamer als der übertragungszyklus ist :thinking: oder war das nur als test? Parität und stopbit passt aber? Z.b. 8N1?

verwechselst du das grade vielleicht mit der Sample Rate? Die muss natürlich höher sein als die Sende rate, nur hohe Sampling Rate -> kleine Sampling Time. Oder was übersehe ich an deiner Antwort?

Ja ist beides auf 8_N_1 und 9600 Baud gestellt.

Hardware Settings

Serial Receive Block

Arduino Sketch - Setup auf Sender [ESP32]

void setup() {
  Serial.begin(115200);
  Serial1.begin(9600, SERIAL_8N1, RX1, TX1);
  Serial2.begin(9600, SERIAL_8N1, RX2, TX2);
  pinMode(button, INPUT_PULLUP);
  while (digitalRead(button) == HIGH) {}
}

verwechselung ist natürlich nie ausgeschlossen :upside_down_face:

ich meinte dieses bild in post #4.

hast du ne möglichkeit in den generiert code reinzuschauen?

So wie ich das verstehe behandelt Simulink das quasi wie die Frequenz des Prozesses an sich. Also analog zur CPU Frequenz.

Nicht das ich wüsste, jedenfalls ist mir kein Weg bekannt und im Ordner befindet sich nur das kompilierte Hex File.

Es macht auch nichtmal einen Unterschied ob Little Endian Byte oder Big Endian Byte wise gesendet wird.

Also bei aller liebe aber das kann doch nicht so schwer sein 4 aufeinander gesendet Bytes zu einem INT32 Wert wieder zusammenzufügen...

also möchtest du 4 byte schicken? in deinem bild zum serial receive wählst du nur ein byte aus?
image

Serial2.begin(9600, SERIAL_8N1, RX2, TX2);

Kannst du RX2 und TX2 und SERIAL_8N1 nicht weglassen?
Die sind bei dir mit defines auf 12 und 13 gelegt. im datenblatt sehe ich aber das und das irritiert mich etwas:

1 Like

Doch.
Wenn Du das in der Arduino-Umgebung machen willst, musst Du auch eingehend 32bit casten.
(Duck & Weg)

1 Like

Wie gesagt, in reinem Quellcode ist das simpel die Serielle Kommunikation umzusetzen. Das bringt mir aber nichts weil ich über Simulink meine Regelstrecke simuliere und das Signal auf den eigentlichen Mikrocontroller gebe und von diesem auch wieder einlesen muss in Simulink. Und das funktioniert halt nicht...

Mein Sender ist aktuell ein ESP32. Hatte ich etwas weiter oben in der Überschrift zu stehen.

Dein Tip mit den 4 Bytes hat jetzt endlich des Rätsels Lösung gebracht. Wieso das nicht mehr auf 4 Bytes gestellt war, weiß ich selbst grade nicht.

Jedenfalls hab ichs jetzt.

Des Rätsels Lösung ist jedenfalls mit dem Sender zu warten bis der Simulink Sketch läuft. Macht ja am Ende eigentlich auch nur Sinn, da sonst die Reihenfolge im Inputbuffer nicht mehr stimmt.
Jedenfalls was noch wichtiger ist, was ich aber nirgendwo finden konnte, ist, dass die Daten in Little Endian gesendet werden.

Zusammenfassung:

    1. Sample Time von Serial Receive unter der Sendezeit?
    1. Daten in Little-Endian-Byte-Reihenfolge senden
    1. Sketch auf Empfänger starten -> Simulink
    1. Sketch auf Sender starten -> Arduino

ich war auchgrad am raetseln.
Ich hätte dem Empfänger im setup gesagt, das der serielle Puffer zu leeren ist, bis serial.read() -1 bringt...
Wenn der Sender dann nicht irgendwas anderes bringt, ist es egal in welcher reihenfolge gestartet wird.

Das verstehe ich grade nicht so wirklich?
Der Empfänger ist an Simulink angeschlossen. Da kann man nicht einfach den Seriellen Input Buffer leeren. Jedenfalls kann ich dazu keinen Baustein finden.

Der Hauptknackpunkt war eigentlich dass die Daten in Little-Endian-Byteweise gesendet werden müssen. Das konnte ich nirgendwo finden und kam mir auch relativ spät der Gedanke, dass es daran liegen könnte. Jedenfalls wird jetzt sauber alle 10ms die -10 eingelesen.

Ah.. doch, irgendwo hatten wir das schon mal.
Aber ich bin heute auch raus - mein Weg und der akku ist zu Ende.
Schön, wenns klappt.

1 Like

Ich denke mal, das rührt daher, weil die AVR ja auch in Little Endian Byteweise mit den Daten umgehen. Naja wie dem auch sei, vielen Dank an die Helfenden und noch einen schönen Sonntag Abend.

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.