Os Botões são utilizados na criação de interfaces entre máquinas e humanos. Neste post veremos como fazer com que o Arduino conheça o estado de um botão.
Para este tutorial requer o conhecimento em assuntos explicados nos posts anteriores. Caso tenha dificuldades em acompanhar os assuntos abordados aqui, verifique alguns dos nossos tutoriais anteriores.
Hardware
Para que o Arduino consiga saber o estado na qual o botão se encontra devemos fazer com que cada um dos seus estados defina um nível analógico diferente na entrada na qual ele esta conectado. Para isso podemos utilizar o pull up interno do Arduino como mostra o esquema abaixo.
No esquema a cima quando o botão estiver pressionado o pino escolhido estará com 0V e quando não estiver pressionado estará com 5V.
A imagem abaixo mostra o esquema de ligação para os exemplos apresentados a seguir. A resistência de 1k é utilizada para proteger o pino 9 de um possível curto para a terra.
Exemplo 1: Utilizando o botão para controlar um led
void setup() { pinMode(13, OUTPUT); // Configura o pino 13 (led interno) como saída; pinMode(8, INPUT_PULLUP); // Configura pino 8 como entrada e habilita pull up interno; } void loop() { if (digitalRead(8) == LOW) { // Botão Pressionado; digitalWrite(13, HIGH); // Liga led. } else { // Botão Não Pressionado digitalWrite(13, LOW); // Desliga led. } }
Apesar do esquema acima funcionar perfeitamente um fenómeno indesejado está acontecer. Vamos analisa-lo.
Bounce
Ao pressionar um botão nós fazemos com que os seus contatos se unam o que fará que o botão trepide um pouco antes de se estabilizar. Esse fenómeno é similar ao que acontece com uma bolinha de ping pong quando a jogada contra o chão, faz com que bata algumas vezes antes de se estabilizar.
Podemos observar que o botão varia entre o nível alto e baixo várias vezes antes de se estabilizar em 0V, ou seja, o led do exemplo 1 pisca várias vezes, cada vez que o botão é pressionado, porém isso acontece tão rápido que nosso olho não consegue perceber.
Exemplo 2: Detetando o Bounce
O código abaixo representado implementa um contador, que conta o número de vezes que o botão mudou de estado. Essas quantias é impressa na porta serial a cada segundo. Ao apertar e soltar o botão esperamos que esse contador incremente de duas unidades.
bool last; // Guarda o último estado do botão; uint32_t print_timer; // Timer para a impressão na porta serial; uint8_t counter = 0; // Conta o número de mudança de estados no botão; void setup() { Serial.begin(9600); pinMode(8, INPUT_PULLUP); // Configura pino 8 como entrada e habilita pull up interno; last = digitalRead(8); } void loop() { bool now = digitalRead(8); // Lê o estado atual do botão; if (now != last) { // Checa se houve uma mudança de estado; ++counter; last = now; // Atualiza o ultimo estado; } if (millis() - print_timer > 1000) { // Imprime a quantidade de mudanças a cada segundo; Serial.println(counter); print_timer = millis(); } }
Exemplo 3: Tratamento simples para o Bounce.
Podemos tratar a trepidação de um botão utilizando um pequeno delay assim que uma mudança por detetada. Se ao final desse delay a mudança ainda persiste então realmente houve uma alteração no estado do botão. O tempo na qual um botão trepida dependerá de vários fatores e pode ser diferente até mesmo em botões similares. Experimente diferentes valores de delay.
bool last; // Guarda o último estado do botão uint32_t print_timer; uint8_t counter = 0; void setup() { Serial.begin(9600); pinMode(8, INPUT_PULLUP); // Configura pino 8 como entrada e habilita pull up interno; last = digitalRead(8); } void loop() { bool now = digitalRead(8); // Lê o estado atual do botão; if (now != last) { // Checa se houve uma mudança de estado; delay(10); // Espera até que a trepidação pare; if (now == digitalRead(8)) { // Checa se a mudança ainda persiste; ++counter; last = now; // Atualiza o ultimo estado; } } if (millis() - print_timer > 1000) { Serial.println(counter); // Imprime um ponto para indicar a mudança; print_timer = millis(); } }
Por utilizar um delay essa abordagem faz com que o Arduino fique bloqueado/parado enquanto o botão trepida o que não é interessante.
Exemplo 4: Tratando Bounce sem bloquear o Arduino
Criaremos uma variável para guardar o tempo em millisegundos. Sempre que uma mudança for detectada no botão essa variável receberá o tempo do millis atual. Caso a diferença entre o millis atual e essa variável seja maior que o tempo de bounce o botão parou de trepidar e então podemos verificar se a mudança realmente aconteceu.
bool stable; // Guarda o último estado estável do botão; bool unstable; // Guarda o último estado instável do botão; uint32_t bounce_timer; uint8_t counter = 0; bool changed() { bool now = digitalRead(8); // Lê o estado atual do botão; if (unstable != now) { // Checa se houve mudança; bounce_timer = millis(); // Atualiza timer; unstable = now; // Atualiza estado instável; } else if (millis() - bounce_timer > 10) { // Checa o tempo de trepidação acabou; if (stable != now) { // Checa se a mudança ainda persiste; stable = now; // Atualiza estado estável; return 1; } } return 0; } void setup() { Serial.begin(9600); // Configura comunicação serial a uma taxa de 9600 bauds. pinMode(8, INPUT_PULLUP); // Configura pino 8 como entrada e habilita pull up interno; stable = digitalRead(8); } void loop() { if (changed()) { ++counter; Serial.println(counter); } // Outras tarefas; }
Artigo gentilmente cedido por Vida de Silicio
Todos os produtos utilizados neste artigo podem ser encontrados na Loja de Eletrónica e Robótica – ElectroFun.
Gostaram deste artigo? Deixem o vosso comentário no formulário a baixo e partilhem com os vossos amigos.
Não se esqueçam de fazer like na nossa Página no Facebook.
Podem ainda colocar as vossas dúvidas no nosso Forum da Comunidade Arduino em Portugal ou no nosso Grupo no Facebook Arduino Portugal – Qual o teu projeto?