Tratando o bounce com o ESP8266 NodeMCU

Em nosso tutorial sobre a utilização de botões com os módulos ESP8266 NodeMCU, nós te mostramos como você deve proceder para usá-los em seus projetos de automação. Entretanto, apesar de termos te apresentado uma situação bem legal para reproduzir, ela não é tão útil assim na maioria dos casos, devido a um evento chamado bounce que, por sua vez, neste tutorial, nós vamos aprender o que é e como tratá-lo de maneira rápida.

Antes de entrarmos diretamente no tópico deste tutorial, você pode estar se perguntando por que nós dissemos que a situação apresentada no tutorial anterior não é tão útil na maioria dos casos. Bem, perceba que o projeto que foi desenvolvido necessitava que o botão fosse continuamente pressionado para que o led permanecesse aceso.

Normalmente, o que nós buscamos em aplicações que utilizam botões é a transição entre estados de algum elemento baseada apenas no acionamento destes, independentemente do fato de continuarmos pressionando eles ou não. Em outras palavras, o que nós buscamos, utilizando o contexto do tutorial anterior, é que ao simplesmente apertarmos o botão (e soltarmos em seguida), uma variável booleana tenha o seu conteúdo invertido e permaneça com ele inalterado até que o botão seja pressionado novamente. É isso que faremos aqui!

[toc]
kit arduino robótica educacional

Mãos à obra – Entendendo o bounce na prática e aprendendo a tratá-lo

Para que seja possível entendermos o que é o bounce e a relação dele com a aplicação que queremos desenvolver, vamos dividir esta seção de mãos à obra em duas partes, de modo que, na primeira delas, fazer uma pequena experiência para mostrar o problema causado pelo bounce e na segunda, resolveremos este impasse.

Componentes necessários

Montando o projeto

A montagem deste circuito é bem simples e consiste apenas no encaixe do módulo ESP8266 NodeMCU no protoboard e na inclusão do botão no circuito.

Circuito com o NodeMCU e push-button

Programando – Parte 1: identificação do problema

Nesta parte, nós queremos te mostrar o resultado da criação de uma aplicação com a utilização de um botão, no qual o usuário deverá apertar o botão (sem segurar) para que o led mude de estado, ou seja, de apagado para aceso ou de aceso para apagado.

bool estado;

void setup()
{
   Serial.begin(9600);
   pinMode(D2,INPUT);
}
void loop() 
{ 
   if(digitalRead(D2) == 1) 
   { 
      estado = !estado; 
      Serial.println(estado);
      while(digitalRead(D2) == 1) 
      { 
      
      }
   }
}

Caso você compile este código, você perceberá que em algumas vezes, ao apertar o botão, o seu módulo ESP8266 NodeMCU irá apresentar no Serial Monitor a transição correta do conteúdo da variável estado (isto é, de nível lógico baixo para nível lógico alto e vice-versa), no entanto, em outros momentos você poderá presenciar uma espécie de confusão, sem que você tenha controle sobre a transição, com o conteúdo da variável estado sendo alterado aleatoriamente.

Janela do Serial Monitor com o resultado sem o tratamento do bounce
Resultado sem o tratamento do bounce

 

Entendendo este código

A primeira coisa que nós fizemos foi declarar uma variável booleana (que só admite dois estados, 0 ou 1) chamada estado antes da função setup().

bool estado;

Em seguida, determinamos, dentro da função setup(), o modo de operação do pino D2 para que ele atue como uma porta de entrada digital e também habilitamos a comunicação serial através da sentença Serial.begin().

bool estado;

void setup()
{
   Serial.begin(9600)
   pinMode(D2,INPUT);
}

Por fim, dentro da função loop(), vamos recorrer a uma estrutura condicional if() para detectar o momento em que o botão for pressionado, ou seja, o momento em que um sinal de nível lógico alto estiver presente na porta de entrada digital D2, utilizando a função digitalRead(), de modo que, caso esta situação aconteça, nós iremos inverter o conteúdo da variável estado, imprimi-lo no Monitor Serial e manter o programa preso no laço while até que o botão seja solto.

void loop() 
{ 
   if(digitalRead(D2) == 1) 
   { 
      estado = !estado; 
      Serial.println(estado);
      while(digitalRead(D2) == 1) 
      { 
      
      }
   }
}

Analisando este código, parece que tudo irá funcionar da maneira que nós queremos, pois, ao apertarmos o botão, o conteúdo da variável estado será invertido e o programa só voltará a ser executado desde o começo quando o botão for solto.

Note que apesar da lógica utilizada para realizarmos este tipo de automação estar correta, o projeto não vai funcionar da maneira que nós queremos, simplesmente por que nós não estamos levando em conta alguns detalhes do processo.

