Raspberry Pi Pico Binäruhr (6 LEDs + Taster)
Diese Uhr kommt ohne Ziffern aus! Wir bauen mit dem Raspberry Pi Pico eine Uhr, die die Zeit binär anzeigt. Die 6 LEDs sind die Stellen 32-16-8-4-2-1; zählst du die leuchtenden zusammen, liest du Sekunden, Minuten oder Stunden. Ein einziger Taster wechselt das Feld und stellt die Uhr, und zu jeder vollen Stunde läuft ein Lichtlauf über die LEDs.

Video
Schaltplan

Quellcode
1# ─────────────────────────────────────────
2# BlueGrays · bluegrays.com
3# Raspberry Pi Pico Binäruhr (6 LEDs + Taster)
4# ─────────────────────────────────────────
5# Eine Uhr, die die Zeit als Binärzahlen anzeigt. Die 6 LEDs sind die
6# Stellen 32-16-8-4-2-1; die leuchtenden LEDs ergeben zusammen den Wert.
7# Ein kurzer Druck wechselt zwischen Sekunden, Minuten und Stunden, ein
8# langer Druck stellt das Feld ein. Zu jeder vollen Stunde läuft ein
9# Lichtlauf, die LED auf der Platine tickt die Sekunden.
10#
11# Pins:
12# GP2 -> LED 1 (Bit 0), über 220 Ohm
13# GP3 -> LED 2 (Bit 1), über 220 Ohm
14# GP4 -> LED 4 (Bit 2), über 220 Ohm
15# GP5 -> LED 8 (Bit 3), über 220 Ohm
16# GP6 -> LED 16 (Bit 4), über 220 Ohm
17# GP7 -> LED 32 (Bit 5), über 220 Ohm
18# GP15 -> Taste (anderes Beinchen an GND)
19# LED -> LED auf der Platine (Sekundentakt)
20# GND -> LED-Kathoden, Taster
21
22from machine import Pin
23import time
24
25# ============ EINSTELLUNGEN ============
26START_TIME = (12, 59, 50) # Startzeit (h, m, s)
27SEC, MIN, HOUR = range(3)
28START_MODE = SEC # Beim Start angezeigtes Feld
29LONG_MS = 800 # Dauer für langen Druck
30DEBOUNCE_MS = 20 # Entprellzeit des Tasters
31MODE_MS = 500 # Wie lange die Feldmarkierung angezeigt wird
32BLINK_MS = 300 # Blinktakt im Stellmodus
33SET_TIMEOUT_MS = 10000 # Stellmodus speichert nach dieser Ruhezeit
34SWEEP_STEP_MS = 60 # Schritt des Lichtlaufs zur vollen Stunde
35SWEEP_ROUNDS = 2 # Anzahl der Lichtläufe
36TICK_MS = 100 # Leuchtdauer der LED auf der Platine
37LOOP_MS = 5 # Schleifenschritt
38
39# Der Reihe nach Bit 0 (1) ... Bit 5 (32)
40LED_PINS = (2, 3, 4, 5, 6, 7)
41MODE_NAMES = ("SANIYE / SECONDS", "DAKIKA / MINUTES", "SAAT / HOURS")
42# Feldmarkierung: 1, 2 oder 3 LEDs von links (Sekunden, Minuten, Stunden)
43MODE_MARKS = (0b100000, 0b110000, 0b111000)
44
45
46# ============ HARDWARE ============
47leds = [Pin(gp, Pin.OUT, value=0) for gp in LED_PINS]
48# Der Name "LED" findet die LED auf der Platine beim Pico und beim Pico W (beim W kein GP-Pin)
49tick_led = Pin("LED", Pin.OUT, value=0) # Die LED auf der Pico-Platine
50
51
52class Button:
53 # Taster mit Pull-up: liest 0 beim Drücken. update() 1 = gedrückt, -1 = losgelassen
54 def __init__(self, gp):
55 self.pin = Pin(gp, Pin.IN, Pin.PULL_UP)
56 self.down = False
57 self.changed_at = time.ticks_ms()
58
59 def update(self, now):
60 pressed = self.pin.value() == 0
61 if pressed != self.down and time.ticks_diff(now, self.changed_at) >= DEBOUNCE_MS:
62 self.down = pressed
63 self.changed_at = now
64 return 1 if pressed else -1
65 return 0
66
67 def held_ms(self, now):
68 return time.ticks_diff(now, self.changed_at)
69
70
71button = Button(15)
72shown = -1 # Letztes Muster auf den LEDs
73
74
75def show_bits(pattern):
76 # Wenn sich das Muster geändert hat, die 6 LEDs schreiben: Bit i -> LED i
77 global shown
78 if pattern == shown:
79 return
80 shown = pattern
81 for i, led in enumerate(leds):
82 led.value((pattern >> i) & 1)
83
84
85def binary(v):
86 # 6-stelliger Binärtext, z. B. 13 -> 001101
87 return "".join("1" if v >> i & 1 else "0" for i in range(5, -1, -1))
88
89
90# ============ UHR ============
91clock_s = (START_TIME[0] * 3600 + START_TIME[1] * 60 + START_TIME[2]) % 86400
92start = time.ticks_ms()
93next_second = time.ticks_add(start, 1000)
94tick_off_at = start
95
96
97def hms():
98 return clock_s // 3600, clock_s // 60 % 60, clock_s % 60
99
100
101def field_value(m):
102 h, mi, s = hms()
103 return (s, mi, h)[m]
104
105
106def time_text():
107 return "%02d:%02d:%02d" % hms()
108
109
110# ============ ZUSTAND ============
111mode = START_MODE
112setting = False # Stellmodus
113long_done = False # Langer Druck für diesen Druck schon erledigt
114marker_until = start # Wann die Feldmarkierung endet
115sweep_at = None # Beginn des Lichtlaufs
116blink_ref = start # Beginn des Blinkzyklus
117last_press = start # Letzter Druck im Stellmodus
118
119
120def report(prefix):
121 v = field_value(mode)
122 print("%s %s: %d = %s (%s)" % (prefix, MODE_NAMES[mode], v, binary(v), time_text()))
123
124
125def save_setting(now):
126 global setting
127 setting = False
128 print("Saat ayarlandi / Time set: %s" % time_text())
129
130
131def on_short(now):
132 global mode, marker_until, clock_s, blink_ref, last_press
133 if setting:
134 # Im Stellmodus erhöht jeder kurze Druck das gewählte Feld um 1
135 h, mi, s = hms()
136 if mode == HOUR:
137 h = (h + 1) % 24
138 else:
139 mi = (mi + 1) % 60
140 clock_s = h * 3600 + mi * 60 + s
141 blink_ref = now
142 last_press = now
143 report("+1")
144 else:
145 mode = (mode + 1) % 3
146 marker_until = time.ticks_add(now, MODE_MS)
147 report("Mod / Mode")
148
149
150def on_long(now):
151 global setting, clock_s, next_second, blink_ref, last_press
152 if setting:
153 if mode == MIN:
154 # Nach dem Stellen der Minuten beginnen die Sekunden bei null
155 clock_s -= clock_s % 60
156 next_second = time.ticks_add(now, 1000)
157 save_setting(now)
158 elif mode == SEC:
159 # Im Sekundenfeld setzt ein langer Druck die Sekunden auf null (Abgleich mit einem
160 # Zeitzeichen)
161 clock_s -= clock_s % 60
162 next_second = time.ticks_add(now, 1000)
163 print("Saniye sifirlandi / Seconds zeroed: %s" % time_text())
164 else:
165 setting = True
166 blink_ref = now
167 last_press = now
168 report("Ayar / Set")
169
170
171def frame(now):
172 # Das aktuelle LED-Muster: Lichtlauf > Feldmarkierung > Stellen (blinkend) > Wert
173 if sweep_at is not None:
174 step = time.ticks_diff(now, sweep_at) // SWEEP_STEP_MS
175 pos = step % 10
176 return 1 << (pos if pos < 6 else 10 - pos) # hin und her
177 if time.ticks_diff(marker_until, now) > 0:
178 return MODE_MARKS[mode]
179 if setting and time.ticks_diff(now, blink_ref) // BLINK_MS % 2:
180 return 0
181 return field_value(mode)
182
183
184# ============ HAUPTSCHLEIFE ============
185print("== BlueGrays · bluegrays.com ==")
186print("Pico Ikili Saat / Binary Clock")
187print("Kisa basis: alan degistir, uzun basis: ayarla / Short press: next field, long: set")
188print("LED'ler / LEDs: 32 16 8 4 2 1")
189report("Mod / Mode")
190
191next_loop = time.ticks_ms()
192while True:
193 now = time.ticks_ms()
194
195 # Sekundenzähler: jede neue Sekunde wird auf die letzte addiert, so driftet nichts
196 if time.ticks_diff(now, next_second) >= 0:
197 next_second = time.ticks_add(next_second, 1000)
198 clock_s = (clock_s + 1) % 86400
199 tick_led.value(1)
200 tick_off_at = time.ticks_add(now, TICK_MS)
201 if clock_s % 60 == 0:
202 print("Saat / Time %s" % time_text()[:5])
203 if clock_s % 3600 == 0 and not setting:
204 sweep_at = now # Volle Stunde: Lichtlauf
205 if not setting and time.ticks_diff(now, tick_off_at) >= 0:
206 tick_led.value(0)
207 if sweep_at is not None and time.ticks_diff(now, sweep_at) >= SWEEP_STEP_MS * 10 * SWEEP_ROUNDS:
208 sweep_at = None
209
210 # Taster: ein kurzer Druck wirkt beim Loslassen, ein langer sobald LONG_MS vorbei ist
211 b = button.update(now)
212 if b == 1:
213 long_done = False
214 sweep_at = None # Ein Druck stoppt den Lichtlauf
215 elif button.down and not long_done and button.held_ms(now) >= LONG_MS:
216 long_done = True
217 on_long(now)
218 elif b == -1 and not long_done:
219 on_short(now)
220
221 if setting:
222 tick_led.value(1) # LED auf der Platine leuchtet beim Stellen
223 if time.ticks_diff(now, last_press) >= SET_TIMEOUT_MS:
224 save_setting(now)
225
226 show_bits(frame(now))
227
228 # Fester Schritt: bis zu den nächsten 5 ms warten
229 next_loop = time.ticks_add(next_loop, LOOP_MS)
230 wait = time.ticks_diff(next_loop, time.ticks_ms())
231 if wait > 0:
232 time.sleep_ms(wait)
233 else:
234 next_loop = time.ticks_ms()
235FAQ
Wie liest man eine Binäruhr ab?
Von links nach rechts sind die LEDs 32, 16, 8, 4, 2 und 1 wert. Addiere die Werte der leuchtenden LEDs: Beim Muster 001101 leuchten 8, 4 und 1, also 13. Stunden gehen höchstens bis 23, deshalb bleibt die linke LED im Stundenfeld immer aus. Der serielle Monitor zeigt jeden Wert mit seiner Binärform.
Warum reichen 6 LEDs?
Mit 6 Bit zählt man von 0 bis 63 (2 hoch 6 = 64 Werte). Sekunden und Minuten gehen bis 59, Stunden bis 23, alles passt in 6 Bit. Um Stunden, Minuten und Sekunden gleichzeitig zu sehen, bräuchtest du für jedes Feld eine eigene LED-Reihe (insgesamt 17 LEDs).
Wird die Uhr nach einem Stromausfall zurückgesetzt?
Ja. Der Pico hat keine batteriegepufferte Uhr, der Code startet bei jedem Einschalten mit `START_TIME`. Ein gepuffertes RTC-Modul wie der DS1307 würde die Zeit halten. In diesem Projekt stellst du Stunden und Minuten nach dem Einschalten in wenigen Sekunden per Taster.
Kann ich andere LED-Farben verwenden?
Ja. Rote, grüne, gelbe und orange LEDs leuchten an 3,3 V mit 220 Ω gut. Blaue und weiße LEDs brauchen etwa 3 V und wirken an 3,3 V oft schwach; nimm für sie 100 Ω. Wenn die hohen Stellen eine andere Farbe haben, lässt sich die Uhr leichter ablesen.
