

Bildbox 1 (klick hier)
Hardware
- 1,69-Zoll-IPS-LCD-Touch-Display WS-30126 (RP 2350)
- USB-A zu USB-C Kabel
Firmware
- CircuitPython 10.0.0
Unser Board ist mit einem kapazitiven 1.69 Zoll Touch-LCD-Display ausgestattet. Auf der Seite 'erste Schritte' habe ich bereits gezeigt, wie man es in Betrieb nimmt. Jetzt geht es um die Nutzung der Touchfunktion. Angesteuert wird der CST816D-Chip mit dem I2C-Bus. Der I2C-Bus ist die serielle Kommunikationsschnittstelle, die über zwei Leitungen (SCL für den Takt und SDA für die Daten) die Kommunikation ermöglicht. Wenn man den Bus scannt, erfährt man, dass er die Adresse 0x15 nutzt. Der CST816D nutzt zusätzlich einen Interrupt Request (IRQ), um eine Datenübertragung anzufordern oder eine Aktion abzuschließen und außerdem ein Reset-Signal (RST).
Über folgende Pins sind diese ansprechbar:
I2C_SDA = board.GP6
I2C_SDL = board.GP7
I2C_IRQ = board.GP21
I2C_RST = board.GP22
Dem Rechnung tragend, habe ich wie schon beim Acc-Sensor einen Treiber für MicroPython als Grundlage verwendet und auf CircuitPython angepasst. Das Ergebnis ist ein Treiber 'my_cst816d.mpy'. Die Bibliothek können Sie als zip-Datei hier herunterladen , entpacken und in den lib-Ordner ihres 'CIRCUITPY'-Laufwerkes kopieren. Beim Entpacken stellen Sie fest, dass sich ein zweiter Treiber 'my_cst816d_r.mpy' in der zip-Datei befindet. Auch den kopieren Sie schon mal mit in den 'lib_Ordner'. Der wird bei der schon erwähnten Orientierung des Displays (USB nach rechts oder USB nach links) gebraucht. Waveshare geht offensichtlich davon aus, dass der USB-Anschluss im Normalfall nach links zeigt.
1. touch.get_point()
Ich zeige zuerst, wie der Sensor durch Antippen genutzt wird. Dazu lege ich auf dem Display vier Rechtecke (mit abgerundeten Ecken) an und zwar: im oberen Bereich, mittleren Bereich, unten links und unten rechts (Zeilen 40 bis 55). Die Füllfarbe ist gün. Tippt man nun auf eines der Rechtecke, so ändert es die Farbe in rot.


