#202Anfänger

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.

0.0(0)
Raspberry Pi Pico Binäruhr (6 LEDs + Taster)
Eine Uhr, die die Zeit mit Lichtern statt mit Ziffern anzeigt: Sechs LEDs zeigen Sekunden, Minuten oder Stunden im Binärsystem. Von links nach rechts sind die LEDs 32, 16, 8, 4, 2 und 1 wert, und die Summe der leuchtenden ergibt den aktuellen Wert. Mit einem einzigen Knopf wechselst du zwischen Sekunden, Minuten und Stunden, mit einem langen Druck stellst du die Uhr, und zu jeder vollen Stunde läuft ein Lichtlauf über die LEDs.

Video

Schaltplan

Raspberry Pi Pico Binäruhr (6 LEDs + Taster) - Circuit

Quellcode

MicroPython
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()
235

FAQ

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.