Ich habe seit der Umstellung von seriellen Verbindungen zwischen drei Arduinos auf I2C nun festgestellt, dass sich der Mega der die Daten empfängt und per I2C dann an die anderen Arduino Uno's weiterleitet nach willkürlicher Zeit hängen bleibt. Ich sende dem Mega dann Daten, aber es tut sich nichts mehr. Ich frage mich nun, ob dies hier Probleme mit dem Speicher verursacht?
while(Serial1.available() > 0){ //while serial is available, make...
var = Serial1.read(); //store first character from serial to var
switch(var){
case 'A' : DP1 = Serial1.parseInt(); //if var is equal to A, then store second character from serial to DP1
break; //finish the command and return
case 'B' : DP2 = Serial1.parseInt();
break;
case 'C' : DP3 = Serial1.parseInt();
break;
case 'D' : DP4 = Serial1.parseInt();
break;
case 'E' : DP5 = Serial1.parseInt();
break;
case 'F' : DP6 = Serial1.parseInt();
break;
case 'G' : DP7 = Serial1.parseInt(); //if var is equal to G, then store second character from serial to DP7
Wire.beginTransmission(2); //transmit to device #2
Wire.write('G'); //send the character G by I2C
Wire.write((uint8_t*)&DP7, sizeof DP7); //send DP7 by I2C
Wire.endTransmission(); //stops transmitting
break;
case 'H' : DP8 = Serial1.parseInt();
Wire.beginTransmission(2);
Wire.write('H');
Wire.write((uint8_t*)&DP8, sizeof DP8);
Wire.endTransmission();
break;
......
}
}
Zur Erläuterung, ich sende mit einem Joystick Werte zwischen 0 und 180 und sende diese an einen Arduino Uno der zwei Motoren steuert. Im Prinzip sendet der Joystick ja "permanent" Werte wenn ich ihn immer bewege. Gibt es da Konflikte, da die Daten vom Mega eingelesen werden, über I2C aber nicht gleich schnell weg gehen? Oder gibt es hier generell Konflikte wenn die serielle Schnittstelle mit der Wire Library verwendet wird?
Schule - Diktat
Was passiert, wenn der Lehrer schneller spricht, als die Schüler schreiben können?
Ich kann es dir sagen: Der Ringpuffer zwischen den Ohren läuft über!
Wenn nachfolgend auf mehr als 1 Zeichen reagiert werden soll, dann sollte man vorher auch schon auf die (minimal) erwartete Zeichenzahl warten. Sonst wartet parseInt() bis mehr Zeichen eintrudeln, und so lange ist der Controller blockiert.
Wenn der Joystick permanent Daten schickt, dann würde ich auf 5 oder mehr Zeichen warten, bevor ich die Eingabe parse.
Oder Du implementierst einen nicht-blockierenden Parser.
Es wird immer ein Buchstabe mit einem Zahlenwert gesendet, z.B. A179, dieser wird dann mit dem Character var gelesen was das A liest und im switch/case durchläuft. Dort wird dann der Wert 179 mit parseInt() auf DP1 gespeichert. Der Joystick sendet so für jeden geänderten Wert, sprich für jede Bewegung den neuen Wert und dazugehörigen Buchstaben. Wenn ich dies so parse und wenn nötig sogar noch per I2C weiterleite, dann hat der Speicher ja sicherlich genügend empfangene Daten die gelesen werden sollten/möchten, oder nicht?
Das Problem ist, dass sich der Arduino nur nach einem Reset oder Neustart (stromlos und wieder anschliessen) funktioniert. Wenn man wartet passiert nichts mehr, er hängt und bleibt in diesem Zustand.
Einen nicht blockierenden Parser kann ich versuchen, hast Du da ein Beispiel? Die Frage stellt sich jedoch, da es vorher mit seriellen Verbindungen funktioniert hatte und ich keine Hänger hatte, ob das wirklich was hilft. Ist I2C schneller als eine serielle Verbindung, dass sich der Parser als blockierend erweisen kann?
Gibt es ein Ende-Zeichen nach der Ausgabe von "A179"? Dann kann man mit dem Parsen warten bis dieses Zeichen eintrifft, Dann blockiert parseInt() nichts mehr, da ja der String schon vollständig gelesen wurde. Oder man schickt alle Zahlen mit fester Stellenzahl (3-4), dann kann man auf das Eintreffen der entsprechenden Anzahl von Zeichen warten.
Nein, ein Endzeichen wird hier nicht gesendet. Der Buchstabe wird mit Serial.print() und der Zahlenwert dann per Serial.println() gesendet. Wenn ich hier dann einlese, dann ist das println doch auch wie ein Endzeichen und mit parseInt wird nur bis zur neuen Zeile/Buchstabe eingelesen?
Was ich noch gefunden habe, kann es sein, dass das Wire. endTransmission() hängen bleibt? Scheinbar hatten da andere so ihre Probleme mit. Die WSWire.h hatte abhilfe geschaffen. Das Problem was dort wäre, diese deaktiviert ja die internen Pullups. Ich habe aber meine externen Widerstände so gewählt, dass ich ca. 4.7kOhm mit den internen Pullups habe. Wenn diese jetzt deaktiviert werden, dann habe ich einen zu grossen Widerstand.
Ich schaue morgen mal noch, ob sich mit ändern der Taktrate des I2C Buses was positiv verändert.
Wie kann man dies in dieser Form machen wie mein Sketch aktuell aufgebaut ist? Das Serial.parseInt() nimmt ja einfach den nächsten Wert und dann verlässt es die switch/case Anweisung. Danach geht es zwangsläufig wieder zurück zum Serial.read() was den neuen Character nimmt/liest.
Ich versuche heute mal per serielle Ausgabe den Wire.endTransmission auszulesen und sehen ob dieser hängen bleibt oder was passiert. Da alle Befehle nicht mehr weitergeleitet werden gehe ich mal davon aus, dass sich die Wire Library aufhängt, da ich wie gesagt, vorher per serieller Verbindungen keine Probleme hatte. Zumindest nicht in der Häufigkeit und relativ kurz nach dem Einschalten. Ich gebe mir sonst die empfangenen Werte in der Switch/Case Anweisung vor den Wire.begin() aus. Wenn diese bis zum Stillstand noch durchgekommen sind, dann sollte man den Fehler ja sehen?! Und die endTransmission Werte auch gleich, vielleicht sieht man dann genau wo es hängt.
Ich werde mir dies mal ausgeben und schauen wo es genau hängt:
while(Serial1.available() > 0){ //while serial is available, make...
var = Serial1.read(); //store first character from serial to var
switch(var){
case 'A' : DP1 = Serial1.parseInt(); //if var is equal to A, then store second character from serial to DP1
Serial.print("DP1 = ");
Serial.println(DP1);
break; //finish the command and return
case 'B' : DP2 = Serial1.parseInt();
Serial.print("DP2 = ");
Serial.println(DP2);
break;
case 'C' : DP3 = Serial1.parseInt();
Serial.print("DP3 = ");
Serial.println(DP3);
break;
case 'D' : DP4 = Serial1.parseInt();
Serial.print("DP4 = ");
Serial.println(DP4);
break;
case 'E' : DP5 = Serial1.parseInt();
Serial.print("DP5 = ");
Serial.println(DP5);
break;
case 'F' : DP6 = Serial1.parseInt();
Serial.print("DP6 = ");
Serial.println(DP6);
break;
case 'G' : DP7 = Serial1.parseInt(); //if var is equal to G, then store second character from serial to DP7
Serial.print("DP7 = ");
Serial.println(DP7);
Wire.beginTransmission(2); //transmit to device #2
Wire.write('G'); //send the character G by I2C
Wire.write((uint8_t*)&DP7, sizeof DP7); //send DP7 by I2C
Wire.endTransmission(); //stops transmitting
Serial.print("Status von endTransmission DP7 = ");
Serial.println(Wire.endTransmission());
break;
case 'H' : DP8 = Serial1.parseInt();
Serial.print("DP8 = ");
Serial.println(DP8);
Wire.beginTransmission(2);
Wire.write('H');
Wire.write((uint8_t*)&DP8, sizeof DP8);
Wire.endTransmission();
Serial.print("Status von endTransmission DP8 = ");
Serial.println(Wire.endTransmission());
break;
......
So, ich habe heute mal die serielle Ausgabe angeschaut! Es passiert folgendes:
FDUD = 63
Status von endTransmission FDUD = 0
FDUD = 63
Status von endTransmission FDUD = 0
FDUD = 62
Status von endTransmission FDUD = 0
FDUD = 63
Status von endTransmission FDUD = 0
FDLR = 180
Status von endTransmission FDLR = 0
FDUD = 61
Status von endTransmission FDUD = 0
FDLR = 179
Status von endTransmission FDLR = 0
FDLR = 17
Status von endTrans
Die Übertragung bricht komplett inmitten der Ausgabe ab und der Arduino/die Arduinos hängt/hängen. Also der Mega bleibt sicher hängen, von dem auch die Ausgabe.
Was ich gemerkt habe, dass die seriellen Ausgaben die ich wie im Sketch oben gepostet nun für die Ausgabe am Monitor eingefügt habe, alles verlangsamt und zum Teil etwas falsche Werte ausgibt/übermittelt. Die Motoren drehen zum Teil einfach weiter und stoppen erst nach nochmaligem betätigen des Joysticks. Als würde der Stopwert nicht oder viel zu langsam übermittelt mit all den seriellen Ausgaben am Monitor.
Nun zurück zum Problem. Was könnte ein kompletter Hänger des Megas verursachen?
Ich versuche jetzt noch den Takt des I2C Buses zu erhöhen. Vielleicht hilft dies?
Die Ausgabe mit ergänztem RAM anzeigen gibt auch keine Fehler aus:
Free RAM: 5192
Free RAM: 5192
Free RAM: 5192
Free RAM: 5192
FDUD = 89
Status von endTransmission FDUD = 0
FDUD = 88
Status von endTransmission FDUD = 0
FDLR = 179
Status von endTransmission FDLR = 0
FDUD = 89
Status von endTransmission FDUD = 0
FDLR = 180
Status von endTransmission FDLR = 0
FDUD = 88
Status von endTransmission FDUD = 0
FDUD = 89
Status von endTransmission FDUD = 0
FDUD = 88
Status von endTransmission FDUD = 0
FDUD = 89
Status von endTransmission FDUD = 0
FDUD = 88
Status von endTransmission FDUD = 0
FDUD = 89
Status von endTransmission FDUD = 0
FDLR = 174
Status von endTransmission FDLR = 0
FDLR = 163
Status von endTransmission FDLR = 0
FDUD = 88
Status von endTransm
Der RAM bleibt bei 5192 bytes die noch frei sind, also mehr als genug!
Meinst du das endTransmission() im Serial.print? Das ist nur dazu da um die Übertragungsfehler anzuzeigen falls es hat. Oder muss ich dies direkt oben vor das erste endTransmission() setzen? Dann ist doch aber die Übertragung von Wire noch nicht erfolgt?!
Ich kann schon den ganzen code posten, habe aber schonmal gesagt bekommen es sei zu viel code... Ich sehe im Moment ja nicht was wichtig ist und wo der Fehler sein könnte. Darum kann ich nur alles posten! Ich werde den Code vom Mega der hägen bleibt mal ohne Kommentare posten. Ich bearbeite die Kommentare kurz raus.
Das Verhalten habe ich aber schon vorher, bevor ich die Serial.print(Wire.endTransmission()); zugefügt habe. Dies habe ich nur getan, um mögliche Fehler bei der Übertragung von I2C zu sehen am seriellen Monitor.
Wenn ich jetzt nur so schreibe, funktioniert dann das senden per I2C da das endTransmission nur noch im print() steht?
```
Wire.beginTransmission(2); //transmit to device #2
Wire.write('G'); //send the character G by I2C
Wire.write((uint8_t*)&DP7, sizeof DP7); //send DP7 by I2C
Serial.print("Status von endTransmission DP7 = ");
Serial.println(Wire.endTransmission());
```