Quando nós pressionamos um push button, mesmo que rapidamente, ocorre uma espécie de trepidação no mecanismo de fechamento do contato existente que faz com que o nível lógico que chega na porta de entrada digital D2 dê uma certa variação indo de alto para baixo e vice-versa. Desta forma, existe a possibilidade de ESP8266 NodeMCU entender que o estado estável do botão é o existente em alguma parte da trepidação e sendo assim nós não conseguimos afirmar qual será o resultado do acionamento do mesmo. Este tipo de fenômeno é chamado de bounce.

Bounce ocorrendo

Desta forma, existe a possibilidade de ESP8266 NodeMCU confundir o estado estável do botão com alguma parte da variação dos níveis lógicos existentes trepidação. Visualmente, como dissemos antes, este acontecimento será detectado por meio da aleatoriedade das transições do conteúdo da variável estado.


Programando – Parte 2: tratando o bounce

Nesta parte, nós queremos te mostrar o resultado da criação de uma aplicação com a utilização de um botão com o tratamento do bounce realizado.

Instalando a biblioteca

Basicamente, para tratarmos o bounce, nós temos que fazer com que ao detectar um aperto no botão, o nosso módulo ESP8266 NodeMCU espere alguns instantes e confira se o botão ainda está apertado após a ocorrência da trepidação. Existem muitas formas de realizar este procedimento, mas como aqui é um guia rápido, nós vamos pela que eu acho mais rápida. Ela consiste na utilização de uma biblioteca chamada bounce 2.

Ela pode ser encontrada neste link: https://github.com/thomasfredericks/Bounce2

Após abrir a página sugerida, clique no botão verde escrito “clone or download” e posteriormente na opção Download ZIP.

 

Depois deste procedimento, você deverá abrir a Arduino IDE, selecionar o menu Sketch, selecionar a opção incluir biblioteca e por último, marcar a alternativa Adicionar biblioteca ZIP. Neste momento, você deve selecionar o arquivo que acabou baixar no passo anterior.

Criando o código

#include <bounce2.h>

bool estado;

Bounce tratador = bounce()

void setup()
{    
  tratador.attach(D2);
  tratador.interval(25);
}

void loop() 
{
   tratador.update();
   if (tratador.fell()) 
   {  
     estado = !estado; 
     Serial.println(estado); 
   }
}

Ao contrário do caso anterior, caso você compile este código, você verá que a cada aperto de botão, o conteúdo da variável estado será alterado de uma maneira consistente, sem erros.

Serial Monitor apresentando o resultado com tratamento do bounce
Resultado com o tratamento do bounce

Entendendo este código

Agora, nós já podemos efetuar algumas mudanças no código apresentado anteriormente para atingirmos o resultado que desejamos. A primeira delas é a inclusão da biblioteca que nós acabamos de baixar antes da declaração da variável estado. Isto deve ser feito da seguinte maneira:

#include <bounce2.h>

bool estado;

Depois de executarmos este passo, nós devemos criar um objeto chamado tratador que será responsável por efetuar o tratamento do bounce. Este objeto pode ser inserido em nosso código após a variável estado.

#include <bounce2.h>

bool estado;

Bounce tratador = bounce()

Em seguida, nós vamos substituir a sentença que define o pino D2 como um pino de entrada digital por outras duas sentenças, veja:

void setup()
{
  Serial.begin(9600);
   
  tratador.attach(D2);
  tratador.interval(25);
}

A primeira sentença utiliza o método attach() para definir qual porta de entrada digital será tratada e o método interval() diz respeito ao intervalo de tempo estipulado da trepidação, para que o NodeMCU leia o sinal apenas em um tempo posterior a este,

Por fim, na função loop(), nós vamos utilizar a sentença update atrelada ao objeto que nós criamos para atualizar o estado do nosso botão e também vamos recorrer à estrutura condicional if() e utilizar como argumento o método fell() em conjunto com o mesmo objeto citado (isto servirá para programa detectar quando o botão for solto, ou seja, proporcionando uma variação do sinal de tensão de 3,3V para 0 V).

Caso esta sentença seja verdadeira, nós vamos inverter o conteúdo da variável estado da mesma forma que realizamos anteriormente.

void loop() 
{
   tratador.update();
   if (tratador.fell()) 
   {  
     estado = !estado; 
     Serial.println(estado); 
   }
}

Considerações finais

Esperamos que você tenha gostado deste tutorial e que você consiga implementar este tipo de técnica nos seus projetos com ESP8266 NodeMCU. Se tiver alguma dúvida, deixe ela nos comentários abaixo.