Hexdaten über die serielle Schnittstelle empfangen und auswerten

    This site uses cookies. By continuing to browse this site, you are agreeing to our Cookie Policy.

    • Hexdaten über die serielle Schnittstelle empfangen und auswerten

      Hallo.

      ich habe hier einen Distanzsensor TF Mini-S
      reichelt.de/benewake-tfmini-s-…2m-tf-mini-s-p287742.html

      Konfiguriert habe ich ihn so, das er nur Daten auf Anfrage sendet. Auf den Befehl "5A 04 04 62"
      schickt er einen Messwert. Den Befehl sende ich mit:
      Printbin #3 , 90 ; 4 ; 4 ; 98
      Das funktioniert auch, ich hab erst mal am Ausgang ein Terminal, da kommt der Messwert
      wie erwartet an.
      Das Datenpaket besteht aus 9 Byte. Die ersten beiden sind der Header, da sendet er 2x 59.
      Die beiden folgenden Bytes enthalten den Entfernungswert, die würde ich benötigen

      Das ist aus der Anleitung:
      Byte0 0x59, frame header, same for each frame
      Byte1 0x59, frame header, same for each frame
      Byte2 Dist_L distance value low 8 bits
      Byte3 Dist_H distance value high 8 bits
      Byte4 Strength_L low 8 bits
      Byte5 Strength_H high 8 bits
      Byte6 Temp_L low 8 bits
      Byte7 Temp_H high 8 bits
      Byte8 Checksum is the lower 8 bits of the cumulative sum of the numbers of the first 8 bytes.

      Wie stelle ich das am besten an?

      Gruß Ralf
    • Ralf wrote:

      Bleibt der nicht dann im Buffer? Ich würde jede Sekunde Daten lesen.
      Nur wenn einer angelegt ist.
      Bascom merkt sich ob er leergelesen ist. Der AVR auch falls nur 6 Byte gelesen werden.
      Sicherheitshalber ihn leeren bevor gesendet wird. (Falls sich ein Byte verirrt) :/

      Eine Vielzahl Möglichkeiten, nimm den persöhnlich angenehmsten.
      Ich würde ein Array füllen. Fertigmeldung nach 9 Byte. Auswertung kontolliert die Header evt auch Checksumme, Datenübergabe per Overlay . Bei nächster Anfrage Arrayzähler auf Anfang (auch ohne Fertigmeldung).

      The post was edited 2 times, last by Pluto25 ().

    • So funktioniert es:


      BASCOM Source Code

      1. Dim A As Word , C As Byte , I As Byte
      2. Do
      3. Printbin #3 , 90 ; 4 ; 4 ; 98 'Datensatz anfordern
      4. Inputbin #3 , A '2 Byte einlesen
      5. If A = 22873 Then 'Stimmt die Kennung?
      6. Inputbin #3 , A 'Wenn ja, Entfernung lesen.
      7. For I = 0 To 4 '5 Byte auslesen und verwerfen
      8. Inputbin #3 , C
      9. Next I
      10. Locate 1 , 1 : Lcd A 'Wert auf Display schreiben
      11. Else
      12. Locate 1 , 1 : Lcd "Fehler!" 'Stimmt Kennung nicht > Fehler!
      13. End If
      14. Wait 3
      15. Cls
      16. Loop
      Display All

      Falls mal irgendein Byte fehlt, darf das Programm auf keinen Fall da hängenbleiben.
      Da stellen sich zwei Probleme:
      1. Stimmt die Kennung nicht, müßte ich ja dem Empfangspuffer löschen und ich weiß nicht, wie viele Bytes da drin sind.
      2. Wenn die Kennung stimmt und ich den Rest auslese, aber das letzte Byte ist irgendwie verlorengegangen, dann würde Printbin ewig warten.

      Gibt es einen Befehl, mit dem ich den Empfangspuffer komplett löschen kann?
    • BASCOM Source Code

      1. Dim A As Word , C As Byte , I As Byte , Istwasda As Byte
      2. Do
      3. Istwasda = Ischarwaiting(#3) 'Sind Zeichen im Buffer?
      4. While Istwasda = 1 'Alle auslesen
      5. Inputbin #3 , C
      6. Istwasda = Ischarwaiting(#3)
      7. Wend
      8. Printbin #3 , 90 ; 4 ; 4 ; 98 'Datensatz anfordern
      9. Inputbin #3 , A '2 Byte einlesen
      10. If A = 22873 Then 'Stimmt die Kennung?
      11. Inputbin #3 , A 'Wenn ja, Entfernung lesen.
      12. Locate 1 , 1 : Lcd A 'Wert auf Display schreiben
      13. Else
      14. Locate 1 , 1 : Lcd "Fehler!" 'Stimmt Kennung nicht > Fehler!
      15. Locate 2 , 1 : Lcd A
      16. End If
      17. Wait 1
      18. Cls
      19. Loop
      Display All
      So funktioniert es erst mal.
      Eine Sache stört mich noch:
      Wenn ich in Zeile 9 einen Datensatz anfordere, der Sensor aber nicht reagiert, dann würde das Programm
      ewig in Zeile 10 warten.

      Wie könnte ich das lösen?
    • Hallo Ralf,
      die Kommunikation mit dem Sensor ist bei deiner Version komplett in die Hauptschleife integriert.
      Da wird es schwierig, auf Ausnahmefälle zu reagieren. Außerdem musst du alles andere, was dein Programm evtl. noch machen soll, da mit reinnehmen. Am Ende wird das unübersichtlich.
      Allerdings würde das bedeuten, dass du dich mit Interrupts und Timer beschäftigen musst. Wenn das ok ist, würde ich definitiv diesen Weg gehen.
      Und den Vorschlag von Pluto25 in #5 implementieren.
    • Franz wrote:

      die Kommunikation mit dem Sensor ist bei deiner Version komplett in die Hauptschleife integriert.
      Nur, zum Testen.

      Franz wrote:

      Allerdings würde das bedeuten, dass du dich mit Interrupts und Timer beschäftigen musst. Wenn das ok ist, würde ich definitiv diesen Weg gehen.
      Und den Vorschlag von Pluto25 in #5 implementieren.
      Das Programm ist mittlerweise ziemlich umfangreich, da laufen 4 Timer und Portpins werden auch per Interrupt ausgelesen.
      Gibt es hierfür nicht eine einfache Lösung.
      Also ich fordere die Daten an und wenn nach 100 Millisekunden nichts ankommt geht es weiter im Programm?
    • Wenn du die Timer eh schon drin hast, kannst du das doch sicher über einen steuern.
      Und wenn du auch mit Interrupts arbeitest, würde ich dir empfehlen, auch den UART per Interrupt zu verarbeiten. In einem komplexen Programm wird es sonst recht kompliziert.
      Also
      • URXC Int nutzen, dort die einlaufenden Daten in ein Array aus 9 Byte einlesen,
      • merken, wieviele eingelesen wurden,
      • per Timer überprüfen, ob alle 9 Bytes in der Zeit angekommen sind. Wenn nicht, wieder von vorne anfangen
      Wenn du es leicht machen willst, legst du mehrere Variablen als Overlay über das Array, dann brauchst du nichts hin- und herkopieren, sondern kannst direkt darauf zugreifen.
    • Franz wrote:

      Wenn du die Timer eh schon drin hast, kannst du das doch sicher über einen steuern.
      Und wenn du auch mit Interrupts arbeitest, würde ich dir empfehlen, auch den UART per Interrupt zu verarbeiten. In einem komplexen Programm wird es sonst recht kompliziert.
      Das wollte ich gerade vermeiden und das hat seinen Grund. Mit dem Programm werden unter anderem zwei Servomotore mit veränderlicher Winkelgeschwindigkeit angesteuert. Die bekommen durch die Timer in schneller Folge Impulse. Jede Sekunde habe ich aber eine kleine Pause, da könnte ich solche Sachen erledigen.
      Das Programm ist auch fertig und läuft stabil. Da mir die Zeit wegläuft kann ich da nicht mehr grundsätzlich was ändern.
      Das mit dem Entfernungsmesser ist ein nettes, zusätzliches Gimmick, aber nicht der Hauptbestandteil des Projektes.
      Ich könnte einen Watchdog starten und das Programm resetten, wenn kein Input da ist, das wäre aber nicht so gut, denn wenn der Sensor mal defekt ist startet er ewig neu.
      Ich kann es auch so lassen und hoffen, das der Sensor stabil funktioniert.
      Die beste Lösung wäre es aber, wenn er einfach ignoriert wird, wenn er keine Daten liefert.

      Gibt es denn eine Möglichkeit, nach eine gewissen Wartezeit den Inputbin Befehl abzubrechen?
      Vielleicht reicht mir schon ein Stichwort?

      Wie groß ist der Hardwarebuffer des Mega2560 überhaupt und kann man irgendwie abfragen, wieviel Zeichen drin sind, dann wäre das Problem doch schon gelöst?
    • Es gibt z.B. $timeout um abzubrechen.
      Der Mega hat nur zwei Byte im HW Buffer, das wird dir nicht helfen.
      Gerade über Interrupts sollte es einfach sein, die Funktion noch hinzunehmen, aber das ist deine Entscheidung.
      Ist denn der µC so ausgelastet, dass du nicht zwischendrin mal 200 Takte für den UART hast?
    • Franz wrote:

      Es gibt z.B. $timeout um abzubrechen.
      Klasse, wenn der mit inputbin funktioniert, wäre es das was ich suche.

      Franz wrote:

      Der Mega hat nur zwei Byte im HW Buffer, das wird dir nicht helfen.
      Das verstehe ich leider nicht, im Fehlerfall wäre ja nichts da.

      Franz wrote:

      Gerade über Interrupts sollte es einfach sein, die Funktion noch hinzunehmen, aber das ist deine Entscheidung.
      Ist denn der µC so ausgelastet, dass du nicht zwischendrin mal 200 Takte für den UART hast?
      Ich hatte schon mal angefragt:
      Geschwindigkeit Schrittmotor linear verändern

      Da ging es nur um einen Motor, jetzt sind es zwei. Es ist wirklich alles sehr eng.

      Wie auch immer, wenn es mit §timeout funktioniert, wäre das Problen doch gelöst!
      Ich probiere es nachher aus, muß blos mal weg.

      Vielen Dank!
    • 1) Array of Byte definieren
      2) Variable "Pointer auf Array" erstellen (Byte)
      2) wenn Zeit ist, Pointer auf Element 0 stellen
      3) Anfrage an Sensor senden
      4) Ankommende Bytes im Interrupt in Array schreiben, Pointer erhöhen
      5) wenn Pointer Arraygrenze erreicht, Flag für gültige Daten setzen
      6) Solange Flag für gültige Daten gesetzt, keine Daten mehr annehmen im Interrupt!
      7) ganz gemütlich in der Hauptschleife reagieren, wenn Flag für gültige daten an ist, CRC prüfen, Daten verwenden
      8 ) Pointer wieder zurücksetzen auf Element 0, Flag gültige daten zurücksetzen

      vielleicht noch einen Timoutzähler, welcher Sensoranfrage nach einer gewissen Zeit alles zurücksetzt, falls etwas außer Tritt kommt

      so ähnlich würde ich das machen...
      Code first, think later - Natural programmer :D
    • Hallo six1,

      ich werde mich mal in Ruhe damit beschäftigen.

      Mein Problem ist, es handelt sich um die Zuarbeit für eine Masterarbeit und in wenigen Tagen ist Prüfung. Ich muß mechanisch noch einiege Sachen erledigen und kann grundlegende Dinge am Programm jetzt nicht ändern. Nach der Prüfung habe ich alle Zeit der Welt.

      Es funktioniert jetzt so, wie ich es gemacht habe, das wäre der Stand:

      BASCOM Source Code

      1. Do
      2. Istwasda = Ischarwaiting(#3)
      3. While Istwasda = 1
      4. Inputbin #3 , C
      5. Waitms 100
      6. Istwasda = Ischarwaiting(#3)
      7. Wend
      8. Printbin #3 , 90 ; 4 ; 4 ; 98 'Datensatz anfordern
      9. $timeout = 1000000
      10. Inputbin #3 , A '2 Byte einlesen
      11. If A = 22873 Then 'Stimmt die Kennung?
      12. Inputbin #3 , A 'Wenn ja, Entfernung lesen.
      13. For I = 0 To 4 '5 Byte auslesen und verwerfen
      14. Inputbin #3 , C
      15. Next I
      16. Locate 1 , 1 : Lcd A 'Wert auf Display schreiben
      17. Else
      18. Locate 1 , 1 : Lcd "Fehler!" 'Stimmt Kennung nicht > Fehler!
      19. Locate 2 , 1 : Lcd A
      20. End If
      21. Loop
      Display All
      Ich hätte zwei ganz konkrete Fragen, vielleicht kann die jemand beanworten.

      Wie berechne ich die Timeoutzeit, die Anzahl der Takte sind es nicht, Millisekunden wohl auch nicht. Dachte, das wird überall zu finden sein.

      Ich habe im Programm einen ganz seltsamen Effekt. Wenn ich den Sensor abziehe und $timeout in der 9. Zeile auskommentiere läuft das Programm trotzdem weiter, obwohl der Eingangsbuffer geleert ist. Kommentiere ich darüber die Zeile 8, wo der Befehl zum Sensor gesendet wird auch aus, so bleibt das Programm wie erwartet bei Inputbin hängen.
      Wie kann das sein? Ich dachte schon an ein Übersprechen auf den Leitungen, aber der Wert, der gelesen wird (A) ist immer 1114.

      Nehme ich $timeout wieder rein, läuft das Programm weiter, A ist dann 0.


      Vielen Dank!
      Gruß Ralf
    • $Timeout zählt halt in einer Schleife den Wert runter auf 0.
      Die Schleife wird schon einige Takte benötigen um die Long Variable runterzuzählen, auf 0 zu vergleichen und zurückzuspringen. Also etwa Takte=Wert*50.

      1114 is übrigens &H045A, sieht also sehr nach dem Printbin aus.
    • Franz wrote:

      $Timeout zählt halt in einer Schleife den Wert runter auf 0.
      Die Schleife wird schon einige Takte benötigen um die Long Variable runterzuzählen, auf 0 zu vergleichen und zurückzuspringen. Also etwa Takte=Wert*10.
      Danke!


      Franz wrote:

      1114 is übrigens &H045A, sieht also sehr nach dem Printbin aus.
      Stimmt, die Kennung vom Befehl der gesendet wird!
      Wie kommt das auf den Eingang, der Sensor ist nicht dran?

      Hab den Sensor jetzt ins Programm eingebunden. Es entsteht einmal pro Sekunde eine winzige, unbedeutende Verzögerung. Aber eben zu der Zeit, wo es nicht stört.
    • Hallo six1,

      das man eine serielle Schnittstelle so konfigurieren kann, das die empfangenen Daten als
      Echo zurückgesendet werden habe ich schon gehört, aber nie gebraucht.
      In dem Fall hängen ja die Sende und Empfangsleitung in der Luft, was der Sender ja
      gar nicht mitbekommt.
      Wie kommen dann die gesendeten Daten in das Empfangsregister und welchen Sinn soll das haben?
      Habs versucht zu verstehen, leider ohne Erfolg.
      Der positive Nebeneffekt ist, das ich $timeout dann nicht benötige, es ist immer was da zum lesen
      und ich werte ja aus, ob der Header stimmt.

      Gruß Ralf