10 ( 5 ) Kanal Schalter für RC Signal

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

    • 10 ( 5 ) Kanal Schalter für RC Signal

      Hallo zusammen,

      ich versuche gerade einen 10 Kanal Schalter für ein RC Signal zu programmieren. Leider funktioniert es noch nicht so, wie es soll. Einen 4 Kanal Schalter mit Memory Funktion habe ich schon mal programmiert. Dort habe ich die PPM Abfrage auch auf diesem Weg gemacht. Das funktioniert auch so.

      Meine Idee:
      Es wird Abfragt, ob der Hebel nach oben ausgelenkt ist. Wenn ja, soll er so lange warten, bis der Hebel wieder in Mittelstellung ist. Ist er in Mittelstellung, so wird eine Variable ( Zaehler_oben ) um 1 erhöht. Danach wird wieder gefragt, ob der Hebel oben oder in Mittelstellung ist. Ist er in Mittelstellung, wird in ein Unterprogramm gesprungen ( Select Case ), wo dann entsprechend von 1 - 5 ein Ausgang geschaltet wird. Dann wird 2 Sekunden gewartet und es wieder erneut abgefragt. Sollte der Hebel bei der 2. Abfrage nicht in der Mittelstellung sein, sondern wieder oben, so wird die Variable wieder um 1 erhöht.

      So die Theorie. In der Praxis funktioniert das leider nicht. Der Einfachheit halber habe ich das ganze erstmal mit den Kanälen 1 - 5 gemacht. Also nur eine Richtung am Sender. Wenn es hier funktioniert, kann ich die 2. Richtung ja noch hinzufügen.

      Habt ihr eine Idee, was es sein könnte ? Habe es mal versucht so gut wie möglich zu kommentieren. ;)

      Hier nun der Code:

      BASCOM Source Code

      1. '*************************************************************************************************
      2. '* *
      3. '* 10 Kanalschalter mit Tiny2313 *
      4. '* *
      5. '* 10 Kanal Schalter mit memoy Funktion. 5 x nach oben oder 5 x nach unten *
      6. '* *
      7. '*************************************************************************************************
      8. $regfile = "attiny2313.dat"
      9. $crystal = 8000000
      10. $hwstack = 16
      11. $swstack = 8
      12. $framesize = 24
      13. ' Die Portbelegung ist wie folgt:
      14. ' Kanal1 = PB0
      15. ' Kanal2 = PB1
      16. ' Kanal3 = PB2
      17. ' Kanal4 = PB3
      18. ' Kanal5 = PB4
      19. ' später noch K6 - 10
      20. ' RC Signal an PD4
      21. 'Alias festlegen:
      22. K1 Alias Portb.0
      23. K2 Alias Portb.1
      24. K3 Alias Portb.2
      25. K4 Alias Portb.3
      26. K5 Alias Portb.4
      27. ' Ein/Ausgänge konfigurieren
      28. Config Portb = Output
      29. Config Pind.4 = Input
      30. 'Variabeln festlegen:
      31. Dim Ppm As Byte
      32. Dim Mittelpunkt As Byte
      33. Dim Oberer_nullpunkt As Byte
      34. Dim Unterer_nullpunkt As Byte
      35. Dim Zaehler_oben As Byte
      36. Dim Zaehler_unten As Byte
      37. Zaehler_oben = 0 ' Zahler_oben auf 0 setzen
      38. ' Erstmal alle Ausgänge ausschalten ( 0 = EIN, 1 = Aus ):
      39. K1 = 1
      40. K2 = 1
      41. K3 = 1
      42. K4 = 1
      43. K5 = 1
      44. ' Warten, bis ein ordentliches Signal vom Empfänger kommt:
      45. Do
      46. Ppm_abfrage:
      47. Pulsein Ppm , Pind , 4 , 1 ' Signal an PIND4 messen
      48. If Ppm < 10 Then ' ist der Wert kleiner als 10 Than
      49. nop ' mache nichts
      50. Else ' Ansonsten
      51. Goto Los ' Gehen zu los
      52. End If
      53. Loop
      54. ' Jetzt beginnt das Hauptprogramm:
      55. Los:
      56. Wait 2 ' Warte 2 Sekunden
      57. Pulsein Mittelpunkt , Pind , 4 , 1 ' Signal an PIND4 messen
      58. Oberer_nullpunkt = Mittelpunkt + 2 ' Oberer Nullpunkt ist Mittelpunkt + 2
      59. Unterer_nullpunkt = Mittelpunkt - 2 ' unterer Nullpunkt ist Mittelpunkt - 2
      60. Do
      61. Pulsein Ppm , Pind , 4 , 1 ' Sigmal an PIND4 messen und als PPm speichern
      62. If Ppm > Oberer_nullpunkt Then ' Ist PPM größer als Oberer Nullpunkt ( Knüppel hoch ) ? Wenn ja ...
      63. Incr Zaehler_oben ' Variable Zähler_oben um 1 erhöhen
      64. End If ' Ende der If Abfrage
      65. Do
      66. Loop Until Ppm < Oberer_nullpunkt And Ppm > Unterer_nullpunkt ' Warte solange, bis Knüppel wieder in Mittelstellung ist
      67. Wait 1 ' Warte 1 Sekunde
      68. If Ppm > Oberer_nullpunkt Then ' Ist Knüppel immer noch nach oben ? Wenn ja ...
      69. Incr Zaehler_oben ' Variable Zähler_oben um 1 erhöhen
      70. Do
      71. Loop Until Ppm < Oberer_nullpunkt And Ppm > Unterer_nullpunkt ' Warte bis Knüppel wieder in Mittelstellung ist
      72. Else ' Ansonsten
      73. Gosub Zaehler_oben_abfrage ' Gehe zu Zähler_oben_Abfrage
      74. End If
      75. Loop ' Spriinge wieder zurück
      76. ' Hier werden nun die Zähler abgefragt und entschieden, was passiert.
      77. Zaehler_oben_abfrage:
      78. Select Case Zaehler_oben
      79. Case 1 : Toggle K1 ' Ist Zähler_oben = 1, dann Toggle K1
      80. Case 2 : Toggle K2 ' Ist Zähler_oben = 1, dann Toggle K1
      81. Case 3 : Toggle K3 ' Ist Zähler_oben = 1, dann Toggle K1
      82. Case 4 : Toggle K4 ' Ist Zähler_oben = 1, dann Toggle K1
      83. Case 5 : Toggle K5 ' Ist Zähler_oben = 1, dann Toggle K1
      84. Case 6 To 255 : Zaehler_oben = 0 ' Ist Zähler_oben zwischen 6 und 255 setze Zähler_oben auf 0
      85. Wait 2 ' Warte 2 Sekunden
      86. End Select ' Ende der Auswahl.
      87. Return ' springe aus dem Unterprogramm zurück.
      Display All
    • Da versteh ich schon die Ausgangssituation nicht ?(


      Wenn Du z.B. K5 umschalten möchtest, muss der RC-Kanal
      - zunächst in Mittelstellung sein,
      - dann nimmst Du den Hebel nach oben,
      - zeitgleich startest Du eine Stoppuhr, nach 5 Sekunden
      - nimmst Du den Hebel wieder in Mittelstellung und hoffst,
      - dass Du den K5 auch tatsächlich getroffen hast?


      Hab ich das so richtig verstanden? Ich hoffe, Du steuerst damit keine kritischen Funktionen :/
    • Also:

      Möchte ich K1 schalten, lenke ich den Hebel 1 x hoch aus
      Möchte ich K2 schalten, lenke ich den Heben 2 x hoch aus
      Möchte ich K3 schlaten, lenke ich den Hebel 3 x hoch raus
      usw.

      Später dann:

      Möchte ich K6 schalten, lenke ich den Hebel 1 x runter aus
      Möchte ich K7 schalten, lenke ich den Hebel 2 x runter aus
      Möchte ich K8 schalten, lenke ich den Hebel 3 x runter aus
      usw.
    • Er bleibt so lange in der Schleife, bis der Hebel wieder in Mittelstellung ist. Dann wartet er 1 Sekunde. Ist er nach einer Sekunde wieder oben, wird der Zähler erhöht. Wenn nicht, wird in das Unterprogramm der Ausgabe gesprungen.

      So die Idee. In der Praxis funktioniert es jedoch nicht.

      Hier der Teil der Hebel Abfrage:

      BASCOM Source Code

      1. Do
      2. Pulsein Ppm , Pind , 4 , 1 ' Sigmal an PIND4 messen und als PPm speichern
      3. If Ppm > Oberer_nullpunkt Then ' Ist PPM größer als Oberer Nullpunkt ( Knüppel hoch ) ? Wenn ja ...
      4. Incr Zaehler_oben ' Variable Zähler_oben um 1 erhöhen
      5. End If ' Ende der If Abfrage
      6. Do
      7. Loop Until Ppm < Oberer_nullpunkt And Ppm > Unterer_nullpunkt ' Warte solange, bis Knüppel wieder in Mittelstellung ist
      8. Wait 1 ' Warte 1 Sekunde
      9. If Ppm > Oberer_nullpunkt Then ' Ist Knüppel immer noch nach oben ? Wenn ja ...
      10. Incr Zaehler_oben ' Variable Zähler_oben um 1 erhöhen
      11. Do
      12. Loop Until Ppm < Oberer_nullpunkt And Ppm > Unterer_nullpunkt ' Warte bis Knüppel wieder in Mittelstellung ist
      13. Else ' Ansonsten
      14. Gosub Zaehler_oben_abfrage ' Gehe zu Zähler_oben_Abfrage
      15. End If
      Display All
    • Jetzt kommen wir der Sache näher. Pluto25 hat ja bereits auf die fehlende Erfassung des RC-Signals hingewiesen. Dennoch zwingt Dein Codeaufbau den Benutzer dazu, sich exakt an ein Timing zu halten. Wenn Du den Knüppel wärend dem "wait 1" 2x nach oben nimmst, wird trotzdem nur um 1 weitergezählt (wenn man sehr zügig den Küppel bewegt, wird vielleicht sogar kein einziger Schaltvorgang erfasst). Das wird früher oder später zu Frust beim Nutzer führen.

      Funktionssicherer und benutzerfreundlicher würde der Code, wenn Du ihn in folgender Art und Weise aufbaust:

      -Mittelstellung einmalig ermitteln:
      Hierzu einen zulässigen Bereich festlegen, in welchem sich das RC-Signal befinden muss, damit es als Mittelstellung akzeptiert wird (ist einfach ein zusätzlicher Schutz).

      -Jedes Hochlegen des Knüppels erhöht die Variable "Zaehler_oben"
      -Gleichzeitig(!) starte ein 1 sec Zeitfenster (mittels Timer). Dieses Zeitfenster wird bei JEDEM Hochlegen erneut gesetzt!
      -Solange der Knüppel immer wieder von der Mittelstellung nach oben und zurück bewegt wird, wird "Zaehler_oben" erhöht und das Zeitfenster verlängert.
      -Läuft diese Zeitfenster ab, ohne das der Knüppel erneut hochgesetzt wurde, wird der in "Zaehler_oben" gespeicherte Kanal getoggled und "Zaehler_oben" automatisch resettet.

      Der Vorteil bei diesem Aufbau ist, dass es (fast) keine Rolle spielt, wie schnell man den Knüppel hin und her bewegt. Egal, ob man 1,5sec oder 4,5sec braucht, um den Knüppel 5x zu bewegen, man landet immer auf K5 :)

      Nette Grüße
      Robert
    • @Sven Loeffler

      Das ließe sich auch recht einfach mit einer kleinen Statemachine erledigen.

      Zustände wären:
      • ST_DEFAULT (Hebel in Mittelstellung)
      • ST_HANDLE_HIGH (Hebel oben)
      • ST_HANDLE_LOW (Hebel unten)
      • ST_ACTION (Aktion ausführen)
      Damit ließe sich auch das Problem vermeiden, das bei Hebel oben/unten auftritt.
      Denn wenn man da die Variable inkrementiert, wenn PPM > Schwelle oder PPM < Schwelle ist, rast der Zähler bei jedem Schleifendurchlauf los.
      Hier muss man die Flanken erkennen, also den Übergang von Mittelstellung nach Hebel oben bzw Hebel unten.

      Das Problem wird durch die definierten Zustände und die Abfrage stateChanged() bereits erschlagen. Siehe Link Statemachine oben.

      Wenn du Fragen hast, helfe ich gerne.
    • Hallo zusammen,

      Robert, ich habe das mal versucht so einigermaßen zu übernehmen. Fehlt sicher noch was. Ist das soweit schon mal ok ? Bin aktuell auf einen Mega88A umgestiegen.

      BASCOM Source Code

      1. '*************************************************************************************************
      2. '* *
      3. '* 10 Kanalschalter mit atmega88 *
      4. '* *
      5. '* 10 Kanal Schalter mit memoy Funktion. 5 x nach oben oder 5 x nach unten *
      6. '* *
      7. '*************************************************************************************************
      8. $regfile = "m88adef.dat "
      9. $crystal = 8000000
      10. $swstack = 40
      11. $hwstack = 16
      12. $framesize = 32
      13. ' Die Portbelegung ist wie folgt:
      14. ' Kanal1 = PD0
      15. ' Kanal2 = PD1
      16. ' Kanal3 = PD2
      17. ' Kanal4 = PD4
      18. ' Kanal5 = PB6
      19. ' Kanal6 = PB7
      20. ' Kanal7 = PD7
      21. ' Kanal8 = PB0
      22. ' Kanal9 = PB4
      23. ' Kanal10 = PB5
      24. ' RC Signal an PC5
      25. 'Alias festlegen:
      26. K1 Alias Portd.0
      27. K2 Alias Portd.1
      28. K3 Alias Portd.2
      29. K4 Alias Portd.4
      30. K5 Alias Portb.6
      31. K6 Alias Portb.7
      32. K7 Alias Portd.7
      33. K8 Alias Portb.0
      34. K9 Alias Portb.4
      35. K10 Alias Portb.5
      36. ' Ein/Ausgänge konfigurieren
      37. Config Portd.0 = Output
      38. Config Portd.1 = Output
      39. Config Portd.2 = Output
      40. Config Portd.4 = Output
      41. Config Portb.6 = Output
      42. Config Portb.7 = Output
      43. Config Portd.7 = Output
      44. Config Portb.0 = Output
      45. Config Portb.4 = Output
      46. Config Portb.5 = Output
      47. Config Pinc.5 = Input
      48. 'Variabeln festlegen:
      49. Dim Ppm As Byte
      50. Dim Mittelpunkt As Byte
      51. Dim Oberer_nullpunkt As Byte
      52. Dim Unterer_nullpunkt As Byte
      53. Dim Zaehler_oben As Byte
      54. Dim Zaehler_unten As Byte
      55. Dim Zeit As Byte
      56. ' Timer konfigurieren.
      57. Const Timer1_preload = 34286
      58. Config Timer1 = Timer, Prescale = 256
      59. Enable Timer1
      60. Stop Timer1
      61. Timer1 = Timer1_Preload
      62. On Timer1 Isr_Timer1
      63. Enable Interrupts
      64. ' Erstmal alle Ausgänge ausschalten ( 0 = EIN, 1 = Aus ):
      65. K1 = 1
      66. K2 = 1
      67. K3 = 1
      68. K4 = 1
      69. K5 = 1
      70. K6 = 1
      71. K7 = 1
      72. K8 = 1
      73. K9 = 1
      74. K10 = 1
      75. ' Warten, bis ein ordentliches Signal vom Empfänger kommt:
      76. Do
      77. Ppm_abfrage:
      78. Pulsein Ppm , Pinc , 5 , 1 ' Signal an PIND4 messen
      79. If Ppm < 10 Then ' ist der Wert kleiner als 10 Than
      80. nop ' mache nichts
      81. Else ' Ansonsten
      82. Goto Los ' Gehen zu los
      83. End If
      84. Loop
      85. ' Jetzt beginnt das Hauptprogramm:
      86. Los:
      87. Wait 2 ' Warte 2 Sekunden
      88. Pulsein Mittelpunkt , Pinc , 5 , 1 ' Signal an PIND4 messen
      89. Oberer_nullpunkt = Mittelpunkt + 4 ' Oberer Nullpunkt ist Mittelpunkt + 2
      90. Unterer_nullpunkt = Mittelpunkt - 4 ' unterer Nullpunkt ist Mittelpunkt - 2
      91. Main:
      92. ' Abfrage oben:
      93. Do
      94. Pulsein Ppm , Pinc , 5 , 1 ' Sigmal an PIND4 messen und als PPm speichern
      95. If Ppm > Oberer_nullpunkt Then ' Ist PPM größer als Oberer Nullpunkt ( Knüppel hoch ) ? Wenn ja ...
      96. Incr Zaehler_oben
      97. Start Timer1
      98. End If
      99. Loop
      100. ' Hier werden nun die Zähler abgefragt und entschieden, was passiert.
      101. Zaehler_oben_abfrage:
      102. Select Case Zaehler_oben
      103. Case 1 : Toggle K1 ' Ist Zähler_oben = 1, dann Toggle K1
      104. Zaehler_oben = 0
      105. Goto Main
      106. Case 2 : Toggle K2 ' Ist Zähler_oben = 1, dann Toggle K2
      107. Zaehler_oben = 0
      108. Goto Main
      109. Case 3 : Toggle K3 ' Ist Zähler_oben = 1, dann Toggle K3
      110. Zaehler_oben = 0
      111. Goto Main
      112. Case 4 : Toggle K4 ' Ist Zähler_oben = 1, dann Toggle K4
      113. Zaehler_oben = 0
      114. Goto Main
      115. Case 5 : Toggle K5 ' Ist Zähler_oben = 1, dann Toggle K5
      116. Zaehler_oben = 0
      117. Goto Main
      118. Case 6 To 255 : Zaehler_oben = 0 ' Ist Zähler_oben zwischen 6 und 255 setze Zähler_oben auf 0
      119. Wait 2 ' Warte 2 Sekunden
      120. End Select ' Ende der Auswahl.
      121. Return ' springe aus dem Unterprogramm zurück.
      122. Isr_Timer1:
      123. Stop Timer1
      124. Timer1 = Timer1_Preload
      125. Gosub Zaehler_oben_abfrage
      126. Return
      Display All
    • Den Hardwarestack solltest du auf 40 setzen.*
      Statt Goto Los würde ich hier lieber Exit Do nehmen.
      Nach dem Timereinsprung geht es per Gosub in ein Unterprogramm und von dort per Goto zurück ins Hauptprogramm.
      Ich habe mich geirrt, du brauchst deutlich mehr Stackwerte ;)

      * das habe ich geschrieben, als ich in deinem Programm die ersten Zeilen gesehen habe.
      Für ein normales Programm mit Timer und einem Gosub würde das reichen.
      Hier verschachtelst du die Sprünge bis der Speicher überläuft.

      Versuch, deine Programme ohne Goto zu schreiben.
      Und versuch bitte einen Plan, wie dein Programm strukturiert ist (Programmablaufplan)
    • @Sven Loeffler wichtig! Wenn eine sub angesprungen wird muss immer das 'return' bzw das 'end sub' ausgeführt werden. Beim Programmablauf wird die aktuelle Stelle des Programms auf dem stack gespeichert, von wo in die sub gesprungen wird, damit nach dem Abarbeiten der sub wieder da weiter gemacht wird. Beim Rücksprung durch das return, bzw dem end sub, wird dieser 'Merker' wieder vom stack entfernt, aber eben nur dadurch (ja ja, man kann es auch anders machen, aber warum sollte man). Wird das nicht gemacht, vergrößert sich der Platz für den stack immer weiter, bis er wichtige Variaben überschreibt und das Programm nicht mehr das gewünschte macht.
      Raum für Notizen

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

      -----------------------------------------------------------------------------------------------------
    • Hi Sven,

      muss gleich weg, daher nur ganz kurz:
      GOTO wird nur von 2 Leuten verwendet: Vom Profi und vom Anfänger, aber nur einer von beiden weiß ganz genau, was er tut. a_38_b45e201d
      Spaß beiseite, mit den Gotos wirst Du nicht glücklich. Das erste GOTO in Deinem Programm bringst Du ganz einfach weg (und prüfst nebenbei sogar noch die von mir vorgeschlagene Gültigkeit der Mittelstellung). Etwa so:

      BASCOM Source Code

      1. Dim Mittelstellung_erkannt as Bit
      2. Dim Counter_Mittelstellung as Byte
      3. ' Prüfung, ob gültige Mittelstellungs-Signale vom Empfänger kommen
      4. ' Startwerte setzen
      5. Mittelstellung_erkannt = 0
      6. Counter_Mittelstellung = 0
      7. Do
      8. Pulsein Ppm , Pinc , 5 , 1 ' Signal an PINC5 messen
      9. If Ppm > 140 AND Ppm < 160 then ' wir erwarten bei Mittelstellung einen Wert im Bereich von 150
      10. Incr Counter_Mittelstellung ' wir zählen, wieviele Messungen im Bereich der Mittelstellung liegen
      11. If Counter_Mittelstellung => 10 then ' erst wenn 10 aufeinanderfolgende Messungen im gültigen Bereich liegen ...
      12. Mittelpunkt = Ppm ' ...akzeptieren wir den Wert und
      13. Mittelstellung_erkannt = 1 ' setzen das Flag zum Verlassen
      14. End If
      15. Else ' liegt das RC-Signal außerhalb des erwarteten Bereichs...
      16. Counter_Mittelstellung = 0 ' ... setzen wir lediglich den Counter auf Null
      17. End If
      18. Waitms 50 ' etwas warten (mit dem Wert 50 dauert es ca 0,5 bis 0,7sec, bis alle 10 Messungen gemacht sind)
      19. Loop Until Mittelstellung_erkannt = 1 ' durch das gesetzte Flag verlassen wir nun die Schleife
      20. ' Hier beginnt nun das Hauptprogramm
      21. Do
      22. .
      23. .
      24. Loop
      25. End
      Display All

      Sofern Du das Projekt nicht als Statemaschine aufbauen möchtest, würde ich auch dringend empfehlen, "Totbereiche" einzubauen. Das sind Messbereiche in Deiner RC-Messung, die keinerlei Einfluss auf Deine Steuerung haben. Stell Dir vor, Dein RC Signal schwankt genau auf der Schaltschwelle zwischen "Mittlerere Bereich" und "Oberere Bereich" (Du nennst diese Schaltschwelle Oberer_nullpunkt). Dann würde das Programm unkontrolliert weiterschalten. Die folgende Skizze soll den ganzen RC-Wertebereich zeigen. Es sind 3 Bereiche festgelegt, ein unterer, ein mittlerer und ein oberer. Dazwischen (in weiß) liegen die besagten Totbereiche. RC-Signale im weißen Bereich haben dann keinen Einfluss auf Deine Steuerung und es kommt nicht zu unkontrolierten Schaltvorgängen. :)

      Servobereich.jpg


      Nette Grüße,
      Robert
    • Die Do-Loop-Schleife wartet wohl, bis die Mittelstellung erkannt wird.
      Vorher passiert nix weiter und das ganze Programm wird blockiert.

      Da ich ja ein Statemachine-Freak bin hier mal eine solche Variante.

      BASCOM Source Code

      1. '*************************************************************************************************
      2. '* *
      3. '* 10 Kanalschalter mit Tiny2313 *
      4. '* *
      5. '* 10 Kanal Schalter mit memoy Funktion. 5 x nach oben oder 5 x nach unten *
      6. '* *
      7. '*************************************************************************************************
      8. ' Autor: Mitch64 2020
      9. ' Für: Sven Löffner
      10. ' Version: Entwurf
      11. $regfile = "attiny2313.dat"
      12. $crystal = 8000000
      13. $hwstack = 16
      14. $swstack = 8
      15. $framesize = 24
      16. ' Die Portbelegung ist wie folgt:
      17. ' Kanal1 = PB0
      18. ' Kanal2 = PB1
      19. ' Kanal3 = PB2
      20. ' Kanal4 = PB3
      21. ' Kanal5 = PB4
      22. ' später noch K6 - 10
      23. ' RC Signal an PD4
      24. 'Alias festlegen:
      25. ' Definition der Kanäle
      26. K1 Alias Portb.0
      27. K2 Alias Portb.1
      28. K3 Alias Portb.2
      29. K4 Alias Portb.3
      30. K5 Alias Portb.4
      31. ' Allgemeine Konstanten
      32. Const TRUE = 1
      33. Const FALSE = 0
      34. ' Definierte Zustände
      35. Const ST_DEFAULT = 0 ' Hebel in Mittelstellung
      36. Const ST_HANDLE_HIGH = 1 ' Hebel hoch gezogen
      37. Const ST_HANDLE_LOW = 2 ' Hebel runter gezogen
      38. Const ST_ACTION = 3 ' Aktion ausführen
      39. ' Schwellen für RC-Kanal
      40. Const RC_LIMIT_HIGH = 170 ' >1.7ms Schwelle Hebel hoch
      41. Const RC_LIMIT_LOW = 130 ' <1.3ms Schwelle runter
      42. Const RC_RANGE_HIGH = 160 ' Normalbereich (Hebel Mittelstellung) von
      43. Const RC_RANGE_LOW = 140 ' 1.4 bis 1.6ms
      44. ' Variablen
      45. Dim RC_Value as Word ' RC-Kanalwert
      46. Dim Counter_High as Word ' Zähler Hebel oben
      47. Dim Counter_Low as Word ' Zähler Hebel unten
      48. ' Makro liest RC-Kanalwert (PinD.4) in Variable 'RC_Value' ein
      49. Macro RC_PulseIn
      50. PulseIn RC_Value , PinD , 4 , 1 ' positiver Puls am PinD.4 messen
      51. End Macro
      52. ' Deklarationen
      53. Declare Sub setState(Byval newState as Byte)
      54. Declare Function getState() as Byte
      55. Declare Function stateChanged() as Byte
      56. ' Initialisierung
      57. DDRB = DDRB or &b00011111 ' K1 bis K5 als Ausgang
      58. PortB = PortB Or &b00011111 ' K1 bis K5 HIGH setzen
      59. Config Timer1 = Timer , Prescale = 256 ' 1 Tick = 32µs
      60. ' Timeout besimmt, nach welcher Zeit die Aktion ausgelöst wird
      61. ' Berechnung: Limit = Zeit [s] / 0.000032
      62. Const TIMEOUT_LIMIT = 18750 ' 0.6s
      63. ' ############################################################################
      64. ' ## ##
      65. ' ## Hauptschleife ##
      66. ' ## ##
      67. ' ############################################################################
      68. Call setState(ST_DEFAULT) ' Startzustand setzen
      69. Do
      70. Select Case getState()
      71. ' ------------------------------
      72. Case ST_DEFAULT ' Hebel in Mittelstellung
      73. ' ------------------------------
      74. If stateChanged() = TRUE then
      75. Timer1 = 0 ' Timeout zurückstellen
      76. End If
      77. RC_PulseIn ' RC Puls messen
      78. ' auf RC-Puls reagieren
      79. Select Case RC_Value
      80. Case Is > RC_LIMIT_HIGH ' Hebel wurde hoch gezogen
      81. Call setState(ST_HANDLE_HIGH)
      82. Case Is < RC_LIMIT_LOW ' Hebel wurde runter gezogen
      83. Call setState(ST_HANDLE_LOW)
      84. Case RC_RANGE_LOW to RC_RANGE_HIGH ' Hebel Mittelstellung
      85. If Counter_High > 0 or Counter_Low > 0 then
      86. If Timer1 > TIMEOUT_LIMIT then ' Aktion starten
      87. Call setState(ST_ACTION)
      88. End If
      89. End If
      90. End Select
      91. ' ------------------------------
      92. Case ST_HANDLE_HIGH ' Hebel hoch gezogen
      93. ' ------------------------------
      94. If stateChanged() = TRUE then
      95. Incr Counter_High ' Zähler Hebel hoch
      96. End If
      97. RC_PulseIn ' RC Puls messen
      98. If RC_Value < RC_RANGE_HIGH then ' Hebel wieder Mittelstellung?
      99. Call setState(ST_DEFAULT)
      100. End If
      101. ' ------------------------------
      102. Case ST_HANDLE_LOW ' Hebel runter gezogen
      103. ' ------------------------------
      104. If stateChanged() = TRUE then
      105. Incr Counter_Low ' Zähler Hebel runter
      106. End If
      107. RC_PulseIn ' RC Puls messen
      108. If RC_Value > RC_RANGE_LOW then ' Hebel wieder Mittelstellung?
      109. Call setState(ST_DEFAULT)
      110. End If
      111. ' ------------------------------
      112. Case ST_ACTION ' Aktion ausführen
      113. ' ------------------------------
      114. ' Kanäle K1 bis K5
      115. Select Case Counter_High
      116. Case 1 : Toggle K1
      117. Case 2 : Toggle K2
      118. Case 3 : Toggle K3
      119. Case 4 : Toggle K4
      120. Case 5 : Toggle K5
      121. End Select
      122. ' Kanäle 6 bis K10
      123. ' Select Case Counter_Low
      124. ' Case 1
      125. ' Case 2
      126. ' Case 3
      127. ' Case 4
      128. ' Case 5
      129. ' End Select
      130. Counter_High = 0 ' Zähler wieder auf 0 setzen
      131. Counter_Low = 0 ' Zähler wieder auf 0 setzen
      132. Call setState(ST_DEFAULT)
      133. End Select
      134. Loop
      135. ' ############################################################################
      136. ' ## ##
      137. ' ## Hilfsroutinen und Variablen für Statemachine ##
      138. ' ## ##
      139. ' ############################################################################
      140. Dim _state as Byte
      141. Dim _stateChanged as Bit
      142. ' ----------------------------------------------
      143. ' Setzt einen neuen Zustand
      144. ' ----------------------------------------------
      145. Sub setState(Byval newState as Byte)
      146. _state = newState ' Zustand setzen
      147. _stateChanged = TRUE ' Flag setzen, Zustand wurde verändert
      148. End Sub
      149. ' ----------------------------------------------
      150. ' Gibt aktuellen Zustand zurück
      151. ' ----------------------------------------------
      152. Function getState() as Byte
      153. getState = _state ' Rückgabe aktueller Zustand
      154. End Function
      155. ' ----------------------------------------------
      156. ' Gibt TRUE zurück, wenn der Zustand seit
      157. ' letzter Abfrage geändert wurde.
      158. ' ----------------------------------------------
      159. Function stateChanged() as Byte
      160. If _stateChanged = TRUE then ' Flag ist gesetzt
      161. _stateChanged = FALSE ' Flag löschen
      162. stateChanged = TRUE ' Rückgabe, Zustand wurde geändert
      163. Else
      164. stateChanged = FALSE ' Rückgabe, Zustand wurde nicht geändert
      165. End If
      166. End Function
      Display All
      Das ist auch nicht weiter kompliziert.
      Hier wird aber das Hauptprogramm nicht blockiert.
      Man kann also nebenher noch anderes machen.
    • Hallo Mitch64,

      Vielen Dank für deine Hilfe. Ich bin was Bascom und Programmieren angeht absoluter Neuling, jedoch finde ich deinen Statemachine Aufbau hochinteressant. Wäre es auch möglich, anstatt die Kanäle zu Togglen sie bei einer Statusänderung in ein Unterprogramm zu schicken? Um dort zb. eine Blinkfrequenz für ein Rundumlicht oder Doppelblitz laufen zu lassen?
      Meine Frage kommt daher, mein Idee war es eine kleine Platine zu erstellen auf der sich ein Tiny zb. Mega88a befindet, der einen 8-10 Kanalschalter und 2 Fahrregler beinhaltet, von denen einer mit Bremslicht und Rückfahrlicht ausgestattet ist

      Viele Grüße Lennart
    • Lennart wrote:

      Wäre es auch möglich, anstatt die Kanäle zu Togglen sie bei einer Statusänderung in ein Unterprogramm zu schicken?
      Wenn du aus der Statemachine z.B. mit einem Call in ein Unterprogramm springst, und dort eine Endlosschleife hast um eine LED blinken zu lassen, dann hast du die Statemachine ausgenockt.
      Sprich, in der Hauptschleife ist dann alles tot, bis du von dem Unterprogramm zurück kehrst.

      Das kann man machen. Sollte man aber nur machen, wenn es Sinn macht. Oder wenn man die Vorzüge für die Dauer des Blinkens nicht nutzen möchte.

      Hier findest du übrigens ein Tutorial zur Statemachine in diesem Forum.

      Übrigens ist in obigem Programm der Zustand ST_ACTION kein wirklicher Zustand, da er nur ein paar Codezeilen ausführt und dann sofort den Zustand ST_DEFAULT aktiviert.
      Es wird also nicht auf ein Ereignis gewartet, der den Zustand ändert.

      Ein Blinken kannst du in dieser Art machen.
      Z.B. ST_BLINKEN hinzufügen und den State dann wenn gewünscht aktivieren.
      Dort Lässt du die LED toggeln. Solltest aber nicht mit Wait das Blinken drosseln, sondern mit Timeout arbeiten oder ein Intervall-Timer einrichten.
      Die Statemachine sollte nicht mit Waits blockiert werden.

      Aber lese dir erst mal das Tutorial durch.

      The post was edited 1 time, last by Mitch64 ().