Ausprobiert Teil 3

Rundes 1.28-Zoll-IPS-LCD-Display 240 x 240 Pixel
- RP2040, 6-Achsen-Sensor - Waveshare 22668
Anleitung für die Firmware CircuitPython



Hardware

- Rundes 1,28-Zoll-IPS-LCD-Display
- RP Pico 2040 (inclusive)
- USB-A zu USB-C Kabel


Nachdem wir den mathematischen Teil hinter uns haben, realisieren wir in dieser Folge eine erste (einfache) Uhrfunktion auf dem runden Display. Dabei nutzen wir aus der zweiten Folge die Darstellung von Kreisen für die Hintergrundgestaltung und drei sich im Kreis bewegende Punkte für die Darstellung der Sekunden, Minuten und Stunden. In der Mitte werden die Stunden und Minuten digital angezeigt.

Los gehts

Kopieren Sie den Code aus dem unteren Kasten ins Thonny und schauen sich die hinzugekommenen Teile an. Zunächst wird in Zeile 15 das Modul zum Zeichnen von Linien importiert. (Bei Ihnen ist evtl. ganz oben eine Leerzeile, die Sie löschen). Damit stellen wir kurze Striche zur Veranschaulichung der Minuten und Stunden dar. Dies geschieht in den Zeilen 43 bis 58. Dazwischen ordnen wir gelbe Ringe an. Wenn Sie das Programm starten, können Sie den Displayaufbau gut beobachten. Die Ausgabe des freien Speichers im Terminal zeigt, dass gar nicht mehr viel übrig ist. In Zeile 76 steht jetzt 'time.sleep(1)'. Damit wird vorläufig der Sekundentakt erzeugt, während der kleine weisse Punkt im äußeren Ring läuft.

  
  

1  # SPDX-FileCopyrightText: 2023 Detlef Gebhardt, written for CircuitPython
2  # SPDX-FileCopyrightText: Copyright (c) 2023 Detlef Gebhardt
3  #
4  # SPDX-License-Identifier: GEBMEDIA
5  import time
6  import gc
7  import board
8  import busio
9  from busio import I2C
10 import displayio
11 import terminalio
12 import gc9a01
13 from adafruit_display_text import label
14 from adafruit_display_shapes.circle import Circle
15 from adafruit_display_shapes.line import Line
16 import random
17 import math
18
19 # Release any resources currently in use for the displays
20 displayio.release_displays()
21
22 # Make the displayio SPI bus and the GC9A01 display
23 spi = busio.SPI(clock=board.LCD_CLK, MOSI=board.LCD_DIN)
24 display_bus = displayio.FourWire(spi, command=board.LCD_DC, chip_select=board.LCD_CS, reset=board.LCD_RST)
25 display = gc9a01.GC9A01(display_bus, width=240, height=240, rotation=90, backlight_pin=board.LCD_BL)
26
27 # Make the display context
28 group1 = displayio.Group()
29 display.show(group1)
30
31 width = 240
32 height = 240
33 xpos = 120
34 ypos = 120
35 radius = 120
36 i = 0
37
38 # Make some circles and lines:
39 circle = Circle(xpos, ypos, 120, fill=0xff0000, outline=0x000000)
40 group1.append(circle)
41 circle = Circle(xpos, ypos, 115, fill=0x000000, outline=0x000000)
42 group1.append(circle)
43 # Sekundenstriche
44 for i in range(60):
45     line = Line(xpos+int(105*math.cos(i*math.pi/30)),ypos-int(105*math.sin(i*math.pi/30)),
46                 xpos+int(110*math.cos(i*math.pi/30)), ypos-int(110*math.sin(i*math.pi/30)),0xffffff)
47     group1.append(line)
48     display.show(group1)
49 circle = Circle(xpos, ypos, 100, fill=0xffff00, outline=0xffff00)
50 group1.append(circle)
51 circle = Circle(xpos, ypos, 95, fill=0x000000, outline=0x000000)
52 group1.append(circle)
53 # Stundenstriche
54 for i in range(12):
55     line = Line(xpos+int(95*math.cos(i*math.pi/6)),ypos-int(95*math.sin(i*math.pi/6)),
56                 xpos+int(90*math.cos(i*math.pi/6)), ypos-int(90*math.sin(i*math.pi/6)),0xffffff)
57     group1.append(line)
58     display.show(group1)
59 circle = Circle(xpos, ypos, 80, fill=0xffff00, outline=0xffff00)
60 group1.append(circle)
61 circle = Circle(xpos, ypos, 75, fill=0x000000, outline=0x000000)
62 group1.append(circle)
63
64 circle = Circle(xpos, ypos, 5, fill=0xffffff, outline=0x000000)
65 group1.append(circle)
66
67 while True:
68     for i in range (60):
69         delta_x = xpos_neu - xpos
70         xpos = xpos_neu
71         ypos_neu = int(height/2 + 108*math.sin((i -15)*math.pi/30))
72         delta_y = ypos_neu - ypos
73         ypos = ypos_neu
74         circle.x = circle.x + delta_x
75         circle.y = circle.y + delta_y
76         time.sleep(1)
77         print(gc.mem_free())
  

