#202Principiante

Orologio binario con Raspberry Pi Pico (6 LED + pulsante)

Questo orologio non usa cifre! Costruiamo con il Raspberry Pi Pico un orologio che mostra l'ora in binario. I 6 LED sono le posizioni 32-16-8-4-2-1; somma quelli accesi e leggi i secondi, i minuti o le ore. Un solo pulsante cambia campo e regola l'ora, e a ogni ora esatta i LED fanno una scia di luce.

0.0(0)
Orologio binario con Raspberry Pi Pico (6 LED + pulsante)
Un orologio che dice l'ora con le luci invece che con le cifre: sei LED mostrano i secondi, i minuti o le ore in binario. Da sinistra a destra i LED valgono 32, 16, 8, 4, 2 e 1, e la somma di quelli accesi dà il valore del momento. Con un solo pulsante passi tra secondi, minuti e ore, con una pressione lunga regoli l'orologio, e allo scoccare di ogni ora un giro di luce attraversa i LED.

Video

Schema circuito

Orologio binario con Raspberry Pi Pico (6 LED + pulsante) - Circuit

Codice sorgente

MicroPython
1# ─────────────────────────────────────────
2#   BlueGrays · bluegrays.com
3#   Orologio binario con Raspberry Pi Pico (6 LED + pulsante)
4# ─────────────────────────────────────────
5# Un orologio che mostra l'ora in numeri binari. I 6 LED sono le posizioni
6# 32-16-8-4-2-1; i LED accesi sommati danno il valore. Una pressione breve
7# passa tra secondi, minuti e ore; una lunga regola il campo. A ogni ora
8# esatta parte una scia di luce e il LED della scheda batte i secondi.
9#
10# Pin:
11#   GP2  -> LED 1 (bit 0), tramite 220 ohm
12#   GP3  -> LED 2 (bit 1), tramite 220 ohm
13#   GP4  -> LED 4 (bit 2), tramite 220 ohm
14#   GP5  -> LED 8 (bit 3), tramite 220 ohm
15#   GP6  -> LED 16 (bit 4), tramite 220 ohm
16#   GP7  -> LED 32 (bit 5), tramite 220 ohm
17#   GP15 -> Pulsante (altro piedino a GND)
18#   LED  -> LED della scheda (battito dei secondi)
19#   GND  -> Catodi dei LED, pulsante
20
21from machine import Pin
22import time
23
24# ============ IMPOSTAZIONI ============
25START_TIME = (12, 59, 50)  # Ora di partenza (h, m, s)
26SEC, MIN, HOUR = range(3)
27START_MODE = SEC       # Campo mostrato all'avvio
28LONG_MS = 800          # Durata della pressione lunga
29DEBOUNCE_MS = 20       # Tempo di antirimbalzo del pulsante
30MODE_MS = 500          # Quanto resta visibile il segno di modo
31BLINK_MS = 300         # Periodo di lampeggio in regolazione
32SET_TIMEOUT_MS = 10000 # La regolazione salva dopo questo tempo senza pressioni
33SWEEP_STEP_MS = 60     # Passo della scia dell'ora esatta
34SWEEP_ROUNDS = 2       # Numero di scie
35TICK_MS = 100          # Durata del lampo del LED della scheda
36LOOP_MS = 5            # Passo del ciclo
37
38# In ordine bit 0 (1) ... bit 5 (32)
39LED_PINS = (2, 3, 4, 5, 6, 7)
40MODE_NAMES = ("SANIYE / SECONDS", "DAKIKA / MINUTES", "SAAT / HOURS")
41# Segno di modo: 1, 2 o 3 LED da sinistra (secondi, minuti, ore)
42MODE_MARKS = (0b100000, 0b110000, 0b111000)
43
44
45# ============ HARDWARE ============
46leds = [Pin(gp, Pin.OUT, value=0) for gp in LED_PINS]
47# Il nome "LED" trova il LED della scheda sia sul Pico sia sul Pico W (sul W non è un pin GP)
48tick_led = Pin("LED", Pin.OUT, value=0)   # Il LED sulla scheda del Pico
49
50
51class Button:
52    # Pulsante con pull-up: legge 0 quando è premuto. update() 1 = premuto, -1 = rilasciato
53    def __init__(self, gp):
54        self.pin = Pin(gp, Pin.IN, Pin.PULL_UP)
55        self.down = False
56        self.changed_at = time.ticks_ms()
57
58    def update(self, now):
59        pressed = self.pin.value() == 0
60        if pressed != self.down and time.ticks_diff(now, self.changed_at) >= DEBOUNCE_MS:
61            self.down = pressed
62            self.changed_at = now
63            return 1 if pressed else -1
64        return 0
65
66    def held_ms(self, now):
67        return time.ticks_diff(now, self.changed_at)
68
69
70button = Button(15)
71shown = -1                 # Ultimo schema sui LED
72
73
74def show_bits(pattern):
75    # Se lo schema è cambiato, scrivi i 6 LED: bit i -> LED i
76    global shown
77    if pattern == shown:
78        return
79    shown = pattern
80    for i, led in enumerate(leds):
81        led.value((pattern >> i) & 1)
82
83
84def binary(v):
85    # Testo binario a 6 cifre, es. 13 -> 001101
86    return "".join("1" if v >> i & 1 else "0" for i in range(5, -1, -1))
87
88
89# ============ OROLOGIO ============
90clock_s = (START_TIME[0] * 3600 + START_TIME[1] * 60 + START_TIME[2]) % 86400
91start = time.ticks_ms()
92next_second = time.ticks_add(start, 1000)
93tick_off_at = start
94
95
96def hms():
97    return clock_s // 3600, clock_s // 60 % 60, clock_s % 60
98
99
100def field_value(m):
101    h, mi, s = hms()
102    return (s, mi, h)[m]
103
104
105def time_text():
106    return "%02d:%02d:%02d" % hms()
107
108
109# ============ STATO ============
110mode = START_MODE
111setting = False            # Modalità regolazione
112long_done = False          # Pressione lunga già gestita per questa pressione
113marker_until = start       # Quando finisce il segno di modo
114sweep_at = None            # Inizio della scia di luce
115blink_ref = start          # Inizio del ciclo di lampeggio
116last_press = start         # Ultima pressione in regolazione
117
118
119def report(prefix):
120    v = field_value(mode)
121    print("%s %s: %d = %s  (%s)" % (prefix, MODE_NAMES[mode], v, binary(v), time_text()))
122
123
124def save_setting(now):
125    global setting
126    setting = False
127    print("Saat ayarlandi / Time set: %s" % time_text())
128
129
130def on_short(now):
131    global mode, marker_until, clock_s, blink_ref, last_press
132    if setting:
133        # In regolazione ogni pressione breve aggiunge 1 al campo scelto
134        h, mi, s = hms()
135        if mode == HOUR:
136            h = (h + 1) % 24
137        else:
138            mi = (mi + 1) % 60
139        clock_s = h * 3600 + mi * 60 + s
140        blink_ref = now
141        last_press = now
142        report("+1")
143    else:
144        mode = (mode + 1) % 3
145        marker_until = time.ticks_add(now, MODE_MS)
146        report("Mod / Mode")
147
148
149def on_long(now):
150    global setting, clock_s, next_second, blink_ref, last_press
151    if setting:
152        if mode == MIN:
153            # Dopo aver regolato i minuti, i secondi ripartono da zero
154            clock_s -= clock_s % 60
155            next_second = time.ticks_add(now, 1000)
156        save_setting(now)
157    elif mode == SEC:
158        # In modalità secondi una pressione lunga azzera i secondi (sincronia con un segnale orario)
159        clock_s -= clock_s % 60
160        next_second = time.ticks_add(now, 1000)
161        print("Saniye sifirlandi / Seconds zeroed: %s" % time_text())
162    else:
163        setting = True
164        blink_ref = now
165        last_press = now
166        report("Ayar / Set")
167
168
169def frame(now):
170    # Schema dei LED in questo momento: scia > segno di modo > regolazione (lampeggia) > valore
171    if sweep_at is not None:
172        step = time.ticks_diff(now, sweep_at) // SWEEP_STEP_MS
173        pos = step % 10
174        return 1 << (pos if pos < 6 else 10 - pos)     # avanti e indietro
175    if time.ticks_diff(marker_until, now) > 0:
176        return MODE_MARKS[mode]
177    if setting and time.ticks_diff(now, blink_ref) // BLINK_MS % 2:
178        return 0
179    return field_value(mode)
180
181
182# ============ CICLO PRINCIPALE ============
183print("== BlueGrays · bluegrays.com ==")
184print("Pico Ikili Saat / Binary Clock")
185print("Kisa basis: alan degistir, uzun basis: ayarla / Short press: next field, long: set")
186print("LED'ler / LEDs: 32 16 8 4 2 1")
187report("Mod / Mode")
188
189next_loop = time.ticks_ms()
190while True:
191    now = time.ticks_ms()
192
193    # Contatore dei secondi: ogni nuovo secondo si somma al precedente, così non c'è deriva
194    if time.ticks_diff(now, next_second) >= 0:
195        next_second = time.ticks_add(next_second, 1000)
196        clock_s = (clock_s + 1) % 86400
197        tick_led.value(1)
198        tick_off_at = time.ticks_add(now, TICK_MS)
199        if clock_s % 60 == 0:
200            print("Saat / Time %s" % time_text()[:5])
201        if clock_s % 3600 == 0 and not setting:
202            sweep_at = now                 # Ora esatta: scia di luce
203    if not setting and time.ticks_diff(now, tick_off_at) >= 0:
204        tick_led.value(0)
205    if sweep_at is not None and time.ticks_diff(now, sweep_at) >= SWEEP_STEP_MS * 10 * SWEEP_ROUNDS:
206        sweep_at = None
207
208    # Pulsante: la pressione breve agisce al rilascio, quella lunga appena passa LONG_MS
209    b = button.update(now)
210    if b == 1:
211        long_done = False
212        sweep_at = None                    # Una pressione ferma la scia
213    elif button.down and not long_done and button.held_ms(now) >= LONG_MS:
214        long_done = True
215        on_long(now)
216    elif b == -1 and not long_done:
217        on_short(now)
218
219    if setting:
220        tick_led.value(1)          # LED della scheda acceso durante la regolazione
221        if time.ticks_diff(now, last_press) >= SET_TIMEOUT_MS:
222            save_setting(now)
223
224    show_bits(frame(now))
225
226    # Passo fisso: attendere fino ai prossimi 5 ms
227    next_loop = time.ticks_add(next_loop, LOOP_MS)
228    wait = time.ticks_diff(next_loop, time.ticks_ms())
229    if wait > 0:
230        time.sleep_ms(wait)
231    else:
232        next_loop = time.ticks_ms()
233

