Função para debouncing de um botão: o que eu não estou entendendo direito??

Olá, boa noite.

Estou começando com o Arduino seguindo o livro do Jeremy Blum. Nesse momento estou tentando entender o código para debounce de um botão (listagem 2.5 do livro), mas estou com uma dúvida. O código abaixo corresponde ao código da listagem 2.5 do livro (só mudei o nome das variáveis para português, mas o restante é igual), e funciona perfeitamente, ou seja: quando eu clico no botão o led acende, e quando eu clico de novo no botão o led apaga:

// Define variáveis:
const int led = 9;
const int botao = 2;
boolean botao_anterior = LOW;
boolean botao_atual = LOW;
boolean led_ligado = false;

// Define pinos e setup inicial
void setup() {
  pinMode(botao, INPUT);
  pinMode(led, OUTPUT);
}

// Funcao de debouncing do botao:
boolean debounce(boolean d_botao_anterior){
  boolean d_botao_atual = digitalRead(botao);
  if ( d_botao_anterior != d_botao_atual ) {
    delay(5);
    d_botao_atual = digitalRead(botao);
    return d_botao_atual;
  }
}

// Programa principal
void loop() {
  botao_atual = debounce(botao_anterior);
  
  if ( botao_anterior == LOW && botao_atual == HIGH ){
    led_ligado = !led_ligado; // Inverte o status do LED: era false e passa a ser true
  }
  
  botao_anterior = botao_atual;
  
  digitalWrite(led, led_ligado);
}

Quando o LED está apagado e eu clico no botão para acendê-lo, eu consigo entender a lógica do programa acima: a função debounce lê o botao (que foi clicado e está em HIGH) e compara com o botao_anterior (que estava definido como LOW), espera o delay para fazer o debouncing, lê novamente o botao (que ainda está em HIGH) e retorna esse valor HIGH para a variável botao_atual. Depois o if do loop principal do programa compara o botao_anterior (que era LOW) e o botao_atual (que agora é HIGH) e, como ambas as condições são verdadeiras, o if altera o status do led (que era false para true) e a função digitalWrite acende o led. A variável botao_anterior também foi igualada à variável botao_atual e ambas estão em HIGH.

Enquanto eu não clico novamente no botão, ambas as variáveis estão em HIGH e o if do loop principal não roda pois as condições não batem. Até aqui tudo bem.

Agora vem minha DÚVIDA: quando eu clico novamente no botão, a função debounce lê o botão, que está em LOW, compara com o botao_anterior, que era HIGH, espera o delay, lê novamente o botão e retorna o valor LOW para a variável botao_atual no loop principal. Nesse exato momento eu tenho a seguinte situação: botao_anterior é HIGH e botao_atual é LOW. Essa situação NÃO CASA COM AS CONDIÇÕES DO if do loop principal, mas mesmo assim o status do LED é alterado (de true para false) e o led apaga.
Por que o if é executado e o status do led é alterado se as condições não casam com as condições do if????

Ou eu estou entendendo tudo errado? O código acima funciona perfeitamente mas eu não entendo como o if pode alterar o status do led se as condições não foram atendidas.

Onde estou entendendo errado?

Antes de mais bem vindo.Por acaso tambem comprei o livro do Jeremy :grin:

Quando o LED está apagado e eu clico no botão para acendê-lo, eu consigo entender a lógica do programa acima: a função debounce lê o botao (que foi clicado e está em HIGH)

Isto contradiz isto

Agora vem minha DÚVIDA: quando eu clico novamente no botão, a função debounce lê o botão, que está em LOW.

Se acabaste de carregar no botao como isto poder ser LOW?

Essa situação NÃO CASA COM AS CONDIÇÕES DO if do loop principal, mas mesmo assim o status do LED é alterado (de true para false) e o led apaga.
Por que o if é executado e o status do led é alterado se as condições não casam com as condições do if????

Isto é o que tu pensas.O IF CASA e o microcontrolador nao perdoa , é um gajo muito certinho que faz tudo o que lhe mandam
Revê o teu pensamento sobre os estados e vais entender
Acho que a tua confusao esta em teres dado nomes muito parecidos as variaveis.Isso faz com que entender a logica pareca confuso.
No final de contas o programa esta a funcionar e acredita que a falha nao é no if mas na logica da tua cabeça.
Bons estudos

HugoPT:
Se acabaste de carregar no botao como isto poder ser LOW?

Entendi, entendi!!

Muito, muito obrigado por sua orientação. A pergunta acima me mostrou claramente onde meu raciocínio estava errado e finalmente consegui entender o código! Puxa vida, fiquei horas tentando entender e não conseguia... bastou uma única pergunta sua e entendi.

Obrigado novamente!

Abrantes

Nota também que esse é um debouncing um pouco fatela... Algo que li e tento implementar sempre que poss´vel é uma funcão que vê o estado dos botões de 20 em 20 milisegundos.

Se houver um pulso que se mantém por mais de 20 ms, então usa-se esse pulso e espera-se que volte abaixo.

Isto evita outras estratégias usadas para combater o debouncing... se bem que a minha estratégia favorita (e odiada por quem tem de abrir os cordões à bolsa) é mesmo comprar botões bons. Ter um botão bom é meio caminho andado para resolver o debouncing. O problema é que estes são caros. :frowning: