Joystick + LED - PicoBoy Color


technische Daten wie beim RPi Pico
MC RP2040 - 1,69 Zoll Farbdisplay mit 240 x 280 Pixeln

Projekte und Anleitung in CircuitPython 9.x.x



Bildbox 1 (klick hier)

Es folgt die Nutzung des Joysticks und der beiden Tasten.

Los gehts

Joystick:
Up - GPIO 4
DOWN - GPIO 2
LEFT - GPIO 3
RIGHT - GPIO 1
CENTER - GPIO 0


Tasten:
Taste 1 - GPIO 27
Taste 2 - GPIO 28


In CircuitPython kann eine Tasteneingabe entweder über digitalio.Pull.UP oder digitalio.Pull.UP erfolgen. Wenn das Board über einen internen Pull-up-Widerstand verfügt, wird mit Pull.UP der Eingang so eingestellt, dass er einen hohen digitalen Logikpegel liest, wenn nichts anderes angeschlossen ist. Verfügt das Board über einen internen Pull-down-Widerstand, kann der Eingang einen niedrigen digitalen Logikpegel lesen, wenn nichts anderes angeschlossen ist. Sind keine Pull-Up- oder Pull-Down-Widerstände vorhanden, liest der Eingang den mit ihm verbundenen Logikpegel und "schwebt" auf zufällige hohe oder niedrige Werte, wenn nichts angeschlossen ist!
Der PicoBoy - Color verfügt über interne Pull-Up-Widerstände. Deshalb sieht ein erster Button-Test so aus:

  
  

1  import time
2  import board
3  import digitalio
4
5  led = digitalio.DigitalInOut(board.GP14)
6  led.direction = digitalio.Direction.OUTPUT
7  led.value = False
8
9  button_1 = digitalio.DigitalInOut(board.GP0)
10 button_1.switch_to_input(pull=digitalio.Pull.UP)
11
12 while True:
13     # Joystick 'OK' clicken
14     if button_1.value == False:
15         led.value = True
16         print("schalte LED an")
17         time.sleep(0.3)
18         led.value = False
  

Nebenher ist gleich noch die Nutzung einer der drei LED's zu sehen. Die sind an folgende GPIO's angeschlossen

LED's:
LED ROT - GPIO 14
LED GELD - GPIO 13
LED GRÜn - GPIO 12


Zurück zu den Tasten. Der Joystick bietet ja fünf verschiedene und die beiden Tasten noch einmal zwei Eingabemöglichkeiten. Deshalb bietet es sich hier an, gleich die 'keypad' Bibliothek zu benutzen. Die ist standardmäßig im CircuitPython enthalten und braucht nicht aus dem Bundle mit den Bibliotheken kopiert werden. Probieren Sie das Beispiel aus dem unteren Kasten:

  
  

