Arduino C Serial()

  • Hallo zusammen

    ich habe eine Routine für das lesen der Kommandos aus der USB Schnittstelle. Die Schnittstelle bekommt die Daten vom PC bzw. Raspberry.

    z.B:

    Code
    "Forward slow: 1 \n"

    Die Zykluszeit des Arduino beträgt ca. 400ms. Der PC kann die Kommandos schneller anliefern z.B. 2 oder 3 Kommandos innerhalb der Zykluszeit des Arduino.

    Werden die Daten im Arduino (Betriebssystem) gepuffert, wie gross ist dieser Puffer?
    Es kommt vor dass ich im Arduino überschriebene Kommandos sehe (hab sie zum PC gespiegelt)


    ich rufe die Routine 1x im Zyklus des Arduino auf. Solange die Kommandos einzeln kommen ist alles richtig.

    Code
    SerialParser();
       if (ByteCount  > 0) {
         CommandString = Command;
         .....

    Softwarefehler suchen ist wie Pilze suchen. Wenn man erst einen gefunden hat, findet man meist mehrere.

    Bei Hardware ist es schlimmer, da findet man bereits Fehler wenn man gar keine sucht!

    Einmal editiert, zuletzt von Wolfgang Glück (3. Mai 2016 um 13:50)

  • Hallo Wolfgang,

    in einem solchen Fall empfiehlt sich, eine Kommunikation zu programmieren.

    Deine Lösung lässt sich kurz beschreiben als: Der, der schneller sprechen kann, quasselt drauf los. Der andere bekommt nur Bruchstücke mit.

    Zu einer guten Kommunikation gehört wie im richtigen Leben:
    - Einer sendet - der andere hört zu
    - Der Sender wartet nach dem Senden auf irgendwelche Rückmeldungen ("Aha!", "So so", "Echt?", "Super!", ...), was der Empfänger rückmeldet, wenn die Botschaft angekommen und verstanden wurde
    - Oder der Empfänger meldet "Häh" zurück, was im Hessenlande soviel bedeutet wie "Entschuldigen Sie, mein Herr / meine Dame. Ich habe Sie da gerade nicht richtig verstanden. Könnten Sie das nochmals sagen? L a n g s a m e r oder mit anderen Worten, so dass selbst ich das verstehen kann?"
    - Solange der Empfänger nur Bahnhof versteht, wiederholt der Sender seine Mitteilung.
    - Erst nach Bestätigung der Botschaft durch den Empfänger wird was Neues geschickt.

    Jetzt bist Du dran, das programmtechnisch umzusetzen.

    Beste Grüße

    Andreas

    Ich bin wirklich nicht darauf aus, Microsoft zu zerstören. Das wird nur ein völlig unbeabsichtigter Nebeneffekt sein.
    Linus Torvalds - "Vater" von Linux

    Linux is like a wigwam, no windows, no gates, but with an apache inside dancing samba, very hungry eating a yacc, a gnu and a bison.

  • Zunächst kommt das auf die verwendete Baudrate an, die entscheidet wie schnell Daten übermittelt und aus dem 64 bytes großen Buffer des Arduinos ausgelesen wird
    Der Buffer kann evtl. durch setzen von "#define SERIAL_BUFFER_SIZE 128" (HardwareSerial) erhöht werden, allerdings kann das auch Probleme verursachen da das mehr RAM belegt..

    Desweiteren gehen die meisten so vor das Char für Char (oder Byte für Byte) in einen selbst angelegten Buffer ausgelesen wird, was aber einige Zeit beansprucht. Der selbst angelegte Buffer kann zB mit "byte buff[92];" initialisiert worden sein. Ich nutze ganz gerne "dataString = Serial.readStringUntil('\n');" um auf ein Schlag die komplette Zeile auszulesen und danach setz ich noch ein "Serial.flush();" ab um sicherzustellen das nichts mehr im Buffer schlummert.

    Siehe dazu auch:
    http://arduino.stackexchange.com/questions/1726…buffer-overflow
    http://internetofhomethings.com/homethings/?p=927

    Was aber auch eine Rolle spielt ist die PC-Seite, wie dort der Umgang mit Serial aussieht. Es kann nämlich auch der PC-seitige Buffer Schuld sein...

    Eine Form der "Kommunikation" kann auch sein, Anfang und Ende zu definieren. Wenn du also vor hast "Forward slow:1" zu senden machst du zum Beispiel einfach "%Forward slow:1@" und sobald du @ ausgelesen hast sendest du ein "#" um dem PC zu sagen "angekommen" und der wiederum flush't seinen Buffer.

    Leerzeichen würde ich aber generell vermeiden, überleg dir stattdessen lieber etwas ohne Leerzeichen und ggf auch Abkürzungen wie "FS:1".
    In einem Projekt von mir lese ich Char-für-Char aus und nutze zB DH1 was für " Digital HIGH 1 " steht, es wird also der Digitale Pin 1 auf HIGH gestellt, vorher noch ein "PO1" senden um den Pin 1 auf OUTPUT zu stellen... DR1 um read zu machen, DW1 für write etcpp

  • Hallo Andreas, ich mache gerne was nötig ist.

    Die Dokumentation von serial ist eher nicht so geeignet mir zu sagen was nötig ist.

    In der anderen Richtung habe ich einen Prozess, der nur liest, also da funktioniert alles ohne Protokoll.

    Ich versuche mir vorzustellen was da auf der Strecke passiert:
    - PC sendet einen Befehl der 18 Zeichen lang ist
    Wenn nun nichts weiter gesendet wird landen diese 18 Bytes wo? ich meine solange der Empfänger nicht liest

    - Ich kann ja zeigen, dass einzeln gesendete Sequenzen bis \n richtig ankommen. Also kann das Problem nicht innerhalb einer Bytesequenz liegen.

    - meine Frage zielt auf den nicht dokumentierten Teil. wo sind die Bytes während des Sendens solange das Lesen noch nicht aktiv ist? in einem Puffer auf PC Seite?
    - was passiert wenn der PC die zweite Sequenz hinterherschickt? wird die erste auf PC Seite schon überschrieben? das kann man dann nur über ein Protokoll lösen , soweit einverstanden

    Softwarefehler suchen ist wie Pilze suchen. Wenn man erst einen gefunden hat, findet man meist mehrere.

    Bei Hardware ist es schlimmer, da findet man bereits Fehler wenn man gar keine sucht!


  • ...
    Werden die Daten im Arduino (Betriebssystem) gepuffert, wie gross ist dieser Puffer?
    ...


    Der Arduino hat kein Betriebssystem im eigentlichen Sinne. Ob und wieviele Bytes gepuffert werden, müsste man mal in der Serial-Klasse der IDE recherchieren. Ist aber im Grunde vollkommen irrelevant ...
    Ausgangsbasis für die Überlegungen solcher "Kommandoschnittstellen" sollte sein, dass keine Zeichen seitens des µC gepuffert werden.


    ...
    Die Zykluszeit des Arduino beträgt ca. 400ms. Der PC kann die Kommandos schneller ...

    und da wäre wir dann schon beim ersten Denkfehler. Warum liest Du die "Kommandos" nur alle 400 ms aus, wenn sie schneller eintreffen können?


    ...
    Ich versuche mir vorzustellen was da auf der Strecke passiert:
    - PC sendet einen Befehl der 18 Zeichen lang ist
    Wenn nun nichts weiter gesendet wird landen diese 18 Bytes wo? ich meine solange der Empfänger nicht liest

    stellt sich die erste Frage: werden die Daten tatsächlich gesendet oder irgendwie auf dem PC zwischengepuffert?
    Das weisst nur Du ...
    die zweite Frage: warum liest der Empfänger nicht, wenn er was geschickt bekommt. Da die Kommunikation in der "Standard-Einstellung" ohne Handshake erfolgt, und wir davon ausgehen, dass der µC nichts puffert (siehe oben) verschwinden 17 Byte im Nirvana, das 18.te steht im Empfangsregister des µC. Vorausgesetzt wieder, dass der PC nichts zwischenspeichert und wirklich alle 18 Zeichen gesendet wurden ...


    ...
    - meine Frage zielt auf den nicht dokumentierten Teil. wo sind die Bytes während des Sendens solange das Lesen noch nicht aktiv ist? in einem Puffer auf PC Seite?


    wieso sollten sie auf dem PC zurückgehalten werden? Ohne Handshake werden die einfach rausgeschrieben.



    ...
    - was passiert wenn der PC die zweite Sequenz hinterherschickt? wird die erste auf PC Seite schon überschrieben? das kann man dann nur über ein Protokoll lösen , soweit einverstanden

    s.o.
    Deine Vorgehensweise mit dem Lesen im 400 ms Takt ist in Deinem Fall nicht zielführend.
    Besser wäre es (und so wird das afaik auch gehandhabt) permanent die Daten der rs232 auszulesen und die enthaltenen Kommandos, die Du Dir z.B. in ein eigenes Protokoll verpackst, rauszufiltern.
    Da kommt Dir nix aus und wenn Du zusätzlich den handshake aktivierst (z.B. XON/XOFF - Hadware ist etwas aufwändig auf dem RPi ) und das Ganze mit Parity überträgst, dann hat das Hand und Fuss ...

    cu,
    -ds-

  • Das sind ja alles sehr gut gemeinte Ratschläge, aber keiner kann mir meine Fragen beantworten

    recherchieren in der Tiefe des Systems... ohne mich, ich finde es lausig wie das Zeug dokumentiert ist.

    In Empfangsrichtung läuft wie gesagt ein ganzer Prozess, der nur die Schnittstelle liest und ich bekomme keinen einzigen Fehler!

    Warum ich die Daten nur alle 400ms lese im Arduino, liegt daran dass alle Beispiele das lesen nur im Zyklus machen, ich habe noch kein Beispiel gesehen das auf Timerinterrupt Basis die Schnittstelle liest. Wenn das alle so ohne Zwischenpuffer funktionieren würde könnte ich kein einziges Byte richtig empfangen...

    Ich werde mal einen anderen Ansatz versuchen:

    - Ich weiss wieviele Daten in 400ms auflaufen können, das sind maximal 4 konkurrierende Befehle macht maximal 100Byte
    - Ich übertrage mit 38200 Baud
    - Die Kommandos werden falls welche vorhanden sind nach jedem empfangenen Satz in Melderichtung einzeln runtergeschickt (\n als Trennzeichen)
    - Ich werde im Arduino die Befehlsschnittstelle mehrfach auslesen (bis \n), bis sie leer ist
    - Ich werde nun versuchen rauszufinden wo auf dem Arduino der Puffer versteckt ist und wie gross der ist.

    Ein handshake oder acknowledge würde die Befehle ja weiter verzögern bis hin zu einem Befehl pro Zyklus, das ist auch nicht zielführend

    ich weiss sehr gut was ein Protokoll ist und was es leistet. Habe früher mal mit Fernwirktechnik zu tun gehabt. Nur für meinen Anwendungsfall ist das oversized. Ich will ja nicht einen kontinuierlichen Datenstrom steuern...

    Softwarefehler suchen ist wie Pilze suchen. Wenn man erst einen gefunden hat, findet man meist mehrere.

    Bei Hardware ist es schlimmer, da findet man bereits Fehler wenn man gar keine sucht!

  • Hi,


    ...
    Warum ich die Daten nur alle 400ms lese im Arduino, liegt daran dass alle Beispiele das lesen nur im Zyklus machen, ich habe noch kein Beispiel gesehen das auf Timerinterrupt Basis die Schnittstelle liest.
    ...


    wieso Timer?
    Wieso Beispiel?
    Wo liegt Dein (Verständnis-)Problem, einfach bei Eintritt in loop() mal

    Code
    if( Serial.available() )
    {
     while Serial.available() 
     {
       myBuffer[idx++] = Serial.read();
     }
     parseCommand(myBuffer);
    }


    einzubauen und die Zeichen in Deinen eigenen Buffer zu lesen?

    Aber mach, wie Du meinst ...

    cu,
    -ds-

  • Wenn du meinen Code anschaust wirst du sehen dass ich genau das mache, was dazu führt dass die Schnittstelle im loop (440ms) 1 x gelesen wird.

    Softwarefehler suchen ist wie Pilze suchen. Wenn man erst einen gefunden hat, findet man meist mehrere.

    Bei Hardware ist es schlimmer, da findet man bereits Fehler wenn man gar keine sucht!

  • am Arduino gehts nur so wie -ds- schrieb und funktioniert prima mit dem PC,

    am PI komme ich auch ins Schleudern weil das Linux ist und mit Streams gebuffert arbeitet, da habe ich auch Probleme mit dem Zusammenspiel und das "Problem" erst mal nach ganz hinten verschoben, bzw. mache nix mehr damit!


    Wenn du meinen Code anschaust wirst du sehen dass ich genau das mache, was dazu führt dass die Schnittstelle im loop (440ms) 1 x gelesen wird.

    wieso das? wer macht die 440ms und warum?

    lasst die PIs & ESPs am Leben !
    Energiesparen:
    Das Gehirn kann in Standby gehen. Abschalten spart aber noch mehr Energie, was immer mehr nutzen. Dieter Nuhr
    (ich kann leider nicht schneller fahren, vor mir fährt ein GTi)

    Einmal editiert, zuletzt von jar (4. Mai 2016 um 11:24)

  • Naja der Arduino hat einges zu tun da ist die loop halt 400ms lang
    Klar sind die Beispiele in den Büchern alle schnell weil ausser dem Beispiel nix läuft!

    Softwarefehler suchen ist wie Pilze suchen. Wenn man erst einen gefunden hat, findet man meist mehrere.

    Bei Hardware ist es schlimmer, da findet man bereits Fehler wenn man gar keine sucht!

    Einmal editiert, zuletzt von Wolfgang Glück (4. Mai 2016 um 12:13)

  • Hi,


    ...
    am PI komme ich auch ins Schleudern weil das Linux ist ...


    das geht auf dem RPi genauso. Du musst nur den raw-Mode aktivieren und die Bufferung deaktivieren. Ausserdem sollte der fd auf die Schnittstelle non-blocking sein. Dann klappt das ;)


    Naja der Arduino hat einges zu tun da ist die loop halt 400ms lang
    ...


    das ist aber dann imho ein konzeptioneller Fehler. Du kannst keiner Komponente mehr Arbeit aufs Auge drücken, als sie erledigen kann. Und ein µC, gerade im Bereich Steuerung, ist nicht dazu gedacht komplexe Aufgaben zu übernehmen ...

    cu,
    -ds-

  • ich kann ehrlich gesagt keine einzige "habe probleme" aussage hier in diesem thread nachvollziehen, egal womit.

    Ich hab keine Probleme trotz des extrem hohen Traffics der bei mir zustande kommt.

    Ein µC gibts in verschiedenen Ausführungen - welchen Wolfgang letztlich nutzt weiß derzeit glaub ich keiner. Es gibt 32bit'ige, aber die meisten haben nur 8bit... Dann gibts welche mit nur 1 MHz und andere mit 84 MHz.. usw Die 8bit'igen können zB keine echte Parallelisierung auch wenn das der ein oder andere behauptet aber das stimmt nicht - ein Schedule ist nichts wo zeitgleich mehrere Sachen auf einmal bearbeitet werden.

    Auch verwirren wie ich finde Aussagen wie "Raspberry bzw. PC". Unter PC verstehe ich etwas anderes als unter Raspberry

    Aber so wie dreamshader schon sagte: ein µC ist nicht dafür konstruiert komplexe Aufgaben zu übernehmen - was auch ein Grund ist wieso ich ihn nur als "Port Expander" verwende, trotzdem habe ich einen hohen Verkehr da ständig Daten/Bestätigungen/Werte/whatever hin und her geschickt werden - aber nicht mit 38200 Baud sondern 57600 ... Die Zahl nannte ich dir glaub ich schon mal Wolfgang, du hattest nämlich sofern ich mich recht erinnere schon mal Probleme mit einer anderen Baudrate.

    "Das sind ja alles sehr gut gemeinte Ratschläge, aber keiner kann mir meine Fragen beantworten" :-/ Deine eine Frage in Beitrag#1 wurde durch aus beantwortet, auch die zwei Fragen in Beitrag#4 wurden beantwortet - aber ignoriere mich ruhig weiter :fies:


  • Naja der Arduino hat einges zu tun da ist die loop halt 400ms lang

    es ist und bleibt ein konzeptioneller Fehler,

    wenn der serielle IRQ kommt dann sammel doch einfach nur in einem Buffer Zeichen ein der groß genug ist um 2 Sekunden zu überbrücken.
    Das Verarbeiten des Buffers machst du dann wenn dein Arduino Zeit dafür hat!

    Das ist doch keine Schwierigkeit und kann doch ohne Zeichenverlust erfolgen,

    Rx IRQ -> Zeichen sammeln, keines geht dir verloren, nur irgendawann musst du sie verarbeiten, man kann ja auch mit XonXoff Handshake fahren, einer muss dann eben warten bis Hr. Arduino wieder bereit ist.

    lasst die PIs & ESPs am Leben !
    Energiesparen:
    Das Gehirn kann in Standby gehen. Abschalten spart aber noch mehr Energie, was immer mehr nutzen. Dieter Nuhr
    (ich kann leider nicht schneller fahren, vor mir fährt ein GTi)

  • Die Zeichen werden ja gesammelt, nämlich im Buffer. Nur sendet Wolfgang unkontrolliert immer weiter egal ob der µC bereits etwas ausgelesen hat - das ist sein Fehler.

    Wie bereits beschrieben sollte er erst eine Bestätigung vom µC abwarten bevor weiteres verschickt wird.

  • Ja und nein ...
    Serial ist, wenn ich das recht in Erinnerung habe, Teil der Stream-Klasse. Da könnte man einen Ringpuffer-Handler auf das .OnReceive()-event kleben.

    Es macht aber keinen Sinn mehrere Kommandos ziwschenzupuffern. Schon gar nicht bei einem "Zyklus" ( wieso eigentlich Zyklus ... ist Dein Arduino ein weibliches Säugetier? ) von 400 ms. Dann wird die Stop-Anweisung erst ausgeführt, wenn das Teil schon im Graben liegt und dort noch nach rechts fährt ;)
    So was kann man bei Licht ein/aus oder so machen ... wobei 1 bis 2 Sekunden Verzögerung auch hier schon Unfug ist.


    cu,
    -ds-


  • So was kann man bei Licht ein/aus oder so machen ... wobei 1 bis 2 Sekunden Verzögerung auch hier schon Unfug ist.
    cu,
    -ds-

    nun ja ich meinte einen Buffer für 1-2 Sekunden, keine Verzögerung.

    Niemand muss Buffer voll oder überlaufen lassen!

    nur wenn er erst alle 400 ms Zeit hat wäre ein 2 Sekundenbuffer doch mehr als ausreichend für alle Fälle

    lasst die PIs & ESPs am Leben !
    Energiesparen:
    Das Gehirn kann in Standby gehen. Abschalten spart aber noch mehr Energie, was immer mehr nutzen. Dieter Nuhr
    (ich kann leider nicht schneller fahren, vor mir fährt ein GTi)

    Einmal editiert, zuletzt von jar (4. Mai 2016 um 15:35)

  • Ich glaub ihr fehl interpretiert da etwas...

    Wenn der Arduino nicht nur empfangen sondern auch verarbeiten soll muss es einen Buffer geben - und den gibts auch, standardmäßig, ohne eigenes Zutun.

    Eine Zeitspanne hat damit IMHO auch eher wenig zu tun. Man kann auch einen 2MB Buffer innerhalb weniger Sekunden befüllen, wenn man Daten unkontrolliert rein schaufelt :fies:

    Bei mir funktioniert das wie bereits beschrieben sehr schnell und reibungslos. Ich "buffer" aber auch nur ein Kommando, bevor ein weiteres geschickt wird bedarf es erst einer Empfangsbestätigung.


    Ja und nein ...
    Serial ist, wenn ich das recht in Erinnerung habe, Teil der Stream-Klasse. Da könnte man einen Ringpuffer-Handler auf das .OnReceive()-event kleben.

    Es macht aber keinen Sinn mehrere Kommandos ziwschenzupuffern.

    Und wenn wir schon beim Stichwort Ringbuffer sind: https://github.com/arduino/Arduin…no/RingBuffer.h


  • Ich glaub ihr fehl interpretiert da etwas...

    wir mit Sicherheit eher nicht, der Systemfehler steckt beim TO nur alle 400ms zu reagieren!

    lasst die PIs & ESPs am Leben !
    Energiesparen:
    Das Gehirn kann in Standby gehen. Abschalten spart aber noch mehr Energie, was immer mehr nutzen. Dieter Nuhr
    (ich kann leider nicht schneller fahren, vor mir fährt ein GTi)


  • Also ein Puffer für Kommandos auf einem µC, dessen Zweck es ist, möglichst in Echtzeit zu arbeiten ... das widerspricht sich in meiner Welt.

    in meiner auch, aber ich selber habe ja auch "Tasks" die nicht zeitkritisch sind

    LCD update z.B.

    Ziel nur 4x pro Sekunde ein LCD update zu fahren, also setze eich alle 250ms ein update Flag, ob das LCD nun in 250ms oder in 300ms ein Update bekommt ist mir schnuppe, mehr sehe ich eh nie, ich will nur keine Flimmer LCD oder Sekunden die im 1/10 s Bereich von 9 auf 10 hüpfen

    lasst die PIs & ESPs am Leben !
    Energiesparen:
    Das Gehirn kann in Standby gehen. Abschalten spart aber noch mehr Energie, was immer mehr nutzen. Dieter Nuhr
    (ich kann leider nicht schneller fahren, vor mir fährt ein GTi)

Jetzt mitmachen!

Du hast noch kein Benutzerkonto auf unserer Seite? Registriere dich kostenlos und nimm an unserer Community teil!