Reloj binario con Raspberry Pi Pico (6 LED + botón)
¡Este reloj no usa números! Vamos a crear con la Raspberry Pi Pico un reloj que muestra la hora en binario. Los 6 LED son las posiciones 32-16-8-4-2-1; suma los que están encendidos y lees los segundos, los minutos o las horas. Un solo botón cambia de campo y pone el reloj en hora, y cada hora en punto los LED hacen un barrido de luz.

Video
Diagrama del circuito

Código fuente
1# ─────────────────────────────────────────
2# BlueGrays · bluegrays.com
3# Reloj binario con Raspberry Pi Pico (6 LED + botón)
4# ─────────────────────────────────────────
5# Un reloj que muestra la hora en números binarios. Los 6 LED son las
6# posiciones 32-16-8-4-2-1; los LED encendidos suman el valor. Una
7# pulsación corta cambia entre segundos, minutos y horas; una larga ajusta
8# el campo. Cada hora en punto hay un barrido de luz y el LED de la placa
9# marca los segundos.
10#
11# Pines:
12# GP2 -> LED 1 (bit 0), con 220 ohm
13# GP3 -> LED 2 (bit 1), con 220 ohm
14# GP4 -> LED 4 (bit 2), con 220 ohm
15# GP5 -> LED 8 (bit 3), con 220 ohm
16# GP6 -> LED 16 (bit 4), con 220 ohm
17# GP7 -> LED 32 (bit 5), con 220 ohm
18# GP15 -> Botón (otra patilla a GND)
19# LED -> LED de la placa (pulso de segundos)
20# GND -> Cátodos de los LED, botón
21
22from machine import Pin
23import time
24
25# ============ AJUSTES ============
26START_TIME = (12, 59, 50) # Hora de inicio (h, m, s)
27SEC, MIN, HOUR = range(3)
28START_MODE = SEC # Campo mostrado al arrancar
29LONG_MS = 800 # Duración de la pulsación larga
30DEBOUNCE_MS = 20 # Tiempo antirrebote del botón
31MODE_MS = 500 # Cuánto se muestra la marca de modo
32BLINK_MS = 300 # Periodo de parpadeo en modo ajuste
33SET_TIMEOUT_MS = 10000 # El modo ajuste guarda tras este tiempo sin pulsar
34SWEEP_STEP_MS = 60 # Paso del barrido de la hora en punto
35SWEEP_ROUNDS = 2 # Número de barridos
36TICK_MS = 100 # Duración del destello del LED de la placa
37LOOP_MS = 5 # Paso del bucle
38
39# En orden bit 0 (1) ... bit 5 (32)
40LED_PINS = (2, 3, 4, 5, 6, 7)
41MODE_NAMES = ("SANIYE / SECONDS", "DAKIKA / MINUTES", "SAAT / HOURS")
42# Marca de modo: 1, 2 o 3 LED desde la izquierda (segundos, minutos, horas)
43MODE_MARKS = (0b100000, 0b110000, 0b111000)
44
45
46# ============ HARDWARE ============
47leds = [Pin(gp, Pin.OUT, value=0) for gp in LED_PINS]
48# El nombre "LED" encuentra el LED de la placa en la Pico y en la Pico W (en la W no es un pin GP)
49tick_led = Pin("LED", Pin.OUT, value=0) # El LED de la placa de la Pico
50
51
52class Button:
53 # Botón con pull-up: lee 0 al pulsar. update() 1 = pulsado, -1 = soltado
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 # Último patrón en los LED
73
74
75def show_bits(pattern):
76 # Si el patrón cambió, escribir los 6 LED: 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 # Texto binario de 6 dígitos, p. ej. 13 -> 001101
87 return "".join("1" if v >> i & 1 else "0" for i in range(5, -1, -1))
88
89
90# ============ RELOJ ============
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# ============ ESTADO ============
111mode = START_MODE
112setting = False # Modo ajuste
113long_done = False # Pulsación larga ya atendida en esta pulsación
114marker_until = start # Cuándo termina la marca de modo
115sweep_at = None # Inicio del barrido de luz
116blink_ref = start # Inicio del ciclo de parpadeo
117last_press = start # Última pulsación en modo ajuste
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 # En modo ajuste cada pulsación corta suma 1 al campo elegido
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 # Tras ajustar los minutos, los segundos vuelven a cero
155 clock_s -= clock_s % 60
156 next_second = time.ticks_add(now, 1000)
157 save_setting(now)
158 elif mode == SEC:
159 # En el modo segundos una pulsación larga pone los segundos a cero (sincronizar con una
160 # señal horaria)
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 # Patrón de LED del momento: barrido > marca de modo > ajuste (parpadeo) > valor
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) # ida y vuelta
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# ============ BUCLE PRINCIPAL ============
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 # Contador de segundos: cada segundo nuevo se suma al anterior, así no hay deriva
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 # Hora en punto: barrido de luz
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 # Botón: la pulsación corta actúa al soltar, la larga en cuanto pasa LONG_MS
211 b = button.update(now)
212 if b == 1:
213 long_done = False
214 sweep_at = None # Una pulsación corta el barrido
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 placa encendido durante el ajuste
223 if time.ticks_diff(now, last_press) >= SET_TIMEOUT_MS:
224 save_setting(now)
225
226 show_bits(frame(now))
227
228 # Paso fijo: esperar hasta los siguientes 5 ms
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()
235Preguntas frecuentes
¿Cómo se lee un reloj binario?
De izquierda a derecha los LED valen 32, 16, 8, 4, 2 y 1. Suma los valores de los LED encendidos: en el patrón 001101 lucen 8, 4 y 1, así que es 13. Las horas no pasan de 23, así que en el campo de horas el LED de la izquierda no se enciende. El monitor serie muestra cada valor en binario.
¿Por qué bastan 6 LED?
Con 6 bits se cuenta de 0 a 63 (2 elevado a 6 = 64 valores). Los segundos y los minutos llegan a 59 y las horas a 23, así que todo cabe en 6 bits. Para ver horas, minutos y segundos a la vez necesitarías una fila de LED para cada campo (17 LED en total).
¿El reloj se reinicia si se corta la luz?
Sí. La Pico no tiene un reloj con batería, así que el código arranca en `START_TIME` cada vez. Un módulo RTC con pila como el DS1307 mantendría la hora. En este proyecto puedes poner las horas y los minutos con el botón en pocos segundos tras encenderla.
¿Puedo usar LED de otros colores?
Sí. Los LED rojos, verdes, amarillos y naranjas lucen bien a 3,3 V con 220 Ω. Los azules y blancos necesitan unos 3 V y pueden verse tenues a 3,3 V; baja su resistencia a 100 Ω. Dar otro color a las posiciones altas hace el reloj más fácil de leer.
