Arquivos Mensais: agosto \31\UTC 2014

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

 

 

Método de Entrada ASCII com um Potenciômetro – Arduino

Esse é um projeto de método de entrada de caracteres ASCII para o Arduino utilizando um potenciômetro para escolher o caractere. Esse projeto pode ser ainda mais simples, utilizando apenas um botão e um potenciômetro para inserir qualquer caractere da tabela ASCII. Nesse aqui, no entanto, eu adicionei um botão para automaticamente inserir o caractere ESPAÇO, dividi a tabela ASCII em categorias (tipos) de caracteres e adicionei um botão para alternar entre essas/esses categorias/tipos, e ainda um terceiro botão que serve para apagar um caractere ou, se pressionado por mais de meio segundo, toda a linha.  Esse método de entrada pode ser usado em substituição a um teclado para inserir pequenos grupos de caracteres, como para colocar senhas, por exemplo, em algum sistema de controle de acesso.

Seguem o código, o diagrama e um vídeo do projeto montado e funcionando.

#include <LiquidCrystal.h>

// configura os pinos do LCD

LiquidCrystal lcd(7, 8, 9, 10, 11, 12);

int inserir = 3;
int apagar = 5;
int espaco = 4;
int sel_tipo = 2;
int tipo = 0;
char palavra[16];
int i = 0;

void setup() {
lcd.begin(16,2);
pinMode(inserir, INPUT_PULLUP);
pinMode(apagar, INPUT_PULLUP);
pinMode(sel_tipo, INPUT_PULLUP);
pinMode(espaco, INPUT_PULLUP);
}

void loop() {

lcd.setCursor(0,0); // seta a posicao do cursor para o inicio

if(digitalRead(sel_tipo) == LOW){ // quando o botao ‘sel_tipo’ eh pressionado
delay(500); // o delay de meio segundo eh para evitar dupla execucao da funcao
if(tipo < 6){
tipo++;
} else {
tipo = 0;
}
}

int primeiro = 65; // valor que inicia o mapeamento da entrada analogica
int ultimo = 90; // valor que termina o mapeamento da entrada analogica

switch(tipo){ // esse switch vai definir as faixas de mapeamento pela tabela ASCII
case 0:
primeiro = 65;
ultimo = 90;
lcd.print(“ABC”);
break;

case 1:
primeiro = 97;
ultimo = 122;
lcd.print(“abc”);
break;

case 2:
primeiro = 48;
ultimo = 57;
lcd.print(“123”);
break;

case 3:
primeiro = 33;
ultimo = 47;
lcd.print(“!*.”);
break;

case 4:
primeiro = 58;
ultimo = 64;
lcd.print(“>?@”);
break;

case 5:
primeiro = 91;
ultimo = 96;
lcd.print(“[\\]”);
break;

case 6:
primeiro = 123;
ultimo = 126;
lcd.print(“{|}”);
break;
}

/* Esse bloco eh o responsavel pela selecao do caractere.
A funcao ‘map’ ira mapear o valor analogica lida em ‘A0’, que na transformacao
analogico-digital interna do ATMEGA varia de 0 a 1023, para a faixa escolhida pelo
‘switch’ logo acima, que eh escolhida pressionando o botao ‘sel_tipo’. Por exemplo,
se ‘tipo’ for igual a 0, o valor de ‘analogRead(A0)’ sera transportado da faixa de
0 a 1023 para a faixa de 65 a 90, ou seja, de A a Z.
*/
char caractere = map(analogRead(A0), 0, 1023, primeiro, ultimo);
lcd.setCursor(14,0);
lcd.print(caractere);

if(digitalRead(inserir) == LOW){ // quando o botao ‘inserir’ eh pressionado
delay(500);
if(i == 15){ // se o cursor esta no final, nao insere caractere e avisa!
lcd.clear();
lcd.setCursor(0,0);
lcd.print(” CHEGA! Delete “);
lcd.setCursor(0,1);
lcd.print(” alguma coisa! “);
delay(700);
lcd.clear();
} else {
palavra[i] = caractere; // insere caractere na string ‘palavra’
i++;
}
}

if(digitalRead(espaco) == LOW){ // adiciona o caractere ESPACO quando
delay(500); // o botao ‘espaco’ eh pressionado
if(i == 15){ // se o cursor esta no final do display, nao insere caractere e avisa!
lcd.clear();
lcd.setCursor(0,0);
lcd.print(” CHEGA! Delete “);
lcd.setCursor(0,1);
lcd.print(” alguma coisa! “);
delay(700);
lcd.clear();
} else {
palavra[i] = 32; // insere caractere ESPACO -> ASCII 32
i++;
}
}

if(digitalRead(apagar) == LOW){ // quando o botao ‘apagar’ eh pressionado
if(i > 0){ // testa se existe algo para apagar
i–;
}
palavra[i] = false; // ‘unseta’ o caractere da posicao ‘i’ no vetor/string ‘palavra’
delay(500);
if(digitalRead(apagar) == LOW){ // se o botao ‘apagar’ ficar
for(int j=0;j<16;j++){ // pressionado mais de meio-segundo
palavra[j] = false; // ‘unseta’ todos os caracteres do vetor/string ‘palavra’
i = 0; // e retorna o indice ‘i’ para o inicio do vetor
}
}
lcd.clear(); // eh importante para nao deixar o cursor perdido
}

// muda para a segunda linha do LCD, mostra a palavra (se existir) e o cursor
lcd.setCursor(0,1);
lcd.print(palavra);
lcd.print(“_”);
}