Im nächsten Schritt brauchen wir eine Uhrzeit. Dazu nutzen wir, solange die Uhr am PC angeschlossen ist time.localtime() und definieren hour, minute, second als Variable für die Stunden, Minuten und Sekunden. Diese Ergänzungen finden Sie im unteren Kasten ab Zeile 67. In den Zeilen 75 bis 80 werden noch die Minuten- und Stundenpunkte festgelegt. Die 'while'-Schleife beginnt jetzt in Zeile 82. Kopieren Sie den Code und dann sehen wir uns die Veränderungen in der Schleife an.

  
  

1   # SPDX-FileCopyrightText: 2023 Detlef Gebhardt, written for CircuitPython
2   # SPDX-FileCopyrightText: Copyright (c) 2023 Detlef Gebhardt
3   #
4   # SPDX-License-Identifier: GEBMEDIA
5   import time
6   import gc
7   import board
8   import busio
9   from busio import I2C
10  import displayio
11  import terminalio
12  import gc9a01
13  from adafruit_display_text import label
14  from adafruit_display_shapes.circle import Circle
15  from adafruit_display_shapes.line import Line
16  import random
17  import math
18
19  # Release any resources currently in use for the displays
20  displayio.release_displays()
21
22  # Make the displayio SPI bus and the GC9A01 display
23  spi = busio.SPI(clock=board.LCD_CLK, MOSI=board.LCD_DIN)
24  display_bus = displayio.FourWire(spi, command=board.LCD_DC, chip_select=board.LCD_CS, reset=board.LCD_RST)
25  display = gc9a01.GC9A01(display_bus, width=240, height=240, rotation=90, backlight_pin=board.LCD_BL)
26
27  # Make the display context
28  group1 = displayio.Group()
29  display.show(group1)
30
31  width = 240
32  height = 240
33  xpos = 120
34  ypos = 120
35  radius = 120
36  i = 0
37
38  # Make some circles and lines:
39  circle = Circle(xpos, ypos, 120, fill=0xff0000, outline=0x000000)
40  group1.append(circle)
41  circle = Circle(xpos, ypos, 115, fill=0x000000, outline=0x000000)
42  group1.append(circle)
43  # Minutenstriche
44  for i in range(60):
45      line = Line(xpos+int(105*math.cos(i*math.pi/30)),ypos-int(105*math.sin(i*math.pi/30)),
46                  xpos+int(110*math.cos(i*math.pi/30)), ypos-int(110*math.sin(i*math.pi/30)),0xffffff)
47      group1.append(line)
48      display.show(group1)
49  circle = Circle(xpos, ypos, 100, fill=0xffff00, outline=0xffff00)
50  group1.append(circle)
51  circle = Circle(xpos, ypos, 95, fill=0x000000, outline=0x000000)
52  group1.append(circle)
53  # Stundenstriche
54  for i in range(12):
55      line = Line(xpos+int(95*math.cos(i*math.pi/6)),ypos-int(95*math.sin(i*math.pi/6)),
56                  xpos+int(90*math.cos(i*math.pi/6)), ypos-int(90*math.sin(i*math.pi/6)),0xffffff)
57      group1.append(line)
58      display.show(group1)
59  circle = Circle(xpos, ypos, 80, fill=0xffff00, outline=0xffff00)
60  group1.append(circle)
61  circle = Circle(xpos, ypos, 75, fill=0x000000, outline=0x000000)
62  group1.append(circle)
63
64  circle = Circle(xpos, ypos, 5, fill=0xffffff, outline=0x000000)
65  group1.append(circle)
66
67  current_time = time.localtime()
68  hour = current_time[3]
69  minute = current_time[4]
70  second = current_time[5]
71  xpos_min = 120
72  ypos_min = 88
73  xpos_hour = 120
74  ypos_hour = 68
75  # Minutenpunkt in grün
76  circle_m = Circle(xpos_min,ypos_min, 5, fill=0x00ffff, outline=0x00ffff)
77  group1.append(circle_m)
78  # Stundenpunkt in rot
79  circle_h = Circle(xpos_hour, ypos_hour, 5, fill=0xff0000, outline=0xff0000)
80  group1.append(circle_h)
81
82  while True:
83      # minute setzen
84      xpos_min_neu = int(width/2 + 88*math.cos((minute-15)*math.pi/30))
85      delta_min_x = xpos_min_neu - xpos_min
86      xpos_min = xpos_min_neu
87      ypos_min_neu = int(height/2 + 88*math.sin((minute-15)*math.pi/30))
88      delta_min_y = ypos_min_neu - ypos_min
89      ypos_min = ypos_min_neu
90      circle_m.x = circle_m.x + delta_min_x
91      circle_m.y = circle_m.y + delta_min_y
92      gc.collect()
93      # hour
94      xpos_hour_neu = int(width/2 + int(68*math.cos((hour)*math.pi/6 + minute/2*math.pi/180 - math.pi/2)))
95      delta_hour_x = xpos_hour_neu - xpos_hour
96      xpos_hour = xpos_hour_neu
97      ypos_hour_neu = int(height/2 + int(68*math.sin((hour)*math.pi/6 + minute/2*math.pi/180 - math.pi/2)))
98      delta_hour_y = ypos_hour_neu - ypos_hour
99      ypos_hour = ypos_hour_neu
100      circle_h.x = circle_h.x + delta_hour_x
101     circle_h.y = circle_h.y + delta_hour_y
102     for i in range (60):
103         second *= 1
104         xpos_neu = int(width/2 + 108*math.cos((i -15)*math.pi/30))
145         delta_x = xpos_neu - xpos
106         xpos = xpos_neu
107         ypos_neu = int(height/2 + 108*math.sin((i -15)*math.pi/30))
108         delta_y = ypos_neu - ypos
109         ypos = ypos_neu
110         circle.x = circle.x + delta_x
111         circle.y = circle.y + delta_y
112         time.sleep(1)
113         gc.collect()
114         print(gc.mem_free())
115     minute += 1
116     second = 0
117     if minute == 60:
118         minute = 0
119         hour += 1
120         if hour == 24:
121             hour = 0
  

