⬤ LCD · Avançado
🕐 Relógio e Cronómetro
⏱️ 35 min
🧩 millis() · HH:MM:SS · Cronómetro · Acertar hora · Alarme
⏰ Relógio Digital com millis()
ℹ️O Arduino não tem RTC (Real Time Clock) integrado. Simula-se um relógio com millis(), que conta milissegundos desde o início. Não é perfeito (deriva ~1s/hora) mas é suficiente para displays educativos. Para projetos reais usa um módulo DS3231.
ex_relogio.ino
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
LiquidCrystal_I2C lcd(0x27, 20, 4);
// Hora inicial (acerta aqui antes de carregar)
int h=10, m=30, s=0;
unsigned long tUltimoTick = 0;
// Imprime inteiro com zero à esquerda: 7 → "07"
void p2(int v) { if(v < 10) lcd.print("0"); lcd.print(v); }
void mostrarHora() {
lcd.setCursor(4, 1); // centrado — 4 + 8 chars = 12; 20-12=8÷2=4
p2(h); lcd.print(":"); p2(m); lcd.print(":"); p2(s);
}
void tick() {
s++;
if(s >= 60) { s=0; m++; }
if(m >= 60) { m=0; h++; }
if(h >= 24) h=0;
}
void setup() {
lcd.init(); lcd.backlight();
lcd.setCursor(3, 0); lcd.print("RELOGIO DIGITAL");
lcd.setCursor(0, 3); lcd.print("PR.FT9_5 LED 2025 ");
mostrarHora();
}
void loop() {
if (millis() - tUltimoTick >= 1000) {
tick();
mostrarHora();
tUltimoTick = millis();
}
// [outros sensores/motores podem actualizar aqui sem bloqueio]
}
RELOGIO DIGITAL 10:30:47 PR.FT9_5 LED 2025
🎛️ Acertar a Hora com Dois Botões
ex_relogio_set.ino
#define BTN_SEL 2 // Seleciona campo (h → m → s → normal)
#define BTN_INC 3 // Incrementa o campo selecionado
int campo = 0; // 0=normal, 1=horas, 2=minutos, 3=segundos
unsigned long tSel=0, tInc=0;
void mostrarModoSet() {
lcd.setCursor(0, 3);
switch(campo) {
case 0: lcd.print("SEL: normal "); break;
case 1: lcd.print("SEL: >>> HORAS <<< "); break;
case 2: lcd.print("SEL: >>> MINUTOS <<"); break;
case 3: lcd.print("SEL: >>> SEGUNDOS <"); break;
}
}
void loop() {
// Botão SEL — seleciona campo
if (digitalRead(BTN_SEL)==LOW && millis()-tSel>300) {
campo = (campo+1) % 4;
mostrarModoSet(); tSel=millis();
}
// Botão INC — incrementa campo selecionado
if (digitalRead(BTN_INC)==LOW && millis()-tInc>200) {
switch(campo) {
case 1: h=(h+1)%24; break;
case 2: m=(m+1)%60; break;
case 3: s=(s+1)%60; break;
}
mostrarHora(); tInc=millis();
}
// Tick normal apenas quando não está a acertar
if (campo==0 && millis()-tUltimoTick>=1000) {
tick(); mostrarHora(); tUltimoTick=millis();
}
}
⏱️ Cronómetro com Lap Time
ex_cronometro.ino
#define BTN_START 4 // START/STOP
#define BTN_LAP 5 // LAP / RESET (quando parado)
bool a_correr = false;
unsigned long acumulado = 0;
unsigned long tInicio = 0;
unsigned long lap = 0;
int nLap = 0;
unsigned long tStart=0, tLap=0;
unsigned long tempoTotal() {
return acumulado + (a_correr ? millis() - tInicio : 0);
}
void printCrono(int linha, unsigned long ms) {
int cs = (ms/10) % 100;
int sg = (ms/1000) % 60;
int mn = (ms/60000) % 60;
lcd.setCursor(4, linha);
p2(mn); lcd.print(":"); p2(sg); lcd.print("."); p2(cs);
}
void setup() {
lcd.init(); lcd.backlight();
pinMode(BTN_START, INPUT_PULLUP); pinMode(BTN_LAP, INPUT_PULLUP);
lcd.setCursor(2,0); lcd.print("CRONOMETRO LAP:0");
}
void loop() {
// Actualiza display
printCrono(1, tempoTotal());
if (lap > 0) {
lcd.setCursor(0,2); lcd.print("LAP "); lcd.print(nLap); lcd.print(":");
printCrono(2, lap);
}
lcd.setCursor(0,3); lcd.print(a_correr ? "A CORRER " : "PARADO ");
// Botão START/STOP
if (digitalRead(BTN_START)==LOW && millis()-tStart>300) {
if(!a_correr) { tInicio=millis(); a_correr=true; }
else { acumulado=tempoTotal(); a_correr=false; }
tStart=millis();
}
// Botão LAP (em curso) / RESET (parado)
if (digitalRead(BTN_LAP)==LOW && millis()-tLap>300) {
if(a_correr) { lap=tempoTotal(); nLap++; lcd.setCursor(17,0); lcd.print(nLap); lcd.print(" "); }
else { acumulado=0; lap=0; nLap=0; lcd.setCursor(17,0); lcd.print("0 "); }
tLap=millis();
}
}
CRONOMETRO LAP:3 01:23.45 LAP 3: 00:28.91 A CORRER
🔔 Alarme Simples
ex_alarme.ino
// Alarme: quando h==hA && m==mA, o buzzer soa e o LCD pisca
#define BUZZER 8
int hA=11, mA=0; // Alarme às 11:00
bool alarmeSoou=false;
void loop() {
if(millis()-tUltimoTick>=1000) { tick(); mostrarHora(); tUltimoTick=millis(); }
bool hora_alarme = (h==hA && m==mA && s<30);
if(hora_alarme && !alarmeSoou) {
// Toca 3 bips e pisca retroiluminação
for(int i=0;i<3;i++) {
tone(BUZZER, 1000, 400);
lcd.noBacklight(); delay(400);
lcd.backlight(); delay(200);
}
lcd.setCursor(0,3); lcd.print("** ALARME ATIVO ** ");
alarmeSoou = true;
}
if(!hora_alarme) alarmeSoou=false;
}
🏆 Para ir mais longe
- Adiciona acerto de alarme com os mesmos botões do relógio — modo extra 'SET ALARM'
- Implementa múltiplos alarmes: guarda 3 horas em arrays e verifica todas no loop()
- Usa o cronómetro para medir o tempo de uma experiência com o motor DC — regista lap a cada mudança de velocidade
- Integra o relógio com o motor: o motor arranca automaticamente às HH:MM definidas pelo utilizador