Esse é o diagrama que gerei com o Fritzing. Os botões do tipo “pushbutton” estão na ordem: ‘sel_tipo’, ‘inserir’, ‘espaco’, ‘apagar’ (ver comentários do código). O display LCD está com um brilho fixo através do resistor de 1k no terceiro pino, caso queira colocar um potenciômetro para ajuste, sem problemas: consulte a página do arduino sobre isso se tiver dúvida.

ASCII_input_pot_bb

Aqui está o vídeo de demonstração do projeto. No vídeo, aparecem alguns componentes (resistor e LM7805 – tinha mais um LED mas tirei pra fazer o vídeo) que adicionei para fazer o projeto funcionar fora da porta USB – que está servindo para alimentar o circuito com 5V -, alimentando com uma bateria de 7.4 V sucateada de um tablet… rs. Enjoy! =)

RESOLVIDO! “Skype can’t connect” no Ubuntu 13.10

Instalei hoje a versão mais atual do Ubuntu 13.10, instalei o Skype e… não conectou. A mensagem? “Skype can’t connect” e era isso. Tive ainda um problema com a conta da Microsoft (a grande vilã, sempre) mas, enfim, deu tudo certo. Acontece que uso Skype desde muito antes da grande vilã tomar conta da casa. Enfim… não interessa. O caso é que tive esse problema. Como resolvi? Simples, surfando, encontrei a solução: o problema é que o Skype do repositório oficial do Ubuntu no meu sistema recém baixado e instalado contém a versão 4.2 do Skype, que é antiga, e não é mais suportada pelos servidores. Bingo! Por isso não funciona. A soluçao é baixar o pacode deb do site do Skype e instalar manualmente com o dpkg. Eu tinha usado um tutorial do Sempre Update para instalar o Skype, só que tive esse problema porque era a versão antiga.

Como o tutorial é ótimo e completo (o único problema mesmo é a versão do skype que é antiga), vou apenas dizer o que precisa ser mudado. Quando seguir o tutorial, que pode ser acessado nesse link, substitua a linha:

sudo wget http://download.skype.com/linux/skype-ubuntu-precise_4.2.0.11-1_i386.deb

Por essa:

sudo wget http://download.skype.com/linux/skype-ubuntu-precise_4.3.0.37-1_i386.deb

É só mudar a url do pacote deb! #Chuta

Cláusula Perdida

Saulo Ramos, ex-ministro da Justiça e Consultor-Geral da República, intitulou seu livro de memórias de Código da Vida, fazendo referência à sua vida de estudar e trabalhar com códigos, numa conclusão de que a vida também tem o seu.

Pois nesse Código da Vida, às vezes,  a gente não passa de uma cláusula perdida que o Legislador esqueceu… dá até pra ouvir as vozes jurisconsultas: “é uma cláusula perdida!”