Controle de LED com botão no ESP32 (alternância)
Cada vez que o botão é pressionado, o estado do LED muda: se estiver aceso, apaga; se estiver apagado, acende. É o padrão clássico de alternância. Com debounce, eliminamos o ruído mecânico dos contatos do botão para garantir uma única mudança a cada pressionamento.

Vídeo
Esquema do circuito

Código-fonte
1// ─────────────────────────────────────────
2// BlueGrays · bluegrays.com
3// Controle de LED com botão no ESP32 (alternância)
4// ─────────────────────────────────────────
5// Cada aperto do botão alterna o LED: aceso vira apagado, apagado vira
6// aceso. Um debounce de 50 ms garante que um aperto dê exatamente uma
7// troca.
8//
9// Pinos:
10// GPIO 5 -> LED vermelho (com resistor de 220 ohm)
11// GPIO 4 -> Botão (outra perna no GND)
12
13const int LED_PIN = 5; // Saída do LED
14const int BUTTON_PIN = 4; // Entrada do botão
15
16bool ledState = false; // O LED está aceso agora
17bool lastButton = HIGH; // Leitura anterior do botão
18bool stableButton = HIGH; // Estado estável do botão (após debounce)
19unsigned long lastChange = 0; // Última vez que a leitura mudou (ms)
20const unsigned long DEBOUNCE = 50; // Tempo de debounce (ms)
21
22void setup() {
23 pinMode(LED_PIN, OUTPUT);
24 pinMode(BUTTON_PIN, INPUT_PULLUP); // Lê HIGH quando não está pressionado
25}
26
27void loop() {
28 bool buttonState = digitalRead(BUTTON_PIN);
29
30 // Reinicia o temporizador sempre que a leitura muda
31 if (buttonState != lastButton) lastChange = millis();
32
33 // Uma leitura que fica igual por DEBOUNCE ms conta como estável. O LED alterna uma vez, só quando
34 // o estado estável vira LOW (um novo aperto).
35 if (millis() - lastChange > DEBOUNCE && buttonState != stableButton) {
36 stableButton = buttonState;
37 if (stableButton == LOW) {
38 ledState = !ledState;
39 digitalWrite(LED_PIN, ledState);
40 }
41 }
42 lastButton = buttonState;
43}
44
Perguntas frequentes
Qual deve ser o tempo de debounce?
Para a maioria dos botões, 20–50 ms são suficientes. Se o tempo for curto demais, as oscilações dos contatos ainda serão detectadas; se for longo demais, pressionamentos rápidos e consecutivos não serão detectados.
Qual estado devo detectar para alternar o LED?
Detecte apenas o instante em que o botão é pressionado (a transição de HIGH para LOW, se estiver usando INPUT_PULLUP). Para evitar que o LED alterne repetidamente enquanto o botão estiver pressionado, armazene o estado anterior do botão em uma variável.
É correto usar `delay()` para debounce?
Funciona em projetos simples, mas delay() pausa a execução atual de loop(), atrasando outras operações no mesmo fluxo. Outras tarefas do ESP32 podem continuar em execução. A temporização com millis() é adequada para executar operações dentro de loop() sem bloqueá-lo.
É possível lembrar o último estado do LED após desligar e ligar?
Sim, no ESP32, você pode usar a biblioteca Preferences para gravar o estado na memória não volátil e lê-lo na inicialização. Assim, mesmo que a alimentação seja interrompida e volte, o LED inicia no último estado.
