#202Iniciante

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.

0.0(0)
Relógio binário com Raspberry Pi Pico (6 LEDs + botão)
Um relógio que mostra o horário com luzes em vez de algarismos: seis LEDs exibem os segundos, minutos ou horas em binário. Da esquerda para a direita, os LEDs valem 32, 16, 8, 4, 2 e 1, e a soma dos que estão acesos dá o valor atual. Um único botão alterna entre segundos, minutos e horas; um toque longo permite ajustar o horário e, a cada hora cheia, uma sequência de luz percorre os LEDs.

Vídeo

Esquema do circuito

Relógio binário com Raspberry Pi Pico (6 LEDs + botão) - Circuit

Código-fonte

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

Perguntas 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.