Relógio binário com Raspberry Pi Pico (6 LEDs + botão)
Este relógio não usa algarismos! Vamos montar um relógio com um Raspberry Pi Pico que mostra as horas em binário. Os 6 LEDs representam os valores 32-16-8-4-2-1; some os que estão acesos para ler os segundos, minutos ou horas. Um único botão alterna entre os campos e ajusta o horário, e uma sequência de luz percorre os LEDs a cada hora cheia.

Vídeo
Esquema do circuito

Código-fonte
1# ─────────────────────────────────────────
2# BlueGrays · bluegrays.com
3# Relógio binário com Raspberry Pi Pico (6 LEDs + botão)
4# ─────────────────────────────────────────
5# Um relógio que mostra a hora em números binários. Os 6 LEDs são as casas
6# 32-16-8-4-2-1; os LEDs acesos somados dão o valor. Um aperto curto
7# alterna entre segundos, minutos e horas; um aperto longo ajusta o campo.
8# A cada hora cheia roda uma varredura de luz, e o LED da placa marca os
9# segundos.
10#
11# Pinos:
12# GP2 -> LED 1 (bit 0), por 220 ohm
13# GP3 -> LED 2 (bit 1), por 220 ohm
14# GP4 -> LED 4 (bit 2), por 220 ohm
15# GP5 -> LED 8 (bit 3), por 220 ohm
16# GP6 -> LED 16 (bit 4), por 220 ohm
17# GP7 -> LED 32 (bit 5), por 220 ohm
18# GP15 -> Botão (outra perna no GND)
19# LED -> LED da placa (tique dos segundos)
20# GND -> Cátodos dos LEDs, botão
21
22from machine import Pin
23import time
24
25# ============ CONFIGURAÇÕES ============
26START_TIME = (12, 59, 50) # Hora inicial (h, m, s)
27SEC, MIN, HOUR = range(3)
28START_MODE = SEC # Campo mostrado no início
29LONG_MS = 800 # Tempo do aperto longo
30DEBOUNCE_MS = 20 # Tempo de debounce do botão
31MODE_MS = 500 # Quanto tempo o marcador de modo aparece
32BLINK_MS = 300 # Período do pisca no modo de ajuste
33SET_TIMEOUT_MS = 10000 # O modo de ajuste salva depois deste tempo parado
34SWEEP_STEP_MS = 60 # Passo da varredura da hora cheia
35SWEEP_ROUNDS = 2 # Número de varreduras
36TICK_MS = 100 # Duração da piscada do LED da placa
37LOOP_MS = 5 # Passo do loop
38
39# Em ordem bit 0 (1) ... bit 5 (32)
40LED_PINS = (2, 3, 4, 5, 6, 7)
41MODE_NAMES = ("SANIYE / SECONDS", "DAKIKA / MINUTES", "SAAT / HOURS")
42# Marcador de modo: 1, 2 ou 3 LEDs a partir da esquerda (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# O nome "LED" encontra o LED da placa tanto no Pico quanto no Pico W (no W ele não é um pino GP)
49tick_led = Pin("LED", Pin.OUT, value=0) # O LED da placa do Pico
50
51
52class Button:
53 # Botão com pull-up: lê 0 quando pressionado. update() 1 = pressionado, -1 = solto
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 padrão nos LEDs
73
74
75def show_bits(pattern):
76 # Se o padrão mudou, escreve nos 6 LEDs: 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 binário de 6 dígitos, ex.: 13 -> 001101
87 return "".join("1" if v >> i & 1 else "0" for i in range(5, -1, -1))
88
89
90# ============ RELÓGIO ============
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 de ajuste
113long_done = False # Aperto longo já tratado neste aperto
114marker_until = start # Quando o marcador de modo termina
115sweep_at = None # Início da varredura de luz
116blink_ref = start # Início do ciclo de pisca
117last_press = start # Último aperto no modo de 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 # No modo de ajuste, cada aperto curto soma 1 ao campo selecionado
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 # Depois de ajustar os minutos, os segundos recomeçam do zero
155 clock_s -= clock_s % 60
156 next_second = time.ticks_add(now, 1000)
157 save_setting(now)
158 elif mode == SEC:
159 # No modo de segundos, um aperto longo zera os segundos (sincroniza com um sinal de hora)
160 clock_s -= clock_s % 60
161 next_second = time.ticks_add(now, 1000)
162 print("Saniye sifirlandi / Seconds zeroed: %s" % time_text())
163 else:
164 setting = True
165 blink_ref = now
166 last_press = now
167 report("Ayar / Set")
168
169
170def frame(now):
171 # O padrão de LED agora: varredura > marcador de modo > ajuste (piscando) > valor
172 if sweep_at is not None:
173 step = time.ticks_diff(now, sweep_at) // SWEEP_STEP_MS
174 pos = step % 10
175 return 1 << (pos if pos < 6 else 10 - pos) # vai e volta
176 if time.ticks_diff(marker_until, now) > 0:
177 return MODE_MARKS[mode]
178 if setting and time.ticks_diff(now, blink_ref) // BLINK_MS % 2:
179 return 0
180 return field_value(mode)
181
182
183# ============ LOOP PRINCIPAL ============
184print("== BlueGrays · bluegrays.com ==")
185print("Pico Ikili Saat / Binary Clock")
186print("Kisa basis: alan degistir, uzun basis: ayarla / Short press: next field, long: set")
187print("LED'ler / LEDs: 32 16 8 4 2 1")
188report("Mod / Mode")
189
190next_loop = time.ticks_ms()
191while True:
192 now = time.ticks_ms()
193
194 # Contador de segundos: cada segundo novo é somado ao último, então ele nunca se desloca
195 if time.ticks_diff(now, next_second) >= 0:
196 next_second = time.ticks_add(next_second, 1000)
197 clock_s = (clock_s + 1) % 86400
198 tick_led.value(1)
199 tick_off_at = time.ticks_add(now, TICK_MS)
200 if clock_s % 60 == 0:
201 print("Saat / Time %s" % time_text()[:5])
202 if clock_s % 3600 == 0 and not setting:
203 sweep_at = now # Hora cheia: varredura de luz
204 if not setting and time.ticks_diff(now, tick_off_at) >= 0:
205 tick_led.value(0)
206 if sweep_at is not None and time.ticks_diff(now, sweep_at) >= SWEEP_STEP_MS * 10 * SWEEP_ROUNDS:
207 sweep_at = None
208
209 # Botão: um aperto curto age ao soltar, um aperto longo assim que passa LONG_MS
210 b = button.update(now)
211 if b == 1:
212 long_done = False
213 sweep_at = None # Um aperto para a varredura
214 elif button.down and not long_done and button.held_ms(now) >= LONG_MS:
215 long_done = True
216 on_long(now)
217 elif b == -1 and not long_done:
218 on_short(now)
219
220 if setting:
221 tick_led.value(1) # LED da placa aceso durante o ajuste
222 if time.ticks_diff(now, last_press) >= SET_TIMEOUT_MS:
223 save_setting(now)
224
225 show_bits(frame(now))
226
227 # Passo fixo: espera até os próximos 5 ms
228 next_loop = time.ticks_add(next_loop, LOOP_MS)
229 wait = time.ticks_diff(next_loop, time.ticks_ms())
230 if wait > 0:
231 time.sleep_ms(wait)
232 else:
233 next_loop = time.ticks_ms()
234Perguntas frequentes
Como ler um relógio binário?
Da esquerda para a direita, os LEDs valem 32, 16, 8, 4, 2 e 1. Some os valores dos LEDs acesos: no padrão 001101, os valores 8, 4 e 1 estão acesos, totalizando 13. As horas nunca passam de 23, então o LED mais à esquerda fica apagado no campo de horas. O Monitor Serial exibe cada valor com sua forma binária.
Por que 6 LEDs são suficientes?
Com 6 bits, é possível contar de 0 a 63 (2 elevado a 6 = 64 valores). Segundos e minutos vão até 59, e horas até 23, então todos cabem em 6 bits. Para ver horas, minutos e segundos ao mesmo tempo, seria necessária uma fileira separada de LEDs para cada campo (17 LEDs no total).
O relógio reinicia quando falta energia?
Sim. O Pico não tem um relógio com bateria de backup, então o código começa em `START_TIME` a cada inicialização. Um módulo RTC com bateria, como o DS1307, manteria o horário. Neste projeto, você pode ajustar as horas e os minutos com o botão em poucos segundos após ligar.
Posso usar LEDs de cores diferentes?
Sim. LEDs vermelhos, verdes, amarelos e laranja acendem bem com 3,3 V e 220 Ω. LEDs azuis e brancos precisam de cerca de 3 V e podem ficar fracos com 3,3 V; reduza o resistor deles para 100 Ω. Usar outra cor nos valores mais altos facilita a leitura.
