Debouncing via software com Arduino sem usar delay – millis()

Nesse post quero compartilhar minha tradução (com algumas alterações) do código de debounce da documentação do Arduino. Primeiro, para quem desconhece o que significa debounce em eletrônica digital, aconselho a leitura desse excelente artigo do site Embarcados, autoria do Rodrigo Almeida, que trata desde o conceito de bouncing (com excelentes ilustrações), até as formas de debouncing através de hardware e software (o exemplo do artigo é para o PIC). Lembrando que o ideal é utilizar uma combinação das duas formas, para que o tempo de resposta seja o maior possível; pois, como veremos adiante, o tratamento do bouncing por software implica um delay (atraso) na resposta ao comando.

Em um outro post que fiz aqui, utilizei como método de debouncing por software a própria função delay() – nessa postagem também não testo se o estado da chave foi modificado, de forma que se o usuário mantiver pressionado o botão por tempo superior ao delay() o comando será executado repetidas vezes.  Mas utilizar a função delay() não é a forma correta. Por quê? Simplesmente porque ela congela a execução do programa pelo microcontrolador (Arduino), atrasando todos as demais tarefas que sua rotina deve fazer, por exemplo, atualizar uma amostragem de algum dado num display LCD. A forma de contornar isso é utilizando instruções condicionais if que testam se já passou um determinado tempo (cria um delay apenas para essa tarefa, digamos assim, de verificar a alteração de estado da chave), a partir de comparação com o tempo total e absoluto de execução do programa no Arduino, que é obtido em milissegundos através da função millis().

        OBS.: Em um código que encontrei na internet, o programador usou uma instrução while para testar se o tempo havia passado, e isso resolve… NADA! Por quê? Simplesmente porque a execução do programa ficará nesse while [tempo_não_passa] até que o tempo realmente tenha passado, o que equivale a usar a função delay()! Se for para fazer isso, melhor usar delay(), em vez de ficar declarando e configurando novas variáveis apenas para a estrutura do while [tempo_nao_passa] nao_faz_nada funcionar…

        OBS. 2: A principal alteração que fiz no código da documentação está na retirada do resistor de PULL DOWN (previsto no circuito da documentação). Como ficou então nosso circuito? Optei por utilizar o resistor de PULL UP interno do próprio Arduino, tendo para que funcionasse assim apenas de inverter a lógica da detecção de alteração de estado da chave ou do botão de entrada. Atenção: Importante lembrar que a maneira mais simples e enxuta de habilitar o resistor de PULL UP interno do Arduino é declarando explicitamente em “pinMode(pinodeentrada, INPUT_PULLUP)“, dessa forma. É possível também declarar “pinMode(pinodeeentrada, INPUT)” e na outra linha “digitalWrite(pinodeentrada, HIGH)“. Isso também irá habilitar o resistor interno de PULL UP do Arduino, mas o ideal é enxugar o código e usar apenas as instruções necessárias, ocupando menos espaço em ambas as memórias e por isso mesmo otimizando a execução do programa.

Mais informações nos próprios comentários do código. Segue abaixo também o desenho da montagem do circuito, feito no Fritzing.

/*
Debounce – Estabilizacao

Cada vez que o pino de entrada vai de HIGH para LOW (e.g. devido ao pressionamento
do botao), o pino de saida eh alternado de LOW para HIGH ou de HIGH para LOW. Existe
um pequeno atraso entre essas alternancias para estabilizar o circuito (i.e. para
ignorar o ruido).

O circuito:
* LED do pino 13 ao GND (terra ou negativo)
* botao pulsante (pushbutton) do pino 2 ao GND (terra ou negativo)

* Nota: Na maioria das placas Arduino, jah existe um LED na placa conectado
ao pino 13, assim vc nao precisa adicionar nenhum componente neste circuito.
Ateh mesmo o botao pulsante pode ser substituido por um mero ‘jumper’ (um ‘fiozinho’)
com o qual vc podera simular o pressionamento do botao fazendo contato entre
o pino 2 e qualquer GND do Arduino.

criado em 21 Nov 2006
por David A. Mellis
modificado em 30 Ago 2011
por Limor Fried
modificado em 28 Dez 2012
por Mike Walters
modificado e traduzido em 31 Ago 2014
por Jeter Silveira

Esse codigo foi copiado e alterado para disponibilizacao gratuita na internet em:
http://www.jetersilveira.com.br

O original tambem eh dominio publico e pode ser encontrado na pagina oficial de
documentacao do Arduino no endereco abaixo:

http://www.arduino.cc/en/Tutorial/Debounce

*/

