Analog-Digital Uhr
Rundes 1.28-Zoll-IPS-LCD-Display 240 x 240 Pixel
- RP2040, 6-Achsen-Sensor - Waveshare 22668
Anleitung für die Firmware CircuitPython 9.0.x
Hardware
- Rundes 1,28-Zoll-IPS-LCD-Display
- RP Pico 2040 (inclusive)
- USB-A zu USB-C Kabel
Analog-Digital Uhr
Rundes 1.28-Zoll-IPS-LCD-Display 240 x 240 Pixel- RP2040, 6-Achsen-Sensor - Waveshare 22668
Anleitung für die Firmware CircuitPython 9.0.x
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. Vieleicht haben Sie schon einmal eine s.g. 'Magneto-Uhr' für
150 bis 200 Euro gesehen. Wir werden darauf achten, daß unser Beispiel dem nicht zu ähnlich wird, da wir keine Post von deren
Anwälten bekommen wollen.
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.root_group = 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=0xae2323, 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.root_group = group1 49 circle = Circle(xpos, ypos, 100, fill=0x726b6b, outline=0x726b6b) 50 group1.append(circle) 51 circle = Circle(xpos, ypos, 95, fill=0x282323, 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.root_group = group1 59 circle = Circle(xpos, ypos, 80, fill=0x726b6b, outline=0x726b6b) 60 group1.append(circle) 61 circle = Circle(xpos, ypos, 75, fill=0x282323, outline=0x000000) 62 group1.append(circle) 63 circle = Circle(xpos, ypos, 60, fill=0xae2323, outline=0x726b6b) 64 group1.append(circle) 65 66 circle_sec = Circle(xpos, ypos, 5, fill=0xffffff, outline=0xffffff) 67 group1.append(circle_sec) 68 69 while True: 70 for i in range (60): 71 xpos_neu = int(width/2 + 108*math.cos((i -15)*math.pi/30)) 72 delta_x = xpos_neu - xpos 73 xpos = xpos_neu 74 ypos_neu = int(height/2 + 108*math.sin((i -15)*math.pi/30)) 75 delta_y = ypos_neu - ypos 76 ypos = ypos_neu 77 circle_sec.x = circle_sec.x + delta_x 78 circle_sec.y = circle_sec.y + delta_y 79 time.sleep(1) 80 gc.collect() 81 print(gc.mem_free()) 82
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 69. In den Zeilen 74 bis 77 werden noch die Minuten- und Stundenpunkte festgelegt. Die 'while'-Schleife beginnt jetzt in Zeile 80. 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.root_group = 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=0xae2323, 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.root_group = group1 49 circle = Circle(xpos, ypos, 100, fill=0x726b6b, outline=0x726b6b) 50 group1.append(circle) 51 circle = Circle(xpos, ypos, 95, fill=0x282323, 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.root_group = group1 59 circle = Circle(xpos, ypos, 80, fill=0x726b6b, outline=0x726b6b) 60 group1.append(circle) 61 circle = Circle(xpos, ypos, 75, fill=0x282323, outline=0x000000) 62 group1.append(circle) 63 circle = Circle(xpos, ypos, 60, fill=0xae2323, outline=0x726b6b) 64 group1.append(circle) 65 66 circle_sec = Circle(xpos, ypos, 4, fill=0xffffff, outline=0xffffff) 67 group1.append(circle_sec) 68 69 xpos_min = 120 70 ypos_min = 33 71 xpos_hour = 120 72 ypos_hour = 52 73 # Minutenpunkt in gruen 74 circle_min = Circle(xpos_min,ypos_min, 5, fill=0x00cc00, outline=0x000000) 75 group1.append(circle_min) 76 # Stundenpunkt in rot 77 circle_hour = Circle(xpos_hour, ypos_hour, 5, fill=0xff0000, outline=0xff0000) 78 group1.append(circle_hour) 79 80 while True: 81 current_time = time.localtime() 82 hour = current_time[3] 83 minute = current_time[4] 84 second = current_time[5] 85 # minute setzen 86 xpos_min_neu = int(width/2 + 88*math.cos((minute-15)*math.pi/30)) 87 delta_min_x = xpos_min_neu - xpos_min 88 xpos_min = xpos_min_neu 89 ypos_min_neu = int(height/2 + 88*math.sin((minute-15)*math.pi/30)) 90 delta_min_y = ypos_min_neu - ypos_min 91 ypos_min = ypos_min_neu 92 circle_min.x = circle_min.x + delta_min_x 93 circle_min.y = circle_min.y + delta_min_y 94 gc.collect() 95 # hour 96 xpos_hour_neu = int(width/2 + int(68*math.cos((hour)*math.pi/6 + minute/2*math.pi/180 - math.pi/2))) 97 delta_hour_x = xpos_hour_neu - xpos_hour 98 xpos_hour = xpos_hour_neu 99 ypos_hour_neu = int(height/2 + int(68*math.sin((hour)*math.pi/6 + minute/2*math.pi/180 - math.pi/2))) 100 delta_hour_y = ypos_hour_neu - ypos_hour 101 ypos_hour = ypos_hour_neu 102 circle_hour.x = circle_hour.x + delta_hour_x 103 circle_hour.y = circle_hour.y + delta_hour_y 104 for i in range (60): 105 second *= 1 106 xpos_neu = int(width/2 + 108*math.cos((i -15)*math.pi/30)) 107 delta_x = xpos_neu - xpos 108 xpos = xpos_neu 109 ypos_neu = int(height/2 + 108*math.sin((i -15)*math.pi/30)) 110 delta_y = ypos_neu - ypos 111 ypos = ypos_neu 112 circle_sec.x = circle_sec.x + delta_x 113 circle_sec.y = circle_sec.y + delta_y 114 time.sleep(1) 115 gc.collect() 116 print(gc.mem_free())
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 86 bis 94 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 96 bis 103 aktualisiert.
In den Zeilen 104 bis 115 wird der Sekundenpunkt wie gehabt gesetzt.
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
81 bis 91. Auch in der 'while'-Schleife sind die Zeilen 98 und 99 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.root_group = 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=0xae2323, outline=0x000000) 41 group1.append(circle) 42 circle = Circle(xpos, ypos, 115, fill=0x000000, outline=0x000000) 43 group1.append(circle) 44 # Sekundenstriche 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.root_group = group1 50 circle = Circle(xpos, ypos, 100, fill=0x726b6b, outline=0x726b6b) 51 group1.append(circle) 52 circle = Circle(xpos, ypos, 95, fill=0x282323, 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.root_group = group1 60 circle = Circle(xpos, ypos, 80, fill=0x726b6b, outline=0x726b6b) 61 group1.append(circle) 62 circle = Circle(xpos, ypos, 75, fill=0x282323, outline=0x000000) 63 group1.append(circle) 64 circle = Circle(xpos, ypos, 60, fill=0xae2323, outline=0x726b6b) 65 group1.append(circle) 66 67 circle_sec = Circle(xpos, ypos, 4, fill=0xffffff, outline=0xffffff) 68 group1.append(circle_sec) 69 70 xpos_min = 120 71 ypos_min = 33 72 xpos_hour = 120 73 ypos_hour = 52 74 # Minutenpunkt in gruen 75 circle_min = Circle(xpos_min,ypos_min, 5, fill=0x00cc00, outline=0x000000) 76 group1.append(circle_min) 77 # Stundenpunkt in rot 78 circle_hour = Circle(xpos_hour, ypos_hour, 5, fill=0xff0000, outline=0xff0000) 79 group1.append(circle_hour) 80 81 # Rechteck mit abgerundeten Ecken 82 roundrect1 = RoundRect(65, 100, 110, 45, 10, fill=0x282323, outline=0xae2323, stroke=3) 83 group1.append(roundrect1) 84 85 ## create the time-label 86 updating_label1 = label.Label(font=terminalio.FONT, text="", scale=2, color=0xffffaa,line_spacing=1) 87 # set label position on the display and add label 88 updating_label1.anchor_point = (0, 0) 89 updating_label1.anchored_position = (92, 110) 90 group1.append(updating_label1) 91 display.root_group = group1 92 93 while True: 94 current_time = time.localtime() 95 hour = current_time[3] 96 minute = current_time[4] 97 second = current_time[5] 98 zeit = "{:02}:{:02}".format(hour,minute) 99 updating_label1.text = zeit 100 # minute setzen 101 xpos_min_neu = int(width/2 + 88*math.cos((minute-15)*math.pi/30)) 102 delta_min_x = xpos_min_neu - xpos_min 103 xpos_min = xpos_min_neu 104 ypos_min_neu = int(height/2 + 88*math.sin((minute-15)*math.pi/30)) 105 delta_min_y = ypos_min_neu - ypos_min 106 ypos_min = ypos_min_neu 107 circle_min.x = circle_min.x + delta_min_x 108 circle_min.y = circle_min.y + delta_min_y 109 gc.collect() 110 # hour 111 xpos_hour_neu = int(width/2 + int(68*math.cos((hour)*math.pi/6 + minute/2*math.pi/180 - math.pi/2))) 112 delta_hour_x = xpos_hour_neu - xpos_hour 113 xpos_hour = xpos_hour_neu 114 ypos_hour_neu = int(height/2 + int(68*math.sin((hour)*math.pi/6 + minute/2*math.pi/180 - math.pi/2))) 115 delta_hour_y = ypos_hour_neu - ypos_hour 116 ypos_hour = ypos_hour_neu 117 circle_hour.x = circle_hour.x + delta_hour_x 118 circle_hour.y = circle_hour.y + delta_hour_y 119 for i in range (60): 120 second *= 1 121 xpos_neu = int(width/2 + 108*math.cos((i -15)*math.pi/30)) 122 delta_x = xpos_neu - xpos 123 xpos = xpos_neu 124 ypos_neu = int(height/2 + 108*math.sin((i -15)*math.pi/30)) 125 delta_y = ypos_neu - ypos 126 ypos = ypos_neu 127 circle_sec.x = circle_sec.x + delta_x 128 circle_sec.y = circle_sec.y + delta_y 129 time.sleep(1) 130 gc.collect() 131 #print(gc.mem_free())
Viel Spass und Erfolg beim Ausprobieren.
Viel Spass und Erfolg beim Ausprobieren.