EasyMeter auslesen

    Diese Seite verwendet Cookies. Durch die Nutzung unserer Seite erklären Sie sich damit einverstanden, dass wir Cookies setzen. Weitere Informationen

    Aufgrund technischer Veränderungen ist der Mailverkehr innerhalb des Forums (Private Nachrichten) nur noch eingeschränkt möglich. Die Einschränkung ist notwendig, um zusätzliche Betriebskosten für das Forum zu vermeiden. Näheres zu den Hintergründen im Thread "Aktuelles zum Forum".Wir bitten um Verständnis.

    Hinweis kann nach Kenntnisnahme deaktiviert werden!

    • Beim config input gibst du irgend ein echo an. Beim Befehl input kommt dann noecho als Dings, äh (Scheiß Glühwein), äh, Option noch hinten dran.
      Raum für Notizen

      -----------------------------------------------------------------------------------------------------

      -----------------------------------------------------------------------------------------------------
    • Sehr gut, läuft die letzten Tage im ständigen Test und das zufriedenstellend. Aber, wir schweifen ab. Babette ist übrigens nicht der Grund für den Glühweinkonsum, der gehört zur Lebensfreude.
      Raum für Notizen

      -----------------------------------------------------------------------------------------------------

      -----------------------------------------------------------------------------------------------------
    • Michael schrieb:

      Wieso schreibst du das in die Config-Zeile?
      Weil es dort sinnvoll wäre.


      Michael schrieb:

      Ich hatte geschrieben


      die ist gar nicht so schlecht:
      Ja ich war dahintergekommen. Da hatte das grün versagt

      aber auch nicht wirklich klar in dem Fall

      Oskar schieb: Ja, aber ohne Komma. - Die Zitatfunktion versagt:-(

      Input Buffer , Noecho ' Datensatz einlesen bis CR wird nicht bemängelt
    • oscar schrieb:

      Lt. Hilfe ist dort kein Komma vorgesehen...und ...wird ein Echo ausgegeben (mit oder ohne Komma)?
      Ich hab das gerade mal probiert :

      Quellcode

      1. $Regfile = "m32def.dat"
      2. $crystal = 16000000
      3. $hwstack = 100
      4. $swstack = 100
      5. $framesize = 100
      6. Config Com1 = 9600 , Synchrone = 0 , Parity = None , Stopbits = 1 , Databits = 8 , Clockpol = 0
      7. ' Vorschlag
      8. Config Input = Crlf , Echo = Cr
      9. Dim Buffer As String * 255 ' gegebenenfalls Buffer anpassen
      10. Dim A As Byte
      11. Print "mit Komma"
      12. Do
      13. ' Input beendet das Einlesen, wenn es auf ein CR trifft
      14. If A < 5 Then
      15. Input Buffer , Noecho ' Datensatz einlesen bis CR
      16. Else
      17. If A > 9 Then
      18. Input Buffer Noecho
      19. Else
      20. Input Buffer
      21. End If
      22. End If
      23. Print Str(a) + "*" + Buffer
      24. Incr A
      25. If A > 14 Then A = 1
      26. nop
      27. Loop
      Alles anzeigen
      und nun ist die Verwirrung komplett. ?( Nur bei Noecho ohne Komma gibt er ein Echo heraus sonst nicht auch nicht ohne noecho.
      Sollte es dann nicht besser Echo,Makeecho oder doecho heißen und nicht Noecho?
    • Hallo in die Runde.

      Das Kommando

      BASCOM-Quellcode

      1. Config Input = ...

      macht wohl nur Sinn, wenn man auch ein Echo senden will.

      Wenn es gänzlich aus sein soll, kann man das abschalten mit:

      BASCOM-Quellcode

      1. Echo off

      Ich habe noch vernommen, dass die Daten auf SD gespeichert werden sollen und möglichst wenig platz verbraucht werden soll.
      Mein Tip wäre:
      Keine Strings zu speichern, sondern Werte.
      Für Fließkomma (Zählerstand) sollte Single reichen (verbraucht 4 Byte) und für die ZählerNr. z.B. Long (verbraucht 4 Byte).
      Für den Gesamtzählerstand evtl. auch ein Double (8 Byte)

      Ein Datensatz wäre dann
      Zählernr: 4 Byte (Long)
      Zählerstand: 8 Byte (Double)
      Leistung 1 bis 3 je 4 Byte (Single)
      Leistung (L1 bis L3): 4 Byte (Single)

      Sind in Summe: 4+8+12+4 = 28 Byte pro Datensatz

      Das wäre doch akzeptabel, oder nicht?

      Micha.
    • Hier mal eine Alternative, wie die Daten per Interrupt eingelesen werden können.
      Die Werte werden direkt den entsprechenden Variablen zugewiesen.

      In der Hauptschleife müssen nur noch, wenn ein bestimmter Zustand erreicht ist (State=ST_END), die Daten weiter veratrbeitet werden.
      Danach den State wieder auf Anfang setzen, um das nächste Datenpaket zu erhalten (State=ST_WAIT_BEGIN).

      Einmalig vorne Echo Off verwenden, das Input fällt weg.

      Vorteil dieser Methode:
      - Wenig RAM Verbrauch im Gegensatz zur String-Buffer mit 255 Byte Länge.
      - Datenpakete werden im Hintergrund empfangen
      - Einfache Verarbeitung
      - Übersichtlicher Code

      Nachteil:
      - Die ISR ist etwas aufwendiger, aber Trotzdem effektiv.
      - Etwas redundanter Code in der ISR (dafür übersichtlich und nachvollziehbar)

      Man könnte die Prüfung (in der ISR), ob die Klammer auf ist und das Flag setzen, auch in eine Funktion auslagern.
      Ich hab mir das jetzt aber gespart.

      Das ganze soll ein Lösungsansatz sein. Der Code könnte eigentlich sogar schon funktionieren, wenn ich kein Bug eingebaut habe.
      Habs nicht ausprobiert.

      In dem Sinne noch einen schönen Advent!

      Gruß Mitch

      BASCOM-Quellcode

      1. ' Ein anderer Ansatz die Daten einzulesen
      2. ' ISR verwendet eine einfache Statemachine, um in den ankommenden Daten
      3. ' den Anfang, das Ende und die einzelnen Werte
      4. ' voneinander zu unterscheiden und zuzuweisen.
      5. $Regfile = "m32def.dat"
      6. $hwstack = 80
      7. $swstack = 64
      8. $framesize = 80
      9. $Crystal = 8000000
      10. Echo OFF
      11. Config Com1 = 9600 , Synchrone = 0 , Parity = Even , Stopbits = 1 , Databits = 7 , Clockpol = 0
      12. On URXC ISR_URXC
      13. Enable URXC
      14. ' Variable für Zustand
      15. Dim State as Byte ' Zustand der Statemachine in der ISR
      16. ' Die Zustände beim Einlesen des Datensatzes
      17. Const ST_WAIT_BEGIN = 0 ' Beginn Datensatz erkennen ('/')
      18. Const ST_ZAEHLERNR = 1 ' Einlesen ZählerNr
      19. Const ST_ZAEHLERSTAND = 2 ' Einlesen Zählerstand
      20. Const ST_LEISTUNG_L1 = 3 ' Einlesen Leistung1
      21. Const ST_LEISTUNG_L2 = 4 ' Einlesen Leistung2
      22. Const ST_LEISTUNG_L3 = 5 ' Einlesen Leistung3
      23. Const ST_LEISTUNG_TOTAL = 6 ' Einlesen Leistung Total
      24. Const ST_END = 7 ' Letzter Zahlenwert eingelesen
      25. ' Buffer und RxByte werden von der ISR verwendet.
      26. Dim Buffer as String * 15 ' Buffer für ISR
      27. Dim RxByte as Byte ' Buffer Enfangenes Byte
      28. Dim Flags as Byte ' Flags
      29. Const KLAMMER_AUF = 0 ' Flag 0, gesetzt, wenn Klammer auf gefunden
      30. ' Hier liegen nach dem Einlesen des Datensatzes alle Werte zur Weiterverarbeitung bereit
      31. Dim ZaehlerNr as Long
      32. Dim ZaehlerStand as Double
      33. Dim Leistung1 as Single
      34. Dim Leistung2 as Single
      35. Dim Leistung3 as Single
      36. Dim LeistungTotal as Single
      37. Enable Interrupts
      38. ' ---------------------------------------------------------
      39. ' Hauptschleife
      40. ' ---------------------------------------------------------
      41. Do
      42. If State = ST_END then ' Jetzt stehen die Daten bereit zur Verarbeitung
      43. ' Datenverarbeitung durchführen
      44. ' Danach den Empfang des nächsten Datenpakets wieder zulassen!
      45. State = ST_WAIT_BEGIN ' Warten auf nächstes Datenpaket
      46. End If
      47. Loop
      48. ' #########################################################
      49. ' ISR-Routine mit Statemachine
      50. ISR_URXC:
      51. RxByte = UDR ' Empfangene Byte einlesen
      52. ' Abhängig vom Zustand der Statemachine mit dem Byte umgehen
      53. Select Case State
      54. ' -----------------------------------------------------
      55. Case ST_WAIT_BEGIN ' Wir suchen das Zeichen '/'
      56. ' -----------------------------------------------------
      57. If RxByte = "/" then ' 1. Wert im Datensatz erreicht
      58. Buffer = "" ' Buffer leeren
      59. Reset Flags.KLAMMER_AUF
      60. State = ST_ZAEHLERNR
      61. End If
      62. ' -----------------------------------------------------
      63. Case ST_ZAEHLERNR ' ZählerNr einlesen
      64. ' -----------------------------------------------------
      65. If Flags.KLAMMER_AUF = 1 then
      66. If RxByte = ")" then ' Ende Zähler-Nr erkannt
      67. ZaehlerNr = Val(Buffer) ' ZählerNr merken
      68. Buffer = "" ' Buffer löschen
      69. Reset Flags.KLAMMER_AUF ' Flag löschen für nächsten Wert
      70. State = ST_ZAEHLERSTAND ' in den nächsten State
      71. Else
      72. Buffer = Buffer + Chr(RxByte) ' Einlesen
      73. End If
      74. Else
      75. If RxByte = "(" then Set Flags.KLAMMER_AUF
      76. End If
      77. ' -----------------------------------------------------
      78. Case ST_ZAEHLERSTAND ' Zählerstand einlesen
      79. ' -----------------------------------------------------
      80. If Flags.KLAMMER_AUF = 1 then
      81. If RxByte = ")" then ' Ende Zähler-Nr erkannt
      82. ZaehlerStand = Val(Buffer) ' ZählerNr merken
      83. Buffer = "" ' Buffer löschen
      84. Reset Flags.KLAMMER_AUF ' Flag löschen für nächsten Wert
      85. State = ST_LEISTUNG_L1 ' in den nächsten State
      86. Else
      87. Buffer = Buffer + Chr(RxByte) ' Einlesen
      88. End If
      89. Else
      90. If RxByte = "(" then Set Flags.KLAMMER_AUF
      91. End If
      92. ' -----------------------------------------------------
      93. Case ST_LEISTUNG_L1 ' Leistung1 einlesen
      94. ' -----------------------------------------------------
      95. If Flags.KLAMMER_AUF = 1 then
      96. If RxByte = ")" then ' Ende Zähler-Nr erkannt
      97. Leistung1 = Val(Buffer) ' ZählerNr merken
      98. Buffer = "" ' Buffer löschen
      99. Reset Flags.KLAMMER_AUF ' Flag löschen für nächsten Wert
      100. State = ST_LEISTUNG_L2 ' in den nächsten State
      101. Else
      102. Buffer = Buffer + Chr(RxByte) ' Einlesen
      103. End If
      104. Else
      105. If RxByte = "(" then Set Flags.KLAMMER_AUF
      106. End If
      107. ' -----------------------------------------------------
      108. Case ST_LEISTUNG_L2 ' Leistung2 einlesn
      109. ' -----------------------------------------------------
      110. If Flags.KLAMMER_AUF = 1 then
      111. If RxByte = ")" then ' Ende Zähler-Nr erkannt
      112. Leistung2 = Val(Buffer) ' ZählerNr merken
      113. Buffer = "" ' Buffer löschen
      114. Reset Flags.KLAMMER_AUF ' Flag löschen für nächsten Wert
      115. State = ST_LEISTUNG_L3 ' in den nächsten State
      116. Else
      117. Buffer = Buffer + Chr(RxByte) ' Einlesen
      118. End If
      119. Else
      120. If RxByte = "(" then Set Flags.KLAMMER_AUF
      121. End If
      122. ' -----------------------------------------------------
      123. Case ST_LEISTUNG_L3 ' Leistung 3 einlesen
      124. ' -----------------------------------------------------
      125. If Flags.KLAMMER_AUF = 1 then
      126. If RxByte = ")" then ' Ende Zähler-Nr erkannt
      127. Leistung3 = Val(Buffer) ' ZählerNr merken
      128. Buffer = "" ' Buffer löschen
      129. Reset Flags.KLAMMER_AUF ' Flag löschen für nächsten Wert
      130. State = ST_LEISTUNG_TOTAL ' in den nächsten State
      131. Else
      132. Buffer = Buffer + Chr(RxByte) ' Einlesen
      133. End If
      134. Else
      135. If RxByte = "(" then Set Flags.KLAMMER_AUF
      136. End If
      137. ' -----------------------------------------------------
      138. Case ST_LEISTUNG_TOTAL ' Gesamtleistung einlesen
      139. ' -----------------------------------------------------
      140. If Flags.KLAMMER_AUF = 1 then
      141. If RxByte = ")" then ' Ende Zähler-Nr erkannt
      142. LeistungTotal = Val(Buffer) ' ZählerNr merken
      143. Buffer = "" ' Buffer löschen
      144. Reset Flags.KLAMMER_AUF ' Flag löschen für nächsten Wert
      145. State = ST_END ' in den nächsten State
      146. Else
      147. Buffer = Buffer + Chr(RxByte) ' Einlesen
      148. End If
      149. Else
      150. If RxByte = "(" then Set Flags.KLAMMER_AUF
      151. End If
      152. ' -----------------------------------------------------
      153. Case ST_END ' Alle Werte vom Datenpaket eingelesen
      154. ' -----------------------------------------------------
      155. ' Hier gibt es nichts zu tun, Einlesen fertig.
      156. ' Daten liegen in den Variablen
      157. End Select
      158. Return
      Alles anzeigen

      Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von Mitch64 ()

    • Danke Micht für das Programmbeispiel der Auswertung serieller Inputs per ISR und State Machine...werde ich als Vorlage für eigene Experimente speichern. Ich verwende für solche seriellen Eingaben zwar auch isr aber die herangehensweise mit state machine ist ist für mich noch ziemlich ungewohnt. Da muss ich noch viel lernen (man ist ja schließlich nicht zu alt um Neues zu lernen). Überhaupt ist die Verwendung der state machine bei der programmierung etwas komplexerer Anwendung unerlässlich, sonst verliert man den Überblick und sucht sich einen Wolf wenn es nicht so klappt wie es soll.
      State machine = Zaubertrank des Programmieres. ;)
      Danke nochmals für die Anregung.
      Gruß Chris
      Einen schönen 2. Advent an Alle
    • Ich hatte früher auch keine Ahnung von State-Maschinen.
      Habe viel im Internet recherchiert, kam aber nur auf theoretische, mathematische Abhandlungen, die viel zu kompliziert waren.
      So ein Beispiel ist Wikipedia.
      Die kommen gleich mit UML-Diagrammen und andere Varianten samt kryprischer Mathematik.

      Das habe ich nie kapiert. Ich bin Realschüler und kein Informatiker, Bachelor oder Ingenieur.
      Ich suchte lange und irgendwann hats dann mal bei mir geklickt.

      Verwirrend ist, dass mal von FSM (engl. Finite State Machine) und mal vom Zustandsautomat (endlicher Zustandsautomat) gesprochen wurde.

      Im Grunde ist es aber simpel.

      Eine Statemachine ist charakterisiert sich durch eine Variable, die einen Zustand (engl. State) repräsentiert.
      Dann wird Code abhängig von dem Zustand ausgeführt.

      Das erreicht man in Bascom besonders einfach durch eine solche Struktur:

      BASCOM-Quellcode

      1. Dim State as Byte ' Zustand
      2. Do
      3. Select Case State
      4. Case Zustand1
      5. Case Zustand2
      6. Case Zustand3
      7. ...
      8. End Select
      9. Loop
      Es ist empfohlen Zustände (States) durch Konstanten zu definieren. So kann man die Zustände erweitern, ohne in der Struktur die Case xx Werte zu ändern.
      Das sieht dann etwa so aus:

      BASCOM-Quellcode

      1. Dim State as Byte ' Zustand
      2. Const Zustand1 = 0 ' vernünftige Bezeichnungen verwenden, die nachvollziehbar sind!
      3. Const Zustand2 = 1
      4. Const Zustand3 = 2
      5. Do
      6. Select Case State
      7. Case Zustand1
      8. Case Zustand2
      9. Case Zustand3
      10. ...
      11. End Select
      12. Loop
      Alles anzeigen
      Diese Struktur kann im einfachsten Fall in der Hauptschleife eingebaut werden.

      Ein Zustand bezieht sich ja immer irgendwie auf ein Objekt. Im obigen Beispiel z.B. auf den Datemempfang von Uart0.

      Angenommen, von einen weiteren Port müssten Daten Empfangen werden, dann können da andere Zustände herrschen.

      Dann kann man 2 State-Maschinen oder auch mehrere parallel laufen lassen.

      Dazu lagert man die State-Verarbeitungs-Routinen in Subs aus. Je Sub eine Select Case Struktur.

      So können mehrere parallele Objekte verarbeitet werden.

      BASCOM-Quellcode

      1. Dim State1 as Byte ' Zustände des Automaten 1
      2. Const Zustand1 = 0 ' vernünftige Bezeichnungen verwenden, die nachvollziehbar sind!
      3. Const Zustand2 = 1
      4. Const Zustand3 = 2
      5. Dim State2 as Byte ' Zustände des Automaten 2
      6. Const Zustand1 = 0 ' vernünftige Bezeichnungen verwenden, die nachvollziehbar sind!
      7. Const Zustand2 = 1
      8. Const Zustand3 = 2
      9. Do
      10. Call Automat1() ' Quasi parallelle Abarbeitung zweier Objekte
      11. Call Automat2()
      12. Loop
      13. Sub Automat1()
      14. Select Case State
      15. Case Zustand1
      16. Case Zustand2
      17. Case Zustand3
      18. ...
      19. End Select
      20. End Sub
      21. Sub Automat2()
      22. Select Case State
      23. Case Zustand1
      24. Case Zustand2
      25. Case Zustand3
      26. ...
      27. End Select
      28. End Sub
      Alles anzeigen
      Ich will hier keine Abhandlung oder ein Tutorial über Statemachines verfassen, aber was vielleicht noch wichtig ist:

      Was sind States (Zustände) und wie legt man die Fest?
      Hier redefiniert sich das Internet auch immer wieder neu.

      Einfach gesagt ist ein State, ein Zustand, in dem sich der Automat länger (relativ zu sehen) befindet.
      Ein Zustand ändert sich bei bestimmten Ereignissen.

      Man denke da an einen Getränkeautomat. Was macht der?

      Er wartet, bis Geld eingeworfen wird. Das ist ein Zustand, der länger dauert. Ein Ereignis wäre dann, wenn man eine Münze einwirft.
      Dann prüft der Automat, ob genug Gelt für eine Getränkeauswahl eingeworfen wurde.
      Ist dies nicht der Fall, verbleibt der Automat im Zustand, in dem auf Geld gewartet wird.

      Ist das der Fall, geht der Automat in den Zustand Getränkeauswahl über.
      Mögliche Ereignisse sind nun die Tasten, die das gewünschte Getränk repräsentieren oder die Abbruchtaste.

      Und so geht das immer weiter.

      Jeder Zustand ist für eine relative Dauer aktiv. Der Zustand ändert sich in der Regel durch Ereignisse, die auch Timeouts sein können.
      Dann wechselt der Automat in einen anderen Zustand. Das geht endlos so weiter.

      Da man in der Regel eine begrenzte Anzahl an States verwendet, nennt man das Endlicher Automat. Oder englisch Finite Statemachine (abgekürzt FSM).

      Was noch kurz wichtig ist.
      Wenn man in einen Zustand ganz frisch rein kommt, nennt man das Entry. Oder auch Einsprung. Es macht oft Sinn, dann eine einmalige Aktion auszulösen. Eben nur, wenn man ganz neu in den Zustand wechselt. Das nennt man dann Entry-Bedingung. Danneben muss es auch Code in den States geben, die ein Wechsel des Zustands bewirken. Diese sind die Events und nennt man Exit-Bedingungen.

      Das ist Codetechnisch auch recht simpel:

      BASCOM-Quellcode

      1. Select Case State
      2. Case Zustand1
      3. ' Entry-Bedingung
      4. If ZustandNeu = 1 then
      5. ' Code, der einmal ausgeführt werden soll
      6. ZustandNeu = 0
      7. End If
      8. ' Hier Code, der immer ausgeführt werden soll
      9. ...
      10. ' Exit-Bedingung(en)
      11. If Bedingung then
      12. State = Zustand2 ' Zustandswechsel
      13. ZustandNeu = 1 ' Sicherstellen, dass Entry-Bedingung ausgeführt wird
      14. End If
      15. Case Zustand2
      16. ' Entry-Bedingung
      17. If ZustandNeu = 1 then
      18. ' Code, der einmal ausgeführt werden soll
      19. ZustandNeu = 0
      20. End If
      21. ' Hier Code, der immer ausgeführt werden soll
      22. ...
      23. ' Exit-Bedingung(en)
      24. If Bedingung=True then
      25. State = Zustand1 ' Zustandswechsel
      26. ZustandNeu = 1 ' Sicherstellen, dass Entry-Bedingung ausgeführt wird
      27. End If
      28. End Select
      Alles anzeigen
      Ich benutze dieses System mit wachsender Begeisterung. Ist einfach zu implementieren und wirkungsvoll.


      Ich habe hierzu allerdings eine kleine Include-Datei geschrieben,
      die mir die Arbeit mit den Flags setzen und löschen erleichtert.

      So gibts in der Include-Datei im wesentlichen folgende Routinen

      SetState(nächster State as Byte) ' Setzt den nächsten State und Flag ZustandNeu
      GetState() as Byte ' gibt den aktuellen State zurück (für Select Case GetState() )
      IsStateChanged() as Byte ' Abfrage Entry-Bedingung, ob der Code ausgeführt werden soll

      Mit diesen einfachen Routinen kommt man schon recht weit.