Horloge binaire avec Raspberry Pi Pico (6 LED + bouton)
Cette horloge n'a pas de chiffres ! On fabrique avec le Raspberry Pi Pico une horloge qui affiche l'heure en binaire. Les 6 LED sont les rangs 32-16-8-4-2-1 ; additionne celles qui sont allumées et tu lis les secondes, les minutes ou les heures. Un seul bouton change de champ et règle l'heure, et à chaque heure pile un balayage lumineux parcourt les LED.

Vidéo
Schéma du circuit

Code source
1# ─────────────────────────────────────────
2# BlueGrays · bluegrays.com
3# Horloge binaire avec Raspberry Pi Pico (6 LED + bouton)
4# ─────────────────────────────────────────
5# Une horloge qui affiche l'heure en nombres binaires. Les 6 LED sont les
6# rangs 32-16-8-4-2-1 ; les LED allumées s'additionnent pour donner la
7# valeur. Un appui court passe des secondes aux minutes et aux heures, un
8# appui long règle le champ. À chaque heure pile un balayage lumineux
9# passe, et la LED de la carte bat les secondes.
10#
11# Broches :
12# GP2 -> LED 1 (bit 0), via 220 ohms
13# GP3 -> LED 2 (bit 1), via 220 ohms
14# GP4 -> LED 4 (bit 2), via 220 ohms
15# GP5 -> LED 8 (bit 3), via 220 ohms
16# GP6 -> LED 16 (bit 4), via 220 ohms
17# GP7 -> LED 32 (bit 5), via 220 ohms
18# GP15 -> Bouton (autre patte sur GND)
19# LED -> LED de la carte (battement des secondes)
20# GND -> Cathodes des LED, bouton
21
22from machine import Pin
23import time
24
25# ============ RÉGLAGES ============
26START_TIME = (12, 59, 50) # Heure de départ (h, m, s)
27SEC, MIN, HOUR = range(3)
28START_MODE = SEC # Champ affiché au démarrage
29LONG_MS = 800 # Durée d'un appui long
30DEBOUNCE_MS = 20 # Temps anti-rebond du bouton
31MODE_MS = 500 # Durée d'affichage du repère de mode
32BLINK_MS = 300 # Période de clignotement en mode réglage
33SET_TIMEOUT_MS = 10000 # Le mode réglage enregistre après ce temps sans appui
34SWEEP_STEP_MS = 60 # Pas du balayage de l'heure pile
35SWEEP_ROUNDS = 2 # Nombre de balayages
36TICK_MS = 100 # Durée d'éclair de la LED de la carte
37LOOP_MS = 5 # Pas de la boucle
38
39# Dans l'ordre bit 0 (1) ... bit 5 (32)
40LED_PINS = (2, 3, 4, 5, 6, 7)
41MODE_NAMES = ("SANIYE / SECONDS", "DAKIKA / MINUTES", "SAAT / HOURS")
42# Repère de mode : 1, 2 ou 3 LED depuis la gauche (secondes, minutes, heures)
43MODE_MARKS = (0b100000, 0b110000, 0b111000)
44
45
46# ============ MATÉRIEL ============
47leds = [Pin(gp, Pin.OUT, value=0) for gp in LED_PINS]
48# Le nom "LED" trouve la LED de la carte sur le Pico comme sur le Pico W (pas une broche GP sur le
49# W)
50tick_led = Pin("LED", Pin.OUT, value=0) # La LED sur la carte du Pico
51
52
53class Button:
54 # Bouton avec pull-up : lit 0 à l'appui. update() 1 = appuyé, -1 = relâché
55 def __init__(self, gp):
56 self.pin = Pin(gp, Pin.IN, Pin.PULL_UP)
57 self.down = False
58 self.changed_at = time.ticks_ms()
59
60 def update(self, now):
61 pressed = self.pin.value() == 0
62 if pressed != self.down and time.ticks_diff(now, self.changed_at) >= DEBOUNCE_MS:
63 self.down = pressed
64 self.changed_at = now
65 return 1 if pressed else -1
66 return 0
67
68 def held_ms(self, now):
69 return time.ticks_diff(now, self.changed_at)
70
71
72button = Button(15)
73shown = -1 # Dernier motif sur les LED
74
75
76def show_bits(pattern):
77 # Si le motif a changé, écrire les 6 LED : bit i -> LED i
78 global shown
79 if pattern == shown:
80 return
81 shown = pattern
82 for i, led in enumerate(leds):
83 led.value((pattern >> i) & 1)
84
85
86def binary(v):
87 # Texte binaire sur 6 chiffres, par ex. 13 -> 001101
88 return "".join("1" if v >> i & 1 else "0" for i in range(5, -1, -1))
89
90
91# ============ HORLOGE ============
92clock_s = (START_TIME[0] * 3600 + START_TIME[1] * 60 + START_TIME[2]) % 86400
93start = time.ticks_ms()
94next_second = time.ticks_add(start, 1000)
95tick_off_at = start
96
97
98def hms():
99 return clock_s // 3600, clock_s // 60 % 60, clock_s % 60
100
101
102def field_value(m):
103 h, mi, s = hms()
104 return (s, mi, h)[m]
105
106
107def time_text():
108 return "%02d:%02d:%02d" % hms()
109
110
111# ============ ÉTAT ============
112mode = START_MODE
113setting = False # Mode réglage
114long_done = False # Appui long déjà traité pour cet appui
115marker_until = start # Fin du repère de mode
116sweep_at = None # Début du balayage lumineux
117blink_ref = start # Début du cycle de clignotement
118last_press = start # Dernier appui en mode réglage
119
120
121def report(prefix):
122 v = field_value(mode)
123 print("%s %s: %d = %s (%s)" % (prefix, MODE_NAMES[mode], v, binary(v), time_text()))
124
125
126def save_setting(now):
127 global setting
128 setting = False
129 print("Saat ayarlandi / Time set: %s" % time_text())
130
131
132def on_short(now):
133 global mode, marker_until, clock_s, blink_ref, last_press
134 if setting:
135 # En mode réglage, chaque appui court ajoute 1 au champ choisi
136 h, mi, s = hms()
137 if mode == HOUR:
138 h = (h + 1) % 24
139 else:
140 mi = (mi + 1) % 60
141 clock_s = h * 3600 + mi * 60 + s
142 blink_ref = now
143 last_press = now
144 report("+1")
145 else:
146 mode = (mode + 1) % 3
147 marker_until = time.ticks_add(now, MODE_MS)
148 report("Mod / Mode")
149
150
151def on_long(now):
152 global setting, clock_s, next_second, blink_ref, last_press
153 if setting:
154 if mode == MIN:
155 # Après le réglage des minutes, les secondes repartent de zéro
156 clock_s -= clock_s % 60
157 next_second = time.ticks_add(now, 1000)
158 save_setting(now)
159 elif mode == SEC:
160 # En mode secondes, un appui long remet les secondes à zéro (synchro sur un signal horaire)
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 # Motif des LED à cet instant : balayage > repère de mode > réglage (clignote) > valeur
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) # aller-retour
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# ============ BOUCLE PRINCIPALE ============
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 # Compteur de secondes : chaque seconde s'ajoute à la précédente, donc aucune dérive
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 # Heure pile : balayage lumineux
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 # Bouton : un appui court agit au relâchement, un appui long dès que LONG_MS est écoulé
211 b = button.update(now)
212 if b == 1:
213 long_done = False
214 sweep_at = None # Un appui arrête le balayage
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 de la carte allumée pendant le réglage
223 if time.ticks_diff(now, last_press) >= SET_TIMEOUT_MS:
224 save_setting(now)
225
226 show_bits(frame(now))
227
228 # Pas fixe : attendre les 5 ms suivantes
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
Comment lit-on une horloge binaire ?
De gauche à droite, les LED valent 32, 16, 8, 4, 2 et 1. Additionne les valeurs des LED allumées : dans le motif 001101, ce sont 8, 4 et 1, donc 13. Les heures ne dépassent jamais 23, la LED de gauche reste donc éteinte pour les heures. Le moniteur série affiche chaque valeur avec sa forme binaire.
Pourquoi 6 LED suffisent-elles ?
Avec 6 bits on compte de 0 à 63 (2 puissance 6 = 64 valeurs). Les secondes et les minutes montent jusqu'à 59 et les heures jusqu'à 23 : tout tient sur 6 bits. Pour voir heures, minutes et secondes en même temps, il faudrait une rangée de LED par champ (17 LED au total).
L'horloge se remet-elle à zéro après une coupure ?
Oui. Le Pico n'a pas d'horloge sauvegardée par pile, le code repart de `START_TIME` à chaque démarrage. Un module RTC avec pile comme le DS1307 garderait l'heure. Dans ce projet, tu règles les heures et les minutes au bouton en quelques secondes après la mise sous tension.
Puis-je utiliser d'autres couleurs de LED ?
Oui. Les LED rouges, vertes, jaunes et orange s'allument bien en 3,3 V avec 220 Ω. Les LED bleues et blanches demandent environ 3 V et peuvent rester faibles en 3,3 V ; passe leur résistance à 100 Ω. Une autre couleur pour les rangs élevés rend l'horloge plus facile à lire.
