Entprellen leicht gemacht II - Analog Buttons

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

    • Entprellen leicht gemacht II - Analog Buttons

      ADC-Button entprellen

      Zu dem folgenden Codeschnipsel kam es, als ich für ein „schnelles Projekt“ auf Komponenten der Arduino – Schiene zurückgegriffen habe. Darunter das „LCD and keypad shield“. Die Abbildung zeigt ein solches shield, hier von SainSmart. Das gibt es aber auch von vielen anderen Herstellern.
      LCD_keypadShield.jpg

      :!: Die Abfrage der Tasten durch den AD-Wandler stellt in der Regel kein großes Problem dar, ist doch die Schaltung dahinter gut dokumentiert. Auch den Code dazu findet man in allen gängigen Sprachen, immer mit dem gleichen Prinzip –> Anhand der Bewertung werden in einer Byte-Variablen entsprechende Bits gesetzt.

      In der Basis sieht der Code dann so aus:

      Quellcode

      1. sub readAnalogButtonTask()
      2. select case getadc(AnalogButtonChannel)
      3. case is < 100 : Button = 1
      4. case is < 200 : Button = 2
      5. case is < 400 : Button = 4
      6. case is < 600 : Button = 8
      7. case is < 800 : Button = 16
      8. case else : Button = 0
      9. end select
      10. end sub
      :?: Möchte oder muss man nun diese analog abgefragten Tasten mit Debounce weiterbehandeln, steht man vor dem Problem, dass dieser Befehl nun mal nur mit IO- Registern arbeitet. a_45_132ca9f5

      Quellcode

      1. Debounce PINA.0 , 1 , KeyUp , Sub

      Zum Glück gibt es aber freie IO-Register, wie z.B. im ATmega328. Drei Stück sind das und heißen GPIOR0 bis GPIOR2 a_170_58e0202d
      Der Trick dahinter ist also:

      Quellcode

      1. Button alias GPIOR0



      Viel Spaß damit

      Galahat
      Dateien
      • schematic.pdf

        (47,58 kB, 80 mal heruntergeladen, zuletzt: )
    • Soweit ich weiß, legt der Debounce-Befehl nur eine kleine Pause ein, die konfigurierbar ist.
      Warum nicht entsprechend warten? Die Getadc-Abfrage wäre dann natürlich z. B. im Main und
      Auslöser für das Unterprogramm, in dem vor Rücksprung gewartet wird.
      Heisenberg bei einer Radarkontrolle:
      Polizist: "Wissen Sie, wie schnell Sie waren?"
      Heisenberg: "Nein. Aber ich weiß genau, wo ich jetzt bin!"

    • mac5150 schrieb:

      Soweit ich weiß, legt der Debounce-Befehl nur eine kleine Pause ein, die konfigurierbar ist.
      Dann weißt du aber nicht alles.

      Debounce wartet nur, wenn es einen Anlass dazu gibt, also eine Änderung des Pin Levels hin zum parametrierten Level. Nach dieser Wartezeit wird der angegebene Programmteil angesprungen und zwar nur einmal. Erst wenn der Pin wieder den Ausgangspegel führt, kann ein neuer Zyklus beginnen.
    • Danke für die ausführliche Antwort.

      Korrigiere mich bitte, wenn ich mich irre:
      Wenn per Taster ein Wert verändert werden soll und dieser bei betätigtem Taster sich stetig weiter verändern soll,
      vergleichbar einer Minuteneinstellung bei einer Uhr, ist Debounce nicht der Weg der Wahl.
      Heisenberg bei einer Radarkontrolle:
      Polizist: "Wissen Sie, wie schnell Sie waren?"
      Heisenberg: "Nein. Aber ich weiß genau, wo ich jetzt bin!"

    • Auf den ersten Blick stimmt schon Deine Vermutung, doch - ...wieso eigentlich nicht? Es gibt doch nur einen Tastendruck im Sinne der Ausführung, du verstehst.

      Es ist eine Frage des Handlings und des Umgangs mit Debounce, sofern man diese Methode überhaupt verwendet. Es geht ja auch anders.
      Ob Sinnvoll oder nicht, du kannst sogar beide Fälle, also gedrückt und nicht Gedrückt abfragen, wenn es die Sache erleichtert. Dazu ein Beispiel für Dich, das lustigste was mir gerade einfiel. Nett von mir, oder?

      Quellcode

      1. $sim
      2. $regfile = "m88def.dat"
      3. $crystal = 1000000
      4. $hwstack = 40
      5. $swstack = 16
      6. $framesize = 32
      7. config submode = new
      8. const TRUE = 1
      9. const FALSE = 0
      10. const CHANGE_VALUE_BYTE_ADD_ONE = &H01
      11. const CHANGE_VALUE_BYTE_SUB_ONE = &Hff
      12. config Pinb.0 = input
      13. portb.0 = 1
      14. dim changeMinute as bit
      15. dim minute as Byte
      16. sub ChangeValue(value as byte , byval add as byte)
      17. value = value + add
      18. end Sub
      19. do
      20. debounce pinb.0 , 0 , SetIsPressed , sub
      21. debounce pinb.0 , 1 , ReSetIsPressed , sub
      22. if changeMinute = TRUE then call ChangeValue(minute , CHANGE_VALUE_BYTE_SUB_ONE)
      23. Loop
      24. SetIsPressed:
      25. set changeMinute
      26. return
      27. ReSetIsPressed:
      28. reset changeMinute
      29. return
      Alles anzeigen
    • @Galahat:
      Ich finde den Ansatz einer Entprellung wie bei Digitalen Eingängen für den Analogeingang interessant.
      Leider kapier ich Dein Codeschnippsel überhaupt nicht.
      Wird ein Widerstand eines Spannungsteilers durch einen Taster kurzgeschlossen, dann wird doch auch
      die analoge Spannung in der Prellzeit des Tasters zwischen Wert A und Wert B (und dazwischen) hin und her springen.
      Eine Auswertung mit select case wird also eine Spannung dieses moments aufnehmen, und entsprechend den betätigten
      Taster falsch, richtig, oder gar nicht zuweisen. Das bedeutet doch, das eine Entprellung für Analogeingänge mit Taster nur über eine Mehrfachabtastung
      des AD-Wandlers und Mittelwertbildung funktioniert, oder aber, das in der Hauptschleife nur gecheckt wird, ob der AD Wert < 1023 ist.
      Wenn der Wert < 1023, dann warte entprellzeit, Analogwandler nochmal auswerten, und anschließend die select case sache.

      Es wäre schön, wenn ich hier auf dem falschen Weg bin, konnte die Entprellung bis dato aber nicht anders lösen.

      Bitte zeig mir mal ein kurzen Codeschnipsel, wie Du das debounce für AD-Wandler anwendest.

      Schöne Ostern, und Danke

      Sepp
    • Hallo Sepp.

      Der Gedanke hinter dem oben genannten Vorschlag ist der, das der Analogwert im Hintergrund per ISR kontinuierlich gelesen wird und die SelectCase-Struktur je nach Wertigkeit ein Bit im Byte namens Button setzt. Im Hauptprogramm können dann die Bit-Abfragen mithilfe von Debounce kommen, was nur funktioniert, weil Button ein GPIO Register ist.
      Die vordergründige Idee hier ist also, die Zustandsüberführung der Analogtaster derart, das man sie im Programm wie einen realen Io-Port anwenden kann.
      Sollte es also zu unsteten Zuständen kommen, kann Debounce da ja prima wirken.
    • Hallo Galahat,

      ich habe gestern noch etwas experimentiert, und siehe da Dein Vorschlag funktioniert bestens.

      Quellcode

      1. '-------------------------------------------------------------------------------
      2. $regfile = "m328pdef.dat" 'use the ATMEGA32 file
      3. $crystal = 16000000 '16MHz Oszillator
      4. $hwstack = 64
      5. $swstack = 32
      6. $framesize = 32
      7. $PROGRAMMER = 22
      8. '-------------------------------------------------------------------------------
      9. 'Define Pins / Ports
      10. key_status alias GPIOR0 'State which key is pressed
      11. btnRIGHT Alias GPIOR0.0
      12. btnUP Alias GPIOR0.1
      13. btnDOWN Alias GPIOR0.2
      14. btnLEFT Alias GPIOR0.3
      15. btnSELECT Alias GPIOR0.4
      16. '-------------------------------------------------------------------------------
      17. 'Define Variable
      18. dim idx as byte
      19. '-------------------------------------------------------------------------------
      20. '-------------------------------------------------------------------------------
      21. 'Main:
      22. do
      23. gosub read_LCD_buttons
      24. debounce btnUP , 1 , Incr_IDX , sub
      25. debounce btnDOWN , 1 , Decr_IDX , sub
      26. loop
      27. end
      28. '-------------------------------------------------------------------------------
      29. '-------------------------------------------------------------------------------
      30. read_LCD_buttons:
      31. select case getadc(0)
      32. case is < 10 : key_status = 1 'btnRIGHT .0
      33. case 100 to 200 : key_status = 2 'btnUP .1
      34. case 300 to 400 : key_status = 4 'btnDOWN .2
      35. case 460 to 560 : key_status = 8 'btnLEFT .3
      36. case 680 to 780 : key_status = 16 'btnSELECT .4
      37. case 920 to 1023 : key_status = 0 'btnNONE
      38. end select
      39. return
      40. '-------------------------------------------------------------------------------
      41. Incr_IDX:
      42. incr idx
      43. return
      44. '-------------------------------------------------------------------------------
      45. Decr_IDX:
      46. decr idx
      47. return
      48. '-------------------------------------------------------------------------------
      Alles anzeigen
      Ich habe mal eine kurze Zusammenstellung der Umsetzung gemacht,
      vielen Dank dafür.
      Übrigens: Der code benötigt 150 Bytes mehr, als meine Version mit Key_Release_Bit usw., aber es ist wesentlich übersichtlicher.

      Schöne Ostern

      Sepp