Sensores analógicos no Arduino: uma experiência inicial, incluindo funções

Um sensor que custa alguns centavos pode detectar se está escuro, e a partir daí podemos comandar de forma coordenada o funcionamento de 2 leds, fazendo uso de funções em C e de um timer sem delay.

Como primeira experiência prática com sensores analógicos, montei um circuito com um sensor de iluminação.

Para dar um pouco mais de funcionalidade, fiz a montagem com 2 leds independentes, e programei o Arduino para funcionar assim: se o sensor detecta que escureceu (por exemplo, ao apagar a luz do quarto), ele acende 2 leds, e os mantém acesos por um timer.

Na hora de apagar, entretanto, ele não os apaga juntos: apaga primeiro um, aí espera um tempo antes de apagar o outro, para dar tempo de você apertar um botão se quiser que ambos voltem a ficar acesos por mais um ciclo do timer.

Descrevendo o circuito

O circuito é simples, envolvendo 2 leds (L1 e L2) e seus resistores associados (R1 e R2 – e 330Ω é um valor genérico bem seguro para cada um deles), um botão (S1 – chave de 2 terminais 'normalmente aberta'), o sensor (L3 – um simples e barato fotoresistor ou resistor fotossensível), e um resistor comum de 10KΩ (R3) associado a ele, mais o Arduino, uma breadboard, e os jumpers que forem necessários para as conexões (eu usei 6, mas poderia ter usado bem menos).

O esquema simplificado acima mostra os detalhes lógicos da montagem, inclusive em qual pino do Arduino cada componente é montado. Os únicos componentes para os quais você precisa prestar atenção à polaridade são os leds, cuja perna maior precisa ficar conectada ao pino, e a outra perna ao Terra. Os demais componentes podem ser montados de qualquer lado.

A inteligência básica do circuito é dada pelo fotoresistor L3. Note que um lado dele está conectado ao pino de 5V e o outro está conectado simultaneamente ao pino analógico A3 do Arduino e a um resistor de 10KΩ ligado ao terra para fazer o papel de pull-down.

O que o fotoresistor faz é reduzir a sua resistência conforme aumenta a luminosidade que incide sobre ele. Como ele está conectado ao pino A3 e recebendo continuamente a corrente que sai do pino 5V do Arduino, isso significa que quando ele estiver bem iluminado, a resistência dele vai baixar, e mais corrente chegará ao pino A3. Inversamente, quanto mais escuro o ambiente, mais resistência, e menos corrente chegará ao pino A3.

O restante do circuito são conexões bem simples: 2 leds conectados, de um lado, a pinos digitais do Arduino e, do outro, a resistores de 330Ω conectados ao terra, e um botão conectado a um pino digital do Arduino e ao terra.

Descrevendo o programa

O programa para o Arduino precisa tomar várias decisões a partir das 2 fontes de entrada possíveis no circuito acima: o fotoresistor e o botão.

Como o fotoresistor está ligado a uma porta analógica do Arduino, sabemos que a corrente que ele deixar passar será convertida pelo Arduino em um número inteiro na faixa de 0 a 1023. Para facilitar a minha vida, vou usar a função map para sempre converter esse inteiro em um número entre 1 e 10, diminuindo a precisão e passando a ter uma "nota" de 1 a 10 para a luminosidade detectada. A sintaxe dessa conversão é assim: valorConvertido=map(valorOriginal,0,1023,1,10);.

A outra entrada possível é o botão, que está conectado a um pino digital e assim sabemos que ele vai gerar um valor HIGH ou LOW quando pressionado, dependendo do que eu conectar à sua outra ponta. Como eu o conectei a outra ponta ao terra, o valor que ele vai gerar no pino ao ser pressionado é um LOW.

Para garantir que o pino de entrada estará sempre HIGH exceto quando o botão for pressionado, eu não vou inicializá-lo da forma tradicional (que seria pinMode(9, INPUT);), e sim garantindo o uso do pull-up interno do Arduino, com o comando pinMode(chave, INPUT_PULLUP);. E se você ainda não teve curiosidade de ir pesquisar o que é um resistor pull-up, agora seria um bom momento de fazê-lo ;-)

Com todas as informações acima, já dá de imaginar a lógica básica do programa, que é: se o botão for pressionado ou a luz do ambiente apagar (ou seja, se o valor lido do fotoresistor passar a estar abaixo de certo limite), os leds devem acender e o timer para apagá-los deve iniciar.