Mathematisch kommt es jetzt auf die exakte Berechnung der Positionen der Minuten- und Stundenpunkte an.

Minuten: Da eine Stunde 60 Minuten hat und der Zeiger dabei 360 Grad zurücklegt, entspricht 1 Minute 360 / 60 = 6 Grad (also pi / 30). Für die Berechnung ergibt sich daraus:
xpos_min_neu = int(width/2 + 88*math.cos((minute-15)*math.pi/30))
Die 88 steht für den Radius und die -15 wegen der Displaydrehung um 90 Grad (also 15 Minuten). Analog gilt das für die y-Position.
ypos_min_neu = int(height/2 + 88*math.sin((minute-15)*math.pi/30))
Aus diesen neuen Positionen und den alten Positionen wird die Differenz 'delta' bestimmt und in den Zeilen 90, 91 an den Kreis übergeben. So wird der Minutenpunkt in den Zeilen 83 bis 91 aktualisiert.

Stunden: Für den Stundenpunkt ist das Ganze noch etwas aufwendiger, da sich der Stundenzeiger während einer Stunde kontinuierlich mitbewegt. Grundsätzlich gilt: 12 Stunden sind 360 Grad. Also 360 / 12 = 30 Grad (also pi / 6). Für die Berechnung ergibt sich daraus:
xpos_hour_neu = int(width/2 + int(68*math.cos((hour)*math.pi/6 + minute/2*math.pi/180 - math.pi/2)))
und
ypos_hour_neu = int(height/2 + int(68*math.sin((hour)*math.pi/6 + minute/2*math.pi/180 - math.pi/2)))
Die 68 steht für den Radius und die -pi/2 für die Displaydrehung. Der übrige Teil des Ausdrucks sorgt dafür, dass sich der Stundenzeiger in Abhängikeit von den Minuten mitbewegt. So wird der Stundenpunkt von Zeile 93 bis 101 aktualisiert.

