2 gedrückte Tasten abfragen

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

    • 2 gedrückte Tasten abfragen

      Hallo,

      in meinem Programm frage ich 10 Taster mit Debounce ab und möchte durch gleichzeitiges Drücken von 2 Tasten ein Unterprogramm starten.
      Ich hab schon mit Flag setzten gearbeitet aber bin nicht ans Ziel gekommen.
      Hat dafür jemand eine Lösung oder einen Lösungsansatz?

      Vielen Dank!
    • Source Code

      1. 'Config Timer für Mute/Pw Taste
      2. Config Timer2 = Timer , Prescale = 1024
      3. On Timer2 TimerMuteKey
      4. Enable Timer2
      5. Start Timer2
      6. Config Debounce = 20
      7. 'Config Timer für RC5 reset
      8. Config Timer3 = Timer , Prescale = 1024
      9. On Timer3 TimerRc5
      10. Enable Timer3
      11. Enable Interrupts
      12. 'Werte und Variablen für ADC
      13. rem Const Teiler = 5.2 'Teiler für Verstärkungsfaktor, 4 für 256 (+31.4dB) bis 5.2245 für 196 (0dB)
      14. Const Offset1 = 30
      15. Const Offset2 = 1.477
      16. Const Faktor = 128
      17. Const VolMaxOn = 512 'Schwellwert für makimale Einschaltautstärke
      18. Dim Adc_messwert As Word 'wird bei jeder Messung mit dem aktuellen 10 Bit ADC Messwert belegt
      19. Dim Neu_wert As Single 'enthält "entschwankten" Potentiometer Auslesewert
      20. Dim Alt_wert As Word 'enthaelt Adc Messwert aus dem der Neu_wert erzeugt wurde
      21. Dim Differenz As Integer 'maximaler ADC drift, nur Werte grösser dieser Zahl wedren weiter verarbeitet
      22. Dim Spi_raw As Integer 'errechneter Endwert mit Kommastellen
      23. Dim Spi_byte(2) As Byte 'errechneter Endwert ohne Kommastellen als Array
      24. Dim Kanalsave As Byte 'Speicher für eingeschalteten Kanal
      25. Kanalsave = 0
      26. 'Werte und Variablen für RC5
      27. Const GeraeteCode = 0
      28. Const PwKeyCode = 12
      29. Const MuteKeyCode = 15
      30. Const VolMinusCode = 17
      31. Const VolPlusCode = 16
      32. Dim Addr As Byte
      33. Dim Comm As Byte
      34. Dim Togglebit As Byte
      35. Dim Togglebitlast As Byte
      36. Dim FlagRc5 As Bit
      37. Dim Preload As Word
      38. Preload = 62411
      39. Timer3 = Preload
      40. 'Variablen für Mute/Pw Taste
      41. Dim Norm_PreAmp As Bit
      42. Dim FlagMute As Bit
      43. Dim Count As Byte
      44. Dim Pressed_short As Byte 'Zähler für kurze Tastendrücke
      45. Dim Pressed_long As Byte 'Zähler für lange Tastendrücke
      46. 'Start
      47. FlagRc5 = 0
      48. Stop Timer3 'Rc5 Powerkey Timer
      49. Geht_los:
      50. PwOn48V = 0
      51. PWLED = 0
      52. Waitms 1500
      53. 5V12Von = 0
      54. IceStandBy = 0
      55. PGA5V = 0
      56. Select Case Kanalsave
      57. Case 0 : DigIn1 = 0
      58. Case 1 : DigIn2 = 0
      59. Case 2 : DigIn3 = 0
      60. Case 3 : DigIn4 = 0
      61. Case 4 : DigIn5 = 0
      62. Case 5 : DigIn6 = 0
      63. Case 6 : AnaIn1 = 0
      64. AnaDig = 0
      65. Case 7 : AnaIn2 = 0
      66. AnaDig = 0
      67. Case 8 : AnaIn3 = 0
      68. AnaDig = 0
      69. Case 9 : Phono = 0
      70. AnaDig = 0
      71. End Select
      72. Waitms 500
      73. DcProt = 0
      74. Waitms 100
      75. PreAmpModeOn:
      76. Do
      77. Adc_messwert = Getadc(0) 'Messung starten
      78. If Adc_messwert > VolMaxOn Then 'wenn aktueller Wert größer als erlaubter max Wert ist
      79. MotMinus = 1 'dann mit Motorpoti Wert verkleinern
      80. Else
      81. MotMinus = 0
      82. End If
      83. If Adc_messwert < VolMaxOn Then 'Wenn max Wert unterschritten, dann verlasse Schleife
      84. Exit Do
      85. End If
      86. Loop
      87. rem Spi_raw = Adc_messwert / Teiler 'anpassen des Verstärkungsfaktors
      88. Neu_wert = Adc_messwert + Offset1
      89. Neu_wert = Log10(Neu_wert)
      90. Neu_wert = Neu_wert - Offset2
      91. Neu_wert = Neu_wert * Faktor
      92. Spi_byte(1) = Spi_raw 'beschneidung der Kommastellen
      93. Spi_byte(2) = Spi_raw
      94. Spiinit
      95. Spiout Spi_byte(1) , 2 'schreibe aktuellen Wert in den PGA2320
      96. Do
      97. Adc_messwert = Getadc(0)
      98. Differenz = Adc_messwert - Alt_wert 'Differenz zwischen aktuellem Messwert und verwendetem alten feststellen
      99. If Abs(differenz) > 2 Then 'Hysterese hier von 2 Einheiten = maximal Wert der beiden niederwertigsten Bits
      100. Alt_wert = Adc_messwert 'Adc_messwert als neue Referenz für weitere Vergleiche sichern
      101. Neu_wert = Adc_messwert 'setzen der Ergebnisvariablen mit dem "entschwankten" Wert.
      102. rem Spi_raw = Neu_wert / Teiler 'anpassen des Verstärkungsfaktors
      103. Neu_wert = Neu_wert + Offset1
      104. Neu_wert = Log10(Neu_wert)
      105. Neu_wert = Neu_wert - Offset2
      106. Neu_wert = Neu_wert * Faktor
      107. Spi_byte(1) = Spi_raw 'beschneidung der Kommastellen
      108. Spi_byte(2) = Spi_raw
      109. rem Print Spi_byte ; Spc(3) ; Spi_byte(1) ; Spc(3) ; Spi_byte(2) ; Spc(3) ; Neu_wert ; Spc(3) ; Differenz
      110. Spiout Spi_byte(1) , 2 'schreibe aktuellen Wert in den PGA
      111. End If
      112. Getrc5(Addr , Comm) 'Rc5 Empfang starten
      113. If Addr = GeraeteCode Then
      114. Togglebit = Comm 'Togglebit wird extrahiert
      115. Shift Togglebit , Right , 7
      116. Comm = Comm And &B01111111 'Togglebit wird entfernt
      117. Print Addr ; Spc(3) ; Comm
      118. If Comm = PwKeyCode and FlagRc5 = 0 Then
      119. FlagRc5 = 1
      120. Togglebitlast = Togglebit
      121. Start Timer3
      122. Goto Standby
      123. End If
      124. If Comm = PwKeyCode and Togglebit <> Togglebitlast and FlagRc5 = 1 Then
      125. Togglebitlast = Togglebit
      126. Goto Standby
      127. End If
      128. End If
      129. If Addr = GeraeteCode and Comm = VolMinusCode Then 'Wenn "Vol.minus" Taste gegrückt
      130. MotMinus = 1 'dann lege Spannung an Motorpoti
      131. Else
      132. MotMinus = 0
      133. End If
      134. If Addr = GeraeteCode and Comm = VolPlusCode Then
      135. MotPlus = 1
      136. Else
      137. MotPlus = 0
      138. End If
      139. Select Case Comm
      140. Case 1 : Gosub Dig_In1
      141. Case 2 : Gosub Dig_In2
      142. Case 3 : Gosub Dig_In3
      143. Case 4 : Gosub Dig_In4
      144. Case 5 : Gosub Dig_In5
      145. Case 6 : Gosub Dig_In6
      146. Case 7 : Gosub Ana_In1
      147. Case 8 : Gosub Ana_In2
      148. Case 9 : Gosub Ana_In3
      149. Case 0 : Gosub Phono_In
      150. End Select
      151. 'Tasten abfragen
      152. Debounce KeyDig1 , 0 , Dig_In1 , Sub
      153. Debounce KeyDig2 , 0 , Dig_In2 , Sub
      154. Debounce KeyDig3 , 0 , Dig_In3 , Sub
      155. Debounce KeyDig4 , 0 , Dig_In4 , Sub
      156. Debounce KeyDig5 , 0 , Dig_In5 , Sub
      157. Debounce KeyDig6 , 0 , Dig_In6 , Sub
      158. Debounce KeyAna1 , 0 , Ana_In1 , Sub
      159. Debounce KeyAna2 , 0 , Ana_In2 , Sub
      160. Debounce KeyAna3 , 0 , Ana_In3 , Sub
      161. Debounce KeyPhono , 0 , Phono_In , Sub
      162. Debounce PwKey , 0 , Standby , Sub
      163. Debounce KeyMute , 0 , SetFlag , Sub
      164. If FlagMute = 1 Then
      165. If KeyMute = 1 And Count < 50 Then 'Auswertung des kurzen Tastendrucks
      166. Pressed_short = Pressed_short + 1 'Zählen des kurzen Tastendrucks
      167. FlagMute = 0
      168. Count = 0
      169. If Norm_PreAmp = 1 Then
      170. Spi_byte(1) = 0
      171. Spi_byte(2) = 0
      172. Spiout Spi_byte(1) , 2
      173. IceStandBy = 0
      174. Norm_PreAmp = 0
      175. DcProt = 0
      176. Waitms 100
      177. Gosub PreAmpModeOn
      178. Else
      179. Goto Mute
      180. End If
      181. End If
      182. If Count > 150 Then 'Auswertung des langen Tastendrucks
      183. Pressed_long = Pressed_long + 1 'Zählen des langen Tastendrucks
      184. FlagMute = 0
      185. Gosub PreAmpMode
      186. End If
      187. End If
      188. Loop
      189. End
      190. 'Subs:
      191. StandBy:
      192. PwOn48V = 1
      193. PWLED = 1
      194. 5V12Von = 1
      195. PGA5V = 1
      196. DcProt = 1
      197. DigIn1 = 1
      198. DigIn2 = 1
      199. DigIn3 = 1
      200. DigIn4 = 1
      201. DigIn5 = 1
      202. DigIn6 = 1
      203. AnaDig = 1
      204. AnaIn1 = 1
      205. AnaIn2 = 1
      206. AnaIn3 = 1
      207. Phono = 1
      208. Do
      209. Getrc5(Addr , Comm)
      210. If Addr = GeraeteCode Then
      211. Togglebit = Comm
      212. Shift Togglebit , Right , 7
      213. Comm = Comm And &B01111111
      214. If Comm = PwKeyCode and FlagRc5 = 0 Then
      215. FlagRc5 = 1
      216. Togglebitlast = Togglebit
      217. Start Timer3
      218. Goto Geht_los
      219. End If
      220. If Comm = PwKeyCode and Togglebit <> Togglebitlast and FlagRc5 = 1 Then
      221. Togglebitlast = Togglebit
      222. Goto Geht_los
      223. End If
      224. End If
      225. Debounce PwKey , 0 , Geht_los
      226. Loop
      227. End
      228. Dig_In1:
      229. DigIn1 = 0
      230. DigIn2 = 1
      231. DigIn3 = 1
      232. DigIn4 = 1
      233. DigIn5 = 1
      234. DigIn6 = 1
      235. AnaDig = 1
      236. AnaIn1 = 1
      237. AnaIn2 = 1
      238. AnaIn3 = 1
      239. Phono = 1
      240. Kanalsave = 0
      241. Waitms 100 'Sicherheit zum Schalten wegen toggle Befehl
      242. return
      243. SetFlag:
      244. Set FlagMute
      245. Return
      246. Mute:
      247. toggle PgaMute
      248. Return
      249. PreAmpMode:
      250. IceStandBy = 1
      251. DcProt = 1
      252. Set Norm_PreAmp
      253. Goto PreAmpModeOn
      254. 'Timer:
      255. TimerRc5:
      256. Timer3 = Preload
      257. If Comm <> PwKeyCode Then
      258. FlagRc5 = 0
      259. Stop Timer3
      260. End If
      261. Return
      262. End
      263. TimerMuteKey:
      264. If FlagMute = 1 Then Count = Count + 1
      265. Return
      Display All
      Hier ist die "Baustelle".
      Das ist die Steuerung von einem Verstärker. Durch Drücken der Taste PwKey und MuteKey soll der aktuelle Acd_messwert in den Eeprom gesichert werden.
      Das sind meine ersten Gehversuche mit Bascom und Programmieren überhaupt.
      Es funktioniert alles nur sollen noch ein paar kleine Funktion hinzukommen.
    • Schön nur etwas unvollständig. Wecher AVM? DigIn Byte oder Bit? KeyDig/Ana Pins quer über den Avr verteilt oder Port/pin gleich? Die anderen Dig_In1: (2-x) sehen ähnlich aus? Die waitms 100 erscheinen mir dort etwas unschön. Was wenn Mute gedrückt wird? Dann ist das Trommelfell geplatzt bevor er reagiert
    • Pluto25 wrote:

      Debonce bremst die Main Loop und ist eigentlich nur nötig wenn sie mit "Hyperspeed" durchlaufen wird.
      Darüber könnte man streiten. Auf jeden Fall sind mit Debounce die Tastenabfragen entprellt, was ich vorziehen würde, bei direkter abfrage der Pins nicht.
      Wenns die Main-Loop nicht ausbremsen soll (was ja nur ca. 30ms sind und nur wenn man auch die Taste drückt), kann man auch mit Interrupts arbeiten.

      Für einfache Prpjekte ist Debounce bestimmt nicht die schlechteste Lösung

      Leider bietet Debound nicht die Abfrage von 2 Tasten an. Aber man kann das trotzdem mit Debounce machen.

      Ich verwende dafür eine Sub, mit der alle Tasten auf einmal abgefragt werden.
      Etwa so:

      BASCOM Source Code

      1. Dim keyPressed as Byte
      2. Sub readKeys()
      3. Debounde pinKey1,0,labelKey1,Sub
      4. Debounde pinKey2,0,labelKey2,Sub
      5. Debounde pinKey3,0,labelKey3,Sub
      6. Debounde pinKey4,0,labelKey4,Sub
      7. End Sub
      8. labelKey1:
      9. Set keyPressed.0
      10. Return
      11. labelKey2:
      12. Set keyPressed.1
      13. Return
      14. labelKey3:
      15. Set keyPressed.2
      16. Return
      17. labelKey4:
      18. Set keyPressed.3
      19. Return
      Display All


      Die von Debounce angesprungenen Routinen setzen lediglich ein Flag in keyPressed.
      Für jede Taste wird ein anderes Flag gesetzt. Im Beispiel bit 0 bis 3 für die Tasten Key1 bis Key4.

      Dann braucht man im Programm nur noch die Taste per Funktion abfragen, die eigentlich nur das Flag prüft und entsprechend ein True für gedrückt oder False für nicht gedrückt liefert.
      Etwa so:

      BASCOM Source Code

      1. Function getKey1() as Byte
      2. If keyPressed.0 = True then ' Taste wurde gedrückt
      3. keyPressed = 0 ' alle Flags löschen
      4. getKey1 = True ' Rückmeldung für Aufrufer, dass Taste gedrückt wurde
      5. Else
      6. getKey1 = False ' Rückmeldung für Aufrufer, Taste wurde nicht gedrückt
      7. End If
      8. End Function
      Wichtig dabei ist, wenn True zurück gegeben wird, müssel alle Flags gelöscht werden, sonst kann es passieren, dass beim nächsten Schleifendurchlauf noch auf eine andere Taste, die zuvor mal gedrückt wurde, reagiert wird.

      Und jetzt der Knaktus Kaktus mit der Abfrage für 2 Tasten.

      Wenn 2 Tasten gedrückt wurden während der Abfrage mit readKeys(), sind auch die 2 Flags in keyPressed gesetzt.
      jetzt fragt man einfach die Tastenkombinationen zuerst ab, vor den Einzeltasten. Etwa so:

      BASCOM Source Code

      1. Function getKey1UndKey2() as Byte
      2. If keyPressed.0 = True and keyPressed.1 = True then ' beide Tasten waren gedrückt!
      3. keyPressed = 0 ' alle Flags löschen
      4. getKey1UndKey2 = True ' True an Aufrufer, beide Tasten wurden gedrückt
      5. Else
      6. getKey1UndKey2 = False ' False an Aufrufer
      7. End If
      8. End Function
      Das sollte so eigentlich funktionieren. Probiert habe ich es allerdings nicht mit Tastenkombinationen.
    • So würd's auch gehn

      Source Code

      1. if PwKey = 1 and KeyMute = 1 then
      2. if Adc_gespeichert = 0 then
      3. waitms 50 'nötig da die main loop nur 0,15ms benötigt (Entprellung)
      4. writeeeprom Adc_messwert, Adresse
      5. Adc_gespeichert = 1
      6. end if
      7. else
      8. Adc_gespeichert = 0
      9. end if

      PS Es erspart Dir und dem AVR viel Arbeit nicht jeden Pin einzeln zu konfigurieren sondern Portweise:
      DDRB = &B1000000 (128)
      DDRF =0 (Alle Input) Unnötig da alle standartmäßig Input sind nach dem Einschalten

      PORTF =&B11111111(=$FF = 255) Schaltet alle Pullups ein
      PINF.1=1 bewirkt ein toggeln
    • @Pluto25
      Die Configuration habe ich, wenn möglich, Portweise gemacht. Nur hatte ich das "Glück" fast nie eine kompletten Port mit der selben Einstellung zu haben.

      @Murmel
      Eine komplette Schaltung gibt es nicht. Als Endverstärkter kommen 2 B&O ICE250A Module zum Einsatz. Der DAC ist ein Buffalo IIIse von Twisted Pear Audio und die dazugehörige I/V Umwandlerschaltung habe ich zu 95% aus dem Datenblatt des ES9018 und in SMD mit LME49720 auf selber erstellten PCB aufgebaut. Die Netzteile sind alle Linieargeregelt. Zwei LT3045 regeln die +/- 14,5V und wurden auch nach Datenblatt in SMD gebaut. Für die 2x5V Versorgungen sorgen LM317. Im Vorverstärker wird die Lautstärke über den PGA2320 geregelt welcher von einem LME49720 eingangsseitig und ausgangsseitig gepuffert ist. Gesteuert wird alles von einem Mega 2560 Pro.

      Mir gefallen Motorpotis (sie sind so schön 80/90er), aus diesem Grund habe ich keinen Inkrementalgeber verwendet.

      Wie man sieht, greife ich gern auch mal auf fertige Lösungen zurück, wenn sie meine Ansprüche erfüllen. Man muss das Fahrrad ja nicht immer neu erfinden.
      Files
    • Dein Hardwareaufbau ist wirklich beeindruckend.

      Aber funktioniert denn dein Programm auch korrekt?
      Ich habe da so einige Fehler entdeckt, die da dran zweifeln lassen.

      Auch der Ablauf ist zumindest für mich nicht wirklich logisch.

      Wenn die Firmware im Standby ist, kann nur aufgeweckt werden mit Fernbedienung?
      Der Powerknopf ist dann wirkungslos? Absicht?

      Dann werden nach dem letzten geposteten Code auch die PullUps nicht korrekt gesetzt.
      Und dann machst du Sprünge in einem Unterprogramm mit GoSub in die Hauptschleife?

      Das müsste regelmäßig der Stack überlaufen und die Kiste abstürzen.

      Kannst du mal den aktuellen Code nochmal posten? Vielleicht habe ich ja was altes.
    • @Mitch64

      Hast recht, das war nicht die aktuellste Datei.

      Um ehrlich zu sein, hab ich das Proramm noch nicht an der kompletten Hardware getestet sondern immer nur mit Tastern, LEDs und Tsop34436 RC5 Empfänger an meiner Steuerplatine(siehe Anhang) und damit funktioniert alles inkl. SPI Übertragung.

      Das "Wecken" aus dem Standby funktioniert per RC5 und Taste. Hab es gerade noch mal getestet.

      Der Code wurde so nach und nach immer wieder erweitert und darunter hat die Übersichtlichkeit gelitten.

      An welcher Stelle werden die Pullups nicht richtig gesetzt und welchen Gosub Sprung meinst du?

      Die Stacks und Size sich nur erstmal grob gesetzt und mussen am Ende noch genau bestimmt werden.
      Warum sollten die überlaufen? Weil sie zu klein sind?
      Files
    • Bezüglich der falsch konfigurierten Pins z.B. hier:

      'ungenutzte Pins/Ports

      Config Pinb.4 = Input 'Pin B4 als Eingang
      PinB.4 = 1 ' pullup für Pin B4 einschalten
      Config pinb.5 = Input
      Pinb.5 = 1
      Config pinb.6 = Input
      pinB.6 = 1
      Config portb.7 = Output ' Onboard LED zum Testen
      Portb.7 = 0
      TestLed Alias PortB.7
      Config portc = Input ' Port C als Eingang
      portc = 1 ' pullup für Port B einschalten
      Config PIND.4 = Input
      PinD.4 = 1
      Config PIND.5 = Input
      PinD.5 = 1

      Übrigens brauchst du Inputs nicht zu konfigurieren.
      Nach einem Reset sind alle Pins erst mal als Input!
      Allenfalls den PullUp einschalten.
      Dazu muss man aber auf den Port zugreifen.
      Config PortX.X = Output

      Falsche Gosub's z.B. hier:
      If KeyMute = 1 And Count < 50 Then 'Auswertung des kurzen Tastendrucks
      Pressed_short = Pressed_short + 1 'Zählen des kurzen Tastendrucks
      FlagMute = 0
      Count = 0
      If Norm_PreAmp = 1 Then
      Spi_byte(1) = 0
      Spi_byte(2) = 0
      Spiout Spi_byte(1) , 2
      IceStandBy = 0
      Norm_PreAmp = 0
      DcProt = 0
      Waitms 100
      Gosub PreAmpModeOn
      Else
      Goto Mute
      End If
      End If
      If Count > 150 Then 'Auswertung des langen Tastendrucks
      Pressed_long = Pressed_long + 1 'Zählen des langen Tastendrucks
      FlagMute = 0
      Gosub PreAmpMode
      End If


      Und weiter unten:
      PreAmpMode:
      IceStandBy = 1
      DcProt = 1
      Set Norm_PreAmp
      Goto PreAmpModeOn


      Beide rot markierten Gosub müssten Goto sein. Es wird ja jeweils an den Anfang des Programms gesprungen.

      Wo wird in dem Unterprogramm "StandBy:" die Taste zum Aufwecken getestet/abgefragt?

      Ich kann nachvollziehen, dass dein Code immer weiter wächst und daher unübersichtlicher wird.
      Vermutlich wird da noch einiges mehr rein kommen. Die Unübersichtlichkeit wird also noch weiter steigen!

      Hier empfiehlt sich vielleicht eine Statemachine zu verwenden.
      Das ist übersichtlich und einfach zu erweitern.
    • StandBy:
      PwOn48V = 1
      PWLED = 1
      5V12Von = 1
      PGA5V = 1
      DcProt = 1
      DigIn1 = 1
      DigIn2 = 1
      DigIn3 = 1
      DigIn4 = 1
      DigIn5 = 1
      DigIn6 = 1
      AnaDig = 1
      AnaIn1 = 1
      AnaIn2 = 1
      AnaIn3 = 1
      Phono = 1
      Do
      Getrc5(Addr , Comm)
      If Addr = GeraeteCode Then
      Togglebit = Comm
      Shift Togglebit , Right , 7
      Comm = Comm And &B01111111
      If Comm = PwKeyCode and FlagRc5 = 0 Then
      FlagRc5 = 1
      Togglebitlast = Togglebit
      Start Timer3
      Goto Geht_los
      End If
      If Comm = PwKeyCode and Togglebit <> Togglebitlast and FlagRc5 = 1 Then
      Togglebitlast = Togglebit
      Goto Geht_los
      End If
      End If


      Debounce PwKey , 0 , Geht_los
      Loop
      End

      In der letzten Zeile wird die Taste abgefragt.

      Wann man Pin oder Port nutz habe ich inzwischen verinnerlicht. Die ungenutzten Pins waren der Anfang, daher habe ich den Fehler immer übersehen.
      Beim konfigurieren der benötigen Pins hab ich es ja richtig gemacht.

      Das Thema Statemachine muss ich mir erst mal anschauen.