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...
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?
Wieso setzt du die denn runter? ich würd die intuitiv eher hoch setzen damit dein "rechenzyklus" ja deutlich langsamer als der übertragungszyklus ist 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?
also möchtest du 4 byte schicken? in deinem bild zum serial receive wählst du nur ein byte aus?
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:
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:
Sample Time von Serial Receive unter der Sendezeit?
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.
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.