Entenda o efeito Bounce e como fazer Debounce no Arduino ao apertar um Botão
Fala pessoal, tudo certo? Bom, neste post eu vou colocar a resposta do segundo desafio postado no instagram @blogdarobotica (Link: https://www.instagram.com/p/CPEaI-SHjiC ). Se você não viu, então deixo logo abaixo o vídeo do desafio:
Inicialmente para resolver esse desafio é necessário entender algumas coisas que acontecem no circuito elétrico: Ao pressionar o botão uma única vez pode haver um efeito no qual o microcontrolador, no nosso caso o Arduino, entenda como se tivéssemos pressionado o botão mais de uma vez e esse ruído é conhecido como Bounce e gera problemas, principalmente quando o objetivo do nosso código é contar quantas vezes aquele botão foi pressionado. Abaixo vemos a ilustração do efeito Bounce, tanto acontecendo ao apertar, quanto ao soltar o botão. Com isso é possível perceber que o grande problema desse segundo desafio é justamente fazer a contagem correta de quantas vezes o botão foi pressionado, pois se não resolvermos o Bounce vai acabar havendo uma contagem incorreta mesmo que apertemos uma única vez o botão.
Esses ruídos ou trepidações precisam ser resolvidos para que possamos fazer a leitura correta do sinal e contar quantas vezes o botão foi pressionado, de fato. Existe a possibilidade de sanar esse problema via Hardware, que seria acrescentando capacitores que serviriam como filtro do sinal ou então resolver via Software, que é o que iremos fazer. Para isso monte o circuito conforme mostrado abaixo:
No Botão usamos um resistor de 10K que tem a função de PULL-DOWN, ou seja, quando o botão não estiver pressionado a porta do arduino irá ler 0v (LOW) e o resistor pull-down tem a função de deixar o estado lógico muito bem definido, ao pressionar vai ser lido o sinal 5V (HIGH) e ao soltar vai ser lido 0V (LOW). Se tirarmos esse resistor de 10K não teríamos como garantir o estado lógico do circuito. Posteriormente podemos criar uma publicação com mais detalhes sobre resistores de PULL-DOWN e PULL-UP. Já para os LEDs usamos resistores de 220 ou 330 ohms que é para garantir a limitação de corrente elétrica para que eles não queimem.
Debounce via Software
O código abaixo demonstra como depurar uma entrada, o que significa verificar duas vezes em um curto período de tempo para certificar-se de que o botão está realmente sendo pressionado, ou seja, vamos criar a solução do Bounce que é o Debounce, só que através de programação. Este código utiliza a função millis() para controlar o tempo que passou desde que o botão foi pressionado pela última vez. O código abaixo está todo comentado para facilitar o seu entendimento.
/*
----------- Resposta do #Desafio 2 --------------
=================================================
== BLOG DA ROBOTICA - www.blogdarobotica.com ==
=================================================
Autor: Kleber Bastos
E-mail: contato@blogdarobotica.com
Fanpage: facebook.com/blogdarobotica
YouTube: youtube.com/user/blogdarobotica
Instagram: instagram.com/blogdarobotica
*/
#define botao 11 //Porta em que o botão está sendo lido
#define ledVerde 10 //Porta em que o LED verde está conectado
#define ledAmarelo 9 //Porta em que o LED amarelo está conectado
#define ledVermelho 8 //Porta em que o LED Vermelho está conectado
int statusBotao; //Variável que irá receber o status do botão: 1 = Pressionado e 0 = Desacionado
int ultimoStatusBotao = LOW; //Variável Backup que salvará o último status do botão: 1 (HIGH) = Pressionado e 0 (LOW) = Desacionado. Inicialmente ela começa como LOW = 0 Desacionado
int contador = 0; //Variável que armazenará quantas vezes o botão foi pressionado
unsigned long tempoUltimoDebounce = 0; //Variável que armazenará o tempo do último Debounce
unsigned long tempoDebounce = 50; //Tempo (em milissegundos)que é necessário manter o botão pressionado para ter a certeza de que ele foi pressionado de fato.
void setup() {
pinMode(botao, INPUT); //Declara o pino do botão como entrada
pinMode(ledVerde, OUTPUT); //Declara o pino do led verde como saída
pinMode(ledAmarelo, OUTPUT); //Declara o pino do led amarelo como saída
pinMode(ledVermelho, OUTPUT); //Declara o pino do led vermelho como saída
}
//Função principal
void loop() {
debounceBotao(); //Chama a função responsável pelo Debounce
contagem(); //Chama a função responsável por realizar as ações dependendo da quantidade de vezes que o botão foi pressionado
}
//Função responsável por fazer o Debounce
void debounceBotao() {
int leitura = digitalRead(botao); //A variável leitura recebe a leitura do pino do botão: HIGH (pressionado) ou LOW (Desacionado)
if (leitura != ultimoStatusBotao) { //Se a leitura atual for diferente da leitura anterior
tempoUltimoDebounce = millis(); //Reseta a variável tempoUltimoDebounce atribuindo o tempo atual para uma nova contagem
}
if ((millis() - tempoUltimoDebounce) > tempoDebounce) { //Se o resultado de (tempo atual - tempoUltimoDebounce) for maior que o tempo que determinamos (tempoDebounce), ou seja, já passou os 50 milissegundos que é o tempo que o botão precisa ficar pressionado para ter a certeza de que ele realmente foi pressionado? Se sim faça:
if (leitura != statusBotao) { //Verifica se a leitura do botão mudou, ou seja, se é diferente do status que o botão tinha da última vez. Se sim, faça:
statusBotao = leitura; //statusBotao recebe o que foi lido na variável leitura (pressionado = 1 e não pressionado = 0)
if (statusBotao == HIGH) { //Se o statusBotao é igual a HIGH significa que o botão foi pressionado, então faça:
contador++; //Incrementa +1 na variável contador. (contador++ é o mesmo que: contador = contador +1)
}
}
}
ultimoStatusBotao = leitura; //Atualiza a variável ultimoStatusBotao para o que foi lido na variável leitura
}
//Função responsável por realizar as ações de acender os leds de acordo com a quantidade de vezes que o botão foi pressionado
void contagem() {
if (contador == 1) { //Se o contador for 1 significa que o botão foi pressionado uma única vez
digitalWrite(ledVerde, HIGH); //Acender o LED verde
digitalWrite(ledAmarelo, LOW); //Apaga o LED amarelo
digitalWrite(ledVermelho, LOW); //Apaga o LED vermelho
}
if (contador == 2) { //Se o contador for 2 significa que o botão foi pressionado duas vezes
digitalWrite(ledVerde, LOW); //Apaga o LED verde
digitalWrite(ledAmarelo, HIGH); //Acende o LED amarelo
digitalWrite(ledVermelho, LOW); //Apaga o LED vermelho
}
if (contador == 3) { //Se o contador for 3 significa que o botão foi pressionado três vezes
digitalWrite(ledVerde, LOW); //Apaga o LED verde
digitalWrite(ledAmarelo, LOW); //Apaga o LED amarelo
digitalWrite(ledVermelho, HIGH); //Acende o LED vermelho
}
if (contador >= 4) { //Se o contador for maior ou igual a 4 significa que o botão foi pressionado 4 vezes ou mais
contador = 0; //Zeramos a variável contador
digitalWrite(ledVerde, LOW); //Apaga o LED verde
digitalWrite(ledAmarelo, LOW); //Apaga o LED amarelo
digitalWrite(ledVermelho, LOW); //Apaga o LED vermelho
}
}
Obrigado a todos que participaram do desafio e espero que tenham aprendido coisas novas com ele.
Até a próxima! Att. Kleber Bastos.
Bacharel em Engenharia de Computação. Um dos criadores do Blog da Robótica. Faz parte da equipe Casa da Robótica desde 2017. Apaixonado por tecnologias e pelas “loucuras” que é possível criar usando microcontroladores e impressoras 3D. Ex-BBB, mas isso é uma longa história... que poderá ser contada posteriormente.