In den Zeilen 102 bis 114 wird der Sekundenpunkt wie gehabt gesetzt. Die Zeilen 115 bis 121 sorgen für das weiterzählen der Minuten und Stunden, solange keine andere Methode dafür gewählt wird. Auf die Ganggenauigkeit kommt es im Augenblick noch gar nicht an.

Mit ein paar Ergänzungen fügen wir dem Programm noch eine digitale Anzeige, wie auf dem Bild ganz oben, hinzu. Dazu wird ein Rechteck mit abgerundeten Ecken 'roundrect' und ein 'label', welches die Zeit als String ausgibt, angelegt. Jetzt neu in den Zeilen 84 bis 96. Auch in der 'while'-Schleife sind die Zeilen 99 bis 107 jetzt neu. Die nachfolgenden Zeilen verschieben sich dadurch nach hinten. Zur besseren Übersicht gebe ich den geänderten Code noch einmal komplett zum kopieren an.

  
  

1   # SPDX-FileCopyrightText: 2023 Detlef Gebhardt, written for CircuitPython
2   # SPDX-FileCopyrightText: Copyright (c) 2023 Detlef Gebhardt
3   #
4   # SPDX-License-Identifier: GEBMEDIA
5   import time
6   import gc
7   import board
8   import busio
9   from busio import I2C
10  import displayio
11  import terminalio
12  import gc9a01
13  from adafruit_display_text import label
14  from adafruit_display_shapes.circle import Circle
15  from adafruit_display_shapes.line import Line
16  from adafruit_display_shapes.roundrect import RoundRect
17  import random
18  import math
19
20  # Release any resources currently in use for the displays
21  displayio.release_displays()
22
23  # Make the displayio SPI bus and the GC9A01 display
24  spi = busio.SPI(clock=board.LCD_CLK, MOSI=board.LCD_DIN)
25  display_bus = displayio.FourWire(spi, command=board.LCD_DC, chip_select=board.LCD_CS, reset=board.LCD_RST)
26  display = gc9a01.GC9A01(display_bus, width=240, height=240, rotation=90, backlight_pin=board.LCD_BL)
27
28  # Make the display context
29  group1 = displayio.Group()
30  display.show(group1)
31
32  width = 240
33  height = 240
34  xpos = 120
35  ypos = 120
36  radius = 120
37  i = 0
38
39  # Make some circles and lines:
40  circle = Circle(xpos, ypos, 120, fill=0xff0000, outline=0x000000)
41  group1.append(circle)
42  circle = Circle(xpos, ypos, 115, fill=0x000000, outline=0x000000)
43  group1.append(circle)
44  # Minutenstriche
45  for i in range(60):
46      line = Line(xpos+int(105*math.cos(i*math.pi/30)),ypos-int(105*math.sin(i*math.pi/30)),
47                  xpos+int(110*math.cos(i*math.pi/30)), ypos-int(110*math.sin(i*math.pi/30)),0xffffff)
48      group1.append(line)
49      display.show(group1)
50  circle = Circle(xpos, ypos, 100, fill=0xffff00, outline=0xffff00)
51  group1.append(circle)
52  circle = Circle(xpos, ypos, 95, fill=0x000000, outline=0x000000)
53  group1.append(circle)
54  # Stundenstriche
55  for i in range(12):
56      line = Line(xpos+int(95*math.cos(i*math.pi/6)),ypos-int(95*math.sin(i*math.pi/6)),
57                  xpos+int(90*math.cos(i*math.pi/6)), ypos-int(90*math.sin(i*math.pi/6)),0xffffff)
58      group1.append(line)
59      display.show(group1)
60  circle = Circle(xpos, ypos, 80, fill=0xffff00, outline=0xffff00)
61  group1.append(circle)
62  circle = Circle(xpos, ypos, 75, fill=0x000000, outline=0x000000)
63  group1.append(circle)
64
65  circle = Circle(xpos, ypos, 5, fill=0xffffff, outline=0x000000)
66  group1.append(circle)
67
68  current_time = time.localtime()
69  hour = current_time[3]
70  minute = current_time[4]
71  second = current_time[5]
72  xpos_min = 120
73  ypos_min = 88
74  xpos_hour = 120
75  ypos_hour = 68
76  zeit = "00:00"
77  # Minutenpunkt in grün
78  circle_m = Circle(xpos_min,ypos_min, 5, fill=0x00ffff, outline=0x00ffff)
79  group1.append(circle_m)
80  # Stundenpunkt in rot
81  circle_h = Circle(xpos_hour, ypos_hour, 5, fill=0xff0000, outline=0xff0000)
82  group1.append(circle_h)
83
84  # Rechteck mit abgerundeten Ecken
85  roundrect1 = RoundRect(65, 100, 110, 45, 10, fill=0x0, outline=0xffffff, stroke=3)
86  group1.append(roundrect1)
87
88  # create the time-label
89  updating_label1 = label.Label(
90    font=terminalio.FONT, text=zeit, scale=2, color=0xffffff,
91      line_spacing=1)
92  # set label position on the display and add label
93  updating_label1.anchor_point = (0, 0)
94  updating_label1.anchored_position = (92, 110)
95  group1.append(updating_label1)
96  display.show(group1)
97
98  while True:
99      zeit = str(hour) + ":" + str(minute)
100     if second < 10:
101         zeit = str(hour) + ":" + str(minute)
102     if minute < 10:
103         zeit = str(hour) + ":" + "0" + str(minute)
104     if second < 10 and minute < 10:
105         zeit = str(hour) + ":" + "0" + str(minute)
106     # updating zeit
107     updating_label1.text = zeit
108     # minute setzen
109     xpos_min_neu = int(width/2 + 88*math.cos((minute-15)*math.pi/30))
110     delta_min_x = xpos_min_neu - xpos_min
111     xpos_min = xpos_min_neu
112     ypos_min_neu = int(height/2 + 88*math.sin((minute-15)*math.pi/30))
113     delta_min_y = ypos_min_neu - ypos_min
114     ypos_min = ypos_min_neu
115     circle_m.x = circle_m.x + delta_min_x
116     circle_m.y = circle_m.y + delta_min_y
117     gc.collect()
118     # hour
119     xpos_hour_neu = int(width/2 + int(68*math.cos((hour)*math.pi/6 + minute/2*math.pi/180 - math.pi/2)))
120     delta_hour_x = xpos_hour_neu - xpos_hour
121     xpos_hour = xpos_hour_neu
122     ypos_hour_neu = int(height/2 + int(68*math.sin((hour)*math.pi/6 + minute/2*math.pi/180 - math.pi/2)))
123     delta_hour_y = ypos_hour_neu - ypos_hour
124     ypos_hour = ypos_hour_neu
125     circle_h.x = circle_h.x + delta_hour_x
126     circle_h.y = circle_h.y + delta_hour_y
127     for i in range (60):
128         second *= 1
129         xpos_neu = int(width/2 + 108*math.cos((i -15)*math.pi/30))
130         delta_x = xpos_neu - xpos
131         xpos = xpos_neu
132         ypos_neu = int(height/2 + 108*math.sin((i -15)*math.pi/30))
133         delta_y = ypos_neu - ypos
134         ypos = ypos_neu
135         circle.x = circle.x + delta_x
136         circle.y = circle.y + delta_y
137         time.sleep(1)
138         gc.collect()
139         print(gc.mem_free())
140     minute += 1
141     second = 0
142     if minute == 60:
143         minute = 0
144         hour += 1
145         if hour == 24:
146             hour = 0
  




Viel Spass und Erfolg beim Ausprobieren.