Se o timer iniciar, a contagem deve ocorrer considerando os limites diferentes para ambos os leds (porque um apaga antes do outro). Como ela não pode impedir a reação ao eventual pressionamento de um botão, o timer não poderá ser um simples delay(), mas sim ocorrer em paralelo ao funcionamento do loop() do Arduino.

Na animação acima você vê eu usar uma lanterna para trapacear o nível de iluminação do ambiente. No momento em que eu desligo, os 2 leds acendem e, em seguida, apagam de forma escalonada.

O restante do programa são as burocracias: declarar variáveis e constantes, acender e apagar os leds, etc. – mas, para aumentar a clareza às custas do aumento da contagem dos elementos do programa, movi para 2 funções o "filé mignon" do programa: acender os leds (iniciando o timer) e controlar o timer.

Criando o programa para o Arduino

Antes de explicar, vejamos uma versão colorizada do código completo do programa que descrevi acima:

/*  Sensor-acende-led: acende 2 leds quando fica escuro, e os apaga separadamente
  
    (c)  Augusto Campos 28.11.2014 - BR-Arduino.org
    Usage of the works is permitted provided that this instrument is retained 
    with the works, so that any entity that uses the works is notified of 
    this instrument. DISCLAIMER: THE WORKS ARE WITHOUT WARRANTY. */


const int limite_claridade=7; // sensor igual ou abaixo deste valor indica escuro
const int iluminador1=4;  // pino do primeiro led
const int iluminador2=5;  // pino do segundo led
const int chave=9;        // pino onde esta a chave/botao
const int lim_timer1=10000; // ciclos para apagar o primeiro led
const int lim_timer2=20000; // ciclos para apagar o segundo led

int contador=0;
int contando=0;
bool estavaClaro=false;

void setup() {
  pinMode(iluminador1, OUTPUT);
  pinMode(iluminador2, OUTPUT);
  pinMode(chave, INPUT_PULLUP);
}

void loop() {
  int sensor=analogRead(3);
  int luz10=map(sensor,0,1023,1,10);
  if (luz10<=limite_claridade && estavaClaro && contando==0) {
    acendeIluminadores();
  }   
  if (digitalRead(chave)==LOW) {
    acendeIluminadores();
  }  
  if (contando!= 0) controlaContador();
  estavaClaro=(luz10>limite_claridade);
}

void acendeIluminadores() {
  digitalWrite(iluminador1,HIGH);
  digitalWrite(iluminador2,HIGH); 
  contador=0;
  contando=1;
}

void controlaContador() {
  contador++;
  if (contador==lim_timer1) digitalWrite(iluminador1,LOW);
  if (contador==lim_timer2) {
      digitalWrite(iluminador2,LOW);
      contando=0;
  }    
}

Os trechos em cinza são apenas comentários, que podem ser importantes para a compreensão do programa mas não interferem na sua funcionalidade, nem no tamanho do que vai ser transferido para o Arduino após a compilação.

Em marrom temos, primeiro, 6 linhas que começam com a palavra const. Elas definem constantes, que servirão como parâmetro para o funcionamento do programa. A primeira delas, limite_claridade, foi obtida após várias tentativas e erros, até que eu verifiquei que no meu ambiente e sensor, o número 7 corresponde ao valor, na escala de 7 a 10, que indica a escuridão diurna quando fecho a cortina. Num teste noturno, eu reduziria este valor. A seguir temos a definição dos pinos digitais em que estão conectados os componentes, e a duração dos timers para cada led (os números mencionados correspondem a poucos segundos, numa aplicação real eles precisariam ser maiores e, possivelmente, de outro tipo numérico1).

Logo abaixo temos 3 variáveis2, também em marrom, mas eu as diferenciei usando itálico. As duas primeiras são para controle do timer, e a última delas (com o nome de estavaClaro) serve para armazenar um estado anterior do sensor, de modo a ser possível verificar se "já estava escuro" ou se "estava claro e ficou escuro" – só o segundo caso justifica acender os leds.

Aí vem em verde a função setup(), obrigatória, que inicializa o Arduino. No nosso caso, ela se limita a definir os papeis de cada pino digital. Note o uso do papel INPUT_PULLUP – já comentamos sobre ele, acima.