Sollte es zumindest. Aber wie man sieht, sind nach dem Antippen des oberen Rechtecks im linken Bild oben und unten, sowie rechts und links vertauscht. Da liegt daran, dass Waveshare, wie schon erwähnt, davon ausgeht, dass der USB-Anschluss nach links zeigt.
1 # SPDX-FileCopyrightText : 2025 Detlef Gebhardt, written for CircuitPython 10.0.0 2 # SPDX-FileCopyrightText : Copyright (c) 2025 Detlef Gebhardt 3 # SPDX-Filename : multi-uhr-touch for Waveshare round 1.28 touch LCD 4 # SPDX-License-Identifier: dgebhardt.de 5 import time 6 import board 7 import busio 8 import displayio 9 import terminalio 10 import fourwire 11 from adafruit_st7789 import ST7789 12 import my_cst816d 13 from adafruit_display_shapes.roundrect import RoundRect 14 from adafruit_display_shapes.circle import Circle 15 16 touch = my_cst816d.Touch_CST816D(force_high_before_i2c=True) 17 18 # Release any resources currently in use for the displays 19 displayio.release_displays() 20 cs=board.GP9 21 dc=board.GP8 22 sck=board.GP10 23 mosi=board.GP11 24 reset=board.GP13 25 bl=board.GP25 26 # Release any resources currently in use for the displays 27 displayio.release_displays() 28 spi = busio.SPI(sck, mosi) 29 display_bus = fourwire.FourWire(spi, command=dc, chip_select=cs, reset=reset) 30 display = ST7789(display_bus, rotation=0, width=240, height=320, backlight_pin=bl, rowstart=20, colstart=0) 31 display.brightness = 1 32 # Make the display context 33 main = displayio.Group() 34 display.root_group = main 35 36 # Make the display context 37 main_screen = displayio.Group() 38 display.root_group = main_screen 39 40 # oberer Bereich 41 # x > 20 and x < 220 and y > 0 and y < 90 42 roundrect_o= RoundRect(20,0,200,90,10,fill=0x009900, outline=0x00ff00) 43 main_screen.append(roundrect_o) 44 # mittlerer Bereich 45 # x > 40 and x < 200 and y > 110 and y < 170 46 roundrect_f= RoundRect(40,115,160,40,20,fill=0x009900, outline=0x00ff00) 47 main_screen.append(roundrect_f) 48 # unten links 49 # x > 25 and x < 105 and y > 180 and y < 270 50 roundrect_ul= RoundRect(25,180,80,90,10,fill=0x009900, outline=0x00ff00) 51 main_screen.append(roundrect_ul) 52 # unten rechts 53 # x > 135 and x < 215 and y > 180 and y < 270 54 roundrect_ur= RoundRect(135,180,80,90,10,fill=0x009900, outline=0x00ff00) 55 main_screen.append(roundrect_ur) 56 57 while True: 58 # Touchberuehrung registrieren 59 if touch.touched() : 60 x, y = touch.get_point() 61 # oberer Bereich auswaehlen 62 if x > 20 and x < 220 and y > 0 and y < 90: 63 roundrect_o.fill = 0xff0000 64 roundrect_f.fill = 0x009900 65 roundrect_ul.fill = 0x009900 66 roundrect_ur.fill = 0x009900 67 # mittleren Bereich auswaehlen 68 if x > 40 and x < 200 and y > 110 and y < 170: 69 roundrect_f.fill = 0xff0000 70 roundrect_o.fill = 0x009900 71 roundrect_ul.fill = 0x009900 72 roundrect_ur.fill = 0x009900 73 # unten links auswaehlen 74 if x > 25 and x < 105 and y > 180 and y < 270: 75 roundrect_o.fill = 0x009900 76 roundrect_f.fill = 0x009900 77 roundrect_ul.fill = 0xff0000 78 roundrect_ur.fill = 0x009900 79 # unten rechts auswaehlen 80 if x > 135 and x < 215 and y > 180 and y < 270: 81 roundrect_o.fill = 0x009900 82 roundrect_f.fill = 0x009900 83 roundrect_ul.fill = 0x009900 84 roundrect_ur.fill = 0xff0000
Ich möchte aber wegen der späteren Uhranwendung den USB-Anschluss rechts haben. Deshalb habe ich den Treiber 'my_cst816d_r.mpy' vorgesehen.
Mit einer kleinen Änderung kann dann alles so bleiben, wie ursprünglich im oberen Kasten angegeben. Die Änderungen sind:
Zeile 12: import my_cst816d_r
Zeile 16: touch = my_cst816d_r.Touch_CST816D(force_high_before_i2c=True)
zwischen Zeile 60 und Zeile 61 neu einfügen
Zeile 61 neu: x = 240 - x
Zeile 62 neu: y = 270 - y
Die weiteren Zeilen verschieben sich dadurch um zwei.
2. touch.get_gesture()
Es folgen die Gesten. Der Treiber erkennt z.Z. die Gesten:
"UP" : nach oben
"DOWN" : nach unten
"LEFT" : nach links
"RIGHT" : nach rechts
"LONG_PRESS" : lange gedrückt
"DOUBLE_CLICK" : Doppelklick
Ich rufe die Gesten in einer Funktion nach einem Klick auf. Dadurch führt der Sensor zunächst einen 'Reset' aus und holt
die x- und y-Koordinate für den Anfang der Bewegung. Nun wartet 'er' in einer Schleife, ob eine Bewegung erfolgt. (
gesture = touch.get_gesture()). Wenn ja, wird diese ausgewertet, wie z.B.: if gesture == "RIGHT".
(Siehe Kasten).
x, y = touch.get_point() x = 225 - x y = 265 - y while True: gesture = touch.get_gesture() if gesture is not None: if gesture == "RIGHT": #(Punkt nach rechts) x += 5 if x > 225: x = 225
Zum Testen habe ich das Beispiel von oben etwas erweitert. Im Startscreen kann auf die Rechteckfelder getippt werden.
Dabei ändert sich jetzt nicht die Farbe, sondern der Bildschirm wird kurz abgedunkelt. Dies dient der Kontrolle, ob die
Berührung erfasst wurde. Beim Tippen auf das obere Rechteck wird jetzt eine Funktion oben_go()
aufgerufen und ein zweiter Screen mit braunem Hintergrund angezeigt. Dort befindet sich ein gelber Punkt.