1   import board
2   import displayio
3   from fourwire import FourWire
4   from adafruit_display_text import label
5   from adafruit_display_shapes.rect import Rect
6   from adafruit_display_shapes.circle import Circle
7   import terminalio
8   import digitalio
9   import busio
10  from adafruit_st7789 import ST7789
11  import keypad
12
13  dc=board.GP8
14  reset=board.GP9
15  cs=board.GP10
16  sck=board.GP18
17  mosi=board.GP19
18  bl=board.GP26
19  # Release any resources currently in use for the displays
20  displayio.release_displays()
21  spi = busio.SPI(sck, mosi)
22  display_bus = FourWire(spi, command=dc, chip_select=cs, reset=reset)
23  display = ST7789(display_bus, rotation=0, width=240, height=280, backlight_pin=bl, rowstart=20, colstart=0)
24  # Make the display context
25  main = displayio.Group()
26  display.root_group = main
27
28  K_UP = 0x01     # GP4  dez. 1
29  K_DOWN = 0x02   # GP2  dez. 2
30  K_LEFT = 0x04   # GP3  dez. 4
31  K_RIGHT = 0x08  # GP1  dez. 8
32  K_CENTER = 0x10 # GP0  dez. 16
33  K_A = 0x20      # GP27 dez. 32
34  K_B = 0x40      # GP28 dez. 64
35
36  class _Buttons:
37      def __init__(self):
38          self.keys = keypad.Keys((board.GP4, board.GP2, board.GP3, board.GP1, board.GP0, board.GP27, board.GP28),
39                                  value_when_pressed=False, interval=0.05)
40          self.last_state = 0
41          self.event = keypad.Event(0, False)
42          self.last_z_press = None
43
44      def get_pressed(self):
45          buttons = self.last_state
46          events = self.keys.events
47          while events:
48              if events.get_into(self.event):
49                  bit = 1 << self.event.key_number
50                  if self.event.pressed:
51                      buttons |= bit
52                      self.last_state |= bit
53                  else:
54                      self.last_state &= ~bit
55          return buttons
56  buttons = _Buttons()
57
58  # Hintergrundbild
59  color_bitmap = displayio.Bitmap(display.width, display.height, 1)
60  color_palette = displayio.Palette(1)
61  color_palette[0] = 0x660000
62  bg_sprite = displayio.TileGrid(color_bitmap, pixel_shader=color_palette, x=0, y=0)
63  main.append(bg_sprite)
64
65  # Überschrift
66  text_label = label.Label(terminalio.FONT, text="   Buttontest\npress any button", color=0xffff00)
67  text_group = displayio.Group(scale=2, x=30, y=25)
68  text_group.append(text_label)  # Subgroup for text scaling
69  main.append(text_group)
70
71  # Block 1
72  rect1 = Rect(55, 110, 30, 30, fill=0x666666)
73  main.append(rect1)
74  rect2 = Rect(20, 150, 30, 30, fill=0x666666)
75  main.append(rect2)
76  rect3 = Rect(90, 150, 30, 30, fill=0x666666)
77  main.append(rect3)
78  rect4 = Rect(55, 190, 30, 30, fill=0x666666)
79  main.append(rect4)
80  circle1 = Circle(70, 165, 15, fill=0x666666, outline=None)
81  main.append(circle1)
82  circle2 = Circle(150, 205, 15, fill=0x666666, outline=None)
83  main.append(circle2)
84  circle3 = Circle(200, 205, 15, fill=0x666666, outline=None)
85  main.append(circle3)
86
87  debounce = False
88
89  while True:
90      cur_btn_vals = buttons.get_pressed()
91      cur_up = cur_btn_vals & K_UP
92      cur_left = cur_btn_vals & K_LEFT
93      cur_right = cur_btn_vals & K_RIGHT
94      cur_down = cur_btn_vals &  K_DOWN
95      cur_center = cur_btn_vals & K_CENTER
96      cur_a = cur_btn_vals & K_A
97      cur_b = cur_btn_vals & K_B
98      # up
99      if cur_up and not debounce:
100         debounce = True
101         rect1.fill = 0xffff00
102     # down
103     if cur_down and not debounce:
104         debounce = True
105         rect4.fill = 0xffff00
106     # left
107     if cur_left and not debounce:
108         debounce = True
109         rect2.fill = 0xffff00
110     # right
111     if cur_right and not debounce:
112         debounce = True
113         rect3.fill = 0xffff00
114     # center
115     if cur_center and not debounce:
116         debounce = True
117         circle1.fill = 0xffff00
118     # button_a
119     if cur_a and not debounce:
120         debounce = True
121         circle2.fill = 0xffff00
122     # button_b
123     if cur_b and not debounce:
124         debounce = True
125         circle3.fill = 0xffff00
126     if cur_btn_vals == 0:
127         debounce = False
128         rect1.fill = 0x666666
129         rect2.fill = 0x666666
130         rect3.fill = 0x666666
131         rect4.fill = 0x666666
132         circle1.fill = 0x666666
133         circle2.fill = 0x666666
134         circle3.fill = 0x666666
  

Nachdem das Display eingerichtet ist, werden die Namen und die Hexwerte für die Verwendung in der 'Keypad-Liste' festgelegt (Zeilen 28 - 34). Ab Zeile 36 wird eine Klasse definiert mit den GPIO's der Tasten und der Funktion, ob und welche Taste gedrückt wurde.

Die Zeilen 58 bis 85 dienen der Darstellung auf dem Display, worauf an dieser Stelle nicht eingegangen wird.

Zeile 87 definiert die Variable 'debounce' (dt. entprellen) und setzt sie auf 'False'. In der 'while-Schleife' wird dann zuerst bei jedem Durchlauf geprüft, ob eine Taste gedrückt wurde. Damit man sich (v.a. bei sehr vielen Tasten) nicht die ganzen Hex.werte merken muss, werden dafür noch Namen definiert (Zeilen 91 - 97). Wenn eine entsprechende Taste gedrückt wurde, wird 'debounce' auf 'True' gesetzt und das Symbol farblich auf dem Display kenntlich gemacht. Erst wenn keine Taste mehr gedrückt wird (Zeile 126), wird 'debounce wieder auf 'False' gesetzt und alle Symbole bekommen wieder die Ausgangsfarbe.
Diese Methode des "Entprellens" kommt ohne Programmunterbrechung durch 'time.sleep(xx)' aus und ist deshalb bei zeitkritischen Anwendungen vorzuziehen. Die Zeilen 98 - 125) fragen alle 7 Eingabemöglichkeiten ab und können in angepasster Form in vielen anderen Anwendungen eingesetzt werden.



Viel Spass und Erfolg beim Ausprobieren.