Em seguida, em vermelho, vem o loop(), também obrigatório, que é a parte que o Arduino repetirá constantemente. Conjugue a informação a seguir com o que já comentamos na descrição do programa, acima:

  1. o loop lê o sensor e em seguida o converte (na variável luz10) em um número de 1 a 10 indicando a iluminação detectada.
  2. Se luz10 estiver abaixo do limite de claridade definido nos parâmetros3 e se antes estava claro4 e se já não estivermos com os leds acesos5, a função acendeIluminadores() será executada.
  3. Da mesma forma, se o estado do pino a que está conectado nosso botão indicar que ele está pressionado, a função acendeIluminadores() também será executada.
  4. Se a variável contando contiver um valor diferente de zero, significa que estamos com um timer em andamento, e aí chamaremos a função controlaContador() para... controlar o contador.
  5. Encerrando o loop, a variável estavaClaro recebe um valor verdadeiro caso neste momento a iluminação no ambiente esteja acima do nosso limite de claridade, e falso no caso contrário. Isso serve para que possamos detectar o momento em que a luz se apaga, que é aquele no qual a variável estavaClaro indica que na volta anterior do loop ainda estava claro, mas na volta atual do loop o sensor informa que não está mais – como você pode perceber revendo o item 2 desta lista, acima.

Para fechar, vem o filé mignon, em preto: as duas funções responsáveis por acender os leds (e iniciar o timer) e por controlar o timer.

Veremos primeiro a acendeIluminadores(). O que ela faz é bem simples: acende os 2 leds, zera o contador e define a variável contando com o valor 1 – lembra que acima, no item 4 do loop, a presença de um valor diferente de zero nessa variável era usada para ver se estávamos com um contador em andamento?

Completando, a função controlaContador() é a responsável por fazer andar o nosso timer. Para que o programa se mantenha permanentemente responsivo ao pressionamento do botão, optei por não usar um timer baseado na função delay() (que interrompe o processamento6), e sim na contagem de vezes que o loop() é executado (o que não interrompe o processamento).

Note que o funcionamento dela é simples: ela soma 1 ao valor do contador (que foi zerado quando os leds acenderam, na acendeIluminadores()), e compara o novo valor do contador aos limites dos timers de cada um dos leds: se tiver sido alcançado o primeiro deles, o led correspondente é simplesmente apagado. Quando chegar ao limite do segundo led, o outro led será apagado e o valor zero será atribuído à variável contando, indicando que não estamos mais com um timer em andamento.

Um ponto interessante para você observar: o botão tem o poder de acender os 2 leds e zerar o contador até mesmo se os leds já estiverem acesos, e independentemente do estado anterior da variável estavaClaro.

Outro ponto interessante, que eu mesmo preciso observar: este circuito parece bem adequado para quando eu for fazer algum experimento com PWM (para controlar a intensidade dos leds) e com um sensor de presença. E também com os timers internos do Arduino. E com outras interrupções. Creio que voltarei a ele algumas vezes ;-)

 
  1.  Ou eu precisaria implementar outro tipo de timer. Chegarei a isto, mas é uma experiência futura.

  2.  As variáveis estão definidas no cabeçalho porque serão usadas em várias funções – são variáveis globais. Não são a melhor prática de programação aplicável aqui, mas as alternativas prejudicariam a explicação a não-programadores, então preferi recorrer a elas e manter mais clareza.

  3.  O limite de claridade é definido na constante limite_claridade, explicada acima.

  4.  O funcionamento da variável estavaClaro é explicado adiante, no texto.

  5.  Quando os leds estão acesos, haverá um timer em andamento, e por isso a variável contando será diferente de zero, como veremos.

  6.  Uma alternativa seria usar interrupções, mas é cedo para isso, no meu aprendizado.

Comentar

Dos leds ao Arduino, ESP8266 e mais

Aprenda eletrônica com as experiências de um geek veterano dos bits e bytes que nunca tinha soldado um led na vida, e resolveu narrar para você o que descobre enquanto explora esse universo – a partir da eletrônica básica, até chegar aos circuitos modernos.

Por Augusto Campos, autor do BR-Linux e Efetividade.net.

Recomendados

Livro recomendado


Artigos já disponíveis

Comunidade Arduino

O BR-Arduino é integrante da comunidade internacional de entusiastas do Arduino, mas não tem relação com os criadores e distribuidores do produto, nem com os detentores das marcas registradas.

Livros recomendados