Es sieht so aus als muss Serial.flush genutzt werden, damit alle Daten im Sendepuffer auch immer gesendet werden. In der Arduino Doku steht aber auch: Serial.flush wartet bis alle ausgehenden Daten gesendet wurden Nun habe ich im Arduino Source Code nachgesehen, dort steht tatsächlich: void HardwareSerial::flush() { ... while (transmitting && ! (*_ucsra & _BV(TXC0))); ... } Serial.setTimeout hat also hier keinen Effekt Das bedeutet aber doch, wenn sich z.B. das serielle Kabel lösen würde, hängt sich hier das Programm auf. Was kann man da machen? Alles was mir dazu einfällt, ist kompliziert: Timer-Interrupt nutzen, um das hängen zu erkennen. HardwareSerial abändern und Serial.setTimeout in flush einfügen ...
> Das bedeutet aber doch, wenn sich z.B. das serielle Kabel lösen würde, > hängt sich hier das Programm auf. Was kann man da machen? Warum sollte es? Die UART schiebt die Daten raus, egal ob da nen Kabel drin steckt oder nicht.
> Es sieht so aus als muss Serial.flush genutzt werden, damit alle Daten > im Sendepuffer auch immer gesendet werden. Hab zwar nie Arduino genutzt, aber laut Doku ist nen flush nicht nötig - es wird auch so alles gesendet. Mit flush wartet man nur, bis alles gesendet wurde. Meiner Erfahrung nach, liegt das Problem, das Anfänger anscheinden mit nem flush beheben, üblicherweise woanders - nen flush ist nur in seltenen Ausnahmen nötig.
Gestählt, durch langjährige Arduino Erfahrung, muss ich dem foobar uneingeschränkt zustimmen. Lothar schrieb: > Alles was mir dazu einfällt,... Lothar, vielleicht solltest du mal sagen, welche Probleme dich wirklich plagen. Denn höchst vermutlich buddelst du auf der falschen Baustelle.
foobar schrieb: > egal ob da nen Kabel drin steckt oder nicht. einen Kabel? foobar schrieb: > nen flush ist nur in seltenen Ausnahmen nötig. einen Flush? Der Akkusativ ist dem Nominativ sein Tod. Deutsche Sprache - schwäre Sprache. https://wortwuchs.net/grammatik/kasus/
foobar schrieb: > Anfänger Da es um einen Port von 8051 auf Arduino geht bin ich auf Arduino wohl tatsächlich Anfänger ... Die Ursache warum es nur mit flush funktioniert ist vermutlich gefunden. Diese serielle Schnittstelle ist über RS485 angeschlossen und es müssen alle Daten aus dem Sendepuffer raus bevor der Transceiver umgeschaltet wird. Wird sogar hier erklärt: https://www.mikrocontroller.net/articles/RS-485 Eine Überwachung mit Timer-Interrupt ist somit zum sicheren Betrieb mit Timeout erforderlich. Wird z.B. hier erklärt: https://oscarliang.com/arduino-timer-and-interrupt-tutorial/ Da die Timer 0-2 von der Arduino Software genutzt werden - für millis und so - und die Timer 3-5 frei sind auf dem Arduino MEGA kann ich also den Timer 5 dafür nehmen. Jetzt muss ich als AVR Nicht-Nutzer "nur" noch rausfinden, wie man auf dem ATMEGA2560 mit Timern arbeitet. Es gibt zwar auch mehrere Arduino Timer Libraries. Wenn ich das aber richtig verstanden habe, nutzen die alle millis - also Polling - und würden sich mit dem Programm aufhängen.
Lothar schrieb: > Da die Timer 0-2 von der Arduino Software genutzt werden Eigentlich nur Timer0 Lothar schrieb: > und es müssen > alle Daten aus dem Sendepuffer raus bevor der Transceiver umgeschaltet > wird. Das ist ein guter Grund für einen Flush. Was hast du denn jetzt für ein Problem mit den Timern? Eben noch ein Flush Problem und jetzt Timer.... Wie hängt das zusammen? Was willst du wirklich erreichen?
foobar schrieb: > Hab zwar nie Arduino genutzt, Eine optimale Voraussetzung, hier Tipps zu geben :-( > aber laut Doku ist nen flush nicht nötig - es wird auch so alles gesendet. > Mit flush wartet man nur, bis alles gesendet wurde. Ich habe eine Anwendung, wo ich den Arduino kurz nach seiner Aktion schlafen lege. Serial brauche ich nur für die Kalibrierung oder Fehlersuche. Hier gab es Ärger, dass der schlafen geht, bevor die Daten vollständig raus sind - da hilft Serial.flush(), bevor dann LowPower.powerDown(SLEEP_8S, ADC_OFF, BOD_OFF); aus der "#include "LowPower.h" zuschlägt. Lothar schrieb: > Das bedeutet aber doch, wenn sich z.B. das serielle Kabel lösen würde, hängt sich hier das Programm auf. Das tut es hier nicht, Daten gehen stumpf raus, ob etwas dran hängt oder nicht, ist egal.
Arduino Fanboy D. schrieb: > Was willst du wirklich erreichen? Also wenn Du wirklich helfen willst. Ich hatte doch geschrieben: Lothar schrieb: > Port von 8051 auf Arduino Beim 8051 braucht es keinen Flush da kein Sendepuffer. Auf Arduino muss nun aber diese Flush Funktion aufgerufen werden. In der Flush Funktion hat man ein Loop ohne Timeout hinprogrammiert. Es braucht also eine Möglichkeit im Programm festzustellen ob diese Flush Funktion zu Ende ausgeführt wurde oder ob das Programm dort hängt. Für sowas gibt es z.B. den Watchdog. Der würde aber einen Reset machen. Ich würde einen Fehler ausgeben wollen. Dafür könnte man einen Timer vor dieser Flush Funktion starten und danach stoppen. Wenn die Flush Funktion hängt zeigt sich das in der Timer ISR - Timer läuft schon zu lange. Wenn Du eine bessere Lösung hast kannst Du es ja sagen. Was keine Lösung ist: Natürlich hat die Flush Funktion beim Testen bisher noch nie gehangen. Dieser unwahrscheinliche Fall muss aber dennoch abgesichert werden. Meiner Meinung nach. Warum man in der Arduino Software nicht einfach in Serial.flush auch den Serial.setTimeout eingebaut hat - woher soll ich das wissen.
Lothar schrieb: > Also wenn Du wirklich helfen willst. Bei einer solchen Ansage, sagt meine Empfindung: Du willst keine Irrtümer einsehen. So können wir beide nicht zusammen kommen. Lothar schrieb: > Warum man in der Arduino Software nicht einfach in Serial.flush auch den > Serial.setTimeout eingebaut hat - woher soll ich das wissen. Ich kanns dir sagen: Weil es völlig Sinn befreit wäre das zu tun. Lothar schrieb: > Es braucht also eine > Möglichkeit im Programm festzustellen ob diese Flush Funktion zu Ende > ausgeführt wurde oder ob das Programm dort hängt. Wenn Serial.flush() zurückkommt, ist es auch fertig. Und es kommt auf jeden Fall zurück. Es sei denn, die Interrupts sind abgeschaltet. Und dann tuts auch dein Timer Interrupt nicht mehr Das ist dann aber eine Dummheit des Programmierers. Lothar schrieb: > Dafür könnte man einen Timer vor > dieser Flush Funktion starten und danach stoppen. Wenn die Flush > Funktion hängt zeigt sich das in der Timer ISR - Timer läuft schon zu > lange. Habe ich dir schon widerlegt. Lothar schrieb: > Dieser unwahrscheinliche Fall muss aber > dennoch abgesichert werden. Meiner Meinung nach. Deine Meinung in Ehren. Aber hier irrst du. Klarer: Du jagst deine eigenen Hirngespinste/Ängste ums Dorf. (meine Meinung zu diesem Thema) Nachtrag: OK, der WDT kann hier seinen Einsatz bekommen.
Lothar schrieb: > Natürlich hat die Flush Funktion beim Testen > bisher noch nie gehangen. Dieser unwahrscheinliche Fall muss aber > dennoch abgesichert werden. Meiner Meinung nach. Dann erklaere doch mal deine Meinung: Warum sollte flush(), deiner Meinung nach, haengen? Wie soll das gehen? Schau doch mal bitte in das Datenblatt des uC, lies was die Flags der Schnittstelle machen und wie Schnittstelle ueberhaupt funktioniert. Dann wirst du (hoffentlich) verstehen, das du versuchst ein Problem loesen, das gar nicht existiert.
Arduino Fanboy D. schrieb: > Lothar schrieb: >> Es braucht also eine >> Möglichkeit im Programm festzustellen ob diese Flush Funktion zu Ende ausgeführt wurde oder ob das Programm dort hängt. > > Wenn Serial.flush() zurückkommt, ist es auch fertig. > Und es kommt auf jeden Fall zurück . Lothar will es nicht begreifen und ist wohl auch nicht in der Lage, das einfach zu probieren! Ich schrieb es auch schon: Ich habe ein Gerät mit Serial.flush(), wo seit über einem Jahr keine Schnittstelle angeschlossen ist, da hängt nichts, das Ding funktioniert einfach vor sich hin. Die Daten gehen ins Nirgendwo, der ProMini geht schlafen ... wäre das anders, wäre alle paar Tage mein Akku leer.
Ich habe durchaus schon einiges probiert um zu sehen was da vor sich geht. Wenn ich das so mache, dann würde ich erwarten, dass spätestens nach dem delay das Byte raus ist: Serial.write(msg[0]); delay(1000); Ist aber nicht so, erst mit flush geht das Byte raus: Serial.write(msg[0]); Serial.flush(); delay(1000); Das ist wohl so wegen dem Sendepuffer in der Arduino Software. Aber selbst das hier ändert daran nichts: #define SERIAL_TX_BUFFER_SIZE 1 https://github.com/arduino/ArduinoCore-avr/blob/master/cores/arduino/HardwareSerial.h
Zeig doch bitte mal ein minimales, compilierbares Beispiel, das deinen "Problem" zeigt.
Beitrag #5596115 wurde von einem Moderator gelöscht.
Lothar schrieb: > Wenn ich das so mache, dann würde ich erwarten, dass spätestens > nach dem delay das Byte raus ist: > > Serial.write(msg[0]); > delay(1000); > > Ist aber nicht so, erst mit flush geht das Byte raus: Das kann ich nicht bestätigen. Meine Tests zeigen, dass Serial keine Bytes zurückhält. Alles wird sobald wie möglich Ausgegeben.
Arduino Fanboy D. schrieb: > Das kann ich nicht bestätigen. > Meine Tests zeigen, dass Serial keine Bytes zurückhält. > Alles wird sobald wie möglich Ausgegeben. richtig Das flush() bewirkt nur, dass die Ausführung des Code anhält bis das letzte Zeichen gesendet wird. Der Controller wartet bis der Sendebuffer wieder frei ist.
Thomas W. schrieb: > dass die Ausführung des Code anhält bis das > letzte Zeichen gesendet wird Also ich habe mal gelernt dass es - egal ob bei PC Programmierung oder Mikrocontroller - keine Funktion geben darf die das Programm anhält und auf etwas wartet. Das ist Busy Waiting und das macht man nicht. Wenn ich bei der PC Programmierung eine Bibliothek mit so einer Funktion habe dann muss ich entweder dafür einen neuen Thread aufmachen damit das Hauptprogramm nicht hängen bleiben kann. Oder einen Timeout Timer. Bei Mikrocontroller habe ich mit Serial.flush jetzt zum ersten Mal eine Funktion gesehen die ein Busy Waiting while drin hat. > Der Controller wartet bis der Sendebuffer wieder frei ist Also wenn ich das Datenblatt richtig verstanden habe ist das nicht so. Der Controller hat nur ein Byte Senderegister. Wenn es dort rausgeht gibt es ein Polling Flag oder einen Interrupt falls aktiv. Das hält das Programm nicht an. Serial.flush verwendet aber einen 64 Byte Sendebuffer in Software. Daneben steht übrigens dieser Kommentar: "We're using a ring buffer (I think)" https://github.com/arduino/ArduinoCore-avr/blob/master/cores/arduino/HardwareSerial.h
Lothar schrieb: > Serial.flush verwendet aber einen 64 Byte Sendebuffer in Software. Ich meinte mit "Sendebuffer" schon den 64 Byte Sendebuffer Lothar schrieb: > Also ich habe mal gelernt dass es - egal ob bei PC Programmierung oder > Mikrocontroller Da gebe ich dir schon recht. Aber trotzdem gibt es Fälle wo es durchaus Sinn macht, zu warten ...
Lothar schrieb: > Bei Mikrocontroller habe ich mit Serial.flush jetzt zum ersten Mal eine > Funktion gesehen die ein Busy Waiting while drin hat. Das gibt's doch ständig. Alle möglichen Bibliotheken für Displays, SD-Karten und somit auch FAT-Libraries, I²C und darauf basierende Komponenten machen das so; insbesondere im Arduino-Umfeld. Selbst analogRead wartet, bis eine ADC-Wandlung abgeschlossen ist. Das ist m.E. der Hauptgrund, warum Embedded-Bibliotheken oft schlecht skalierbar bzw. wiederverwendbar sind - wenn mehrere davon blockierende Funktionen haben, beeinflussen die sich gegenseitig bzw. brauchen einfach zu viel Zeit. Daher werden ja auch oft RTOS genutzt, um das Problem zu umgehen... Lothar schrieb: > Ist aber nicht so, erst mit flush geht das Byte raus: > > Serial.write(msg[0]); > delay(1000); Ist vielleicht das delay(1000) zu kurz um auf alles zu warten? Setze vor dem delay mal einen Pin, schließe ein Oszilloskop an diesen sowie den UART-TX-Pin an und schau ob danach alles raus kommt.
:
Bearbeitet durch User
Niklas G. schrieb: > analogRead wartet, bis eine ADC-Wandlung abgeschlossen ist Habe ich bisher noch nicht genutzt aber - echt jetzt? Ich würde das so machen dass ein analogRead den ADC startet und spätestens nach Timeout eine globale Variable zurückgibt und diese globale Variable wird in einer ISR vom ADC geupdatet wenn der fertig ist. Alles was dann passieren kann ist dass analogRead noch den alten Wert zurückgibt wenn der ADC noch nicht fertig war. Aber hängen kann es dann nicht. Wenn ich analogRead mal verwende würde ich dann auch sicherheitshalber einen Timeout Timer nutzen. Wie ich das bei Serial.flush auch grade versuche. Thomas W. schrieb: > Aber trotzdem gibt es Fälle wo es durchaus Sinn macht, zu warten ... Schon möglich aber mein Hauptprogramm muss noch andere Dinge zeitkritisch erledigen. Wenn es auf die serielle Schnittstelle warten muss dann wenigstens mit Timeout.
Lothar schrieb: > Habe ich bisher noch nicht genutzt aber - echt jetzt? Ich würde die Referenz so verstehen: https://www.arduino.cc/reference/en/language/functions/analog-io/analogread/ It takes about 100 microseconds (0.0001 s) to read an analog input, so the maximum reading rate is about 10,000 times a second. Lothar schrieb: > Ich würde das so > machen... Und dann beschwert sich wer, dass das API suggeriert, der ADC sei schneller als er tatsächlich ist... Lothar schrieb: > Wenn ich analogRead mal verwende würde ich dann auch sicherheitshalber > einen Timeout Timer nutzen. Wie ich das bei Serial.flush auch grade > versuche. Das muss auch ohne gehen. Einen Timer nur für den UART abzustellen ist overkill...
Gerade das Arduino Framework (ich nenne es mal so) zielt auf schnelle Erfolge für unbedarfte Anwender. Liefert Komfort Funktionen für ein breites Spektrum an µC. Will man was spezielles, muss man es selber bauen. Klarer: Wenn dir die Serial Klasse nicht gefällt, dann nutze sie nicht! Bau dir was eigenes. Serial.print() und seine Brüder sind auch blockierend, wenn der Ringpuffer voll ist. Kehren also erst zurück, wenn alle übergebenen Zeichen im Ringpuffer versenkt werden konnten. Serial.availableForWrite() sagt dir wieviel Platz noch im Ringpuffer ist. Zusätzlich könnten noch ein(zwei?) Byte im UART Sendepuffer stecken. --- analogRead() ist wirklich recht primitiv. Nutzt kaum die Fähigkeiten der verschiedenen AVR ADC aus Hat sogar noch einen Fehler im Bauch, bei der ADC Vorteiler Berechnung. Bei 1, 8 und 16MHZ ist alles OK, aber bei krummen Frequenzen, z.B. bei einem Baudrate Quarz kanns klemmen. Wenn du möchtest, kann ich dir eine "verbesserte" ADC Lib zukommen lassen.
Lothar schrieb: > Also ich habe mal gelernt dass es - egal ob bei PC Programmierung oder > Mikrocontroller - keine Funktion geben darf die das Programm anhält und > auf etwas wartet. Das ist Busy Waiting und das macht man nicht. > > Wenn ich bei der PC Programmierung eine Bibliothek mit so einer Funktion > habe dann muss ich entweder dafür einen neuen Thread aufmachen damit das > Hauptprogramm nicht hängen bleiben kann. Oder einen Timeout Timer. Das ist so pauschal ja erstmal Unfug. "Ich hab das mal so gelernt...", hast du das auch mal hinterfragt? Ganz einfaches Beispiel: Ein Konsolenprogramm das eine Nutzereingabe erwartet. Natuerlich blockiert das Programm an der stelle und wartet bis der Nutzer seine Eingabe gemacht hat. Warum sollte man fuer sowas einen Thread aufmachen (und was soll der Rest des Programms in der Zeit machen?), oder irgendwelche Timer nutzen? Wenn das Programm ohne Nutzereingabe nicht weitermachen kann, dann muss es halt an der Stelle warten.
Hallo, natürlich kann man auch auf einem Microcontroller einen Timer laufen lassen, der zyklisch nachschaut, ob der Sendebuffer endlich leer ist. Dazwischen kann man entweder in der loop() auf die Fertigmeldung des Timer warten (wie sinnvoll in disem Fall...), man kann natürlich auch in der Wartezeit auch die Mining-Funktiuon für die Bitcoins laufen lassen.. PS: mir fällt in vielen Arduinoprogrammen auf, daß die serielle stur auf den default 9600 Baud gelassen wird. 38400 und 76800 gehen mit der gleichen geringen Fehlerrate, 115200 üblicherweise auch noch, obwohl der Fehler da mit 2,1% dicht an der Grenze ist. Schon bei 38400 ist der Sendebuffer in einem viertel der Zeit leer... Gruß aus Berlin Michael
Michael U. schrieb: > natürlich kann man auch auf einem Microcontroller einen Timer laufen > lassen, der zyklisch nachschaut, ob der Sendebuffer endlich leer ist. > Dazwischen kann man entweder in der loop() auf die Fertigmeldung des > Timer warten (wie sinnvoll in disem Fall...), man kann natürlich auch in > der Wartezeit auch die Mining-Funktiuon für die Bitcoins laufen lassen.. Ja und nein... Im Falle Arduino wird der SendePuffer auf jeden Fall irgendwann leer. Es sei denn die Interrupts sind aus, aber dann hilft auch kein Timer Interrupt mehr. Michael U. schrieb: > PS: mir fällt in vielen Arduinoprogrammen auf, daß die serielle stur auf > den default 9600 Baud gelassen wird. 38400 und 76800 gehen mit der > gleichen geringen Fehlerrate, 115200 üblicherweise auch noch, obwohl der > Fehler da mit 2,1% dicht an der Grenze ist. Einerseits hast du natürlich recht... Aber ist denn immer eine hohe Geschwindigkeit sinnvoll? Ok.. die Kabellänge spielt keine Rolle, wenn der USB Adapter mit auf dem Board steckt. Andererseits gibt es auch keine Flusskontrolle, weder in Hardware, noch Software. Da kann es schon passieren, dass die Verarbeitungszeiten auf dem µC zu lang sind, um hohe Datenraten zu verarbeiten. Und das letzte, vielleicht (für mich) wichtigste Argument, für dauerhaft 9600Baud, man muss nicht dauernd umstellen. Aber, wie fast immer: Die Anforderungen bestimmen die Grenzen und sinnvollen Werte.
Kaj schrieb: > Ein Konsolenprogramm das eine Nutzereingabe erwartet Auf einem Mikrocontroller? Und da soll nix währenddessen passieren? Wie Batterie prüfen, irgendwelche I/Os nachsehen. Hatte ich noch nie. Ich habe z.B. aktuell - nicht auf Arduino - einen PID-Regler dem man seriell die Parameter ändern kann. Das wäre nicht so gut wenn der während der seriellen Kommunikation nix macht. Beim PC ist es sogar zwingend für serielle Kommunikation einen Timeout oder Thread zu machen. Führt zwar jetzt hier zu weit aber damit das Programm nicht hängt oder merkwürdige Sachen macht braucht es entweder - einfach - DoEvents oder - mehr Aufwand aber gerne gesehen - Invoke: asynchroner Thread. Die einzige Möglichkeit das zu vermeiden wäre das Konsolenprogramm in eine Datei schreiben zu lassen und das davon getrennte Hauptprogramm die Datei zu prüfen und es dort wenn fertig abzuholen. Das ist aber nicht mehr modern.
Hallo, Arduino Fanboy D. schrieb: > Michael U. schrieb: >> natürlich kann man auch auf einem Microcontroller einen Timer laufen >> lassen, der zyklisch nachschaut, ob der Sendebuffer endlich leer ist. >> Dazwischen kann man entweder in der loop() auf die Fertigmeldung des >> Timer warten (wie sinnvoll in disem Fall...), man kann natürlich auch in >> der Wartezeit auch die Mining-Funktiuon für die Bitcoins laufen lassen.. > > Ja und nein... > Im Falle Arduino wird der SendePuffer auf jeden Fall irgendwann leer. > Es sei denn die Interrupts sind aus, aber dann hilft auch kein Timer > Interrupt mehr. Das bezig sich einerseits auf den Ausgangspunkt, daß man den AVR schalfen schicken will, da ist dann auf Dauer direkt Batteriekapazität. > > Michael U. schrieb: >> PS: mir fällt in vielen Arduinoprogrammen auf, daß die serielle stur auf >> den default 9600 Baud gelassen wird. 38400 und 76800 gehen mit der >> gleichen geringen Fehlerrate, 115200 üblicherweise auch noch, obwohl der >> Fehler da mit 2,1% dicht an der Grenze ist. > > Einerseits hast du natürlich recht... > Aber ist denn immer eine hohe Geschwindigkeit sinnvoll? > > Ok.. die Kabellänge spielt keine Rolle, wenn der USB Adapter mit auf dem > Board steckt. > Andererseits gibt es auch keine Flusskontrolle, weder in Hardware, noch > Software. Da kann es schon passieren, dass die Verarbeitungszeiten auf > dem µC zu lang sind, um hohe Datenraten zu verarbeiten. Mit 115200 habe ich real auch nie ein Problem gehabt, wenn der USB-Wandler per Dupontkabeln o.ä. angeschlossen war. Von ewig langen Leitungen rede ich hier natürlich nicht, eben für Debug-Zwecke. Ich habe schon mehrfach den Zustand gehabt, daß zu umfangreiche Debug-Ausgaben letztlich meinen Ablauf ausgebremst haben. Auch Serial.print() wartet, wenn der Sendebuffer voll ist... Die Verarbeitungszeit spielt erst beim Empfangen eine Rolle, wenn mehr Zeichen kommen als der serielle Buffer aufnehmen kann ohne daß sie abgeholt werden. Beim Senden muß der Empfänger damit klarkommen. Wenn ich auf dem AVR eben nur selten Bytes sende, sind die Pausen dazwischen eben länger. > Und das letzte, vielleicht (für mich) wichtigste Argument, für dauerhaft > 9600Baud, man muss nicht dauernd umstellen. Ist jeweils meine erste Änderung in fremden Sketchen, die ArduinoIDE merkt sich das sowieso und steht damit immer auf den 115200... > Aber, wie fast immer: > Die Anforderungen bestimmen die Grenzen und sinnvollen Werte. So ist es. Gruß aus Berlin Michael Das gilt sowieso immer
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.