// as constantes nao mudam. Elas sao usadas aqui
// para ‘setar’ os numeros dos pinos
const int buttonPin = 2; // o numero do pino do botao pulsante (“pushbutton”)
const int ledPin = 13; // o numero do pino do LED

// Variaveis sofrerao mudancaso
int ledState = HIGH; // o atual estado do pino de saida (LED)
int buttonState; // a leitura atual do pino de entrada
int lastButtonState = HIGH; // a leitura anterior do pino de entrada

// as variaveis seguintes sao to tipo ‘long’ porque o tempo, medido em milissegundos
// rapidamente se tornara um numero maior do que o que cabe em uma ‘int’.
long lastDebounceTime = 0; // a ultima vez que o pino de saida foi modificado (toggled)
long debounceDelay = 50; // o tempo de estabilizacao (debounce);
// aumente se houver oscilacao na saida.

void setup() {
pinMode(buttonPin, INPUT_PULLUP); // habilita o resistor de PULL UP interno do Arduino
pinMode(ledPin, OUTPUT);

// ‘seta’ estado inicial do LED
digitalWrite(ledPin, ledState);
}

void loop() {
// le o estado do botao em uma variavel local
int reading = digitalRead(buttonPin);

// testa para ver se voce recem acaba de apertar o botao
// (i.e. a entrada foi de LOW para HIGH, e vc esperou tempo suficiente
// desde o ultimo pressionamento para ignorar qualquer ruido).

// Se o estado do botao mudou, seja por pressionamento ou por ruido
if (reading != lastButtonState) {
// ‘reseta’ o temporizador de debounce
lastDebounceTime = millis();
}

if ((millis() – lastDebounceTime) > debounceDelay) {
// seja qual for o valor da leitura, ele esta lah a mais tempo que
// o tempo de debounce (debounceDelay), entao podemos utilizar o valor:

// verifica se o botao mudou
if (reading != buttonState) {
buttonState = reading;

// apenas muda o estado (toggle) do LED se buttonState for LOW
if (buttonState == LOW) {
ledState = !ledState;
}
}
}

// ‘seta’ o LED
digitalWrite(ledPin, ledState);

// salva a leitura. Na proxima vez que passar no loop
// essa leitura sera o ultimo estado do botao (lastButtonState).
lastButtonState = reading;
}

 

Diagrama de montagem do circuito. O LED que deverá ser observado é incluido na placa. Observe que é há LED SMD próximo dos LEDS indicadores de TX e RX e do pino 13, indicado pela letra L. Esse LED tem em praticamente todas as placas Arduino e está ligado ao pino 13, para indicar seu status. Daí porquê esse circuito tem apenas o botão, com o objetivo de agilizar e facilitar seu aprendizado da técnica de debouncing por software. Lembre que no início do artigo falamos sobre a importância do debouncing via hardware também. No entanto, para a grande maioria das aplicações a técnica de software que aqui demonstramos é suficiente.

debounce_pullup

 

 

Anúncios

3 Respostas

  1. Este código esta muito confuso, logo vou postar um bem legal.

  2. Legal, Sidney! 😉 Compartilhe com a gente depois um link para sua postagem, se for possível. Esse é o código da documentação oficial do Arduino, apenas fiz a tradução dos comentários para o português, e expliquei porquê é correto usar a função millis() e não a função delay() para o debouncing. Mas não esqueça de compartilhar, se possível! Abraço!

  3. Probablemente se copia alún caracter invisible en la línea:
    if ((millis() – lastDebounceTime) > debounceDelay)
    Reescribí la línea y funcionó.

Deixe um comentário

Preencha os seus dados abaixo ou clique em um ícone para log in:

Logotipo do WordPress.com

Você está comentando utilizando sua conta WordPress.com. Sair / Alterar )

Imagem do Twitter

Você está comentando utilizando sua conta Twitter. Sair / Alterar )

Foto do Facebook

Você está comentando utilizando sua conta Facebook. Sair / Alterar )

Foto do Google+

Você está comentando utilizando sua conta Google+. Sair / Alterar )

Conectando a %s

%d blogueiros gostam disto: