Você já reparou que muitas vezes em seu projeto eletrônico, seja com Arduino ou Scratch + Arduino, usando um botão (switch/push button) mesmo apertando uma única vez o microprocessador lê múltiplas vezes, como se você tivesse apertado mais de uma vez?
Imagine como seria se você quisesse fazer um contador, a cada aperto do botão ele poderia computar pressionadas a mais que o desejado.
Esse efeito é chamado de bounce (traduzindo para o português, seria algo como “ressalto” – mas em eletrônica é mais comum usar o termo original em inglês, portanto ficamos com o bounce [baʊns].
O efeito bounce é muito comum em chaves mecânicas, pois o contato de ferro com ferro, muitas vezes ocorre de maneira imprecisa, gerando ruídos e uma simples “encostadinha” pode gerar um repique e desta forma o microprocessador irá ler o valor mais de uma vez.
Exemplo do efeito Bounce
Um dia resolvi montar um projeto/jogo no Arduino junto com minha filha de 8 anos.
A ideia inicial era para acertar se o próximo número sequencial seria uma divisão exata por 2 ou por 3.
O LED Vermelho acenderia indicando que o número era divisível por 2, se fosse o divisível por 3, o LED Verde acenderia. Caso fosse divisível por 2 e 3 (no caso do número 6) ambos os LED acenderiam.
O primeiro protótipo (sem o visor LCD) era assim:
O programa:
/* HackEduca Divisão sem resto - 2 and 3 - Bounce Detector This sketch was created to show a bounce effect when a button is pressed. Sometimes pressing the button once, the microprocessor detects more than one press. ------------- Este exemplo foi criado para mostrar o efeito de Bounce (Repique) quando um botão é pressionado Algumas vezes mesmo pressionando um botão (push button) uma única vez o Arduino interpreta mais de uma pressionada. Created 21 Nov 2016 by Edson Sobreira This example code is in the public domain. It was initially inpired on StateChangeDetection from Arduino */ // Variables - Variáveis: int switchPin = 2; int counter = 0; int CurrentState = 0; int lastState = 0; const int ledPin = 7; const int ledPin1 = 8; //--------------------------------------- void setup() { pinMode(switchPin, INPUT); Serial.begin(9600); pinMode(ledPin, OUTPUT); pinMode(ledPin1, OUTPUT); } //-------------------------------------- void loop() { CurrentState = digitalRead(switchPin); if (CurrentState != lastState) { if (CurrentState == HIGH) { counter++; if (counter ==1) { Serial.print("O bot"); Serial.write(227); Serial.print("o"); Serial.print(" foi pressionado "); Serial.print(counter); Serial.println(" vez"); } if (counter >>1) { Serial.print("O bot"); Serial.write(227); Serial.print("o"); Serial.print(" foi pressionado "); Serial.print(counter); Serial.println(" vezes"); // Serial.println(counter % 2 == 0); - debug // Serial.println(counter % 3 == 0); - debug } else { } } } lastState = CurrentState; if (counter % 2 == 0) { digitalWrite(ledPin, HIGH); } else { digitalWrite(ledPin, LOW); } if (counter % 3 == 0) { digitalWrite(ledPin1, HIGH); } else { digitalWrite(ledPin1, LOW); } }
Montando o circuito acima e carregando o programa você já poderá ver o que é o efeito Bounce na serial do seu Arduino.
No exemplo foi apertado o botão 10 vezes , no entanto foi computado 15 vezes.
Para o propósito desejado, esse programa não pode ser utilizado, pois a função de contagem que ele possui não pode é eficiente.
Existem, no entanto, algumas soluções para o caso, desde as mais simples até as mais complexas.
As opções mais simples estão relacionadas diretamente a modificação da programação (software), que por sua vez envolve uso de memória, outras envolvem hardware, que por sua vez são mais caras, elevando, desta forma o custo do seu projeto.
Para projetos simples, software está OK.
Veremos a seguir como resolver esse caso:
A solução está no Debounce
Debounce é uma solução encontrada para compensar o erro na leitura. Como já citado anteriormente o contato ferro com ferro pode causar uma leitura dupla/tripla, uma vez que de fato pode ter ocorrido realmente o contato duplo ou foi simplesmente algum ruído.
1ª solução – Capacitor
O capacitor se enche com uma carga de 5v, quando o botão é pressionado e se esvazia quando o botão é liberado.
Esse processo faz com que o sinal que sai para o microprocessador demore alguns ms e desta forma o capacitor “filtra” o sinal.
Nesta caso o polo negativo do capacitor deve estar em Gnd e o positivo, depois do resistor de 10KΩ
Foi pressionado 10 vezes e o programa leu exatamente as 10 vezes | |
2ª solução – delay(50)
Essa solução é a mais simples de todas, porém deve ser evitada, pois ela causa uma parada no programa toda vez que precisa ser executada.
Nesse caso, 50ms não vai fazer diferença em termos de performance, porém em programas mais elaborados a somatória dessa função ao longo do projeto atrapalhará o resultado final.
A função delay (50);
deverá ser colocada na linha 61 do programa acima
delay(50); // debounce - 2nd option
Teste e veja o resultado: 10 pressionadas = 10 registros.
(50milisegundos de atraso no programa é imperceptível.)
3ª solução – millis()
Essa função é mais elaborada e um pouco mais trabalhosa para usar, porém a contagem ocorre com o programa ainda em operação, ou seja , ela não paralisa a execução, causando atrasos, como na função delay ().
Há um exemplo no sketch do seu Arduino chamada BlinkWithoutDelay que faz um bom uso dessa função.
A função millis() utiliza o contador interno do Arduino, cujo contagem, inicia-se junto com a execução do programa ou um através de um Reset.
Neste caso vamos perguntar ao nosso programa quando ocorreu a última pressionada no botão. Caso tenho ocorrido em menos tempo que o estipulado ele não autorizará a execução. É como se descartássemos os toques duplos e triplos (quando ocorrido em tempo inferior a 50ms) que é o tempo suficientemente superior ao típico do bounce.
Veja como o projeto fica:
/* HackEduca Divisão sem resto - 2 and 3 - DeBounced sketch This sketch was created to show a debounce sketch when a button is pressed. Sometimes pressing the button once, the microprocessor detects more than one press - so this program solve the issue ------------- Este exemplo foi criado para mostrar o efeito de Debounce, que é uma correção do Bounce(Repique) quando um botão é pressionado Algumas vezes mesmo pressionando um botão (push button) uma única vez o Arduino interpreta mais de uma pressionada. Created 21 Nov 2016 by Edson Sobreira This example code is in the public domain. It was initially inpired on Debounce program from Arduino IDE */ // Variables - Variáveis int ledPin = 7; // the number of the LED Red pin -- Pino onde o LED Vermelho está conectado int ledPin1 = 8; // the pin that the LED Gren is attached to -- Pino onde o LED Verde está conectado int switchPin = 2; // the number of the pushbutton pin - Pino onde o botão está conectado (Ligado com PullDown Resistor) int counter = 0; int currentState; int lastState; int buttonState; // the currentState from the input pin unsigned long lastDebounceTime = 0; // the last time the output pin was toggled unsigned long debounceDelay = 50; // the debounce time; increase if the output flickers //--------------------------------------------- void setup() { pinMode(switchPin, INPUT); pinMode(ledPin, OUTPUT); pinMode(ledPin1, OUTPUT); Serial.begin(9600); } //--------------------------------------------- void loop() { // read the state of the switch into a local variable: // ler o valor atual do botão e coloca na variável currentState int currentState = digitalRead(switchPin); //--- // If the switch changed, due to noise or pressing: // Se o botão mudar de status por qualquer motivo é iniciado uma nova contagem if (currentState != lastState) { lastDebounceTime = millis(); } //-------- //Verifica se o último toque no botão é superior ao valor do delay (50ms), definido na variável debounceDelay if ((millis() - lastDebounceTime) > debounceDelay) { if (currentState != buttonState) { buttonState = currentState; //------------------------ if (currentState == HIGH) { counter++; if (counter ==1) { Serial.print("O bot"); Serial.write(227); Serial.print("o"); Serial.print(" foi pressionado "); Serial.print(counter); Serial.println(" vez"); } if (counter >>1) { Serial.print("O bot"); Serial.write(227); Serial.print("o"); Serial.print(" foi pressionado "); Serial.print(counter); Serial.println(" vezes"); } } //-------------- } } //Atualiza o lastState para o a informação atual lastState = currentState; // --- Execute the logic for gaming --- if (counter % 2 == 0) { digitalWrite(ledPin, HIGH); } else { digitalWrite(ledPin, LOW); } if (counter % 3 == 0) { digitalWrite(ledPin1, HIGH); } else { digitalWrite(ledPin1, LOW); } // --- End og logic --- }
Scratch
O Scratch, não sofre tanto desse problema quando está integrado ao Arduino, mas é necessário colocar um comando para que a programação aguarde até que ocorra uma mudança da variável, caso contrário ela ficará efetuando a leitura eternamente.
Exemplo do mesmo jogo feito no Arduino:
No Comments