Wischen Sie nun über den Bildschirm nach oben, unten, rechts oder links, so bewegt sich der Punkt in diese Richtung bis
der Bildschirmrand erreicht ist. Das können Sie beliebig lange fortsetzen, oder die Bewegung durch einen kurzen Klick
auf das Display beenden. Mit 'LONG_PRESS' kommen Sie aus der Funktion zurück in den Startscreen. Damit haben Sie sicher
sofort Ideen, wie Sie daraus etwas Sinnvolles machen können. Im unteren Kasten ist der komplette Quellcode zum angegebenen
Beispiel. Kopieren Sie ihn in die Thonny-IDE und probieren es aus.


1 # SPDX-FileCopyrightText : 2025 Detlef Gebhardt, written for CircuitPython 10.0.0 2 # SPDX-FileCopyrightText : Copyright (c) 2025 Detlef Gebhardt 3 # SPDX-License-Identifier: dgebhardt.de 4 import time 5 import board 6 import busio 7 import displayio 8 import terminalio 9 import fourwire 10 from adafruit_st7789 import ST7789 11 import my_cst816d_r 12 from adafruit_display_shapes.roundrect import RoundRect 13 from adafruit_display_shapes.circle import Circle 14 from adafruit_display_text import label 15 16 touch = my_cst816d_r.Touch_CST816D(force_high_before_i2c=True) 17 18 # Release any resources currently in use for the displays 19 displayio.release_displays() 20 cs=board.GP9 21 dc=board.GP8 22 sck=board.GP10 23 mosi=board.GP11 24 reset=board.GP13 25 bl=board.GP25 26 # Release any resources currently in use for the displays 27 displayio.release_displays() 28 spi = busio.SPI(sck, mosi) 29 display_bus = fourwire.FourWire(spi, command=dc, chip_select=cs, reset=reset) 30 display = ST7789(display_bus, rotation=0, width=240, height=320, backlight_pin=bl, rowstart=20, colstart=0) 31 display.brightness = 1 32 # Make the display context 33 main = displayio.Group() 34 display.root_group = main 35 36 # Make the display context 37 main_screen = displayio.Group() 38 group_screen = displayio.Group() 39 display.root_group = main_screen 40 41 # oberer Bereich 42 # x > 20 and x < 220 and y > 0 and y < 90 43 roundrect_o= RoundRect(20,0,200,90,10,fill=0x009900, outline=0x00ff00) 44 main_screen.append(roundrect_o) 45 # mittlerer bereich 46 # x > 40 and x < 200 and y > 110 and y < 170 47 roundrect_f= RoundRect(40,115,160,40,20,fill=0x009900, outline=0x00ff00) 48 main_screen.append(roundrect_f) 49 # unten links 50 # x > 25 and x < 105 and y > 180 and y < 270 51 roundrect_ul= RoundRect(25,180,80,90,10,fill=0x009900, outline=0x00ff00) 52 main_screen.append(roundrect_ul) 53 # unten rechts 54 # x > 135 and x < 215 and y > 180 and y < 270 55 roundrect_ur= RoundRect(135,180,80,90,10,fill=0x009900, outline=0x00ff00) 56 main_screen.append(roundrect_ur) 57 58 # the label for the function 59 label_f = label.Label(font=terminalio.FONT, text="click\nhere", scale=2, color=0xffffff, line_spacing=1) 60 label_f.anchor_point = (0, 0) 61 label_f.anchored_position = (90, 15) 62 main_screen.append(label_f) 63 64 background_func = displayio.Bitmap(240, 280, 1) 65 pal_color = displayio.Palette(3) 66 pal_color[0] = 0x800000 67 group_screen.append(displayio.TileGrid(background_func, pixel_shader=pal_color)) 68 69 circle = Circle(120, 90, 8, fill=0xffff00, outline=None) 70 group_screen.append(circle) 71 72 def oben_go(): 73 x, y = touch.get_point() 74 x = 225 - x 75 y = 265 - y 76 while True: 77 gesture = touch.get_gesture() 78 if gesture is not None: 79 if gesture == "RIGHT": #(Punkt nach rechts) 80 x += 5 81 if x > 225: 82 x = 225 83 if gesture == "LEFT": #(Punkt nach links) 84 x -= 5 85 if x < 0: 86 x = 10 87 if gesture == "UP": #(Punkt nach oben) 88 y -= 5 89 if y < 0: 90 y = 0 91 if gesture == "DOWN": #(Punkt nach unten) 92 y += 5 93 if y > 270: 94 y = 265 95 circle.x = x 96 circle.y = y 97 # oben_go verlassen 98 if gesture == "LONG_PRESS" or gesture == "DOUBLE_CLICK": 99 display.root_group = main_screen 100 display.refresh() 101 break 102 gesture = None 103 time.sleep(.2) 104 105 while True: 106 # Touchberuehrung registrieren 107 if touch.touched() : 108 x, y = touch.get_point() 109 x = 240 - x 110 y = 270 - y 111 # oberer Bereich auswaehlen 112 if x > 20 and x < 220 and y > 0 and y < 90: 113 display.brightness = 0.01 114 time.sleep(0.2) 115 display.brightness = 1 116 display.root_group = group_screen 117 oben_go() 118 time.sleep(0.5) 119 # mittleren Bereich auswaehlen 120 if x > 40 and x < 200 and y > 110 and y < 170: 121 display.brightness = 0.01 122 time.sleep(0.2) 123 display.brightness = 1 124 # unten links auswaehlen 125 if x > 25 and x < 105 and y > 180 and y < 270: 126 display.brightness = 0.01 127 time.sleep(0.2) 128 display.brightness = 1 129 # unten rechts auswaehlen 130 if x > 135 and x < 215 and y > 180 and y < 270: 131 display.brightness = 0.01 132 time.sleep(0.2) 133 display.brightness = 1
Zum Abschluss noch einige Bemerkungen. Die Anpassung des Treibers CST816D ist noch nicht ideal. Sie war durch den von Raspberry
dokumentierten Hardware-Bug E9 beim RP2350 besonders schwierig. Der I2C-Bus nutzt genau die betroffenen GPIO-Pins. Aufgrund des Bugs
bleibt der Bus häufig im Zustand 'Hight' und ist dann nicht mehr ansprechbar. Um das zu umgehen führe ich nach jedem Zugriff
einen 'Reset' durch und zwinge die Pins SDA und SCL in den Zustand 'Low'. Dadurch ist immer eine kurze Pause notwendig. Bemerkbar wird
das für Sie z.B. in Zeile 103. Wenn Sie die Pause hier weglassen, bekommen Sie die Fehlermeldung 'Device not
responding at 0x15'. Mit diesem Wissen im Hintergrund habe ich eine Anwendung für eine Digitaluhr mit 'Stellfunktion',
'Stoppuhr' und 'Timer' programmiert die Sie in der nächsten Anleitung finden.
Viel Spass und Erfolg beim Ausprobieren.
Viel Spass und Erfolg beim Ausprobieren.