Pular para o conteúdo
IDE livre

Projeto

Projeto: relógio de pulso com a placa redonda ESP32-2424S012 (ESP32-C3 e tela de 1,28")

Passo a passo de um relógio analógico na placa redonda ESP32-2424S012, com protótipo no OLED do simulador, hora pela internet e tela que acende no botão.

Por Prof. Rodrigo Faustino · Atualizado em · 11 min de leitura

Métricas deste artigo

Palavras
2.014
Caracteres
10.909
Tempo de leitura
~11 min

Um relógio de pulso feito em sala de aula é um daqueles projetos que fazem a turma inteira querer participar. A placa ESP32-2424S012 torna isso possível sem solda: ela é redonda, tem uma tela colorida de 1,28" com 240 × 240 pixels, uma ESP32-C3 atrás, conector para bateria, carregador e chave liga/desliga. Falta só a pulseira.

Este artigo constrói um relógio analógico — com ponteiros desenhados por seno e cosseno — que acerta a hora pela internet, apaga a tela para economizar bateria e acende quando o botão é apertado. Como a placa redonda ainda não está no simulador, o projeto começa por um protótipo: a mesma ESP32-C3 (na Super Mini) com a tela OLED da bancada, que o simulador conhece bem. A matemática, a lógica do tempo e o desenho são os mesmos; na placa redonda, só muda a tela.

Conhecendo a placa redonda

Desenho da placa redonda com a tela GC9A01 de 240 por 240 pixels e 1,28 polegada, com toque CST816D por cima nas versões com toque. Ao lado, os pinos ligados por dentro: tela por SPI com SCLK no GPIO6, MOSI no 7, CS no 10, DC no 2 e luz de fundo no 3; toque por I2C no endereço 0x15 com SDA no 4, SCL no 5, INT no 0 e RST no 1; botão BOOT no GPIO9. Atrás ficam o ESP32-C3, a USB-C, o carregador IP5306, o conector de bateria e a chave.
Tudo o que a placa redonda tem já vem ligado por dentro. Os pinos são os da configuração do projeto HomeDing e ainda serão conferidos numa placa de verdade.

A ESP32-2424S012 usa um módulo ESP32-C3-MINI-1U, com o mesmo chip da Super Mini. Isso quer dizer que o MicroPython é o mesmo firmware (ESP32_GENERIC_C3), e tudo o que vale para a C3 — o ADC só nos GPIO0 a GPIO4, um único SPI de uso geral, o LED e o botão — vale aqui também. A diferença está no que vem ligado por dentro:

  • a tela GC9A01, por SPI, nos GPIO6 (relógio), 7 (dados), 10 (seleção) e 2 (dado/comando);
  • a luz de fundo da tela, no GPIO3, por um transistor — é ela que mais gasta bateria;
  • nas versões com toque, o controlador CST816D, por I2C, nos GPIO4 e 5;
  • o botão BOOT, no GPIO9, que o programa pode ler como um botão comum depois que a placa ligou;
  • o carregador de bateria e a chave liga/desliga.

Esses pinos vêm da configuração da placa no projeto HomeDing, a fonte mais completa que encontramos. Como os anúncios nem sempre deixam claro qual versão está à venda, o primeiro passo com a placa nas mãos é conferir: o programa de teste da tela (mais adiante) responde se os pinos da tela estão certos, e um I2C(0, scl=Pin(5), sda=Pin(4)).scan() mostra o endereço 0x15 se a placa tiver toque.

Outra diferença importante: a placa não tem barra de pinos. Não dá para ligar sensores externos como na Super Mini. Ela é um relógio pronto, e o que se programa é a tela, o botão, o toque e o rádio.

FastTeacherPara professores

Da ementa ao semestre planejado

  • Plano de ensino e calendário montados sozinhos
  • Diário de aulas pronto para colar no SIGA
  • Slides e listas de exercícios com gabarito
Conhecer o FastTeacher

Versão Community grátis · Windows

O que você vai precisar

Para o protótipo no simulador e na bancada:

  • uma ESP32-C3 Super Mini (ficha) e uma tela OLED SSD1306 de 128 × 64 (ficha), com quatro fios.

Para o relógio de verdade:

  • a placa ESP32-2424S012;
  • uma bateria de lítio pequena, com o conector da placa (confira o conector no anúncio e na própria placa antes de comprar a bateria);
  • uma pulseira de relógio comum e uma caixinha impressa em 3D, ou feita de EVA, para prender a placa;
  • o driver em Python da tela GC9A01 — usamos o gc9a01py, de Russ Hughes, com licença MIT.

Passo 1: da hora ao ponteiro

Um mostrador redondo com o centro marcado, o ponteiro dos minutos e o das horas, e o ângulo a medido a partir das 12 horas. Ao lado, as fórmulas: minutos, a igual a 6 graus vezes o minuto; horas, a igual a 30 graus vezes a hora módulo 12 mais meio grau vezes o minuto; x igual a cx mais r vezes seno de a; y igual a cy menos r vezes cosseno de a.
Seno e cosseno de verdade, usados para alguma coisa: é com eles que a hora vira a ponta de um ponteiro na tela.

Um ponteiro é uma linha que sai do centro do mostrador. O centro é fácil: numa tela de 240 × 240, é o ponto (120, 120). A ponta é que dá trabalho, e é aí que entra a trigonometria:

  • o ponteiro dos minutos anda 6° por minuto (360° ÷ 60);
  • o das horas anda 30° por hora (360° ÷ 12) e mais 0,5° por minuto, para não pular de uma hora para a outra;
  • com o ângulo a medido a partir das 12 horas, no sentido do relógio, a ponta fica em x = cx + r·sen(a) e y = cy − r·cos(a). O sinal de menos aparece porque, nas telas, o y cresce para baixo.

O exemplo calcula as pontas para 10h10min30s — a hora preferida das fotos de relógio — e imprime as coordenadas. Ele roda sem circuito.

import math

CX, CY = 120, 120      # centro da tela redonda de 240 x 240

def ponta(angulo_graus, raio):
    a = math.radians(angulo_graus)
    return round(CX + raio * math.sin(a)), round(CY - raio * math.cos(a))

def ponteiros(h, m, s):
    return {
        'horas':    ponta(30 * (h % 12) + 0.5 * m, 55),
        'minutos':  ponta(6 * m + 0.1 * s, 85),
        'segundos': ponta(6 * s, 95),
    }

for nome, (x, y) in ponteiros(10, 10, 30).items():
    print('%-8s -> (%3d, %3d)' % (nome, x, y))

Confira o resultado com o desenho: às 10h10, o ponteiro das horas aponta para cima e para a esquerda (x menor que 120, y menor que 120), e o dos minutos para cima e para a direita. O dos segundos, aos 30 s, aponta direto para baixo: x igual a 120 e y bem maior. O minuto também anda um pouquinho com os segundos (0,1° por segundo), pelo mesmo motivo da hora.

Passo 2: o protótipo com a tela OLED

Ligações do protótipo: ESP32-C3 Super Mini com 3V3 ao VCC da tela OLED SSD1306, GND ao GND, GPIO5 ao SCL e GPIO4 ao SDA.
O protótipo na bancada: a mesma ESP32-C3, uma tela OLED e quatro fios, nos pinos do I2C do toque da placa redonda.

Na bancada, a Super Mini liga a tela OLED por I2C com SDA no GPIO4 e SCL no GPIO5 — os mesmos pinos do I2C do toque na placa redonda, para o hábito já ficar certo. A tela tem 128 × 64 pixels, então o mostrador cabe num círculo de raio 30 no lado esquerdo, e sobra espaço para a hora em números à direita.

O simulador ainda não tem o machine.RTC para acertar o relógio da placa. O programa faz o que um relógio sem internet faria: começa de uma hora inicial escrita no código e soma o tempo que passou desde que ligou. O exemplo desenha o mostrador por 3 segundos e para; abra-o com o circuito e veja os ponteiros na tela.

from machine import Pin, I2C
from ssd1306 import SSD1306_I2C
import math, time

i2c = I2C(0, scl=Pin(5), sda=Pin(4))
oled = SSD1306_I2C(128, 64, i2c)

CX, CY, R = 32, 32, 30
HORA_INICIAL = 10 * 3600 + 10 * 60 + 30     # 10:10:30, acertada à mão
ligou = time.time()

def ponta(graus, raio):
    a = math.radians(graus)
    return int(CX + raio * math.sin(a)), int(CY - raio * math.cos(a))

def desenhar(h, m, s):
    oled.fill(0)
    oled.ellipse(CX, CY, R, R, 1)
    for marca in range(12):                     # os 12 tracinhos das horas
        x1, y1 = ponta(30 * marca, R - 4)
        x2, y2 = ponta(30 * marca, R - 1)
        oled.line(x1, y1, x2, y2, 1)
    for graus, raio in ((30 * (h % 12) + 0.5 * m, 15), (6 * m + 0.1 * s, 24), (6 * s, 27)):
        x, y = ponta(graus, raio)
        oled.line(CX, CY, x, y, 1)
    oled.text('%02d:%02d' % (h, m), 72, 20)
    oled.text(':%02d' % s, 80, 34)
    oled.show()

for _ in range(3):
    total = (HORA_INICIAL + time.time() - ligou) % 86400
    h, m, s = total // 3600, total % 3600 // 60, total % 60
    desenhar(h, m, s)
    print('%02d:%02d:%02d' % (h, m, s))
    time.sleep(1)

O % 86400 faz o relógio "virar" à meia-noite: 86400 é o número de segundos de um dia. Repare também que o programa apaga e redesenha a tela inteira a cada segundo. Na OLED, isso é instantâneo, porque o desenho acontece na memória e só o show() manda a imagem pronta. Na tela colorida da placa redonda vai ser diferente, como explica o passo 4.

FastMindAssistente de IA local

A IA que lembra da sua vida e mora no seu computador

  • Memória de longo prazo com a fonte de cada resposta
  • Funciona offline: seus dados ficam no seu PC
  • Lê PDFs, slides, fotos e gravações de reunião
Baixar grátis para Windows

Plano Essencial grátis para sempre

Passo 3: a hora certa pela internet

Um relógio que começa de uma hora escrita no código atrasa ou adianta, e "esquece" tudo quando a bateria acaba. O jeito de ter a hora certa é perguntar a um servidor de hora pela internet, com o protocolo NTP. O MicroPython da ESP32 traz o módulo ntptime: com o Wi-Fi conectado, ntptime.settime() acerta o relógio interno da placa.

Só que o NTP entrega a hora UTC, a hora de referência mundial. O horário de Brasília é UTC−3, e o Brasil não usa horário de verão desde 2019 — então basta subtrair 3 horas. Outras regiões do país têm outros fusos: confira o seu. O exemplo faz a conta com um instante qualquer, de madrugada em UTC, para mostrar que o dia também pode mudar.

import time

FUSO_HORAS = -3           # Brasília; ajuste para o seu fuso

def hora_local(segundos_utc):
    return time.localtime(segundos_utc + FUSO_HORAS * 3600)

utc = time.mktime((2026, 11, 10, 2, 5, 0, 0, 0))    # 10/11, 02:05 em UTC
a, mes, d, h, m, s, _, _ = hora_local(utc)
print('UTC:   10/11/2026 02:05')
print('local: %02d/%02d/%d %02d:%02d' % (d, mes, a, h, m))

Às 2h05 de 10/11 em UTC, ainda são 23h05 de 9/11 em Brasília. Um erro comum em relógios caseiros é mostrar a hora certa com a data errada justamente nesse intervalo.

Na placa, o acerto fica assim — uma vez ao ligar e depois uma vez por dia basta, porque o relógio interno segura bem a hora entre um acerto e outro:

import network, ntptime, time

wlan = network.WLAN(network.STA_IF)
wlan.active(True)
wlan.connect('nome-da-rede', 'senha-da-rede')
for _ in range(20):                 # até uns 10 s
    if wlan.isconnected():
        break
    time.sleep_ms(500)
if wlan.isconnected():
    try:
        ntptime.settime()           # relógio da placa em UTC
    except OSError:
        pass                        # sem resposta: fica a hora que já tinha
wlan.active(False)                  # rádio desligado: economiza bateria

Passo 4: na placa redonda

Com a placa em mãos, o programa troca a OLED pela GC9A01. O driver gc9a01py tem métodos parecidos com os da OLED: fill, pixel, line, rect, fill_rect, text (com um módulo de fonte do próprio repositório do driver), e a função color565 para fazer cores. O construtor recebe o SPI e os pinos da tela.

from machine import Pin, SPI
import gc9a01py as gc9a01

spi = SPI(1, sck=Pin(6), mosi=Pin(7))       # na C3, só existe o SPI(1)
tela = gc9a01.GC9A01(
    spi,
    dc=Pin(2, Pin.OUT),
    cs=Pin(10, Pin.OUT),
    backlight=Pin(3, Pin.OUT),
    rotation=0,
)
# TODO(fidelidade): a fonte dos pinos não informa um pino de reset da tela; sem ele, o driver segue sem reset.

PRETO = gc9a01.color565(0, 0, 0)
BRANCO = gc9a01.color565(255, 255, 255)
AMARELO = gc9a01.color565(232, 195, 90)

tela.fill(PRETO)
tela.line(120, 120, 175, 64, AMARELO)       # um ponteiro de teste
tela.line(120, 120, 120, 30, BRANCO)

Se aparecerem as duas linhas, os pinos da tela estão certos. Se a tela ficar preta, confira se a luz de fundo acendeu (o GPIO3) e teste baixar a velocidade do SPI — o argumento baudrate do SPI(); os exemplos do driver mostram valores de partida.

Na tela colorida, apagar e redesenhar tudo a cada segundo é lento: são 240 × 240 pixels, com 2 bytes cada, passando pelo SPI. A técnica clássica é apagar só os ponteiros velhos: desenhar cada ponteiro antigo de novo, na cor do fundo, e depois o novo na cor certa. O mostrador e os tracinhos ficam desenhados de uma vez só, no começo.

anteriores = {}

def ponteiro(nome, graus, raio, cor):
    x, y = ponta(graus, raio)                # a mesma função do passo 1
    velho = anteriores.get(nome)
    if velho and velho != (x, y):
        tela.line(120, 120, velho[0], velho[1], PRETO)   # apaga o antigo
    tela.line(120, 120, x, y, cor)
    anteriores[nome] = (x, y)

Passo 5: economizar bateria

O artigo baterias na ESP32 dedica uma seção inteira aos relógios, e a regra principal é esta: a luz de fundo da tela é a maior conta. Um relógio de pulso não precisa ficar aceso: a pessoa olha por alguns segundos e baixa o braço.

O plano do programa fica assim:

  1. ao apertar o BOOT (GPIO9, que lê 0 quando apertado), acende a luz de fundo e desenha a hora;
  2. depois de 5 segundos sem apertar de novo, apaga a luz de fundo;
  3. com a tela apagada, a placa pode dormir em light sleep e acordar a cada poucos segundos para conferir o botão — ou, melhor, ser acordada pelo próprio botão;
  4. o Wi-Fi liga só uma vez por dia, para acertar a hora, e desliga em seguida.

Como a luz de fundo está num pino, dá até para controlar o brilho com PWM, como no artigo PWM na ESP32, e usar o mínimo que ainda dá para ler. Com o relógio pronto, meça o consumo com a tela acesa e apagada — é o único jeito de saber quanto a sua bateria vai durar.

Passo 6: do protótipo ao pulso

A parte física do relógio é onde o projeto ganha cara de produto, e vale planejar com a mesma atenção do programa:

  1. a bateria primeiro: ligue a bateria no conector da placa com a chave desligada, confira a polaridade (o fio vermelho é o positivo; os conectores pequenos nem sempre seguem a mesma ordem entre fabricantes) e só então ligue a chave. Uma bateria ligada ao contrário pode estragar o carregador da placa;
  2. a caixa: a placa redonda precisa de uma moldura que segure a borda da tela sem apertar o vidro, com espaço atrás para a bateria e uma abertura para a USB-C e outra para alcançar o botão. Uma caixa impressa em 3D é o caminho mais bonito; uma de EVA em camadas, coladas e recortadas, também funciona e é ótima para a primeira versão;
  3. a pulseira: uma pulseira comum de relógio, presa por duas alças na caixa, ou uma tira de velcro, que permite ajustar a qualquer pulso;
  4. a bateria presa: ela não pode ficar solta dentro da caixa, nem ser apertada ou dobrada. Um pedaço de fita dupla face e uma camada de espuma resolvem;
  5. teste de um dia: carregue, use o relógio por um dia normal e anote quanto tempo ele aguentou. Compare com a conta do artigo de baterias e descubra o que gastou mais do que o previsto.

Antes de fechar a caixa, lembre de deixar o acesso à USB-C: é por ela que a bateria carrega e que se grava um programa novo. Um relógio que precisa ser desmontado para atualizar desanima qualquer um depois da terceira vez.

Ideias para ir além

  • Mostradores diferentes: digital, com números grandes; um anel que vai se completando ao longo do minuto; cores que mudam com a hora do dia. Cada um é um exercício de desenho com coordenadas.
  • Toque: nas versões com o CST816D, o toque pode trocar de mostrador. O primeiro passo é o scan() do I2C mostrar o endereço 0x15; para ler os toques, use um driver do CST816 para MicroPython.
  • Cronômetro e timer: a lição Timer mostra como contar o tempo sem travar o programa.
  • Mensagens no pulso: o próximo artigo da série, mensageiro de pulso, transforma dois destes relógios num par de comunicadores por ESP-NOW.

O que este projeto ensina

O relógio é uma aula de matemática disfarçada: ângulos, seno e cosseno, resto da divisão para virar o dia e fusos horários com somas e subtrações. É também uma aula de engenharia: protótipo antes do produto, conferir os pinos antes de confiar no anúncio, desenhar só o que mudou porque a tela é lenta, e economizar energia porque a bateria é pequena. E, no fim, é um objeto que a pessoa usa no próprio pulso — difícil pensar em motivação melhor.

Para continuar

A trilha Displays ensina a tela OLED (varredura I2C e OLED); a trilha Tempo sem travar traz os ticks e o Timer; e a trilha Wi-Fi e HTTP mostra como conectar. O artigo I2C, OLED e LCD na ESP32 aprofunda a tela do protótipo.

Fontes

Para praticar no PyPlaca

Trilhas

Lições

Fichas de componentes

FastMindAssistente de IA local

A IA que lembra da sua vida e mora no seu computador

  • Memória de longo prazo com a fonte de cada resposta
  • Funciona offline: seus dados ficam no seu PC
  • Lê PDFs, slides, fotos e gravações de reunião
Baixar grátis para Windows

Plano Essencial grátis para sempre

FastTeacherPara professores

Da ementa ao semestre planejado

  • Plano de ensino e calendário montados sozinhos
  • Diário de aulas pronto para colar no SIGA
  • Slides e listas de exercícios com gabarito
Conhecer o FastTeacher

Versão Community grátis · Windows

FastMindAssistente de IA local

A IA que lembra da sua vida e mora no seu computador

  • Memória de longo prazo com a fonte de cada resposta
  • Funciona offline: seus dados ficam no seu PC
  • Lê PDFs, slides, fotos e gravações de reunião
Baixar grátis para Windows

Plano Essencial grátis para sempre