FAQ

Come si legge un orologio binario?

Da sinistra a destra i LED valgono 32, 16, 8, 4, 2 e 1. Somma i valori dei LED accesi: nello schema 001101 sono accesi 8, 4 e 1, quindi 13. Le ore non superano mai 23, perciò nel campo delle ore il LED più a sinistra resta spento. Il monitor seriale stampa ogni valore con la sua forma binaria.

Perché bastano 6 LED?

Con 6 bit si conta da 0 a 63 (2 alla sesta = 64 valori). Secondi e minuti arrivano a 59 e le ore a 23, quindi tutto sta in 6 bit. Per vedere ore, minuti e secondi insieme servirebbe una fila di LED per ogni campo (17 LED in tutto).

L'orologio si azzera se manca la corrente?

Sì. Il Pico non ha un orologio con batteria tampone, quindi il codice riparte da `START_TIME` a ogni accensione. Un modulo RTC con batteria come il DS1307 manterrebbe l'ora. In questo progetto regoli ore e minuti con il pulsante in pochi secondi dopo l'accensione.

Posso usare LED di altri colori?

Sì. I LED rossi, verdi, gialli e arancioni si accendono bene a 3,3 V con 220 Ω. Quelli blu e bianchi richiedono circa 3 V e a 3,3 V possono sembrare deboli; per loro scendi a 100 Ω. Dare un altro colore alle posizioni alte rende l'orologio più facile da leggere.