Módulo Bluetooth HC-06 e HC-05 – Arduino

Módulo Bluetooth HC-05 e HC-06 – Acionando um módulo relé via Bluetooth

Dentre os mais diversos protocolos de comunicação atuais, o Bluetooth certamente é um dos mais populares. Sendo assim, neste tutorial, iremos aprender como montar um projeto com uma placa Arduino, usando um smartphone para ligar e desligar uma pequena bomba submersa com o auxílio de um módulo relé e do módulo Bluetooth HC-06 / HC-05 . Para estabelecer a comunicação entre nosso smartphone e o Arduino, iremos utilizar o aplicativo Bluetooth Controller. O aplicativo possui uma interface simples, onde com uma configuração básica seremos capazes de controlar o nosso módulo relé.

[toc]

A importância de um sistema de comunicação sem fio

Sistemas automáticos precisam de meios para interagir com o usuário ou com outros sistemas, de modo que, isso faz da comunicação um assunto muito importante quando estamos tratando de automação.

Ter uma forma de comunicação sólida em um projeto é muito importante, pois será através dela que iremos estabelecer a interface que permitirá a comunicação entre o usuário e o sistema.

Infelizmente, grande parte dos microcontroladores não possuem uma interface sem fio já embutida e como consequência temos a criação de uma grande dificuldade em projetos onde existe a necessidade de um canal de comunicação sem fio. Com isso, uma solução interessante é o uso do padrão Bluetooth, que é voltado para aplicações de baixo consumo. Um módulo capaz de suprir esta demanda, é o módulo HC-06, que veremos a seguir.

Simbolo do padrão Bluetooth
Simbolo do padrão Bluetooth

Seguindo a linha de raciocínio anterior, o padrão Bluetooth, tem como principais vantagens:

  • Baixo consumo energético
  • Velocidade de transmissão considerável
  • Integração com smartphones
  • Padrões retrocompatíveis

Com todas estas características, podemos considerar que o padrão Bluetooth é de fato um ótimo meio para se transmitir dados de forma fácil e com um baixo custo energético para o sistema. Porém, o padrão tem suas limitações, como:

  • Curto alcance
  • Conexão ponto a ponto ( apenas dois pares podem se comunicar por vez )

Protocolo Bluetooth e o uso com Arduino

Em suas versões mais simples, as placas Arduino não contam com uma conexão Bluetooth nativa. Porém, é possível a aquisição de módulos capazes de estabelecer a conexão e a troca de mensagens entre a sua placa Arduino e um outro dispositivo com interface Bluetooth.

Um módulo com este propósito é o HC-06, este circuito é capaz de abstrair toda a parte da comunicação sem fio necessária para a comunicação bluetooth, fornecendo uma interface serial para que o microcontrolador possa enviar ou receber dados.

Com o uso do Bluetooth, você pode desenvolver uma vasta gama de projetos, como por exemplo:

  • Controlar robôs:
Controlando um robô com módulo Bluetooth HC-05
Controlando um robô usando Bluetooth
  • Automatizar praticamente qualquer coisa que esteja conectada ao seu Arduino
Acendendo um LED usando o módulo Bluetooth HC-05 / HC-06
Acendendo um LED usando o módulo Bluetooth HC-05 / HC-06

Módulo Bluetooth HC-05 e HC-06

Estes módulos utilizam a versão 2 do padrão Bluetooth, que por sua vez, apesar de já estar ultrapassado, ainda é viável em projetos como o que será desenvolvido neste tutorial. Com eles você abstrai toda a parte da comunicação sem fio, bastando enviar os dados via comunicação serial para eles.

Esses módulos são muito semelhantes e para nosso projeto você poderá optar por qualquer um dos dois. A diferença entre eles, além da versão do firmware, é o número de pinos. Geralmente os módulos HC-06 possuem apenas 4 pinos, enquanto que geralmente os módulos HC-05 contam com 6 pinos.

É importante ressaltar que o módulo Bluetooth HC-06 não possui o modo de funcionamento master dessa forma se optar pelo seu uso, o módulo ficará restrito a sempre precisar solicitar uma conexão com o dispositivo para a requisição ou transmissão de dados. Caso tenha a necessidade de um módulo capaz de funcionar tanto no modo master quanto slave, você pode utilizar o módulo Bluetooth HC-05, que é capaz de operar nos dois modos.

- Módulo HC-05

O módulo Bluetooth HC-05, dispõe de 6 pinos de entrada e saída de dados, sendo dois deles para alimentação do sistema, dois para transmissão e recepção de dados via serial e dois para programa-lo em modo master. Logo abaixo temos a especificação do dispositivo:

Módulo Bluetooth HC-05
Módulo Bluetooth HC-05
  • Especificações
    • Bluetooth: 2.0V
    • Tensão de funcionamento: 3.3v~5v
    • Taxa de transmissão: 2Mbps
    • Frequência: 2,4 Ghz
    • Nível lógico: 3.3v
    • Pinos: VCC , GND , TXD , RXD;
    • Perfis suportados: Escravo (slave) e Mestre (master)

- Módulo HC-06

O módulo Bluetooth HC-06, dispõe de apenas 4 pinos de entrada e saída de dados, sendo dois deles para alimentação do sistema, e os outros dois para transmissão e recepção de dados via serial. Logo abaixo temos a especificação do dispositivo:

Módulo Bluetooth HC06
Módulo Bluetooth HC-06
  • Especificações
    • Bluetooth: 2.0V
    • Tensão de funcionamento: 3.3v~5v
    • Taxa de transmissão: 2Mbps
    • Frequência: 2,4 Ghz
    • Nível lógico: 3.3v
    • Pinos: VCC , GND , TXD , RXD;
    • Perfis suportados: Escravo (slave) e Mestre (master)

Módulo Relé

É comum, em projetos de automação, termos que acionar ou desligar dispositivos mediante algum parâmetro tal como a temperatura do ambiente, pressão, ou até mesmo a simples solicitação do usuário. Para que isso seja possível, podemos utilizar um circuito comumente conhecido como relé, que por sua vez, nada mais é do que uma simples chave eletromecânica acionada através de uma bobina em seu interior, permitindo ligar e desligar equipamentos elétricos, através da abertura ou fechamento de seu contato em virtude do fornecimento de energia a esta bobina.

Neste projeto, iremos também utilizar um módulo relé para realizar o acionamento da nossa bomba quando requisitado pelo usuário. Este módulo utiliza apenas três pinos, sendo dois para alimentação (5 Volts) e outro para acionamento.

Módulo Relé 1 canal

Mãos à obra - Acionando um módulo relé utilizando o módulo Bluetooth HC-06 ou HC-05 - Arduino

Como esse projeto irá usar o módulo Bluetooth no modo Slave, poremos usar tanto o HC-05 quanto o HC-06. Para nosso projeto usaremos o HC-06, mas você pode adotar os mesmos procedimentos para o HC-05.

Componentes utilizados

Montando o projeto

A montagem deste projeto, pode ser feita seguindo a seguinte ordem para os fios:

Esquema de montagem no Arduino Uno com HC-05
Esquema de montagem no Arduino Uno com HC-05

A montagem do sistema deve ficar semelhante a imagem abaixo

ATENÇÃO: Tanto o módulo HC-06, quanto o HC-05 utilizam o nível lógico de 3.3 volts, logo para utilizar o pino de transmissão TX, você deve adicionar ao projeto um divisor de tensão, já que o nível lógico do Arduino Uno ( 5 Volts ) pode danificar o seu módulo. Porém como neste tutorial não iremos transmitir informações do arduino para o telefone, não iremos precisar do divisor de tensão.

Esquema de montagem do projeto como módulo Bluetooth HC-06 e módulo relé no Arduino Uno na prática
Projeto montado na prática com Módulo Bluetooth HC-06 e Arduino Uno

Sempre monte seu projeto com a alimentação desligada para evitar possíveis curtos circuitos que podem danificar o seu dispositivo.

Programando

Agora que temos o nosso circuito montado, iremos partir para o código responsável por receber os dados através do Bluetooth e determinar se o relé deve ser acionado ou não. Neste exemplo em especial, não será necessária nenhuma biblioteca de terceiros, ou seja todas as bibliotecas que iremos utilizar já se encontram disponíveis na IDE do Arduino. O código abaixo ilustra todo o processo de funcionamento do nosso sistema:

#include <SoftwareSerial.h>
#define RX 8
#define TX 9
#define RELE 7
SoftwareSerial bluetooth(RX, TX); // RX, TX

void setup() {
  Serial.begin(9600); // Inicializa a serial nativa do Arduino
  pinMode(RELE,OUTPUT); // Inicializamos o pino 7 do relé como output
  digitalWrite(RELE,HIGH); // Inicializa a chave como desligada
  bluetooth.begin(9600); // Inicializa a serial via software (Onde está conectado o nosso módulo bluetooth)
}

void verificaBluetooth(){ // Verifica se existe algum dado a ser lido da serial
  if (bluetooth.available()){ // verifica se existem bytes a serem lidos da porta serial virtual
     char dados = bluetooth.read(); // Lê 1 byte da porta serial
     Serial.print(dados); // Mostra esse dado lido na porta serial
     if (dados=='0'){ // Se o byte lido for igual a 0
       digitalWrite(RELE,HIGH); // Desliga a chave
     }
     else{
        if (dados=='1'){ // Se o byte lido for igual a 1
          digitalWrite(RELE,LOW); // Liga a chave e aciona a bomba
        }
     }
  }
}

void loop (){
  verificaBluetooth();
}

Conectando o celular ao Arduino

Agora que temos o código que irá rodar no Arduino, devemos agora instalar o aplicativo que iremos utilizar no controle da bomba. Para instalar o aplicativo basta seguir os seguintes passos:

  • Na play store pesquisar por Bluetooth Controller, e instalar o aplicativo que está marcado

Bluetooth Controller intalando

instalando o Bluetooth Controller

  • Com o aplicativo instalado, iremos agora criar dois botões que serão utilizados para ligar e desligar a nossa mini bomba submersa, para isso devemos clicar no botão SET KEYS:

Configurando o Bluetooth Controller

  • Ao clicar em SET KEYS, seremos direcionados para a tela onde configuramos os botões q serem utilizados. Neste primeiro caso, iremos configurar apenas dois botões, sendo eles responsáveis por ligar e desligar o relé, o tipo de dado enviado também deverá corresponder ao que o nosso código espera, logo enviaremos 1 quando quisermos que a bomba seja ligada, e 0 quando quisermos que a bomba seja desligada.

configurando as saídas do Bluetooth Controller

  • Agora com todos os botões configurados, iremos buscar o dispositivo que queremos nos conectar, para isso selecionamos a opção SCAN   

Bluetooth Controller

  • Ao clicar no botão SCAN, seremos novamente redirecionados para outra tela, sendo esta no caso para selecionar o dispositivo com o qual desejamos nos conectar. No meu caso o dispositivo se chama Controle rele, porém pode ser que o seu se chame HC-05 ou HC-06 dependendo do qual esteja usando.

Na primeira conexão, você deverá fornecer uma senha para que o pareamento seja feito com sucesso, por padrão esta senha é 1234.

Bluetooth Controller procurando por dispositivos

  • Com a conexão estabelecida, agora podemos ligar e desligar a nossa bomba sem a necessidade de contato direto com ela.

Bluetooth Controller pareado com o Arduino e HC06

Colocando para funcionar


Entendendo a fundo

Software

- Incluindo as bibliotecas necessárias

Neste código, em especial, iremos apenas incluir uma única biblioteca, chamada SoftwareSerial. Neste exemplo iremos simular uma porta serial, através dos pinos 8 e 9 do Arduino, desta forma, mantemos a serial em hardware livre para ser utilizada no debug e gravação do código a ser executado. Essa biblioteca é nativa da IDE Arduino.

#include <SoftwareSerial.h>

- Parâmetros de configuração

Para facilitar o uso dos pinos selecionados para este sistema, iremos definir as seguintes constantes como mostra o código logo abaixo:

#define RX 8 
#define TX 9 
#define RELE 7

- Objeto bluetooth

Como dito anteriormente, iremos utilizar uma biblioteca que simula uma comunicação serial, desta forma evitamos a utilização da serial nativa, que pode ser utilizada posteriormente para depuração do código. O trecho de código abaixo, cria o objeto bluetooth, que será responsável por enviar os dados a serem transmitidos através pelo módulo HC-06. Algo que é importante ressaltar é que o módulo HC-06 abstrai toda a parte de comunicação do usuário, bastando apenas com que ele envie os dados que deseja transmitir utilizando a comunicação serial.

SoftwareSerial bluetooth(RX, TX); // RX, TX

-  Inicializando portas de comunicação e configurando relé para desativado

Na função setup, iremos inicializar as duas portas de comunicação (nativa e a que conectamos o nosso módulo bluetooth), através dos comandos Serial.begin(9600) e bluetooth.begin(9600). Também inicializamos o pino onde o módulo relé está conectado como OUTPUT, e inicializamos o módulo relé no estado HIGH. Algo que também deve ser levado em consideração, é o fato de que este módulo relé, diferente dos outros é ativo no nível lógico LOW, por isso inicializamos ele como HIGH.

void setup() { 
Serial.begin(9600); // Inicializa a serial nativa do arduino 
pinMode(RELE,OUTPUT); // Inicializamos o pino 7 do módulo relé como output 
digitalWrite(RELE,HIGH); // Inicializa a chave como desligada 
bluetooth.begin(9600); // Inicializa a serial via software (Onde está conectado o nosso módulo bluetooth) 
}

- Função Verifica loop

Já na função verificaBluetooth, iremos seguir a seguinte lógica:

  1. Verificamos se existe algum dado a ser lido em nossa serial virtual
    1. Se existir nós iremos ler apenas o primeiro byte desta mensagem através do comando bluetooth.read()
    2. Mostramos este dado lido na tela afim de ver se ele é realmente o que enviamos
    3. Logo em seguida verificamos se este valor é 0
      1. Se o valor for igual a 0 iremos abrir a chave do módulo relé ( desligar a bomba )
      2. Caso seja 1 iremos fechar a chave do módulo relé ( ligar a bomba )
      3. Caso não seja nenhum dos dois casos, iremos manter o sistema como está
void verificaBluetooth(){ // Verifica se existe algum dado a ser lido da serial
  if (bluetooth.available()){ // verifica se existem bytes a serem lidos da porta serial virtual
     char dados = bluetooth.read(); // Lê 1 byte da porta serial
     Serial.print(dados); // Mostra esse dado lido na porta serial
     if (dados=='0'){ // Se o byte lido for igual a 0
       digitalWrite(RELE,HIGH); // Desliga a chave
     }
     else{
        if (dados=='1'){ // Se o byte lido for igual a 1
          digitalWrite(RELE,LOW); // Liga a chave e aciona a bomba
        }
     }
  }
}

Considerações Finais

Este tutorial, teve como objetivo mostrar a utilização do módulo Bluetooth HC-06 e HC-05 no modo slave, em um contexto onde a utilização do Arduino é muito aplicada, que é a automação de equipamentos. Com este código apresentado como base, podem ser criados diversos projetos, como automatização residencial e controle de robôs, utilizando um smartphone. Espero que tenham gostado do conteúdo apresentado, sinta-se à vontade para nos dar sugestões, críticas ou elogios. Lembre-se de deixar suas dúvidas nos comentários abaixo.

Caso esteja começando com Arduino recomendamos que conheça a Apostila Arduino Básico.


Sensor de Gás MQ-135 e a Família de sensores MQ

Sensor de Gás MQ-135 e a família MQ de detectores de Gás 

O sensor gás MQ-135 é capaz de detectar a concentração de vários gases tóxicos em um ambiente tais como: amônia, dióxido de carbono, benzeno, óxido nítrico e também fumaça ou álcool. Neste tutorial vamos aprender como usa o módulo sensor de gás MQ-135 junto a um Arduino.  Esse tutorial também pode ser aplicado para outros sensores de gás, com alguns ajustes, tais como: MQ-2, MQ-3, MQ-4, MQ-5, MQ-6, MQ-7, MQ-8,MQ-9, etc.

Detector de gás / sensor de gás MQ-135
Detector de gás / sensor de gás MQ-135

[toc]

A importância dos sistemas de proteção

Os processos industriais envolvem o uso e fabricação de substâncias altamente perigosas, especialmente produtos inflamáveis, tóxicos e oxidantes. Os gases fazem parte desses ambientes como participantes de reações, catalisadores ou produtos finais. Outras vezes são resíduos ou subprodutos indesejáveis. Escapes ocasionais de gás ocorrem e criam um perigo potencial para a planta industrial, seus funcionários e pessoas que vivem nas proximidades. Incidentes e acidentes em todo o mundo, envolvendo asfixia, intoxicação, explosões e perdas de vidas é um lembrete constante desse problema.

Por isso, sistemas automáticos de detecção de gases são fundamentais para a proteção das pessoas envolvidas nesses processos. É necessário que tenhamos sensores adequados e que sejam posicionados em lugares estratégicos, de preferência com redundância.

É claro que esse tipo de proteção não se limita a industria. Podemos ver facilmente a aplicação de sensores de gás e fumaça em uma cozinha residencial ou em ambientes públicos. Enfim, podemos usar a automação a favor da vida, evitando assim acidentes.

Sensor de gás MQ

Existe uma grande gama de sensores de gás, estre eles, temos os MQ's. Esses sensores de detecção modernos e de baixo custo para gás combustível, são do tipo eletro-catalítico. Eles são feitos de uma bobina de fio de platina aquecido eletricamente, coberto primeiro com uma base de cerâmica, tais como alumina e, em seguida, com um revestimento final exterior do catalisador de paládio ou ródio disperso em um substrato de tório.

- Por dentro do sensor MQ

Na figura a seguir podemos entender um pouco melhor como é por dentro de um sensor de gás MQ.

Dentro de um sensor de gás MQ

Na vertical temos um resistência elétrica que aquece o ar. Essa resistência é ligada através da alimentação dos pinos H's, um vai no 5V e o outro no GND (0V).

De A para B temos nosso sensor de gás. Em uma atmosfera onde possa haver gás poluidor, a resistência do sensor de gás diminui conforme a concentração do gás poluente aumenta. Ou seja, quanto mais gás poluente, menor será a resistência entre A e B. Podemos conferir as variação da resistência conforme a concentração de gases no gráfico à seguir retirado da folha de dados do MQ-135:

Comportamento da resistência entre A e B conforme a concentração de alguns gases. para o sensor de gás MQ135
Comportamento da resistência entre A e B conforme a concentração de alguns gases.

Sendo assim, podemos montar um circuito onde temos uma tensão que será proporcional à quantidade de gases  poluentes.

Esquema interno de um sensor de gás MQ 135
Esquema interno de um sensor de gás MQ

Conforme a resistência entre A e B diminuir (mais gases poluentes), maior será a tensão em cima do resistor RL. Falamos um pouco sobre esse tipo de circuito, o divisor de tensão, no tutorial sobre o sensor de luz LDR.

- Encapsulamento dos sensores MQ

Em geral, os sensores da família MQ possuem o formato como o da figura a seguir:

Encapsulamento de um MQ-135
Encapsulamento de um sensor de gás MQ-135

Como você pode ver, na parte de baixo temos alguns pinos. Ao todo são seis. Esse seis pinos dão acesso ao circuito interno já explicado.

Dentro do encapsulamento do MQ-135
Dentro do encapsulamento do sensor de gás MQ-135

Para facilitar o uso, podemos adquirir esse sensores junto a uma placa que já conta com o circuito necessário para seu pronto funcionamento alem de contar com um circuito comparador.

Família de sensores de gás MQ
Família de sensores de gás MQ

Lista de sensores de Gás

Aqui está a lista de alguns dos sensores de gás que você pode encontrar. Você pode escolher o mais adequado para o seu projeto.

Nome do Sensor  Sensível para
MQ-2 Detecção de gases inflamáveis: GLP, Metano, Propano, Butano, Hidrogênio, Álcool, Gás Natural, outros inflamáveis e fumaça.
MQ-3 Detecção de Álcool , Etanol e fumaça.
MQ-4 Detecção de Metano, Propano e Butano.
MQ-5 Detecção de GLP e gás natural
MQ-6 Detecção de gás GLP (Gás de Cozinha), Propano, Isobutano e Gás Natural Liquefeito
MQ-7 Detecção do gás Monóxido de Carbono
MQ-8 Detecção do gás hidrogênio
MQ-9 Detecção de Monóxido de Carbono e gases inflamáveis
MQ-131 Detecção de ozônio
MQ-135 Detecção de Gás Amônia, Óxido Nítrico, Álcool, Benzeno, Dióxido de Carbono e Fumaça
MQ-136 Detecção de Gás Sulfídrico H2S
MQ-137 Detecção de Gás Amônia
MQ-138 Detecção de n-hexano, benzeno, NH3, álcool, fumaça, CO, etc.

Módulo sensor de Gás MQ-135 - Gases tóxicos e Fumaça

O modulo utilizado, MQ-135 funciona bem detecção de fumaça e outros gases tóxicos, especialmente amônia, vapor de sulfeto e benzeno. Sua capacidade de detectar vários gases nocivos e menor custo faz do MQ-135 uma escolha ideal de diferentes aplicações de detecção de gás.

Ele pode detectar concentrações na faixa de 10 a 1.000ppm (partículas por milhão), possuindo um range de tensão de 0 - 5V. Os módulos do MQ135 são capazes de operar na faixa de temperatura de -10 a 70ºC, consumindo uma corrente aproximada de 150mA.

mq-135
Módulo sensor de amônia MQ-135

O módulo também conta com um potenciômetro para regular a sensibilidade do  sensor, girando ele para um dos lados o sensor ficara mais sensível aos gases.

Atrás dp Sensor de Gás MQ-135 - Gases tóxicos e Fumaça
Por trás do módulo Sensor de Gás MQ-135

Mãos a Obra - Desenvolvimento do Projeto

Componentes necessários

Montando o projeto

A montagem do circuito é bem simples e direta. Basta seguir o esquemático abaixo.

Esquema de montagem do Arduino com o Sensor de Gás MQ-135 - Gases tóxicos e Fumaça

O modulo MQ 135 possui 4 pinos: dois pinos para alimentação (Vcc e GND) e dois pinos para emissão dos sinais elétricos, sendo um sinal digital (D0) e o outro um sinal analógico (A0). Para realizar a montagem, iremos conectar os pinos na seguinte ordem:

Pinos do Sensor de Gás MQ-135 - Gases tóxicos e Fumaça

Em nossa experiência conectamos os pinos do sensor direto na placa Uno, sem o auxilio do protoboard, tal como indicado na tabela anterior. Veja como ficou o nosso montado:

Projeto montado na prática com um Arduino Uno e Sensor de Gás MQ-135 - Gases tóxicos e Fumaça

Programando

Segue o código que utilizamos nesse projeto para fazer a detecção de gás no ambiente.

#define MQ_analog A2
#define MQ_dig 7

int valor_analog;
int valor_dig;

void setup() {
   Serial.begin(9600);
   pinMode(MQ_analog, INPUT);
   pinMode(MQ_dig, INPUT);
}

void loop() {
   valor_analog = analogRead(MQ_analog); 
   valor_dig = digitalRead(MQ_dig);

   Serial.print(valor_analog);
   Serial.print(" || ");
   if(valor_dig == 0)
     Serial.println("GAS DETECTADO !!!");
   else 
     Serial.println("GAS AUSENTE !!!");
   delay(500);

}

Colocando para funcionar

Primeiramente precisamos deixar que a resistência interna do sensor de gás esquente o suficiente para que as medições se estabilizem. Espere por 3 minutos. Chamamos essa espera de tempo de queima. Explicaremos isso mais a frente.

Após deixar o sensor de gás esquentar, vamos testa-lo forçando o ambiente com um fosforo/isqueiro para gerar CO2 (fumaça). O monitor serial irá indicar o valor analógico lido pelo sensor e também indicara se o gás foi detectado ou não, isso é uma resposta ao sinal digital emitido pelo módulo, e esse será calibrado conforme nos quisermos ao girar o potenciômetro. Para calibrar a detecção digital vamos estimular o sensor com o gás do isqueiro e quando acharmos que a estimulação seja suficiente, giramos o potenciômetro até que ele altere o estado entre NÃO DETECTADO <-> DETECTADO, assim esse passa a ser o novo ponto de referencia digital.

Testando o Sensor de Gás MQ-135 - Gases tóxicos e Fumaça para calibrar
Sensor de gás sendo exposto à fumaça da queima do fósforo

As imagens a seguir mostram a sequência que o sensor digital teve alternando o estado de LOW <->HIGH quando o valor analógico estava próximo de 82, neste exemplo eu mantive o fosforo acesso por alguns segundos próximo ao sensor apenas. Veja que na sequência de valores analógicos chega até 380, então de acordo com a duração e proximidade do fosforo ao sensor podemos ir calibrando o sensor digital dele.

Detectando a fumaça
Durante a detecção da fumaça
Deixando de detectar a fumaça

Entendo a fundo

Software

– Nomeando os pinos utilizados através da diretiva #define

O primeiro passo do programa consiste fazer o uso das diretivas #define para nomear os pinos que serão utilizados no projeto, ou seja, o pinos que estarão conectados ao sensor apresentado anteriormente. Sendo assim, neste caso temos que o pino de entrada analógica do Arduino UNO A2 passa a ser identificado no código através do nome MQ_analog, enquanto, o pino de entrada digital 7 do mesmo será referenciado no código pelo nome MQ_dig.

#define MQ_analog A2
#define MQ_dig 7

– Declarando a variável responsável por armazenar o estado do sensor

Em seguida, declaramos duas variáveis para armazenar os valores que forem lidos pelas portas do Arduino UNO, sendo uma delas do tipo inteiro, para a parte analógica e a outra, booleana, para a parte digital.

int valor_analog;
bool valor_dig;

– Configurando o sistema

Dentro da função void setup() vamos configurar as portas do Arduino e a comunicação serial. Vamos iniciar a comunicação serial numa taxa de 9600 bits por segundo e as portas utilizadas devem ser setadas como ENTRADAS (INPUT), afinal eles irão receber sinais elétricos para o Arduino.

void setup() {
   Serial.begin(9600);
   pinMode(MQ_analog, INPUT);
   pinMode(MQ_dig, INPUT);
}

– Rodando o programa principal

Dentro do void loop() teremos o programa rodando em loop infinito, sendo assim iremos faremos a leitura das portas do Arduino e imprimiremos na serial os valores para que possamos ter parâmetros mensuráveis. Com a função analogRead() fazemos a leitura analógica da porta A2. Utilizaremos esse valor apenas como parâmetro para calibrar a sensibilidade digital do sensor.

valor_analog = analogRead(MQ_analog);

Utilizando a função digitalRead() temos a leitura booleana do sensor, quando a resposta for 1 o gás esta sendo detectado, e quando for 0 o gás está ausente. Veremos mais adiante que a sensibilidade do sensor precisa ser ajustada com o potenciômetro do modulo.

valor_dig = digitalRead(MQ_dig);

Por fim fazemos a impressão dos valores lidos na serial, para que assim, possamos ver o resultado das leituras.

if(valor_dig == 0)
 Serial.println("GAS DETECTADO !!!");
 else 
 Serial.println("GAS AUSENTE !!!");
Detectando o gás
Detectando o gás

Hardware

– Calibrando o módulo digital

Como dito antes é necessário calibrar o sensor digital do módulo MQ 135. Para isso rode o programa anterior e abra o monitor serial e, com auxilio de uma pequena chave Philips, gire o potenciômetro na parte de trás do módulo até que o você encontre um ponto que altere de 0 pra 1. O valor analógico irá servir como base para mediar a sensibilidade do sensor.

Atrás do sensor de gás e fumaça MQ 135 - Resistência de calibração
Atrás do módulo MQ 135 - Resistência de calibração

- Tempo de queima - Burn-in time

Para que o sensor esteja pronto para fazer as medições é necessário aguardar um tempo denominado como Burn -in time (Tempo de queima) ou preheat (pré aquecimento). Esse tempo varia de modelo para modelo, mas para testes mais simples, como para familiarizar com o sensor, podemos aguardar cerca de 3 minutos. Esse é o tempo necessário para que a resistência do sensor aqueça até a temperatura ideal de funcionamento do sensor. Durante esse período as medições podem oscilar muito.

Para aplicações oficiais, tal como implementação de um detector de incêndio, onde precisamos de uma precisão de medição maior e mais confiável,  é recomendado pelos fabricantes que o tempo de queima seja de pelo menos 24 horas. Esse é o tempo necessário para que o sensor alcance a plena estabilização das medições entre os terminais internos A e B.


Considerações finais

Este projeto apresenta uma utilização básica do sensor MQ 135. Esperamos que você tenha gostado deste conteúdo, sinta-se à vontade para nos dar sugestões, críticas ou elogios. Lembre-se de deixar suas dúvidas nos comentários abaixo.

Caso esteja começando com Arduino recomendamos que conheça a Apostila Arduino Básico.


Banco de dados MySQL com Arduino e Shield Ethernet W5100

Banco de dados MySQL com Arduino e Shield Ethernet W5100 – Registrando temperatura em um banco de dados

Sabemos que a utilização de placas Arduino é bastante difundida nos dias atuais, de modo que, o seu uso está presente em uma grande diversidade de aplicações, que vão desde trabalhos acadêmicos até projetos comerciais e industriais, no entanto, um grande problema surge em todas estas vertentes quando nos deparamos com a necessidade de armazenar informações inerentes a um determinado processo. Sendo assim, neste tutorial iremos aprender como fazer o registro de informações, mais especificamente, de temperatura em um banco de dados MySQL com o auxilio do shield ethernet W5100.

[toc]

O que são bancos de dados?

De uma maneira bem simples, pode-se entender um banco de dados como sendo um local onde podemos armazenar uma série de informações de maneira estruturada, organizada, que por sua vez, estejam à disposição para serem utilizadas tanto por softwares quanto por usuários diferentes. Podemos, por exemplo, armazenar os valores de temperatura coletados ao longo de um dia por uma placa Arduino e armazenar os mesmos numa tabela juntamente com a hora da medição.

Pense em uma industria com centenas de sensores que fazem medições de dados do processo a todo instante. É necessário que os dados estejam organizados de forma adequada e que os mesmos estejam acessíveis sempre que necessário, pois, caso contrario, estes seriam uma gama de informações sem utilidade prática.

Sendo assim, podemos perceber que os bancos de dados são recursos muito importantes e essenciais para o funcionamento dos mais variados tipos de estabelecimentos, desde os menores até as grandes indústrias, hospitais e etc, pois, através dos dados presentes nos mesmos, realiza-se o controle, por exemplo, de funcionários, de material, de custos e além disso, é possível até mesmo auxiliar nas tomadas de decisão em virtude de uma análise estatística feita sobre os mesmos.

Para realizarmos este tutorial deve-se ter em mente que os bancos de dados ficam armazenados em um servidor, portanto, antes de acessarmos um banco de dados, devemos acessar primeiramente o servidor onde estes estão inseridos. Em contrapartida, as estruturas intrínsecas a um banco de dados são as tabelas (estas são, de fato, tabelas, dotadas de linhas e colunas).

Estrutura de um banco de dados MySQL

O MySQL, nosso Banco de dados

Quando realizamos algumas pesquisas sobre o que é o MySQL encontramos algumas fontes dizendo que o mesmo se trata de um banco de dados, enquanto outras, classificam o mesmo como um sistema gerenciador de banco de dados (SGBD) que utiliza a linguagem SQL como interface para realizar manipulação dos dados armazenados. Neste tutorial, como não estamos focados em toda parte teórica por trás deste assunto, basta encararmos o MySQL como um banco de dados, que não teremos maiores problemas.

 

Para utilizamos o MySQL, é necessário instalarmos um servidor, responsável por entre outras coisas, armazenar os dados e responder às requisições feitas por um cliente conectado com mesmo (conforme falando anteriormente, tanto softwares quanto usuários podem interagir com um servidor). O MySQL possui uma versão gratuita para a comunidade, que por sua vez, inclui diversos elementos, entre eles, o servidor e uma interface gráfica para ser utilizada como cliente.

A nossa sugestão é que você realize o download do instalador completo e instale o mesmo no seu computador.


Mãos à obra – Registrando informações no banco de dados

Neste momento, iremos demonstrar todos os passos para que você consiga realizar o objetivo que estamos propondo neste tutorial.

Componentes utilizados:

Montando o projeto

Esquema de montagem do Arduino Uno com Shield W5100 e Sensor de temperatura LM35
Esquema de montagem do Arduino Uno com Shield W5100 e Sensor de temperatura LM35

Programando

Antes de adentrarmos na apresentação do código, disponibilizamos uma seção para ajudar aqueles que são iniciantes no assunto. Sinta-se livre para prosseguir caso você já tem domínio da IDE do Arduino.

Conectando o Arduino ao computador

Primeiramente, conecte seu Arduino ao computador e abra a IDE Arduino. Em seguida, é necessário selecionar a porta COM na qual o Arduino está conectado (este procedimento pode ser feito clicando no menu Ferramentas (tools) e em seguida escolhendo-se a porta correspondente no submenu Porta (port). Neste caso, a porta na qual está o Arduino é apresentada da seguinte maneira: COM3 (Arduino UNO).

IDE Arduino configurando porta de comunicação

Por fim, garanta também que o tipo de placa apropriado esteja selecionado (isso pode ser feito acessando o menu Ferramentas (tools) e o submenu Placa (board)).

Configurando a placa Arduino UNO na IDE Arduino

- Biblioteca

Para desenvolver o projeto proposto  utilizou-se uma biblioteca capaz de atuar sobre um servidor MySQL fazendo com que o Arduino possa manipular dados existentes nas tabelas dos bancos de dados MySQL. Esta biblioteca pode ser encontrada aqui.

Adquirindo e instalando a biblioteca que será utilizada

Para adquirir a biblioteca em questão, basta acessar o link apresentado anteriormente, clicar no botão clone or Download e por fim, no botão Download ZIP, conforme a figura abaixo.

Baixando a biblioteca responsável pela comunicação com o banco de dados MySQL
Baixando a biblioteca responsável pela comunicação com o banco de dados MySQL

Após a realização do download dos arquivos compactados no formato ZIP, abra a IDE do Arduino, selecione o menu Sketch, o submenu Incluir Bilioteca e por fim, basta clicar na opção Adicionar biblioteca .ZIP (Add ZIP Library) e encontrar o arquivo que acabou de ser baixado.

Uma outra forma de fazer isso é extrair o conteúdo do arquivo ZIP dentro da pasta Libraries (onde foi instalada a IDE do Arduino).

– Preparação (VOCÊ DEVE LER ESTA PARTE)

Antes de partir para o código desta aplicação, devemos entender uma coisa: A placa Arduino utilizada não é capaz de criar bancos de dados e tabelas, conforme será visto adiante, portanto, para que seja possível registrarmos valores de temperatura em um banco de dados MySQL, devemos criar manualmente o banco de dados no servidor MySQL e também a tabela na qual serão efetuados os registros.

Além disso, devemos também realizar a criação de um usuário para ser utilizado neste nosso projeto.

O primeiro passo para que seja possível realizar a integração do Arduino com um banco de dados MySQL consiste em criar um usuário para acessar o servidor, bem como, a sua senha de acesso.

Quando nós instalamos um servidor MySQL em um computador, um usuário padrão chamado root (juntamente com uma senha definida pelo usuário) é criado no momento da instalação, porém, recomenda-se que criemos um novo usuário para entrar no servidor através do mesmo. Este procedimento deve ser realizado por dois motivos, onde o primeiro é que o próprio desenvolvedor da biblioteca recomenda que isto seja feito e segundo por que existem vários relatos de que o Arduino não consegue se conectar ao servidor através do usuário root.

Para realizar este procedimento, basta entrar no terminal do servidor MySQL. Isto pode ser feito, primeiramente, acessando o Prompt de comando e percorrendo o caminho até a pasta onde o servidor foi instalado e em seguida, utilizando o comando apresentado na figura a seguir:

Após a realização do passo anterior, você deverá digitar a senha do usuário root (definida na instalação do servidor) e então será possível acessar diretamente o terminal.

Na figura anterior, criamos um usuário chamado arduino, o qual, está atrelado a uma senha também nomeada arduino. O símbolo determina que qualquer IP pode entrar no servidor MySQL através deste usuário. Obviamente, em termos de segurança, este não é o procedimento mais adequado, no entanto, para nossa demonstração, é suficiente.

Agora que já criamos o usuário, devemos criar um banco de dados dentro do servidor, chamado banco_arduino. Este procedimento é bastante simples e pode ser realizado da seguinte maneira:

Por fim, devemos criar uma tabela (que será preenchida pelo Arduino UNO), que por sua vez, será o local onde serão inseridas as informações referentes aos valores de temperatura provenientes do sensor de temperatura LM35. Queremos uma tabela com o seguinte formato:

Exemplo de medições no banco de dados MySQL
Exemplo de medições no banco de dados MySQL

Para isto, devemos proceder conforme a figura abaixo:

Veja como ficou a tabela criada

Neste momento, temos todos os pré-requisitos necessários para começarmos a realizar a aplicação proposta neste tutorial.

– Código do projeto

Segue o código a ser utilizado no Arduino para registrar valores de temperatura em um banco de dados MySQL

#include <Ethernet.h>
#include <MySQL_Connection.h>
#include <MySQL_Cursor.h>
#include <SPI.h>

#define LM35 A0

int leitura;
float leituraconvertida
char sentenca[128];
char valortemp[10];

byte mac_addr[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };

IPAddress server_addr(192,168,25,5);  
char user[] = "arduino";              
char password[] = "arduino";        

char INSERIR_TEMP[] = "INSERT INTO registrotemp (temperatura) VALUES (%s)";
char BANCODEDADOS[] = "USE banco_arduino";

EthernetClient client;
MySQL_Connection conn((Client *)&client);

void setup() 
{ 
   Serial.begin(115200);
   while (!Serial); 
   Ethernet.begin(mac_addr);
   Serial.println("Conectando...");
   if (conn.connect(server_addr, 3306, user, password)) 
   {
      delay(1000);
      
      MySQL_Cursor *cur_mem = new MySQL_Cursor(&conn);
      cur_mem->execute(BANCODEDADOS);
      delete cur_mem;
   }
   else
   {
      Serial.println("A conexão falhou");
      conn.close();
   }
}


void loop() 
{
   Serial.println("Executando sentença");

   leitura = analogRead(LM35);
   leituraconvertida = (float(analogRead(LM35))*5/(1023))/0.01;

   dtostrf(leituraconvertida, 4, 1, valortemp);
   sprintf(sentenca, INSERIR_TEMP, valortemp);
   
   MySQL_Cursor *cur_mem = new MySQL_Cursor(&conn);
   cur_mem->execute(sentenca);
   delete cur_mem;

   delay(2000);
}

Entendendo a fundo

Software

Neste momento, iremos explicar o funcionamento do código apresentado, porém, de maneira bastante detalhada.

- Incluindo as bibliotecas a serem utilizadas no projeto

Primeiramente, para desenvolvermos uma aplicação como esta, devemos incluir todas as bibliotecas que serão utilizadas no código, para que assim, o mesmo possa funcionar de maneira adequada. A biblioteca Ethernet.h é responsável pela comunicação que será estabelecida entre o Arduino UNO e a rede através do Shield ethernet wiznet w5100. Já a biblioteca SPI.h  tem como função coordenar a integração do shield citado com o Arduino UNO por meio do protocolo de comunicação SPI.

As bibliotecas MySQL_Connection MySQL_Cursor têm como função promover a conexão Arduino UNO/servidor MySQL e executar as sentenças de manipulação de informações em um banco de dados.

#include <Ethernet.h>
#include <MySQL_Connection.h>
#include <MySQL_Cursor.h>
#include <SPI.h>

- Nomeando o pino de entrada analógica através da diretiva #define

Em seguida, utilizamos a diretiva #define para associar o pino de entrada analógica A0 ao nome LM35 (vale ressaltar que isso é apenas um recurso para facilitar a didática da programação, portanto, não obrigatório).

#define LM35 A0

- Declarando as variáveis a serem utilizadas no projeto

Posteriormente, temos um bloco onde ocorre a declaração das variáveis que serão utilizadas no decorrer do programa. As variáveis leitura (tipo inteiro) e leituraconvertida (tipo float) são responsáveis por armazenar o valor obtido da porta de entrada analógica A0 (através da função analogRead(), portanto, contido no intervalo de 0 a 1023) e o valor já convertido em temperatura, respectivamente.

int leitura;
float leituraconvertida;

Observe que também foram criados dois vetores do tipo char, estes são: sentenca e valortemp. Os elementos citados servirão para conter as frases (lembre-se que um vetor de elementos do tipo char é um vetor de caracteres) necessárias para a construção das sentenças que serão utilizadas para manipular os dados no servidor MySQL.

O tamanho dos vetores deve ser tal que os mesmos consigam armazenar as mensagens que serão utilizadas, sendo assim, não existe um valor certo para os mesmos, mas sim, um valor que atenda as necessidades conforme será visto mais adiante. Note que também é possível não declarar um valor para o tamanho, deixando que o programa calcule automaticamente a dimensão do mesmo.

char sentenca[128];
char valortemp[10];

- Definindo o endereço MAC do Arduino UNO

O próximo passo consiste em definir o endereço MAC que será atribuído ao Arduino UNO para que a conexão entre o mesmo e a rede possa ser estabelecida. No desenvolvimento deste projeto, conectamos o Shield Ethernet em nosso modem.

Na prática, este endereço pode ser qualquer um, desde que seja único na rede.

byte mac_addr[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };

- Definindo os parâmetros para a conexão com o servidor MySQL

Após a realização dos procedimentos listados anteriormente, deve-se definir os parâmetros necessários para que o Arduino UNO consiga ser conectado ao servidor MySQL existente. A primeira informação essencial é IP do servidor MySQL (caso o servidor esteja rodando, por exemplo, no seu laptop, o IP a ser inserido neste campo será justamente o IP do seu computador na rede local e para consulta-lo basta abrir o prompt de comando, digitar ipconfig e copiar o Endereço IPV4 (se estiver em inglês, IPV4 Address)).

IPAddress server_addr(192.168.25.5);

Veja como esta informação pode ser obtida:

Em seguida, escolhe-se um dos usuários cadastrados e a senha do mesmo, para que o Arduino UNO entre no servidor MySQL através destas informações. Neste caso, utilizamos o usuário chamado arduino cuja senha atribuída ao mesmo é arduino.

char user[] = "arduino";             
char password[] = "arduino";

- Criando as sentenças para manipulação de dados

Agora, devemos criar as sentenças que serão utilizadas pelo Arduino UNO para registrar as informações no banco de dados existente no servidor MySQL. 

A primeira sentença informa ao Arduino UNO qual dos bancos de dados existentes no servidor MySQL será manipulado, neste caso, o banco chamado banco_arduino.

Quando estamos interagindo diretamente com um servidor MySQL através do seu terminal, utilizamos a sentença "USE <nome do banco de dados>;" para selecionar um determinado banco de dados existente no servidor em questão. Sendo assim, declaramos um vetor de variáveis do tipo char, sem tamanho definido, para que este armazene a sentença citada anteriormente, de modo que, quando necessário, o Arduino UNO seja capaz de utilizá-la.

char BANCODEDADOS[] = "USE banco_arduino";

A segunda sentença é responsável por preencher uma linha de uma determinada tabela existente dentro de um banco de dados, neste caso, a tabela chamada registro.

Quando manipulamos uma tabela de um banco de dados através do terminal de um servidor MySQL, utilizamos a sentença "INSERT INTO <nome da tabela> <coluna a ser preenchida da tabela> VALUES <valor a ser colocado na interseção da coluna definida anteriormente com próxima linha vazia não preenchida>;" para preencher uma determinada linha da mesma. Desta maneira, assim como no item anterior, declaramos um vetor de variáveis do tipo char para que seja possível armazenar a sentença adequada para o propósito citado.

char INSERIR_TEMP[] = "INSERT INTO registrotemp (temperatura) VALUES (%s)";

- Declarando os objetos client e conn

Neste momento, cria-se dois objetos que serão utilizados posteriormente, de modo que, um destes é do tipo EthernetClient, chamado client (que representará o elemento responsável pela comunicação via ethernet no código) e outro do tipo MySQL_Connection, chamado conn (que será responsável pela conexão com o servidor MySQL).

Lembre-se: client e conn são apenas nomes, sendo assim, é importante ressaltar que, os objetos identificados por client e conn poderiam ser chamados de quaisquer outros nomes, como por exemplo, conexaoethernet e conexaomysql, respectivamente.

EthernetClient client;
MySQL_Connection conn((Client *)&client);

- Estabelecendo a conexão com o servidor MySQL

Primeiramente, utilizamos a função Serial.begin() para inicializar a comunicação serial. Neste caso, determinamos como parâmetro da função uma taxa de 115200 baud/s em virtude deste valor ter sido utilizado pelo desenvolvedor da biblioteca presente neste tutorial. Em seguida, recorremos à função while() com o argumento !Serial, para que o programa só continue sendo executado após a comunicação serial ter sido estabelecida.

Não só estes procedimentos, como todos os outros que envolvem a manipulação da porta serial, servem apenas para testes, isto é, para que você possa verificar se o programa está com algum tipo de erro ou se está funcionando perfeitamente, portanto, as linhas referentes aos mesmos podem ser comentadas caso o programa esteja funcionando da maneira desejada.

 Serial.begin(115200);
 while (!Serial); // wait for serial port to connect

Em seguida, utilizamos a função Ethernet.begin() para iniciar a comunicação com a rede via Ethernet. Observe que o parâmetro desta função é o endereço MAC definido anteriormente.

Ethernet.begin(mac_addr);

Para facilitar na visualização da execução do programa, imprimimos na porta serial a seguinte informação: "Conectando..."

Serial.println("Conectando...");

A próxima linha de código conta com uma função if(), cujo argumento é uma outra função, responsável pela conexão do Arduino com o servidor MySQL, de modo que, nesta função são passados como parâmetros o endereço IP da máquina onde está o servidor, a porta para o acesso do mesmo (geralmente, na instalação do servidor, a porta que vem definida como padrão é a 3306), o usuário e a senha do mesmo. Caso esta função consiga ser executada com exito, isto é, caso a conexão com o servidor ocorra sem problemas, o argumento testado na função if() será verdadeiro e o seu conteúdo será executado.

if (conn.connect(server_addr, 3306, user, password)) 
{
    ****** Conteúdo da função if() ******
}

O conteúdo da função if() começa com a utilização de uma função delay() para estabelecer um atraso na execução do programa e garantir o estabelecimento da conexão com o servidor MySQL.

delay(1000);

Em seguida, criamos um objeto do tipo MySQL_Cursor, chamado cur_mem. Este cursor será responsável por executar as sentenças que serão utilizadas para manipular as informações do banco de dados.

MySQL_Cursor *cur_mem = new MySQL_Cursor(&conn);

Posteriormente, utilizamos a função execute(), de modo que, o parâmetro da mesma é justamente a variável do tipo char BANCODEDADOS. Lembre-se que o conteúdo desta variável é a frase "USE banco_arduino", que por sua vez, é o comando responsável por selecionar o banco de dados banco_arduino, entre os outros eventuais bancos existentes no servidor.

cur_mem->execute(BANCODEDADOS);

Por recomendação do desenvolvedor da biblioteca, após a execução da sentença desejada, apagamos o cursor criado anteriormente, em virtude do uso de memória.

delete cur_mem;

Confira o conteúdo completo da função if()

if (conn.connect(server_addr, 3306, user, password)) 
{ 
    delay(1000);
  
    MySQL_Cursor *cur_mem = new MySQL_Cursor(&conn);
    cur_mem->execute(BANCODEDADOS);
    delete cur_mem;
}

Caso a condição da função if() não seja satisfeita, isto é, se a conexão com o servidor não tiver ocorrido com sucesso, executa-se o conteúdo da função else, que por sua vez, consiste nas funções Serial.println() para imprimir uma mensagem de falha na conexão e a função close(), responsável por encerrar a tentativa de conexão.

{
     Serial.println("A conexão falhou");
     conn.close();
}

Observe como está a nossa função setup():

void setup() {
 
  Serial.begin(115200);
  while (!Serial); 
  Ethernet.begin(mac_addr);
  Serial.println("Conectando...");
  if (conn.connect(server_addr, 3306, user, password)) 
  {
     delay(1000);
   
     MySQL_Cursor *cur_mem = new MySQL_Cursor(&conn);
     cur_mem->execute(BANCODEDADOS);
     delete cur_mem;
  }
  else
  {
     Serial.println("A conexão falhou");
     conn.close();
  }
}

- Registrando a temperatura em banco de dados MySQL

O primeiro procedimento a ser executado na função loop() é o envio de uma mensagem através da porta serial avisando ao usuário que algum tipo de manipulação no banco de dados está sendo executada.

Serial.println("Executando sentença");

Em seguida, realiza-se a leitura da porta de entrada analógica (através da função analogRead()) na qual está conectado o sensor e armazena-se o resultado na variável leitura.

leitura = analogRead(LM35);

Posteriormente, realizamos a conversão do valor inteiro adquirido para valores de temperatura. O cálculo apresentado e toda explicação sobre o sensor de temperatura LM35 estão presentes no nosso tutorial LM35 - Medindo a temperatura com Arduino.

leituraconvertida = (float(analogRead(LM35))*5/(1023))/0.01;

O próximo passo consiste na conversão do valor de temperatura de float para string. Isso deve ser feito para que este valor possa ser inserido em uma sentença (lembre que elas são montadas sobre um vetor de char) e assim, possa ser utilizado para manipular as informações do banco de dados.

A função utilizada para cumprir este propósito é a dtostrf(). Nesta função, existem quatro parâmetros, onde estes são: a variável do tipo float que queremos converter, o número de algarismos que o resultado da conversão deve ter (incluindo a vírgula), o número de casas após a vírgula e o vetor de char em que será armazenada a informação retornada por esta função.

dtostrf(leituraconvertida, 4, 1, valortemp);

Veja com mais detalhes o funcionamento desta função:

Após a conversão do valor citado, utilizamos a função sprintf() construir a sentença contendo a instrução que será utilizada na manipulação do banco de dados. O primeiro parâmetro desta função consiste na variável do tipo char na qual será armazenada a sentença após ser construída, o segundo, deve conter a variável que armazenou a parte textual da frase e o local onde será inserida a variável (%s) e o terceiro parâmetro é justamente a variável que será inserida no local especificado no segundo parâmetro.

sprintf(sentenca, INSERIR_TEMP, valortemp);

Veja um esquema detalhado do funcionamento da função:

Em seguida, realizamos o mesmo procedimento apresentado anteriormente para manipular o banco de dados, onde, primeiramente criamos o cursor, executamos uma sentença (deste vez é a sentença para incluir uma linha na tabela) e por fim, deletamos o cursor criado.

MySQL_Cursor *cur_mem = new MySQL_Cursor(&conn);
cur_mem->execute(sentenca)
delete cur_mem;

Por fim, utilizamos a função delay() para fazer com que o banco de dados seja preenchido apenas a cada 2 segundos

delay(2000);

Veja como ficou a nossa função loop()

void loop() {
 
  Serial.println("Recording data.");

  leitura = analogRead(LM35);
  conversao = (float(analogRead(LM35))*5/(1023))/0.01;

  dtostrf(conversao, 1, 1, temperatura);
  sprintf(sentenca, INSERIR _TEMP, temperatura);
  
  // Initiate the query class instance
  MySQL_Cursor *cur_mem = new MySQL_Cursor(&conn);
  // Execute the query
  cur_mem->execute(query);
  // Note: since there are no results, we do not need to read any data
  // Deleting the cursor also frees up memory used
  delete cur_mem;
delay(2000);
}

Considerações finais

Neste tutorial demonstramos um conteúdo novo e muito interessante para aqueles que gostam de desenvolver aplicações com uma placa Arduino mas não sabem como, por exemplo, registrar informações para uso posterior. Aqui, apresentamos os procedimentos necessários para fazer com que seja possível elaborar um projeto integrando o processo de aquisição de dados com o Arduino UNO e o armazenamento dos mesmos em um banco de dados de um servidor MySQL. Esperamos que você tenha gostado deste conteúdo e sinta-se à vontade para nos dar sugestões, críticas ou elogios. Lembre-se de deixar suas dúvidas nos comentários abaixo.


Display LCD 20x4 e 16x2 com Adaptador I2C

Display LCD 20x4 e LCD 16x2 com Adaptador I2C – Utilizando o display com Arduino

No tutorial sobre a utilização de um display lcd 16x2 com Arduino aprendemos a importância dos displays e como usar um LCD de caracteres, em especial o 16x2. Apesar de esse LCD ser prático e simples, ele possui um problema, uma grande demanda por ligações. Para resolver isso, podemos usar um módulo adaptador I2C que facilita ainda mais o uso desse tipo de recurso. Nesse tutorial iremos aprender a usar o Display LCD 20x4 com Adaptador I2C junto a um Arduino.

O uso tanto do display LCD 16x2 tanto do display LCD 20x4 é muito semelhante, a diferença entre eles é o numero de caracteres que dispõem na tela. Como falamos sobre o modelo 16x2 no último tutorial, iremos aproveitar a oportunidade para mostrar um pouco mais sobre o modelo 20x4. Caso você tenha em suas mão o 16x2, você poderá facilmente adaptar o programa usado nesse tutorial para você.

[toc]

Porque usar comunicação I2C para controlar seu LCD?

Display LCD 20x4 Azul
Display LCD 20x4 Azul

Na figura acima, percebemos a existência de uma grande quantidade de contatos para realização do seu acionamento. Para facilitar o seu uso, iremos trabalhar com o adaptador I2C para display LCD.

Para usar esse LCD diretamente no Arduino, você irá precisa, além das ligações de alimentação,  de 6 pinos: RS, EN, D7, D6, D5, e D4 para que seu LCD converse com seu Arduino. Se você estiver trabalhando com um projeto mais complexo, talvez você não terá tantos pinos disponíveis no seu Arduino para seu LCD da forma usual.

Com o módulo de interface I2C, você precisará de apenas 2 pinos (I2C) para imprimir as informações que deseja em seu LCD. Se você já tiver usando outros componentes I2C em seu projeto, esse pino não precisará usar mais nenhuma porta, visto que ele poderá usar os mesmo pinos já usado para o outro dispositivo I2C.

Adaptador I2C para Display LCD 20x4 e 16x2

Adaptador I2C para display LCD
Adaptador I2C para display LCD

Para que seja possível a comunicação entre o Arduino e o LCD, precisaremos de um adaptador I2C. Esse adaptador nada mais é  que um conversor cuja função consiste em manipular os contatos do LCD, de modo que, após este processo, teremos apenas 2 contatos para realizar a comunicação com uma placa Arduino através do protocolo I2C.

Ele conta com o chip PCF8574T ou PCF8574AT que é responsável por essa interface . Você pode encontrar vários modelos de módulos ligeiramente diferentes.

Em geral eles possuem o seguinte formato:

detalhamento Adaptador I2C LCD
detalhamento Adaptador I2C para display LCD

Como você pode ver na imagem, a maioria dos módulos de interface I2C para LCD possuem:

  • Pinos para conexão com o Display (16 pinos);
  • Pinos de Alimentação do Módulo (GND e VCC);
  • Pinos de comunicação I2C (SDA e SCL);
  • Trimpot para ajuste de contraste da tela;
  • Jumper para ligar e desligar a luz de fundo (Backlight);
  • Led indicador de módulo ligado.
  • Chip de Interface (PCF8574T ou PCF8574AT )

Endereço do módulo I2C

Para alguns modelos ainda é possível configurar o endereço do módulo I2C através de A0, A1 e A2. Abaixo você pode conferir a tabela de endereços possíveis para cada um dos chips (PCF8574T ou PCF8574AT ):

Endereços configuráveis para os chips PCF8574T e PCF8574AT.( L para 0V e H para 5V)

A0, A1 e A2 são portas do nosso Chip:

Portas do chip PCF8574T e PCF8574AT
Portas do chip PCF8574T e PCF8574AT

Que em geral vem ligados a alimentação do módulo (VCC):

Esquema de ligação dos pinos de endereço
Esquema de ligação dos pinos de endereço

Quando conectamos o ponto 1 com 1, 2 com 2 ou 3 com 3, estamos colocando um nivel lógico baixo em A0, A1 ou A2 respectivamente. Na figura anterior, os pinos A0, A1 e A2 estão conectados ao chip do módulo. Veja que segundo esse esquemático, estamos com 5V em cada um dos 3 pinos. Ou seja, nosso endereço será 0x27 caso o chip seja o PCF8574T ou 0x3F caso o chip seja o PCF8574AT.

tabela do lcd i2c

Para alterar o endereço podemos colocar um ponto de solda para conectar os pinos A0, A1 ou A2 ao GND para as placas que tenha essa opção:

Opção para alteração de endereço

Para conectar os pinos A0, A1 ou A2 ao GND, você precisa pode usar solda de estanho para ligar o ponto de baixo com o de cima, tal como na figura a seguir:

Adaptador com chip PCF8574T com A0, A1 e A2 conectados ao GND. logo o endereço será 0x20.

Display LCD 20x4 com adaptador I2C

Para o nosso tutorial, iremos usar um LCD que já possui o adaptador soldado ao módulo display. Para o display que usaremos não temos a opção de mudança de endereço:

Display LCD 20x4 com adaptador
Display LCD 20x4 com adaptador

Veja em detalhes o módulo I2C usado:

Repare que ele não tem a opção de mudança de endereço. O chip dele é o PCF8574T, ou seja, iremos usar o endereço 0x27.

Display LCD 16x2 com adaptador I2C

Você também pode usar a versão do Display LCD 16x2 com adaptador I2C. A maior diferença é a quantidade de caracteres. Explicaremos mais a frente como adaptar o programa que usamos nesse tutorial para o display LCD 16x2.

O endereçamento funcionará da mesma forma que o explicado anteriormente. Verifique o modelo do seu adaptador para descobrir o endereço do mesmo.

Display LCD 16x2 Azul + Adaptador I2C
Display LCD 16x2 Azul + Adaptador I2C

Mãos à obra – Imprimindo informações no display LCD 20x4 I2C

Componentes utilizados

Caso tenha um LCD 16x2 ou 20x4 e queira adapta-lo, basta adquirir o Módulo i2C separado.  Módulo I2C para Display LCD compativel com 16x02 e 20x4

Montando o projeto

Na figura abaixo, o leitor poderá conferir como foi realizada a montagem do projeto apresentado neste tutorial.  Lembre-se de montar o projeto com o seu Arduino desligado.

Esquema de montagem do Display LCD 20x4 Azul + Adaptador I2C com Arduino Micro
Esquema de montagem do Display LCD 20x4 Azul + Adaptador I2C com Arduino Micro

Esquema de montagem do Display LCD 20x4 Azul + Adaptador I2C com Arduino UNO
Esquema de montagem do Display LCD 20×4 Azul + Adaptador I2C com Arduino UNO

Veja como ficou o nosso:

Projeto montado com Display LCD 20x4 Azul + Adaptador I2C com Arduino Micro

Programando

Antes de adentrarmos na apresentação do código, disponibilizamos uma seção para ajudar aqueles que são iniciantes no assunto. Sinta-se livre para prosseguir caso você já tem domínio da IDE do Arduino.

Conectando o Arduino ao computador

Primeiramente, conecte seu Arduino ao computador e abra a IDE Arduino. Em seguida, é necessário selecionar a porta COM na qual o Arduino está conectado (este procedimento pode ser feito clicando no menu Ferramentas (tools) e em seguida escolhendo-se a porta correspondente no submenu Porta (port). Neste caso, a porta na qual está o Arduino é apresentada da seguinte maneira: COM3 (Arduino Micro).

Por fim, garanta também que o tipo de placa apropriado esteja selecionado (isso pode ser feito acessando o menu Ferramentas (tools) e o submenu Placa (board)).

- Biblioteca

Para desenvolver o projeto proposto com o Display LCD I2C 20X4 utilizou-se uma biblioteca capaz de atuar sobre o protocolo I2C para facilitar os processos de endereçamento e troca de dados que fazem parte do funcionamento do protocolo citado. Esta biblioteca pode ser encontrada aqui.

Adquirindo e instalando a biblioteca que será utilizada

Após a realização do download dos arquivos compactados no formato ZIP, abra a IDE do Arduino, selecione o menu Sketch, o submenu Incluir Bilioteca e por fim, basta clicar na opção Adicionar biblioteca .ZIP (Add ZIP Library) e encontrar o arquivo que acabou de ser baixado.

Uma outra forma de fazer isso é extrair o conteúdo do arquivo ZIP dentro da pasta Libraries (onde foi instalada a IDE do Arduino).

– Código do projeto

Segue o código a ser utilizado no Arduino para imprimir informações no Display LCD I2C 20x4.

#include <Wire.h>
#include <LiquidCrystal_I2C.h>

// Inicializa o display no endereco 0x27
LiquidCrystal_I2C lcd(0x27,2,1,0,4,5,6,7,3, POSITIVE);
 
void setup()
{
 lcd.begin (20,4);
}
 
void loop()
{
  lcd.setCursor(0,0);
  lcd.print("********************");
  lcd.setCursor(9,1);
  lcd.print("VIDA");
  lcd.setCursor(5,2);
  lcd.print("DE SILICIO");
  lcd.setCursor(0,3);
 lcd.print("********************");
}

Entendendo a fundo

Software

- Incluindo as bibliotecas

Inicialmente, observe que foi necessário incluir duas bibliotecas no código para que o mesmo pudesse funcionar corretamente. A biblioteca wire.h é a responsável pela comunicação utilizando o protocolo I2C enquanto a biblioteca LiquidCrystal_I2C.h atua sobre a biblioteca wire.h simplificando o processo de comunicação através do protocolo citado, para que assim, o usuário possa utilizar o Display LCD I2C 20x4 de maneira mais fácil.

#include <Wire.h>
#include <LiquidCrystal_I2C.h>

- Criando o objeto lcd 

Em seguida, cria-se um objeto que será utilizado posteriormente para representar o Display LCD I2C 20x4 no código.

Lembre-se: lcd é apenas um nome, sendo assim, é importante ressaltar que este objeto poderia ser chamado por qualquer outro nome, como por exemplo, display.

LiquidCrystal_I2C lcd(0x27,2,1,0,4,5,6,7,3, POSITIVE);

Essa função é padrão tanto para o LCD 20x4 como para o 16x2. Nela definimos o endereço do adaptador, que para o nosso equivale sempre 0x27.

Além do endereço, definimos, nesse comando, os  pinos no chip I2C usados para conexões no LCD. Como esse pinos sempre são os mesmos, temos esse comando sendo usado para definir apenas o endereço, que para alguns módulos pode ser alterado. As demais configurações são padrões.

// Define os pinos do chip I2C usados para as conexões do LCD:
//               (Endereço,en,rw,rs,d4,d5,d6,d7,bl, blpol)
LiquidCrystal_I2C lcd(0x27, 2, 1, 0, 4, 5, 6, 7, 3, POSITIVE);

- Definindo as configurações iniciais

Dentro da função setup() utilizamos a função lcd.begin() (repare que o nome lcd corresponde ao objeto criado anteriormente) para inicializar o Display LCD I2C 20x4, de modo que, os parâmetros utilizados são o número de colunas e o número de linhas do display, nesta ordem.

void setup()
{
 lcd.begin (20,4);
}

Veja que, caso esteja usando um display LCD 16x2, aqui você definirá o tamanho do LCD com 16 colunas e 2 linhas:

void setup()
{
 lcd.begin (16,2); //configuração para display 16x2
}

- Imprimindo informações no Display

O primeiro passo na manipulação do display consiste em localizar o cursor no local adequado. Este cursor nada mais é do que o elemento que apontará para o espaço que será preenchido com um caractere, sendo assim, utilizamos a função setCursor() para determinar qual será o ponto de partida da escrita de uma sequência de caracteres.

Perceba que a as posições dos espaços para escrita são dadas da seguinte forma:

Desta maneira, ao utilizarmos "0" e "0" como parâmetros, estaremos definindo a coordenada (0,0) como ponto de partida para o começo da escrita.

lcd.setCursor(0,0);

Em seguida, utilizamos a função print() para poder escrever algo a partir da posição que definimos como ponto de partida. Neste caso, simplesmente preencheremos com '*'.

lcd.print("********************");

Posteriormente, utilizamos novamente a função setCursor() para posicionar o cursor na segunda linha.

lcd.setCursor(9,1);

Com o cursor posicionado, escrevemos a palavra 'VIDA'.

 lcd.print("VIDA");

Para continuar, posicionamos o cursor na próxima linha.

lcd.setCursor(4,2);

E escrevemos as palavras "DE SILICIO".

lcd.print("DE SILICIO");

Para finalizar, posicionamos o cursor no início da última linha.

lcd.setCursor(0,3);

Neste momento, iremos proceder da mesma maneira que fizemos na primeira linha, preenchendo a mesma com '*'.

lcd.print("********************");

Veja como ficou nossa função loop():

void loop()
{
  lcd.setCursor(0,0);
  lcd.print("********************");
  lcd.setCursor(0,1);
  lcd.print("aaaaaaaaaaaaaa");
  lcd.setCursor(0,2);
  lcd.print("ssssssssssssssss");
  lcd.setCursor(0,3);
  lcd.print("ddddddddddddddd");
}

Adaptando o programa para o display LCD 16x2

Para adaptar esse programa para o LCD 16x2 você precisa ter em mente que a tela é menor. Tendo 16 colunas e 2 linhas.

- Definindo as configurações iniciais

Dentro da função setup() utilizamos a função lcd.begin()  para inicializar o Display LCD I2C 16x2, de modo que, os parâmetros utilizados são o número de colunas e o número de linhas do display, nesta ordem.

void setup()
{
 lcd.begin (16,2); //configuração para display 16x2
}

- Imprimindo informações no Display

Na manipulação do display precisamos localizar o cursor no local adequado usando o comando setCursor() . Perceba que a as posições dos espaços para escrita são dadas da seguinte forma:

Em seguida basta usar o comando lcd.print().


Considerações finais

Neste tutorial buscamos elaborar um conteúdo semelhante ao que já temos sobre a utilização de displays LCD, no entanto, neste caso, utilizamos um display que ao invés de utilizar vários pinos numa placa Arduino, este necessita apenas de 4 pinos em virtude de a comunicação ser feita através do protocolo de comunicação I2C. Esperamos que você tenha gostado deste conteúdo, sinta-se à vontade para nos dar sugestões, críticas ou elogios. Lembre-se de deixar suas dúvidas nos comentários abaixo.


Sensor de Presença PIR | HC-SR501

Sensor de presença com Arduino | PIR HC-SR501

Automação residencial é claramente uma das áreas mais exploradas entre os grandes amantes de tecnologia. Nesse tutorial iremos aprender a montar um dos sistemas de automação mais comuns em nosso cotidiano, os detectores de presença e movimento. Para isso iremos abordar a utilização do Sensor de presença, também chamado de sensor de movimento, mais especificamente o Sensor PIR HC-SR501 e ensinar os procedimentos básicos na manipulação do mesmo para uso junto com Arduino.

[toc]

Sensores de Presença

É comum em alguns ambientes, tais como, banheiros não residenciais, garagens ou até mesmo corredores de edifícios, as lâmpadas acenderem de forma automática e instantânea.

Os sensores de presença possuem diversas aplicações, entre as mais populares estão a de controlar sistemas de iluminação e a de detectar a presença de invasores em alarmes.  Com certeza você já viu um desses sensores.

sensor de presença
Sensor de presença

Além da preocupação com a segurança, este tipo de comportamento automático também contribui para a economia de energia elétrica, evitando o desperdício da mesma e consequentemente para a diminuição de gastos.

Existem diversos formatos, todos com a mesma finalidade: Detectar a presença de pessoas. E como ele é capaz de fazer isso?

Sensor PIR

Todos esses sensores possuem uma coisa em comum, um sensor Piroelétrico ou também conhecido como Sensor PIR. Esse sensor é um pequeno componente capaz de detectar níveis de irradiação infravermelha emitidas pelo corpo humano.

sensor pir
Sensor PIR

Dentro desse sensor temos dois elementos piroelétricos que podem detectar uma faixa em uma faixa especifica determinados espectros de radiação.

Quando alguém passa na frente desse sensor, primeiramente a pessoa passará na zona de detecção do primeiro elemento piroelétrico e depois na zona de detecção do segundo elemento. Quando a pessoa passa pelo primeiro, ele gera um pulso de tensão na saída, quando ele passa na frente do outro, ele gera um pulso de tensão de sinal contrário. Tal como podemos ver na imagem abaixo:funcionamento sensor pir sr501

Módulo Sensor PIR HC-SR501

Para nosso sistema automático iremos usar o módulo sensor de presença HC-SR501. Uma das vantagens desse sensor é a praticidade de usá-lo unido ao seu pequeno tamanho.

Sensor de presença pir - HC SR501
Sensor de movimento PIR HC-SR501

Tal como os demais detectores de presença, ele também possui um sensor piroelétrico por baixo desse domo branco. Vale ressaltar que esse domo branco tem uma função importante, ele aumenta a zona de alcance do sensor.

Sensor PIR dentro do módulo HC-SR501
Sensor de movimento PIR dentro do módulo HC-SR501

Este módulo já vem com todo sistema para tratamento do sinal e por isso o funcionamento deste sensor é bastante simples, de modo que, basta alimentar o mesmo, esperar a inicialização completa e a partir deste momento, quando algum corpo emissor de radiação infravermelha passar pelo alcance do sensor, o pino de saída deste proporcionará um sinal de nível alto em seu terminal, que por sua vez, pode ser utilizado por uma placa Arduino como sinalização da presença de algum elemento.

O sensor HC-SR501 possui dois potenciômetros na parte traseira onde, em um deles é possível selecionar o tempo em que o pino de saída citado ficará em nível alto quando o sensor detectar algo (este tempo pode variar de 5 segundos a 2 minutos e meio), enquanto o segundo possui a funcionalidade de ajustar a distância máxima de percepção do sensor, de modo que, é possível configurar esta sensibilidade para valores em torno de 3 a 7 metros.

Módulo sensor de presença PIR HC-SR501
Módulo sensor de presença PIR HC-SR501

Mãos à obra – Detectando elementos com o Sensor de presença - Sensor PIR HC-SR501

Componentes utilizados:

Montando o projeto

Na figura abaixo, o leitor poderá conferir como foi realizada a montagem do projeto apresentado neste tutorial.  Lembre-se de montar o projeto com o seu Arduino desligado.

esquema de montagem do sensor de presença e movimento pir HC-SR501 com o Arduino micro

Veja como ficou o nosso:

montagem do projeto de sensor pir na prática

Programando

Antes de adentrarmos na apresentação do código, disponibilizamos uma seção para ajudar aqueles que são iniciantes no assunto. Sinta-se livre para prosseguir caso você já tem domínio da IDE do Arduino.

Conectando o Arduino ao computador

Primeiramente, conecte seu Arduino ao computador e abra a IDE Arduino. Em seguida, é necessário selecionar a porta COM na qual o Arduino está conectado (este procedimento pode ser feito clicando no menu Ferramentas (tools) e em seguida escolhendo-se a porta correspondente no submenu Porta (port). Neste caso, a porta na qual está o Arduino é apresentada da seguinte maneira: COM3 (Arduino Micro).

Por fim, garanta também que o tipo de placa apropriado esteja selecionado (isso pode ser feito acessando o menu Ferramentas (tools) e o submenu Placa (board)).

– Código do projeto

Segue o código a ser utilizado no Arduino para Detectar um elemento com o sensor de Presença PIR - HC-SR501

bool estadoSensor;

void setup() {
   
  pinMode(2,OUTPUT);
  pinMode(3,INPUT);
 
}
 
void loop() {  
   
  estadoSensor = digitalRead(3);

  if (estadosensor == HIGH)
  {
      digitalWrite(2, HIGH);
  } 
  else 
  {
      digitalWrite(2, LOW);
  }

Entendendo a fundo

Software

- Declarando a variável responsável por armazenar o estado do sensor

O primeiro passo no desenvolvimento do código apresentado anteriormente consiste em criar uma variável booleana, ou seja, uma variável que pode assumir apenas dois estados (nível alto e nível baixo, 1 e 0, high e low, entre outras nomenclaturas). Esta variável será utilizada para armazenar a informação proveniente do sensor de presença.

bool estadoSensor;

- Definindo as configurações iniciais

O definição das configurações iniciais do programa ocorre dentro da função setup(). Em um primeiro momento, determinamos o modo de operação do pino 2 como um pino de saída digital (este pino estará conectado ao led responsável por sinalizar quando o sensor detectou algo).

pinMode(2,OUTPUT);

Em seguida, definimos o pino conectado ao sensor de presença como um pino de entrada digital, também através da função pinMode().

pinMode(3,INPUT);

Veja como ficou nossa função setup()

void setup() {
   
  pinMode(2,OUTPUT);
  pinMode(3,INPUT);
 
}

- Detectando a presença

O primeiro procedimento para realizar a detecção de presença corresponde à leitura do nível lógico retornado pelo sensor em um determinado instante. Isto é feito por meio da função digitalRead().

estadoSensor = digitalRead(3);

Posteriormente, utilizamos a função if() para conferir o valor referente ao estado do sensor (armazenado na variável estadoSensor), de modo que, caso o mesmo esteja em nível alto, o conteúdo da função if() será executado.

 if (estadosensor == HIGH)
 {
      ****** Conteúdo da função if() ******
 }

Caso a sentença da função if() seja verdadeira, o Arduino deverá acender o led através da função digitalWrite().

digitalWrite(2, HIGH);

Em contrapartida, caso a condição da função if() não seja satisfeita, ou seja, caso a saída do sensor de presença seja um sinal em nível baixo, deve-se apagar o led.

else 
{
      digitalWrite(2, LOW);
}

Desafio

Agora que sabemos usar o sensor de presença e movimento, que tal usar um módulo relé para acender uma lâmpada? Seria uma boa ideia para automatizar o seu quarto, o que acha?

Faça isso:

  • Ligue uma lâmpada quando detectar movimento no ambiente (Leia nosso Tutorial sobre módulo relé) .

Considerações finais

Neste tutorial demonstramos os procedimentos básicos para utilizar o sensor de presença e movimento HC-SR501 com o Arduino. Esperamos que você tenha gostado deste conteúdo, sinta-se à vontade para nos dar sugestões, críticas ou elogios. Lembre-se de deixar suas dúvidas nos comentários abaixo.


Usando o Display TFT 1.8" ST7735 com NodeMCU ou Arduino

Display TFT 1.8" ST7735 - Utilizando o display com o NodeMCU ou Arduino

A existência de uma interface de visualização de dados é algo muito importante tanto no desenvolvimento de um software quanto no mundo dos sistemas embarcados de maneira geral, de modo que, em virtude de sua importância, precisamos sempre estar construindo interfaces concisas e de fácil entendimento. Entretanto isso é uma tarefa bastante desafiadora no mundo maker, devido a baixa quantidade de recursos disponíveis nas plataformas utilizadas. Sendo assim, apresentamos o Display TFT 1.8" com o controlador ST7735, que por sua vez, consiste em um módulo bem interessante e que pode ser utilizado com o propósito citado.

Nesse tutorial focamos no uso do Display TFT 1.8" ST7735 usando a plataforma NodeMCU. Ainda assim, fizemos uma explicação de como fazer a mesma experiência usando a plataforma Arduino no Tópico: Usando o Display TFT 1.8" ST7735 na plataforma Arduino.

[toc]

O Display TFT 1.8" ST7735

Esta pequena tela tem uma resolução de 128x160 pixels, o que permite sua utilização como um pequeno painel de visualização, sendo possível até mesmo fazer o seu uso em mini computadores como o Raspberry Pi e o Orange Pi. Além disso, ela também conta com uma interface para conexão de cartões SD em sua parte traseira. A tela conta com um total de 8 pinos, sendo dois destes para alimentação, um para o backlight e os outros 5 para comunicação que é feita via SPI.

 Display TFT 1.8" ST7735
Display TFT 1.8" ST7735

Mãos à obra - Imprimindo informações no display usando um NodeMCU

Componentes utilizados:

Montando o projeto

Para realizar a montagem, iremos conectar os pinos na seguinte ordem:

A montagem final deve estar semelhante a imagem abaixo:

 Display TFT 1.8" ST7735

 Veja como ficou a nossa montagem na prática:

montagem Display TFT 1.8" ST7735

Se tudo estiver montado corretamente, quando o sistema for ligado teremos uma tela em branco.

Sempre monte seu projeto com a alimentação desligada para evitar possíveis curtos circuitos que podem danificar o seu dispositivo.

Programando

Antes de adentrarmos na apresentação do código, disponibilizamos uma seção para ajudar aqueles que são iniciantes no NodeMCU. Sinta-se livre para prosseguir caso você já tem domínio da IDE do Arduino e com o NodeMCU.

Esse passo a passo foi tirado do tutorial: Conhecendo a Família ESP – Internet das coisas

– Preparando a IDE Arduino

Usaremos a Arduino IDE, mas você pode programa-lo com LUA, ou até a propria SDK.

1-) Vá em Arquivos>Preferencias, e adicione este link em “URLs Adicionais…”: http://arduino.esp8266.com/stable/package_esp8266com_index.json

2-) Vá em Ferramentas>Placa>Gerenciador de placas.

3-) Procure pelo ESP8266 e instale-o.

4-) Após instalar as placas do ESP8266, selecione-a em Ferramentas>Placa> NodeMCU 1.0 (caso esteja usando uma versão mais antiga do NodeMCU, pode ser que tenha que usar a versão 0.9)

5-) Agora, é só configurar a placa, aconselho a usarem igual ao da foto. Testem primeiramente com o upload a 115200@bps, caso nao funcione, teste com outras velocidades! Não se esqueça de selecionar a porta que estiver seu FTDI.

Sua IDE esta pronta para funcionar com o ESP8266. Vamos seguir!

- Bibliotecas

Neste projeto estaremos utilizando duas bibliotecas, sendo uma para estabelecer a comunicação com o display, e outra para renderizar figuras de forma simplificada. Para isso, iremos fazer o download das duas bibliotecas da seguinte forma:

  •  Na ide do arduino, navegamos até a opção Sketch, selecionamos a opção Incluir biblioteca e navegamos até a opção Gerenciar Bibliotecas como mostra a figura abaixo:

  • Ao selecionar a opção Gerenciar bibliotecas, será aberto um painel como mostra a figura a seguir:
  • Nesta Janela iremos procurar as bibliotecas Adafruit ST7735 e Adafruit GFX Library, ambas podem ser instaladas através deste ambiente (Caso ocorra algum erro ou a imagem não apareça corretamente, a tela pode estar utilizando o controlador ILI9341, neste caso faça o download da biblioteca Adafruit ILI9341).
Biblioteca Adafruit ST7735

Biblioteca Adafruit GFX Library

- Programando

Agora que temos o nosso sistema montado, e as bibliotecas já instaladas, podemos partir para o código. Observem o código a seguir e que pode ser utilizado para diversos projetos.

#include <Adafruit_GFX.h>    // Core graphics library
#include <Adafruit_ST7735.h> // Hardware-specific library
#define D3 0
#define D4 2 
#define D5 14 
#define D7 13 
#define D8 15 
#define TFT_CS     D8
#define TFT_RST    D4  
#define TFT_DC     D3
Adafruit_ST7735 tft = Adafruit_ST7735(TFT_CS,  TFT_DC, TFT_RST); // Instância do objeto tipo Adafruit_ST7735 que recebe como argumentos os pinos de controle
#define TFT_SCLK D5   
#define TFT_MOSI D7 
void setup(void){

  tft.setCursor(0,30); // Move o cursor para a coluna 30 na linha 0 
  tft.initR(INITR_BLACKTAB); // Inicializa a tela com um fundo preto
  tft.setTextSize(2); // Seta o tamanho da fonte de texto para o tamanho 2
  tft.fillScreen(ST7735_BLACK); // Preenche a tela com a cor preta
  tft.setTextColor(ST7735_BLUE); // Seta a cor do texto para Azul
  tft.print("Vida"); // Escreve a palavra Vida Com a cor que foi setada na linha acima
  tft.setTextColor(ST7735_WHITE); // Seta a cor do texto para Branco
  tft.print("De "); // Escreve a palavra Vida com a cor que foi setada na linha acima
  tft.setTextColor(ST7735_BLUE); // Seta a cor do texto para Azul
  tft.print("Silicio"); // Escreve a palavra Silício, com a cor que foi setada na linha acima

} 
void loop(){
  tft.invertDisplay(true); // Inverte as cores que estão na tela
  delay(500); // Aguarda 0,5 segundos
  tft.invertDisplay(false); // Volta as cores originais
  delay(500); // Aguarda 0,5 segundos
} 

Colocando para funcionar

Veja o resultado que obtivemos.

 Display TFT 1.8" ST7735
Display TFT 1.8"

Usando o Display TFT 1.8" ST7735 na plataforma Arduino

As bibliotecas da Adafruit de uma maneira geral possuem um grau bastante elevado de extensibilidade, ou seja podem ser utilizadas em diversas plataformas, como o nodeMCU e também o arduino. Caso você necessite utilizar este mesmo display em outra plataforma, como por exemplo o arduino uno, basta com que siga o padrão de conexão mostrado na tabela abaixo:

Já no código, podemos eliminar a grande parte dos #DEFINES criados anteriormente, utilizando apenas três pinos para estabelecer a comunicação, após isso, o código será exatamente o mesmo de antes.

#include <Adafruit_GFX.h>    // Core graphics library
#include <Adafruit_ST7735.h> // Hardware-specific library
#define TFT_CS     10
#define TFT_RST    8  
#define TFT_DC     9
Adafruit_ST7735 tft = Adafruit_ST7735(TFT_CS,  TFT_DC, TFT_RST); // Instância do objeto tipo Adafruit_ST7735 que recebe como argumentos os pinos de controle
void setup(void){
  tft.setCursor(0,30); // Move o cursor para a coluna 30 na linha 0 
  tft.initR(INITR_BLACKTAB); // Inicializa a tela com um fundo preto
  tft.setTextSize(2); // Seta o tamanho da fonte de texto para o tamanho 2
  tft.fillScreen(ST7735_BLACK); // Preenche a tela com a cor preta
  tft.setTextColor(ST7735_BLUE); // Seta a cor do texto para Azul
  tft.print("Vida"); // Escreve a palavra Vida Com a cor que foi setada na linha acima
  tft.setTextColor(ST7735_WHITE); // Seta a cor do texto para Branco
  tft.print("De "); // Escreve a palavra Vida com a cor que foi setada na linha acima
  tft.setTextColor(ST7735_BLUE); // Seta a cor do texto para Azul
  tft.print("Silicio"); // Escreve a palavra Silício, com a cor que foi setada na linha acima
 
} 
void loop(){
  tft.invertDisplay(true); // Inverte as cores que estão na tela
  delay(500); // Aguarda 0,5 segundos
  tft.invertDisplay(false); // Volta as cores originais
  delay(500); // Aguarda 0,5 segundos
}

E pronto, agora temos o mesmo código sendo executado no arduino


Entendendo a Fundo

Software

– Incluindo as bibliotecas a serem utilizadas no projeto

Inicialmente, observe que foi necessário incluir duas bibliotecas no código para que o mesmo pudesse funcionar corretamente. A biblioteca Adafruit_GFX.h fornece um conjunto de funções gráficas para telas LCD e OLED simplificando o uso desses displays.

A biblioteca Adafruit_GFX sempre trabalha em conjunto com uma segunda biblioteca fornecida para cada tipo específico de display, no nosso caso usamos a biblioteca para o controlador ST7735: Adafruit_ST7735.h.

#include <Adafruit_GFX.h>    // Core graphics library
#include <Adafruit_ST7735.h> // Hardware-specific library

Existem vários tipos de versões de display com controladores diferentes. Para conseguir usar o seu display adequadamente, é fundamental que se saiba exatamente qual o controlador para que consiga encontrar as bibliotecas especificas para ele.

– Declarando o objeto tft

Em seguida, cria-se o objeto que é responsável por realizar a troca de mensagens entre o nodeMCU e o display.  O método construtor da classe Adafruit_ST7735 recebe como parâmetros, os pinos responsáveis por interfacear a comunicação SPI entre o microcontrolador e o display.

Adafruit_ST7735 tft = Adafruit_ST7735(TFT_CS, TFT_DC, TFT_RST);

Lembre-se: tft é apenas o nome que escolhemos, sendo assim, é importante ressaltar que, o objeto identificado por tft poderia ser chamado de qualquer outro nome, como por exemplo, lcd ou display, respectivamente.

- Movendo o cursor do LCD

tft.setCursor(0,30);

Essa função é responsável por mover o cursor responsável por escrever o texto na tela, neste caso o cursor será movido no eixo Y uma distância de 30 pixels da posição onde ela se encontra (no caso a posição 0,0), ficando este na posição (0,30).

- Inicializando a tela

Essa função inicializa o chip do controlador do display no caso o ST7735.

tft.initR(INITR_BLACKTAB);

- Definindo o tamanho da fonte

A biblioteca Adafruit_ST7735 conta com 5 tipos de tamanhos de fonte, sendo eles enumerados do menor 0 até o maior 5, e este valor sendo definido por um número inteiro.

tft.setTextSize(2);

- Preenchendo toda a tela com uma cor

A função fillScreen, como o próprio nome já diz, preenche tudo que está sob a tela com uma única cor, no caso sendo representada pelo define ST7735_NomedaCor.

tft.fillScreen(ST7735_BLACK);

- Definindo a cor do texto

De forma semelhante a função fillScreen, a função setTextColor muda a cor da fonte utilizada para escrever a mensagem desejada.

tft.setTextColor(ST7735_BLUE);

- Escrevendo na tela

A função print, escreve na tela o vetor de caracteres passados como parâmetro, porém é importante ressaltar que a cor e o tamanho da fonte serão sempre os últimos que foram setados antes da chamada desta função.

tft.print("Vida");

- Invertendo as cores do display

Já a função invertDisplay, inverte a cor de tudo que está sendo mostrado na tela no momento,caso o argumento repassado seja true,  caso seja false a cor não será invertida, ou voltará ao estado original.

tft.invertDisplay(true);

Veja que nesse programa inicializamos e escrevemos na tela na função setup() que é executada apenas umas vez. Na função loop() interagimos com a tela invertendo as cores do LCD.

Para um aplicação prática, em geral iremos escrever valores variáveis, tais como temperatura ou vazão. Nesse caso iremos trabalhar com as funções gráficas do display dentro da função loop().


Desafio

O desafio, para este tutorial, consiste em utilizar a seguinte função:

void desenhaCirculos(uint8_t radius, uint16_t color) {
  for (int16_t x=0; x < tft.width()+radius; x+=radius*2) {
    for (int16_t y=0; y < tft.height()+radius; y+=radius*2) {
      tft.drawCircle(x, y, radius, color);
    }
  }
}

Esta função possibilita o desenho de círculos em sequencia na tela, sendo estes espaçados com base em seu raio, ou seja, quanto menor o raio mais círculos teremos na tela, e quanto maior o raio, menos círculos serão desenhados na tela. Você consegue utilizando esta função desenhar círculos de tamanho variável na tela conforme o valor do raio varia ?


Considerações finais

Este tutorial, teve como objetivo apresentar um display muito utilizado como interface homem máquina em plataformas embarcadas. O seu baixo custo e bom funcionamento o tornam um módulo muito interessante de ser utilizado nos mais diversos tipos de aplicações, onde precisamos fornecer informações ao usuário. Espero que tenham gostado do conteúdo apresentado, sinta-se à vontade para nos dar sugestões, críticas ou elogios. Lembre-se de deixar suas dúvidas nos comentários abaixo.

 


RTC3231 Registrando data e hora

RTC DS3231 - Registrando data e hora com Arduino

RTC DS3231 - Registrando data e hora com Arduino 

Bem sabemos como o tempo é a variável mais importante do mundo e da nossa vida. Nos organizamos a partir de horários e datas e por isso precisamos de relógios e agendas para nos guiar a todo momento. Se queremos construir sistemas inteligentes que auxiliam nossas atividades cotidianas, é fundamental saber como manter nosso Arduino sincronizado com a hora e a data do local onde estamos.  Pensando nisso, elaboramos este tutorial voltado para contemplar o uso de um Relógio de Tempo Real (Real-Time Clock) em conjunto com uma placa Arduino, em especial o RTC DS3231.  

Neste conteúdo será demonstrado como utilizar o RTC em questão para adquirir valores de data e hora, assim como, envia-los, por exemplo, através da porta serial para que o leitor possa conferir o resultado do projeto.  Além disso, explicaremos também a importância desse módulo.

[toc]

O que é um RTC?

Um RTC, do inglês Real-Time Clock, é um elemento que possibilita o registro de valores de data e hora no decorrer do tempo. Em poucas palavras, um RTC é um relógio em que o usuário indica os valores iniciais de data e hora, para que então, a partir destes, o mesmo passe a contar o tempo por conta própria (geralmente este dispositivo possui uma fonte de energia própria (como a apresentada na figura abaixo) para manter continuamente os valores de data e hora, de modo que, se o equipamento ao qual o RTC está conectado, ficar sem alimentação, a contagem do tempo não é interrompida).

Note que este tipo de dispositivo existe dentro de muitos aparelhos, como relógios digitais, despertadores, microondas,  entre outros, que mesmo após serem desligados, podem manter a contagem correta do tempo até serem ligados novamente .

 

Exemplo de uma bateria de um RTC em uma placa mãe de um computador

 

Caso você já tenha desmontando um computador certamente já viu uma bateria como a da imagem acima. Ela está associada ao circuito de um circuito RTC, que por sua vez, é responsável por manter seu computador com a data e a hora atualizadas mesmo estando desligado. Quando o horário e data do computador começam a ficar defasados dos valores reais da região, deve-se ficar atento, pois, este pode ser um sinal de que está na hora de trocar esta bateria.

As funções delay() e millis()

Quando um programa é desenvolvido para ser inserido em uma placa Arduino, de modo que, este tenha alguma relação com o conceito de tempo, fala-se, na maioria das vezes em progressão de tempo, por exemplo, pode-se determinar que o Arduino execute uma ação x após alguns segundos de ocorrência de uma condição y. Em grande parte destes casos, a função delay() é suficiente para atingir o objetivo proposto, ao passo que, em alguns casos é mais conveniente a utilização da função millis().

  • delay(): Pausa o programa por um certo tempo (especificado em milissegundos).
  • millis(): Retorna um número (em milissegundos) referente ao tempo que passou desde que o programa atual inserido na placa Arduino começou a rodar.

Note que a função millis() pode ser utilizada para determinar se uma certa quantidade de tempo já se passou, porém, sem que haja algum tipo de "congelamento" do programa que está rodando no Arduino.

Por que utilizar um RTC junto com um Arduino?

Como dito anteriormente, a função millis() atua como um contador, de modo que este, é incrementado a cada momento, no entanto, quando o Arduino for desligado, este contador começará novamente do zero. Por este motivo, pode-se utilizar um RTC para ter um controle melhor sobre a progressão do tempo.

Além disso, é importante saber que a função millis() retorna um elemento do tipo unsigned long (que representa a quantidade de milissegundos), que por sua vez, possui o tamanho de 32 bits. Com esta informação, pode-se chegar a conclusão de que com este tipo de dado pode-se realizar a contagem do tempo em aproximadamente 50 dias, ou seja, pouco menos de 2 meses até que o contador seja reiniciado. Em contrapartida, a autonomia de um RTC pode chegar a 10 anos dependendo do modelo do mesmo e da bateria utilizada.

Características do RTC DS3231

O RTC que será utilizado no desenvolvimento do projeto proposto neste tutorial é o RTC DS3231. Este RTC consiste em um relógio de tempo real de alta precisão, baixo consumo de energia e baixo custo. Este módulo é capaz de trabalhar com informações como segundos, minutos, horas, dias, meses, anos e ainda é capaz de ajustar-se automaticamente em casos de meses com menos de 31 dias e em situações de ocorrência de anos bissextos. Além disso, o RTC DS3231 pode operar tanto no formato 12 horas (utilizando a nomenclatura AM/PM) como no formato 24 horas.

RTC DS32312
RTC DS32312

Ao lado das características citadas, também deve-se ressaltar que o RTC DS3231 se comunica com uma placa Arduino através do protocolo I2C (onde os dados são transferidos através de um barramento bidirecional) e que o mesmo possui um compartimento para que seja inserida uma bateria externa (em caso de falha de energia no elemento principal, esta é automaticamente acionada para manter o controle sobre a passagem do tempo), um sensor de temperatura embutido, dois alarmes programáveis, além de outras características mais avançadas que serão apresentadas em tutoriais posteriores.


Mãos à obra - Realizando a aquisição dos valores de data e hora com o Arduino

Componentes utilizados:

Montando o projeto

Na figura abaixo, o leitor poderá conferir como foi realizada a montagem do projeto apresentado neste tutorial.  Lembre-se de montar o projeto com o seu Arduino desligado.

 

Veja como ficou o nosso:

 

Programando

Antes de adentrarmos na apresentação do código, disponibilizamos uma seção para ajudar aqueles que são iniciantes no assunto. Sinta-se livre para prosseguir caso você já tem domínio da IDE do Arduino.

Conectando o Arduino ao computador

Primeiramente, conecte seu Arduino ao computador e abra a IDE Arduino. Em seguida, é necessário selecionar a porta COM na qual o Arduino está conectado (este procedimento pode ser feito clicando no menu Ferramentas (tools) e em seguida escolhendo-se a porta correspondente no submenu Porta (port). Neste caso, a porta na qual está o Arduino é apresentada da seguinte maneira: COM3 (Arduino Micro).

 

 

Por fim, garanta também que o tipo de placa apropriado esteja selecionado (isso pode ser feito acessando o menu Ferramentas (tools) e o submenu Placa (board)).

 

- Biblioteca

Para desenvolver o projeto proposto com o RTC DS3231 utilizou-se uma biblioteca capaz de atuar sobre o protocolo I2C para facilitar os processos de endereçamento e troca de dados que fazem parte do funcionamento do protocolo citado. Esta biblioteca foi produzida por  Jarzebski e pode ser encontrada aqui.

Adquirindo e instalando a biblioteca que será utilizada

Para adquirir a biblioteca em questão, basta acessar o link apresentado anteriormente, clicar no botão clone or Download e por fim, no botão Download ZIP, conforme a figura abaixo.

Após a realização do download dos arquivos compactados no formato ZIP, abra a IDE do Arduino, selecione o menu Sketch, o submenu Incluir Bilioteca e por fim, basta clicar na opção Adicionar biblioteca .ZIP (Add ZIP Library) e encontrar o arquivo que acabou de ser baixado.

 

 

Uma outra forma de fazer isso é extrair o conteúdo do arquivo ZIP dentro da pasta Libraries (onde foi instalada a IDE do Arduino).

- Código do projeto

Segue o código a ser utilizado no Arduino para imprimir os valores de data e hora no Serial Monitor.

#include <Wire.h>        //Biblioteca para manipulação do protocolo I2C
#include <DS3231.h>      //Biblioteca para manipulação do DS3231

DS3231 rtc;              //Criação do objeto do tipo DS3231
RTCDateTime dataehora;   //Criação do objeto do tipo RTCDateTime

void setup()
{
  Serial.begin(9600);     //Inicialização da comunicação serial
  rtc.begin();            //Inicialização do RTC DS3231

  rtc.setDateTime(__DATE__, __TIME__);   //Configurando valores iniciais 
                                         //do RTC DS3231
}

void loop()
{
  dataehora = rtc.getDateTime();     //Atribuindo valores instantâneos de 
                                     //data e hora à instância dataehora


  Serial.print(dataehora.year);     //Imprimindo o Ano   
  Serial.print("-");
  Serial.print(dataehora.month);    //Imprimindo o Mês
  Serial.print("-");
  Serial.print(dataehora.day);      //Imprimindo o Dia
  Serial.print(" ");
  Serial.print(dataehora.hour);     //Imprimindo a Hora
  Serial.print(":");
  Serial.print(dataehora.minute);   //Imprimindo o Minuto
  Serial.print(":");
  Serial.print(dataehora.second);   //Imprimindo o Segundo
  Serial.println("");

  delay(1000);     //Tempo p atualização do valor enviado pela porta
                   //serial
}

Nota: é importante ler a seção Entendendo a fundo deste tutorial para entender como funciona o ajuste de data e hora.

Após escrever o código, salve e depois clique em Carregar (Upload) para que o programa seja transferido para seu Arduino.

Colocando para funcionar

Para verificar o resultado da gravação deste código no Arduino Micro basta acessar o Serial Monitor (para realizar este procedimento, basta utilizar o atalho Ctrl+Shift+M). Espera-se que o leitor consiga obter um resultado semelhante ao demonstrado a seguir.

 

RTC DS32312 resposta
RTC DS32312 resposta

Entendendo a fundo

Software

- Incluindo as bibliotecas a serem utilizadas no projeto

Inicialmente, observe que foi necessário incluir duas bibliotecas no código para que o mesmo pudesse funcionar corretamente. A biblioteca wire.h é a responsável pela comunicação utilizando o protocolo I2C enquanto a biblioteca DS3231.h atua sobre a biblioteca wire.h simplificando o processo de comunicação através do protocolo citado, para que assim, o usuário possa utilizar o RTC DS3231 de maneira mais fácil.

#include <Wire.h>
#include <DS3231.h>

- Declarando os objetos rtc e dataehora

Em seguida, cria-se dois objetos que serão utilizados posteriormente, de modo que, um destes é do tipo DS3231, chamado rtc (que representará o RTC DS3231 no código) e outro do tipo RTCDateTime, chamado dataehora (que será responsável por manipular os valores de data e hora existentes).

Lembre-se: rtc e dataehora são apenas nomes, sendo assim, é importante ressaltar que, os objetos identificados por rtc e dataehora poderiam ser chamados de quaisquer outros nomes, como por exemplo, modulo e informacaoatual, respectivamente.

DS3231 rtc;                //construindo o objeto rtc da classe DS3231
RTCDateTime dataehora;     //construindo o objeto dataehora da classe RTCDateTime

- Definindo as configurações iniciais

Primeiramente, na função setup(), utiliza-se a função Serial.begin() para inicializar a comunicação serial do Arduino Micro com o computador  (onde será possível ver o resultado do projeto)

 Serial.begin(9600);

Em seguida, utiliza-se a função rtc.begin() (repare que o nome rtc corresponde ao objeto criado anteriormente) para inicializar o RTC DS3231.

rtc.begin();

Posteriormente, recorre-se à função rtc.setDateTime() para configurar os valores iniciais do RTC DS3231, ou seja, os valores de data e hora que servirão de ponto de partida para o mesmo.

Conforme será explicado em seguida, na seção Ajuste de hora do RTC, ao passarmos __DATE__, __TIME__ como parâmetros da função rtc.setDateTime(), fazemos com que os valores iniciais de data e hora do RTC DS3231 sejam correspondentes ao momento da compilação do código.

rtc.setDateTime(__DATE__, __TIME__);

De acordo com a explicação dada, a função setup() deve possuir o seguinte conteúdo:

void setup()
{
  Serial.begin(9600);

  rtc.begin();

  rtc.setDateTime(__DATE__, __TIME__); 
}

- Aquisição dos valores de data e hora

Na função loop(), utiliza-se primeiramente a função rtc.GetDateTime() para atribuir os valores de data e hora de um determinado momento ao objeto dataehora. Neste momento é importante ressaltar que o objeto em questão irá conter várias informações (segundo, minuto, hora, dia, mês e ano), que por sua vez, podem ser acessadas separadamente.

dataehora = rtc.getDateTime();

Imagine que seja necessário extrair a informação referente ao ano que o RTC DS3231 está registrando. Para isso, basta referir-se ao objeto dataehora por dataehora.year. Portanto, se quisermos enviar o valor do ano através da porta serial, deve-se utilizar dataehora.year como argumento da função Serial.print().

Serial.print(dataehora.year);

Observe as demais correspondências na figura abaixo:

 

 

Por fim, veja como ficou a função loop() (perceba que ao final da mesma existe uma função delay() determinando a disponibilização das informações a cada um segundo).

void loop()
{
  dataehora = rtc.getDateTime();

  Serial.print(dataehora.year);   //Imprimindo o ano
  Serial.print("-");
  Serial.print(dataehora.month);  //Imprimindo o mês
  Serial.print("-");
  Serial.print(dataehora.day);    //Imprimindo o dia
  Serial.print(" ");
  Serial.print(dataehora.hour);   //Imprimindo a hora
  Serial.print(":");
  Serial.print(dataehora.minute); //Imprimindo os minutos
  Serial.print(":");
  Serial.print(dataehora.second); //Imprimindo os segundos  
  Serial.println("");

  delay(1000);
}

 

Hardware

As ligações realizadas no hardware em questão são bem simples, de modo que, deve-se lembrar apenas, que a comunicação entre o RTC DS3231 e uma placa Arduino é dada através do protocolo I2C, portanto, no Arduino Micro, além dos pinos referentes à alimentação do módulo, utilizou-se os pinos SDA (pino 3, responsável pela troca de dados entre os dispositivos) e SCL (pino 4, responsável pela sincronização entre os dispositivos). No RTC DS3231 estes pinos estão nomeados, portanto, são de fácil identificação.


Ajuste de hora do RTC

É importante que nosso RTC esteja com a hora correta, portanto, torna-se necessário saber como mante-lo com a hora ajustada.

Primeiramente, note que no código apresentado anteriormente, fizemos o uso um recurso muito interessante, disponibilizado pela biblioteca DS3231.h. Este recurso consiste na utilização dos parâmetros __DATE__ e __TIME__ dentro da função rtc.setDateTime(), que por sua vez, fazem com que os valores data e hora da compilação sejam usados para ajustar a data e a hora do nosso módulo RTC DS3231.

rtc.setDateTime(__DATE__, __TIME__);

Neste momento, o leitor deve estar atento a um pequeno detalhe: Apesar da função apresentada anteriormente determinar os valores iniciais de data e hora do RTC de acordo com o momento da compilação, caso o seu Arduino seja reiniciado, o ele irá definir novamente as informações de partida do módulo RTC DS3231 com os valores referentes ao momento da compilação realizada anteriormente (e não com as dados de data e hora de quando ele foi reiniciado, pois, sempre que o Arduino for ligado, o conteúdo da função setup() será executado e consequentemente, a função rtc.setDateTime() também), portanto, teremos um relógio desatualizado.

Solução para o ajuste dos valores de data e hora

O ideal é que a gravação do programa no Arduino seja feita duas vezes:

  1. Na primeira vez você deve enviar o código tal como apresentado anteriormente.
  2. Em seguida, você terá que modificar a função setup(), comentando ou excluindo a linha que contém a função de ajuste de data e hora, para então, gravar novamente o programa no Arduino.

Primeira gravação:

#include <Wire.h>        //Biblioteca para manipulação do protocolo I2C
#include <DS3231.h>      //Biblioteca para manipulação do DS3231

DS3231 rtc;              //Criação do objeto do tipo DS3231
RTCDateTime dataehora;   //Criação do objeto do tipo RTCDateTime

void setup()
{
  Serial.begin(9600);     //Inicialização da comunicação serial
  rtc.begin();            //Inicialização do RTC DS3231

  rtc.setDateTime(__DATE__, __TIME__);   //Configurando valores iniciais 
                                         //do RTC DS3231
}

void loop()
{
  dataehora = rtc.getDateTime();     //Atribuindo valores instantâneos de 
                                     //data e hora à instância dataehora


  Serial.print(dataehora.year);     //Imprimindo o Ano   
  Serial.print("-");
  Serial.print(dataehora.month);    //Imprimindo o Mês
  Serial.print("-");
  Serial.print(dataehora.day);      //Imprimindo o Dia
  Serial.print(" ");
  Serial.print(dataehora.hour);     //Imprimindo a Hora
  Serial.print(":");
  Serial.print(dataehora.minute);   //Imprimindo o Minuto
  Serial.print(":");
  Serial.print(dataehora.second);   //Imprimindo o Segundo
  Serial.println("");

  delay(1000);     //Tempo p atualização do valor enviado pela porta
                   //serial
}

Segunda gravação:

#include <Wire.h>        //Biblioteca para manipulação do protocolo I2C
#include <DS3231.h>      //Biblioteca para manipulação do DS3231

DS3231 rtc;              //Criação do objeto do tipo DS3231
RTCDateTime dataehora;   //Criação do objeto do tipo RTCDateTime

void setup()
{
  Serial.begin(9600);     //Inicialização da comunicação serial
  rtc.begin();            //Inicialização do RTC DS3231

  //rtc.setDateTime(__DATE__, __TIME__);   *******ESTA LINHA DEVE SER COMENTADA OU EXCLUÍDA*******
}

void loop()
{
  dataehora = rtc.getDateTime();     //Atribuindo valores instantâneos de 
                                     //data e hora à instância dataehora


  Serial.print(dataehora.year);     //Imprimindo o Ano   
  Serial.print("-");
  Serial.print(dataehora.month);    //Imprimindo o Mês
  Serial.print("-");
  Serial.print(dataehora.day);      //Imprimindo o Dia
  Serial.print(" ");
  Serial.print(dataehora.hour);     //Imprimindo a Hora
  Serial.print(":");
  Serial.print(dataehora.minute);   //Imprimindo o Minuto
  Serial.print(":");
  Serial.print(dataehora.second);   //Imprimindo o Segundo
  Serial.println("");

  delay(1000);     //Tempo p atualização do valor enviado pela porta
                   //serial
}


Considerações finais

Neste tutorial elaboramos um conteúdo introdutório sobre o RTC DS3231 visando apresentar os conceitos básicos de funcionamento do mesmo e como utiliza-lo em conjunto com uma placa Arduino. Esperamos que você tenha gostado deste conteúdo, sinta-se à vontade para nos dar sugestões, críticas ou elogios. Lembre-se de deixar suas dúvidas nos comentários abaixo.

 


Registrador de deslocamento

Registrador de deslocamento

Neste tutorial, você irá aprender a aumentar o número de portas do seu micro controlador (MCU) usando um registrador de deslocamento 74HC595 (Shift Register). Funciona com qualquer MCU: ATtiny85, Arduino, PIC, ESP8266, ESP32, Raspberry, Onion, etc. Usaremos neste tutorial um ATtiny85 para controlar 8 LEDs apenas com 3 pinos do MCU!

 

O que são?

Dentro de um registrador de deslocamento há diversos Flip-Flops interligados que de tal forma, consegue converter sinais de um tipo para outro (Serial-Paralelo/Paralelo-Serial) ou até mesmo para expansão de portas de um micro controlador.

Usaremos o 74HC595, um registrador de deslocamento Serial-Paralelo de 8bits, isto significa, que cada registrador irá controlar até 8 componentes. Também é possível liga-los em modo cascata, um após o outro. Com isto, podemos ligar diversos registradores e usando apenas 3 pinos, controlar 40, 80, 160 componentes e assim por diante. Este registrador tem apenas pinos de saída, caso seja necessário leitura de botões (input de dados), procure por outros, existem até alguns com comunicação I2C!

Para mais informações sobre registradores de deslocamento, clique AQUI.

Datasheet do 74HC595.

As aplicações para um registrador de deslocamento são bem variadas, pode tanto fazer a conversão de dados Seriais para Paralelo, Paralelo para Serial, ou quando é necessário mais pinos para nosso MCU. Com 5 registradores de deslocamento de 8 bits em cascata, usamos 3 pinos do MCU para controlar até 40 componentes! Perfeito para matrizes de LED 3D ou robôs com vários atuadores.

Fig 1 - Matriz de LED 3D.

Mãos à obra

Componente necessários

Para este tutorial, usaremos um ATtiny85, mas você pode usar qualquer MCU.

Montando o projeto

Agora vamos conectar os componentes do projeto. Monte seu circuito conforme a figura a seguir. Não se esqueça de ler a explicação do hardware logo abaixo.

 

 

Veja como ficou o nosso:

 

Código do projeto

/*
Pino 0 = Clock.
Pino 1 = Latch.
Pino 2 = Serial IN.
*/

void setup()
{
   for (byte i = 0; i < 3; i++)//Declaração dos pinos de saida.
   {
      pinMode(i, OUTPUT);
   }

   int x = 1;
   for (byte i = 0; i < 8; i++)//Ligamos um LED após o outro, permanecendo o estado do anterior.
   {
      s595(x);//Função que faz o gerencimento do registrador.
      x = (x * 2) + 1;//Conta binaria que faz BitShift: 0b001 -> 0b011 -> 0b111...
      delay(150);
   }
}

void loop()
{
   s595(random(0, 256));
   delay(500);
}

void s595(byte data)//O argumento para acender os LEDs pode ser em binario
{
   digitalWrite(1, LOW);//Fecha o Latch para input de dados.
   shiftOut(2, 0, LSBFIRST, data);//Função própria da Arduino IDE.
   digitalWrite(1, HIGH);//Abre o Latch para output dos dados.
}

Entendendo a fundo

Software

 

-Função s595()

void s595(byte data)
{
    digitalWrite(1, LOW);//Fecha o Latch para input de dados.
    shiftOut(2, 0, LSBFIRST, data);//Função própria da Arduino IDE.
    digitalWrite(1, HIGH);//Abre o Latch para output dos dados.
}

Esta função criada faz todo o gerenciamento do registrador de deslocamento.

Primeiramente fechamos o Latch para a entrada de novos valores, após a entrada dos valores pelo shiftOut(), abrimos o Latch para que as saídas sejam iguais ao dados que definimos com a entrada anterior.

Para entender melhor sobre a função shiftOut(), clique AQUI.

O legal desta função é que podemos usar diretamente binário para representar os LEDs, por exemplo:

s595(0b11001100);

Com isto, os LEDs serão idênticos ao binário, respectivamente Q0 -> Q7. As saídas Q0, Q1, Q4 e Q5 estarão em HIGH e o restante em LOW.

Hardware

Pinos necessários para o registrador funcionar. Adicione MR ao Vcc  e  OE ao GND.

O nosso registrador de deslocamento usado, tem 3 pinos básicos: Serial data IN, Latch e Clock.

  • Serial data IN: Aqui é adicionado os bit's para futuramente após o latch, virarem output.
  • Output Enable (OE): Ativo em LOW.
  • Latch: O latch funciona como se fosse um portão. quando em HIGH, o portão se abre, liberando os bit's que adicionamos anteriormente.
  • Clock: O clock deve ser oscilado a cada bit de entrada, para que sejam armazenados corretamente.
  • Master Reclear (MR): Ativo em LOW.
  • Q7': Este pino é usado para a ligação em cascata de mais registradores de deslocamento.
  • Q0 a Q7: São as saídas do registrador, use elas normalmente como se fossem pinos de saída, obedecendo os limites de tensão e corrente.

 

A figura abaixo mostra o efeito do Serial+Clock

Após a conclusão da entrada de dados, ao abrir o Latch, os pinos marcados com 1, ficarão em HIGH, e pinos com 0, em LOW. Então se usarmos "0b10010011", as saídas (Q0 até Q7) ficarão respectivamente: 1, 0, 0, 1, 0, 0, 1, 1.


Desafio

Primeiramente, veja qual LED acende com s595(0b10000000);  e depois dentro da função s595(), troque "LSBFIRST" para "MSBFIRST", veja qual LED acende e nos conte porque isto acontece!

Finalizando

Em alguns projetos, como matrizes de LED 3D, é necessário o uso de MUX e registradores de deslocamento, uma vez que nosso MCU não tem pinos suficientes para fazer o controle de cada componente. Com este simples e eficiente componente, podemos controlar diversos outros com poucos pinos do MCU, deixando os outros pinos do MCU livres para tarefas mais complicadas.


Leitura da velocidade de ventoinha em RPM

O que vamos aprender?

Aprenderemos a ler as rotações por minuto (RPM) de uma ventoinha (Fan) com 3 fios. Usaremos o Arduino, mas pode ser feito com qualquer MCU.

Leitura de RPM

As ventoinhas com 3 ou 4 fios, tem embutido, um sensor Hall que detecta a variação do campo magnético gerado pela rotação da ventoinha. A maioria das ventoinhas tem dois pólos magnéticos, que quando rotacionado, aciona o Hall e conseguimos efetuar a leitura das rotações.

Como pode ser visto na Figura 1, após uma volta, o Hall ativou a saída duas vezes. Logo, precisamos dividir a contagem das rotações por 2 para se chegar em uma volta completa.

 

 

A leitura de RPM pode ser extremamente útil em casos em que é preciso controle da velocidade ou fluxo de vento em um determinado local, ou até mesmo determinar se a ventoinha esta funcionando corretamente, caso não, o sistema irá detectar e ativar um alarme, já que pode gerar super aquecimentos e até pegar fogo em componentes!


Mãos à obra

Componentes necessários

Montando o projeto

Faça as ligações simples e coloque o terceiro fio (normalmente amarelo ou branco) ao pino 2 do Arduino! Lembre-se da tensão e corrente de sua ventoinha, a usada no o tutorial é suficiente para o Arduino suprir, caso a sua seja "mais forte", será necessário uma fonte externa e divisores de tensão no 3 pino. Ficará parecido com o nosso:

 

Código do projeto

volatile uint32_t rpm;//Váriavel que armazena as rotações.


void setup()
{
   Serial.begin(115200);//Inicia a Serial.
   attachInterrupt(0, ctt, RISING);//Habilita a interrupção 0 no pino 2.
}

void loop()
{
   delay(1000);//Aguarda um segundo.
   Serial.println(rpm * 30);//Mostra o RPM.
   rpm = 0;//Reseta a váriavel para proxima leitura.

   //Como estamos lendo a cada UM segundo, usariamos RPM*60 para determinar as rotações por minuto,
   //porém, como foi dito na explicação, é preciso dividir o valor por 2, por isto 30!
}

void ctt()
{
   rpm++;//Incrementa a váriavel.
}

 

Colocando para funcionar

De acordo com o datasheet da ventoinha aqui testada, era de se esperar cerca de 13000 RPM (Fig 3). Após analisar com o Arduino, o valor variou entre 12000-15000 RPM (Fig 4), mostrando que esta correto!

 

Figura 3 - Datasheet

 

 


Entendendo a fundo

Software

 

-Função attachInterrupt()

attachInterrupt(0, ctt, RISING);

É configurado uma rotina de interrupção para a leitura dos pulsos altos gerados pela ventoinha. Foi usado a interrupção 0, que está ligada ao pino 2 do Arduino Uno.

 

-Mostrando os valores

Serial.println(rpm * 30);

Aqui esta a grande jogada da leitura. É feito a cada 1 segundo, a leitura da variável RPM, que foi modificada pela interrupção da ventoinha. Para converter as rotações por segundo, para rotações por minuto, é necessário multiplicar por 60, já que 1 minuto tem 60 segundos.

Entretanto, no inicio do tutorial, foi mostrado que deve-se dividir por 2 para chegar a uma rotação completa, por isso usamos 30!

 

-Resetando a variável

rpm = 0;

Após a leitura dos pulsos, é necessário resetar a variável, se não, irá interferir nas contas futuras.


Fechamento

Em vários cenários é necessário conhecer sobre o funcionamento de uma ventoinha, que caso venha a falhar, pode gerar terríveis danos ao sistema. Então, aprender a ler a RPM da ventoinha pode ser uma ótima maneira de descobrir se esta tudo correto. Dúvidas? Sugestões? Críticas? Comente abaixo!

 


Segurança de dados com AES

Segurança de dados

A segurança é algo essêncial em muitos projetos, principalmente nos conectados à Internet. Desde esconder senhas ou mensagens para que ninguém além do destino possa ler, a segurança faz parte do nosso cotidiano e iremos aprender a implementa-la nos Microcontroladores. Aprenderemos usar a criptografia AES (Advanced Encryption Standard) com foco em apenas sobre sigilo do dado, o download dela estará ao fim do tutorial. Esta biblioteca para criptografia com AES, funciona tanto para Arduino, quanto para ESP8266 ou ESP32.

 

 

Um pouco sobre segurança

Antes de entrar em detalhes sobre o AES, um resumo sobre a segurança de dados.

 

-Codificação

A codificação é possivelmente o método mais simples e antigo, trata-se da troca de uma linguagem, para outro padrão. É necessário conhecer os caracteres codificados para poder decodificar. O objetivo da codificação não é tornar a mensagem secreta. Exemplo: Morse(Fig 1), que converte os caracteres para pulsos elétricos, sons, luzes, etc.

-Criptografia simétrica

A criptografia simétrica faz o uso de uma chave privada que deve ser mantida em segredo, já que é usada tanto para encriptação, quanto para desencriptação. Esta é mais simples e leve que a criptografia assimétrica. Exemplo: AES, DES.

-Criptografia assimétrica

A criptografia assimétrica faz o uso de duas chaves, uma pública e outra privada. A pública pode ser usada para encriptação e a privada para desencriptação. Esta é mais pesada e lenta. Exemplo: RSA.

O uso delas é bem diferente e logo, a comparação direta não faz sentido. Por exemplo, a assimétrica permite autenticidade dos dados e pode garantir que o dado recebido é de uma pessoa autorizada e não de alguém re-enviando o dado.

 

 

-Hash

Hash é um algoritmo de uma via, ou seja, é irreversível. É muito usado com senhas da seguinte forma: Primeiramente é gerado um Hash da senha e este, será apenas comparado ao Hash armazenado no destino. Caso os Hash's sejam iguais, logo a senha é igual. Exemplo: MD5, SHA-1.

Clique AQUI para mais informações sobre Hash.

 

-AES

AES (Advanced Encryption Standard), é uma criptografia de blocos com chave simétrica (cifra de bloco) e será usado AES-128 no exemplo deste tutorial. AES trabalha com o sistema de blocos de 16 Bytes. É possível utilizar valores de entrada menores sem problemas, mas maiores será necessário dividir em blocos de 16B.

 

 

Imagine que você use dois micro controladores para transmissão de mensagens (Exemplo: Whatsapp, Facebook...), muito provavelmente você deseja que ninguém consiga ler as mensagens, isto pode ser feito com a encriptação, que irá cifrar (embaralhar) a mensagem e deixa-la ilegível para qualquer pessoa sem a chave, garantindo que apenas as pessoas com a chave, consigam ler.

Também pode ser usada para protocolos de comunicação entre dispositivos Wireless ou Wired, para preservar a integridade do mesmo e evitar "curiosos de plantão".


Mãos à obra

Código do projeto

#include <AES.h>//Biblioteca do AES.

AES aes;//Cria a classe aes.
byte key[16], out[16], inp[32];//Cria arrays (vetores) para a chave, input e output de dados.
const char pass[] = "abc";//Define a chave usada, neste exemplo usamos AES128, então precisa ser <= 16 Bytes.


void setup()
{
   Serial.begin(115200);//Habilita a serial.
   Serial.println();//Limpa o monitor.

   enc128("vida de silicio", 1);//Faz a função de encriptação e retorna o HEX encriptado.
}

void loop()
{

}


void enc128(const char txt[], bool db)//Argumentos: (texto e debug)
{
   if (strlen(pass) > 16)//Verifica se a chave tem o tamanho limite de 16 caracteres.
   {
      if (db == true)
      {
         Serial.println("Chave para AES128 <= 16 Bytes");
      }
      return;//Se a chave for maior, irá sair da função.
   }

   if (strlen(txt) > 16)//Verifica se o texto tem o tamanho limite de 16 caracteres.
   {
      if (db == true)
      {
         Serial.println("Frase/numero para AES <= 16 Bytes / bloco");
      }
      return;//Se o texto for maior, irá sair da função.
   }

   for (byte i = 0; i < strlen(pass); i++)//Adiciona a chave(pass) na array key.
   {
      key[i] = pass[i];
   }

   for (byte i = 0; i < strlen(txt); i++)//Adiciona o texto na array input.
   {
      inp[i] = txt[i];
   }

   //Adiciona a chave ao algoritimo.
   if (aes.set_key(key, 16) != 0)//Verifica se a chave esta correta, caso nao, sairá da função.
   {
      if (db == true)
      {
         Serial.println("Erro ao configurar chave");
      }
      return;//Sai da função
   }

   //Faz a encriptação da array INPUT e retorna o HEXA na array OUTPUT.
   if (aes.encrypt(inp, out) != 0)//Verifica se a encriptação esta correta, se não, sairá da função.
   {
      if (db == true)
      {
         Serial.println("Erro ao encriptar");
      }
      return;//Sai da função
   }

   if (db == true)//Se o debug estiver on (1), irá mostrar o HEXA no serial monitor.
   {
      for (byte i = 0; i < 16; i++)
      {
         Serial.print(out[i], HEX);
         Serial.print(" ");
      }
      Serial.println();
   }

   aes.clean();//Limpa a chave e residuos sensiveis da encriptação.
}

Entendendo a fundo

Software

A função que desenvolvemos enc128() torna o uso muito simples, mas você deve estudar mais sobre o AES e a biblioteca usada para entender melhor o funcionamento. Aqui será mostrado apenas a encriptação, mas também é possível fazer a desencriptação da mesma forma, este será o desafio de vocês para aprendizado.


 

-Variaveis usadas

byte key[16], out[16], inp[32];

Criamos os vetores (Arrays) para alocar a CHAVE e mensagens de INPUT e OUTPUT do buffer AES.

 

-Definindo a chave

char pass[] = "abc";

Definimos a Key (chave) da nossa criptografia. Deve ter no mínimo 1 caractere, e no máximo 16 (AES 128).  0 < Key <= 16. Aqui usamos "abc", mas é aconselhado o uso de letras e números aleatórios.

Você deve usar chaves grandes e aleatórias. Sem isso, seu sistema estará em grandes riscos. Usamos uma chave simples para fácil entendimento.

 

-Função enc128()

enc128("vida de silicio", 1);

enc128(texto, debug);

A função criada para encriptação dos dados torna o processo bem fácil. Os parâmetros necessários para ela é o texto que deseja encriptar, e em seguida, o debug, que mostra no serial monitor possíveis erros e por fim, o HEX da encriptação.

O texto para encriptação deve estar entre aspas e ser menor que 17 caracteres (bytes). 0 < texto <= 16.

O debug é ativado com 1 e desativado com 0, aconselhamos a sempre usar 1 para caso aconteça erros.

 

-Função AES::set_key()

aes.set_key(key, 16);

Com esta função, é adicionado a nossa chave ao sistema de criptografia interno.

Obs: A chave para AES é 128/192/256b, porém, para ser didático, foi usado apenas 3 caracteres. Tome cuidado ao usar chaves de outros tamanhos, alguns lugares não aceitam!

 

-Função AES::encrypt()

aes.encrypt(inp, out);

Esta função, faz a encriptação dos dados que estão dentro do vetor INP, e retorna os valores dentro do vetor OUT.


Colocando para funcionar

Ao testar o código que foi mostrado aqui, será gerado exatamente este código em hexadecimal "4A 38 3A 94 FC FB C4 C6 E1 4F D2 5D 34 7B B5 80", este código hexadecimal é a nossa mensagem encriptada. Encontrei um site bem legal que faz a encriptação e desencriptação dos dados AES, usarei ele.

Coloquei a nossa chave "abc" e o código hexadecimal gerado pelo micro controlador. Após clicar para desencriptar, é mostrado a mensagem original, e como podemos ver, funcionou.

o AES permite vários métodos de encriptação, a mais simples é a ECB, a biblioteca usada no tutorial também permite a CBC que é mais segura, porém mais complicada.

Clique AQUI para ir ao site.


Desafio

O desafio para vocês é que façam a desencriptação de um código hex, estudem sobre o assunto e veja as funções da biblioteca! Vocês podem desencriptar o próprio hex gerado da sua encriptação, ou usar o site indicado anteriormente para obter um hex e ver se a desencriptação funciona. Lembrando que esta biblioteca funciona para Arduino, ESP8266 e ESP32.

Download da biblioteca: https://github.com/spaniakos/AES

 

Fechamento

A segurança é extremamente importante em IoT e nao deve ser esquecida. Sempre adicione caso seja necessário em seu projeto, e principalmente em produtos comerciais. Tem dúvidas? sugestões? críticas? Comente abaixo!


Entrada e Saída - Manipulando Registradores

Entrada e Saída - Manipulando Registradores

Para determinar os estados de suas entradas e saídas o microcontrolador possui registradores na qual esses dados são armazenados. Ao chamar as funções de entrada e saída fornecidas pela biblioteca padrão do Arduino o que fazemos é nada mais que modificar tais registradores. Então porque acessar estes registradores diretamente?

A manipulação direta de registradores permite que:

  • A leitura e escrita em pinos seja feita muito mais rápida.
  • Ler e escrever em mais de um pino de uma mesma porta por vez.
  • O código produzido é menor, em alguns casos esse fator pode fazer a diferença entre seu código caber na memória flash ou não.

Essa técnica também possuí desvantagens:

  • O código produzido é menos portável, difícil de debbugar e de ser mantido.

Na abordagem dos conceitos a seguir o microcontrolador atmega328 presente na placa Arduino Uno será utilizado. Para acompanhar esse tutorial é necessário algum conhecimento de lógica digital.

Todos os registradores desse microcontrolador possuem 8 bits. Os pinos de entrada e saída são divididos em PORTs. O atmega328 possui 3 PORTs, como podemos observar no diagrama a seguir:

Cada PORT possui 3 registradores com diferentes funções:

DDR

Os registradores do tipo DDR (Data Direction Register) são responsáveis por determinar se os pinos de um determinado PORT se comportarão como entrada ou saída. Cada bit do registrador DDR controla o estado do respectivo pino. Por exemplo: O bit 1 do registrador DDRB (DDB1) controlará o estado do pino PB1 e consequentemente o pino D9 do Arduino Uno como mostrado no mapa.

Para definir um pino como saída devemos setar seu respectivo bit do registrador DDR como 1 e  para defini-lo como entrada seta-lo para 0.

/* Equivalente:
pinMode(9,OUTPUT);
pinMode(9,INPUT);
*/

DDRB |= (1 << DDB1);
DDRB &= ~(1 << DDB1);

PORT

Os registradores do tipo PORT são responsáveis por determinar se um pino está definido como alto (HIGH) ou baixo (LOW).

portb

Para definir um pino como alto devemos setar seu respectivo bit do registrador PORT como 1 e para defini-lo como baixo seta-lo para 0.

 

/* Equivalente:
pinMode(9,OUTPUT);
digitalWrite(9,LOW);
*/
 
DDRB |= (1 << DDB1);
PORTB &= ~(1 << PORTB1);

Outro exemplo:

/* Equivalente:
digitalWrite(8,HIGH);
digitalWrite(9,HIGH);
digitalWrite(10,HIGH);
digitalWrite(11,HIGH);
digitalWrite(12,HIGH);
digitalWrite(13,HIGH);
*/
 
PORTB = 0xFF;

 

PIN

Os registradores do tipo PIN são responsáveis por guardar o estado lógico de um pino.

/* Equivalente:
pinMode(9,INPUT);
digitalWrite(9,HIGH); //Nesse contexto, ativa o pull-up interno.
bool x = digitalRead(9);
*/
 
DDRB &= ~(1 << DDB1);
PORTB |= (1 << PORTB1);
bool x = (PINB & (1 << PINB1));
Todo o conteúdo apresentado pode ser encontrado no datasheet do microcontrolador.

Arduino - Entradas e Saídas Digitais - Pinos digitais

Arduino - Entradas e saídas digitais - Pinos digitais

Nesse tutorial daremos prosseguimento aos conceitos básicos para aqueles que desejam aprender como utilizar uma placa Arduino. Este conteúdo será voltado para ensinar como configurar e manipular as entradas e saídas digitais em uma placa Arduino, de modo que, no decorrer deste material você aprenderá a desenvolver programas capazes de fazer com que o seu Arduino realize o acionamento de um led e também com que ele consiga saber se um botão, por exemplo, foi pressionado. Entretanto, sugerimos que, antes de acompanhar este conteúdo, você veja nosso tutorial sobre grandezas digitais, analógicas e PWM, para que então, possa extrair o máximo de informação daqui. 

[toc]

Pinos de entrada e saída digital

Primeiramente, deve-se ter em mente que, quando falamos em entradas ou saídas digitais em uma placa Arduino, estamos falando de elementos que trabalham apenas dois níveis de tensão definidos. No caso do Arduino UNO, por exemplo, estes são:

  • Um nível lógico alto, correspondente a 5V;
  • Um nível lógico baixo, correspondente a 0V.

É importante ressaltar que na prática existem faixas de valores próximos a esses números em que o circuito digital entende como nível alto ou baixo e da mesma forma, existe também uma faixa intermediária não definida que pode gerar resultados inesperados e que, portanto, deve ser evitada.

Em um Arduino UNO, as entradas e saídas digitais estão localizadas desde pino 0 até o pino 13. Note que, estes pinos devem ser configurados previamente para que atuem como entradas ou saídas (é importante ressaltar que alguns destes pinos possuem funções especiais, no entanto, isto será tratado em outros tutoriais. Neste momento basta salientar a função destes enquanto entradas e saídas digitais).


Hardware para o desenvolvimento dos projetos

Nas próximas seções deste tutorial serão desenvolvidos 3 exemplos à respeito da utilização das entradas e saídas digitais. Para simplificar, iremos propor o mesmo hardware para executar todas as propostas de projetos citadas, pois, desta forma o leitor poderá aprender os conceitos de maneira mais fácil. Os projetos que serão desenvolvidos são:

  • Acionando um led através de uma saída digital
  • Piscando um led
  • Realizando a leitura de um botão através de uma entrada digital

Componentes utilizados

Montagem do projeto

Placa Arduino Uno - Uso de entradas e saídas digitais
Esquema de montagem da placa Arduino para desenvolvimento do projeto

Veja o nosso como ficou:

Placa Arduino Uno - Uso de entradas e saídas digitais
Circuito montado com uma Placa Arduino Uno

Entendendo o hardware

A função do hardware apresentado anteriormente consiste em criar o cenário propicio para que possamos ensinar o básico que você precisa aprender para poder utilizar um Arduino UNO.

Primeiramente, perceba que, na montagem em questão, temos um led ligado através de um resistor ao pino 10 do Arduino UNO, de modo que, este resistor é colocado para limitar a corrente que passa pelo led, evitando assim, um eventual problema com os componentes. Observe que quando o pino 10 disponibiliza um potencial de 5V em seu terminal, o circuito será fechado, proporcionando o acionamento do led.

Pino digital do Arduino Uno trabalhando como saída
Pino digital do Arduino Uno trabalhando como saída

Em seguida, lembre-se que o hardware utilizado também possui um botão que ao ser pressionado estabelecerá um potencial de 5V no pino 9 do Arduino UNO. Em contrapartida, caso o botão permaneça sem ser pressionado a porta de entrada digital estará com um potencial de 0V. Dessa forma é importante usarmos aqui um resistor de pull-down de 10kΩ(explicado com mais detalhes no nosso artigo sobre grandezas digitais, analógicas e PWM).

Pino digital do Arduino Uno trabalhando como entrada
Pino digital do Arduino Uno trabalhando como entrada

Projeto 1: Acionando um led através de uma saída digital

Neste projeto ensinaremos a você como proceder para utilizar uma saída digital para acionar algum dispositivo através da mesma.

Código do projeto

Segue o código para ser utilizado no Arduino para realizar o acionamento de uma saída digital

void setup() 
{ 
    pinMode(10,OUTPUT);
    digitalWrite(10,HIGH); 
} 

void loop() 
{
 
}

Entendendo o software

- Definindo as configurações iniciais

O primeiro passo para realizar qualquer tipo de interação utilizando um dos pinos de entrada/saída digital consiste em determinar o modo de operação do mesmo. Como queremos acender um led, devemos fazer com que o pino em que o mesmo está conectado se comporte como uma saída digital. Para isso, dentro da função setup() (lembre-se que a esta função é executada somente quando o Arduino UNO é iniciado e apenas uma vez) utiliza-se a função pinMode(), onde os parâmetros passados para a mesma são: o número do pino a ser utilizado e o modo de operação do mesmo (neste caso, definimos o pino 10 como uma saída digital através da palavra OUTPUT).

pinMode(10,OUTPUT);

- Realizando o acionamento

Depois de definirmos o pino 10 como saída digital, deve-se fazer com que o Arduino UNO coloque o mesmo em nível alto, ou seja, que disponibilize 5V na saída em questão. Para realizar este procedimento, utiliza-se a função digitalWrite() (assim como a função pinMode(), esta também possui dois parâmetros, onde o primeiro corresponde ao pino que terá seu estado alterado e o segundo corresponde ao nível que será disponibilizado na saída, HIGH para nível alto e LOW para nível baixo).

digitalWrite(10,HIGH);

Neste projeto não é necessário utilizar a função loop() (apesar de vazia, ela deve estar presente no código), pois, o conteúdo da função setup() é suficiente para cumprir o objetivo proposto.


Projeto 2: Piscando um led

Assim como no projeto anterior, este terá como objetivo acionar um led, porém, de maneira temporizada, fazendo com que o mesmo permaneça aceso somente por alguns instantes.

Código do projeto

Segue o código a ser utilizado no Arduino para piscar um led.

void setup() 
{ 
    pinMode(10,OUTPUT);
} 

void loop() 
{
    digitalWrite(10,HIGH); 
    delay(1000);
    digitalWrite(10, LOW);
    delay(1000);
}

Entendendo o software

- Definindo as configurações iniciais

Assim como no projeto anterior, o primeiro procedimento a ser realizado neste momento consiste em configurar o modo de operação do pino utilizado, de modo que, para isso, utiliza-se a função pinMode() para definir o mesmo como uma saída digital. Como dito anteriormente, este é apenas um procedimento de configuração, portanto, está inserido na função setup().

void setup() 
{ 
    pinMode(10,OUTPUT);
}

- Realizando o ciclo de acionamentos do led

Como sabemos, o conteúdo da função loop() executado repetidamente do início ao fim. A primeira linha de código existente no conteúdo citado consiste na função digitalWrite(), que por sua vez, é utilizada para acionar o led.

digitalWrite(10,HIGH);

Em seguida, utiliza-se a função delay() para fazer com que o programa espere um determinado tempo (este tempo é passado como parâmetro da função e é no formato de milissegundos) antes de prosseguir com a execução das próximas linhas de código.

delay(1000);

Posteriormente, voltamos a utilizar a função digitalWrite(), porém para desligar o led.

digitalWrite(10, LOW);

E por fim, recorremos uma segunda vez à função delay() para que o ciclo não seja reiniciado de maneira abrupta.

delay(1000);

Veja como ficou nossa função loop():

void loop() 
{
    digitalWrite(10,HIGH); 
    delay(1000);
    digitalWrite(10, LOW);
    delay(1000);
}

Projeto 3: Realizando a leitura de um botão através de uma entrada digital

Neste projeto será demonstrado como você deve proceder para realizar a leitura do estado de uma entrada digital. Nestes casos torna-se possível, por exemplo, determinar o estado de um push-button, ou seja, através da leitura do pino (configurado como uma entrada digital) no qual o mesmo está conectado, pode-se determinar se este foi pressionado ou não.

Código do projeto

Segue o código a ser utilizado no Arduino para ler o estado de uma entrada digital, acender um led caso o botão seja pressionado e mantê-lo aceso por 2 segundos.

void setup() 
{ 
  pinMode(10,OUTPUT);
  pinMode(9,INPUT); 
}

void loop() {
  
  if(digitalRead(9) == HIGH)
  {
      digitalWrite(10, HIGH);
      delay(2000);
      digitalWrite(10, LOW);
  }

}

Entendendo o software

- Definindo as configurações iniciais

Primeiramente, na função setup(), deve-se determinar os modos de operação dos pinos que serão utilizados, sendo assim, definimos o pino 10 como uma saída digital (utilizando OUTPUT no segundo parâmetro da função pinMode()), pois, este será responsável por alimentar o led em questão. Além disso, determinamos também que o pino 9 servirá como uma entrada digital, por isso, utilizamos a palavra INPUT no segundo parâmetro da função pinMode()).

  pinMode(10,OUTPUT);
  pinMode(9,INPUT);

Desta forma, a função setup() terá o seguinte conteúdo:

void setup() 
{ 
  pinMode(10,OUTPUT);
  pinMode(9,INPUT); 
}

- Realizando os acionamentos

Neste momento, antes de prosseguirmos com a explicação do conteúdo função loop(), devemos apresentar o funcionamento da função if(), que pos sua vez, consiste em um elemento muito importante para que esta parte do código possa ser entendida de maneira clara.

Entendendo a função IF

Constantemente, ao nos depararmos com um determinado problema, temos que tomar uma ou várias decisões para que o mesmo possa ser resolvido ou amenizado. Sendo assim, quanto mais informações tivermos, ou seja, quanto mais e melhores forem os resultados coletados sobre uma determinada situação, mais fácil será de tomar uma decisão sobre quais ações devem ser realizadas quando nos encontrarmos naquele tipo de situação. É neste cenário que entra a utilização da função if().

Imagine que o Vida de Silício, além produzir os melhores conteúdos e vender os melhores componentes, esteja se aventurando no meio gastronômico, mais especificamente, no ramo da confeitaria. Obviamente, como dominamos este assunto, temos uma grande variedade de receitas bolos que vão de A a Z, no entanto, somente alguns bolos possuem cobertura, os de aniversário. Sendo assim, internamente, elaboramos um algoritmo, ou passo-a-passo, para que nossa equipe esteja atenta a esta situação, veja:

Função bolo(){
 Faça o bolo;
 Se o bolo é de aniversário {
     Faça uma cobertura;
 }Senão
     Não faça uma cobertura
 }
fim

Para ficar mais fácil de visualizar esta situação, preparamos um fluxograma para você. Veja que utilizamos um parâmetro para decidir se iremos ou não executar a atividade.

Operadores lógicos

É importante ressaltar que os recursos de tomadas de decisão, como por exemplo, a função if(), devem ser utilizados juntamente com os operadores lógicos (como veremos a seguir), os quais, são responsáveis por criar as condições de execução de uma estrutura lógica de tomada de decisão.

Agora que já aprendemos o conceito da função if() e que a mesma é responsável por conferir se uma determinada sentença é verdadeira ou falsa e tomar as providências necessárias com base nesta resposta, neste código, desejamos testar se a entrada digital na qual o botão está conectado, está em nível alto, ou seja, queremos saber se o botão está pressionado (isso pode ser feito colocando o elemento, o operador de igualdade "==" e o que queremos saber se é verdade, no argumento da estrutura condicional if()).

if(digitalRead(9) == HIGH)
{
   //****** CONTEÚDO DA ESTRUTURA CONDICIONAL IF() ******
}

Caso a sentença testada anteriormente seja verdadeira, o código parte para a execução do conteúdo da mesma. Logo, caso o botão seja pressionado, ocorrerá uma situação semelhante a do exemplo 2, onde o led será aceso através da função pinMode() e permanecerá assim por 2 segundos até que seja apagado pela mesma função.

   digitalWrite(10, HIGH);
   delay(2000);
   digitalWrite(10, LOW);

Após o led ser apagado, o programa deve ficar esperando por um novo pressionamento do botão. Isto é possível pois esta parte do código está dentro da função loop(), portanto, será executada repetidamente. Veja como ficou a função loop().

void loop() {
  
  if(digitalRead(9) == HIGH)
  {
      digitalWrite(10, HIGH);
      delay(2000);
      digitalWrite(10, LOW);
  }

}

Nota: Nada irá acontecer caso o botão seja pressionado novamente entre o intervalo onde o led permanece aceso, pois, neste momento, o programa estará parado por conta da função delay().


Considerações finais

Produzimos este conteúdo para auxiliar o leitor na manipulação das entradas e saídas digitais encontradas em uma placa Arduino. Esperamos que você tenha gostado deste conteúdo, sinta-se à vontade para nos dar sugestões, críticas ou elogios. Lembre-se de deixar suas dúvidas nos comentários abaixo.

 

Apostila Arduino Básico

 


Introdução a Interrupções e PCINT

INTRODUÇÃO A INTERRUPÇÕES E PCINT

A compreensão do funcionamento de interrupções é essencial para uma programação eficiente de microcontroladores. Entretanto existem muitas dúvidas em torno desse tópico. Nesse post veremos uma pequena explicação de como interrupções funcionam e em seguida focaremos na interrupção por mudança de estado (PCINT). Na abordagem dos conceitos a seguir o microcontrolador atmega328 presente na placa Arduino Uno será utilizado. Apesar de utilizarmos o atmega328, os conceitos abordados aqui podem ser estendidos para outros atmegas.  Para acompanhar esse tutorial é indicado que você tenha entendido o post sobre manipulação de registradores de entrada e saída que pode se encontrado aqui.

O QUE SÃO INTERRUPÇÕES?

Imagine que você está em casa extremamente focado em escrever um texto no computador, porém de repente seu celular toca. Mesmo sendo uma ligação inesperada, você é capaz de parar a escrita do texto, atender a ligação e voltar para onde você parou quando o telefone tocou.

Dessa maneira que funcionam as a interrupções em um microcontrolador. Nós podemos programá-lo para observar eventos externos, como um pino mudando de estado, enquanto o microcontrolador executa as instruções do código principal. Quando um evento ocorrer, o microcontrolador interromperá a execução do código principal, tratará o evento chamando uma função especificada por nós e retornará a execução do código principal. Dessa maneira nosso programa ganha flexibilidade, uma vez que não é mais necessário ficar checando a todo momento se o evento ocorreu. Nós podemos simplesmente configurar a interrupção e a função de tratamento e assim que o evento ocorrer, ele será tratado.

É importante lembrar que nós não estamos fazendo duas coisas ao mesmo tempo. O programa principal será parado enquanto a função de tratamento estiver sendo executada. Esta função de tratamento é denominada ISR (Interrupt Service Routine). Cada interrupção terá seu vetor de interrupção que nada mais é que um índice em uma tabela de interrupções que apontará para nossa rotina de tratamento.

PCINT - PIN CHANGE INTERRUPT

Como o nome indica este tipo de interrupção ocorrerá quando houver uma mudança no estado do pino escolhido. No atmega328 existem 3 vetores de interrupção para esse tipo de interrupção. Cada um deles está ligado a um PORT. Consequentemente, caso dois pinos de um mesmo PORT estejam utilizando essa interrupção ambos compartilharão a mesma rotina de interrupção. Cabe a nós então, implementar a rotina de interrupção de forma que esta seja capaz de identificar em qual dos dois pinos ocorreu a interrupção. O diagrama da Figura 1 nos ajudará no entendimento das explicações a seguir.

PCICR - Pin Change Interrupt Control Register

Este registrador é reponsável por habilitar a interrupção em um determinado PORT quando o respectivo bit PCIEx for setado para 1.

PCMSK - Pin Change Mask Register

Este registrador é responsável por habilitar a interrupção de um pino  em um determinado PORT. Logo, existem 3 registradores desse tipo PCMSK0, PCMSK1 e PCMSK2 referentes aos PORTS B, C e D respectivamente.

SREG - Global Interrupt Flag

Essa flag é responsável por controlar as interrupções de todo o microcontrolador. Funciona como uma chave geral. Uma maneira de modifica-la é através das macros sei() e cli().

  • sei() - Habilita as interrupções globalmente;
  • cli() - Bloqueia as interrupções globalmente.

Analogia com Chaves

Para facilitar a visualização do papel de cada registrador nós preparamos o diagrama a seguir. Ele mostra o caminho que a interrupção deve fazer até chegar ao respectivo vetor de interrupção. As chaves representam cada bit do registrador especificado. Chave fechada representa que o bit está setado (1) e chave aberta que ele está limpo (0).


EXEMPLOS

Exemplo 1

Nesse exemplo nós veremos como habilitar a interrupção por mudança de estado no pino D12. Como podemos ver no diagrama da Figura 1 o pino D12 é equivalente ao pino PB4 do microcontrolador atmega328. Começamos o programa configurando este pino como uma entrada. Durante a execução das configurações devemos desligar as interrupções globalmente. O pino PB4 possui a interrupção PCINT4 essa interrupção é habilitada por PCMSK0 que por sua vez é habilitado por PCIE0. Logo, devemos setar todos esses registradores. Finalmente devemos configurar a função que será chamada quando a interrupção ocorrer. Isso é feito com o auxílio da macro ISR() que recebe como parâmetro o vetor de interrupção que desejamos configurar. No nosso caso o vetor é o PCINT0_vect.

void setup() {
cli();

// Equivalente a pinMode(12, INPUT_PULLUP);
DDRB &= ~(1 << DDB4); // Seta D12 como entrada;
PORTB |= (1 << PORTB4); // Liga Pull-up;

// Seta as "chaves" necessárias para que a interrupção chegue a seu vetor;
PCICR |= (1 << PCIE0);
PCMSK0 |= (1 << PCINT4);

sei();
}

void loop() {
//...
}

/* Função de Tratamento de Interrupção
Como somente o pino D12 foi configurado para chamar esta função, não
precisamos realizar checagens complexas para entender o que ocorreu.
*/
ISR(PCINT0_vect) {
if (PINB & (1 << PINB4)) {
// D12 mudou de LOW para HIGH;
}
else {
// D12 mudou de HIGH para LOW;
}
}

Exemplo 2

Nesse exemplo nós veremos como habilitar a interrupção por mudança de estado nos pinos D12, D11 e D10. Como podemos ver no diagrama da Figura 1 o estes pinos são equivalentes aos pinos PB4, PB3 e PB2 respectivamente do microcontrolador atmega328. Repetimos todos os passos anteriores, só que agora para todos os pinos. Diferentemente do exemplo anterior agora um mesmo vetor será chamado por vários pinos. Para definir qual pino causou a interrupção devemos guardar um histórico do ultimo estado de todo o PORTB.

void setup() {
cli();

/* Equivalente a
pinMode(12, INPUT_PULLUP);
pinMode(11, INPUT_PULLUP);
pinMode(10, INPUT_PULLUP);
*/
DDRB &= ~( (1 << DDB4) | (1 << DDB3) | (1 << DDB2) );
PORTB |= ( (1 << PORTB4) | (1 << PORTB3) | (1 << PORTB2) );

// Seta as "chaves" necessárias para que as interrupções cheguem ao vetor;
PCICR |= (1 << PCIE0);
PCMSK0 |= ( (1 << PCINT4) | (1 << PCINT3) | (1 << PCINT2) );

sei();
}

void loop() {
//...
}
// Variáveis globais que são acessadas por interrupções devem ser declaradas volatile;
volatile uint8_t last_PINB = PINB;

/* Função de Tratamento de Interrupção */
ISR(PCINT0_vect) {
uint8_t changed_bits;
changed_bits = PINB ^ last_PINB;
last_PINB = PINB;

if (changed_bits & (1 << PINB4))
{
if (PINB & (1 << PINB4)) {
// D12 mudou de LOW para HIGH;
}
else {
// D12 mudou de HIGH para LOW;
}
}
else if (changed_bits & (1 << PINB3))
{
if (PINB & (1 << PINB3)) {
// D11 mudou de LOW para HIGH;
}
else {
// D11 mudou de HIGH para LOW;
}
}
else if (changed_bits & (1 << PINB2))
{
if (PINB & (1 << PINB2)) {
// D10 mudou de LOW para HIGH;
}
else {
// D10 mudou de HIGH para LOW;
}
}
}

FINALIZANDO

Este conteúdo foi totalmente voltado para esclarecer alguns pontos à respeito das interrupções. Esperamos que você tenha gostado deste conteúdo, sinta-se à vontade para nos dar sugestões, críticas ou elogios. Lembre-se de deixar suas dúvidas nos comentários abaixo.

 


Arduino - Grandezas digitais, analógicas e PWM

Arduino - Grandezas digitais, analógicas e PWM

Antes de partirmos para o desenvolvimento de aplicações praticas utilizando algum tipo de sistema embarcado como por exemplo, uma placa Arduinoé necessário que o leitor tenha o conhecimento necessário para diferenciar uma grandeza analógica de uma grandeza digital. O domínio destes conceitos é muito importante para que seja possível aprender como estes sistemas trabalham com essas grandezas (de maneira mais específica, como estes sistemas realizam os processos de conversão entre as mesmas). Sendo assim, este tutorial visa trazer informações referentes aos tipos de grandezas citadas, para que então, o leitor possa adentrar com maior segurança em outros conteúdos.

[toc]

 

Diferença entre grandezas digitais e analógicas

Primeiramente, as grandezas digitais são aquelas que podem ser definidas por meio de saltos entre valores bem definidos dentro de uma faixa de valores. Um exemplo de elementos que trabalham com estas grandezas são os relógios digitais, de modo que, nestes, apesar do tempo em si variar continuamente, o visor dos mesmos mostra o tempo em saltos de um em um segundo (observe que os visores destes relógios nunca mostrarão 30,4 segundos, pois, para eles, só existem 30 e 31 segundos, ou seja, qualquer valor intermediário não está definido).

Em contrapartida, as grandezas analógicas são aquelas que, ao contrário das grandezas digitais, podem assumir infinitos valores de amplitude dentro de uma faixa de valores. O velocímetro de um carro, por exemplo, pode ser considerado analógico, pois o ponteiro gira continuamente conforme o automóvel acelera ou freia. Se o ponteiro girasse em saltos, o velocímetro seria considerado digital.

Uma analogia interessante que pode ser feita é a comparação de uma escada com uma rampa, pois, enquanto uma rampa sobe de forma contínua, assumindo todos os valores de altura entre a base e o topo, a escada sobe em saltos, com apenas alguns valores de altura definidos entre a base e o topo. A escada representa, portanto, uma grandeza digital, enquanto a rampa representa uma grandeza analógica.

É importante observar que a quantidade de degraus em uma escada define quais e quantas posições pode-se escolher. Por exemplo, suponha que um determinado degrau em uma escada está a 1,00 m de altura do solo e o próximo está a 1,20 m da mesma referência, note que, neste caso, não é possível ocupar uma posição a 1,15 m do solo porque não existe um degrau lá.

Portanto, percebe-se que ao adicionar mais degraus em uma escada, mais perto de uma rampa esta se aproximará.


Entradas e saídas digitais

Os circuitos e equipamentos elétricos ditos digitais trabalham com apenas dois níveis de tensão definidos. No caso do Arduino UNO, estes são:

  • Um nível lógico alto, correspondente a 5V;
  • Um nível lógico baixo, correspondente a 0V.

Na prática existem faixas de valores próximos a esses números em que o circuito digital entende como nível alto ou baixo. De maneira complementar, existe também uma faixa intermediária não definida que pode gerar resultados inesperados e que, portanto, deve ser evitada.

No Arduino UNO, as entradas e saídas digitais estão localizadas desde pino 0 até o pino 13. Note que, estes pinos devem ser configurados previamente para que atuem como entradas ou saídas (é importante ressaltar que alguns destes pinos possuem funções especiais, no entanto, isto será tratado posteriormente. Neste momento basta salientar a função destes enquanto entradas e saídas digitais).

Entradas digitais do Arduino Uno
Entradas digitais do Arduino Uno

 

Características de uma entrada digital

Quando configuramos um pino como entrada digital ele apresentará uma característica chamada alta impedância. Isso significa que uma pequena corrente consegue fazer com que seu estado mude. Utiliza-se essa configuração, por exemplo, para ler botões, fotodiodos entre outros, de modo que, a partir do estado lido ou das mudanças desses estados conclui-se o que está acontecendo no mundo externo e então pode-se tomar decisões baseadas nessas medidas.

Caso um determinado pino seja configurado como entrada digital mas não esteja conectado a nada, seu estado poderá ser alterado aleatoriamente em virtude de ruídos elétricos do ambiente. Para evitar esse problema utiliza-se um resistor de pull up ou pull down, cuja função é fazer com que a tensão na entrada em questão esteja bem definida quando a mesma não estiver conectada a nada.

As figuras abaixo mostram três ligações de um botão a um pino configurado como entrada digital de um Arduino UNO. Observe o que acontece em cada caso :

  • Caso 1: O estado do pino não estará bem definido fazendo com que este esteja suscetível a ruído.

 

 

  • Caso 2: Neste caso devido à presença do resistor de pull-down seu estado está bem definido e ele enxergará GND (0V). Como consequência seu estado será definido como baixo.

 

Botão com Pull-down no Arduino Uno
Botão com Pull-down

 

  • Caso 3: Neste caso devido à presença do resistor de pull-up, seu estado está bem definido e ele enxergará 5V. Sendo assim, seu estado estará definido como alto.

 

Botão com Pull-up no Arduino Uno
Botão com Pull-up

 

Como curiosidade, vale ressaltar que os microcontroladores presentes nas placas Arduino possuem resistores de pull-up construídos internamente que podem ser acessados por software.

 

Características de uma saída digital

Quando configurados nesse estado os pinos podem fornecer 0 ou 5 V fazendo com que eles drenem ou forneçam corrente. O valor máximo dessa corrente varia de placa para placa, mas, em geral, é de 30mA. Note que esta corrente é mais do que suficiente para ligar um LED de alto-brilho e alguns sensores, porém não é suficiente para ligar a maioria dos relés e motores.

Deve-se ter cuidado, pois, caso uma corrente maior que o limite passe por um pino, este poderá ser danificado.


Entradas analógicas

Com um pouco de observação, pode-se notar que o mundo é quase todo formado por variáveis analógicas, tais como posição, temperatura e pressão, de forma que, torna-se necessário saber trabalhar com esses tipos de grandezas. Um Arduino UNO, por exemplo, possui um conjunto de pinos destinados a serem utilizados como entradas analógicas.

Entradas analógicas no Arduino Uno
Entradas analógicas no Arduino Uno

Como no Arduino UNO tudo é processado de forma digital, é necessário converter as grandezas analógicas em digitais. Para realizar esta tarefa existem conversores já embutidos na placa, de forma que, deve-se apenas compreender o básico do processo de conversão para poder utilizar portas analógicas citadas anteriormente.

De volta no exemplo da escada e da rampa, a quantidade de degraus que temos em uma escada nos podemos associar o conceito de resolução. A resolução de um conversor indica o número de valores discretos (degraus) que o mesmo pode produzir. Quanto mais intervalos (degraus) existirem, mais perto estará um sinal digital de um sinal analógico.

Características de uma entrada analógica

Os conversores analógico-digital do Arduino UNO possuem uma resolução de 10 bits e o intervalo de tensão no qual são realizadas as discretizações (degraus da escada) é de 0 a 5V, ou seja, este intervalo será dividido em 1024 pedaços (210, onde 10 é a resolução do conversor ) , de forma que, o valor atribuído à tensão presente em um determinado pino será o valor discreto (um dos 1024 valores) mais próximo da mesma.

Em outras palavras, com 10 bits de resolução e um intervalo de 0 a 5V de tensão pode-se representar 1024 degraus, os quais, cada um representa um salto de 0,0048828 V (este resultado foi obtido através da razão 5/1024).

Por exemplo, suponha uma tensão de 3,25 V. o valor retornado pela conversão será:

O resultado deve ser inteiro para que o conversor consiga representá-lo, portanto, o valor 666 será escolhido por ser o degrau mais próximo. Esse valor representa uma tensão de 3,251953125 V. Repare que a utilização deste valor insere um erro de 0,001953125 V na medida em questão.


PWM - Simulando saídas analógicas

Além de possuir portas para realizar a leitura de variáveis analógicas, o Arduino UNO conta também com pinos que podem ser usados para simularem saídas analógicas através do PWM, que por sua vez, é uma técnica para obter resultados analógicos por meios digitais. No Arduino UNO, os pinos em questão são: 3,4,6,9,10 e 11, mostrados conforme a figura abaixo.

Saídas PWM
Saídas PWM

 

Este recurso consiste na geração de uma onda quadrada, na qual, controla-se a porcentagem do tempo em que a onda permanece em nível lógico alto. Esta porcentagem é chamada de Duty Cycle e sua alteração provoca mudança no valor médio da onda, indo desde 0V (0% de Duty Cycle) a 5V (100% de Duty Cycle) no caso do Arduino UNO.

O Duty Cycle a ser definido no projeto corresponde a um número inteiro, que é armazenado em um registrador 8 bits. Sendo assim, seu valor vai de 0 (0%) a 255 (100%).

 

 

De maneira mais detalhada, o Duty Cycle é a razão entre o tempo em que o sinal permanece na tensão máxima (5V no Arduino UNO) e o tempo total de oscilação, conforme ilustrado na figura abaixo:

O  Duty Cycle pode ser calculado da seguinte maneira:

Da mesma forma, pode-se também calcular o valor médio da tensão que está sendo entregue pela saída utilizada.


CONSIDERAÇÕES FINAIS

Este conteúdo foi totalmente voltado para esclarecer alguns pontos à respeito dos tipos de grandezas encontradas ao utilizar uma placa Arduino. Esperamos que você tenha gostado deste conteúdo, sinta-se à vontade para nos dar sugestões, críticas ou elogios. Lembre-se de deixar suas dúvidas nos comentários abaixo.

Este conteúdo consiste em uma modificação/revisão do tutorial sobre grandezas digitais, analógicas e PWM do autor Ronan Largura (Eng Elétrica - UFES).

 

Apostila Arduino Básico

 


entradas e saídas anaçógicas

Arduino - Entradas e Saídas Analógicas - PWM

Arduino - Entradas e saídas analógicas

Com um pouco de atenção, podemos perceber que a todo momento estamos rodeados de situações nas quais existem elementos que podem ser definidos como grandezas analógicas, como por exemplo, posição e temperatura. Sabendo a importância deste tipo de grandeza, torna-se necessário que nós aprendamos a lidar com este tipo de informação dentro do cenário que estamos adentrando, sendo assim, neste tutorial abordaremos com maior enfoque, o modo utilizado por uma placa Arduino para lidar com o tipo de grandeza citada.

Para acompanhar este tutorial com maior compreensão, recomendamos que o leitor acompanhe nosso tutorial sobre grandezas digitais, analógicas e PWM.

[toc]

Pinos de entrada e "saída" analógica

Como dissemos no tutorial citado anteriormente, as grandezas analógicas são aquelas que, ao contrário das grandezas digitais, podem assumir infinitos valores de amplitude dentro de uma faixa de valores. Além disso, demos também como exemplo, o velocímetro de um carro, que por sua vez, pode ser considerado analógico, pois o ponteiro gira continuamente conforme o automóvel acelera ou freia. Se o ponteiro girasse em saltos, o velocímetro seria considerado digital.

Uma placa Arduino possui um conjunto de pinos destinados a lidar com este tipo de grandeza, onde, alguns são utilizados como entradas analógicas, isto é, possuem a função de receber dados provenientes de grandezas analógicas, enquanto outros, possuem a função de produzir informações que simulam o comportamento de grandezas analógicas, aqui estamos falando da utilização de uma técnica chamada PWM.

Em um Arduino UNO, as entradas analógicas estão localizadas do pino A0 até o pino A5. Por outro lado, os elementos que podem atuar fornecendo sinais que simulam o comportamento de uma grandeza analógica, são alguns dos pinos caracterizados como pinos de entrada/saída digital (de maneira específica, os pinos 3,5,6,9,10 e 11).


Mãos à obra - Variando a luminosidade de um led com um potenciômetro utilizando PWM

Neste tutorial iremos elaborar um projeto onde você poderá compreender tanto o processo de aquisição de dados a partir das portas de entrada analógicas quanto os procedimentos de utilização do PWM. O hardware consistirá em uma estrutura onde será possível variar a luminosidade de um led através de um potenciômetro..

Componentes utilizados

Montagem do projeto

Veja como ficou o nosso:

Programando

Antes de adentrarmos na apresentação do código, disponibilizamos uma seção para ajudar aqueles que são iniciantes no assunto. Sinta-se livre para prosseguir caso você já tem domínio da IDE do Arduino.

Conectando o Arduino ao computador

Primeiramente, conecte seu Arduino ao computador e abra a IDE Arduino. Em seguida, é necessário selecionar a porta COM na qual o Arduino está conectado (este procedimento pode ser feito clicando no menu Ferramentas (tools) e em seguida escolhendo-se a porta correspondente no submenu Porta (port). Neste caso, a porta na qual está o Arduino é apresentada da seguinte maneira: COM3 (Arduino UNO).

Por fim, garanta também que o tipo de placa apropriado esteja selecionado (isso pode ser feito acessando o menu Ferramentas (tools) e o submenu Placa (board)).

– Código do projeto

Segue o código a ser utilizado no Arduino UNO para alterar a luminosidade do led através do potenciômetro.

unsigned int potenciometro
unsigned int pwm

void setup() 
{
   pinMode(10,OUTPUT);
}

void loop()
{
  
   potenciometro = analogRead(A0);
  
   pwm = map(potenciometro,0,1023,0,255);
  
   analogWrite(10,pwm);

}

Entendendo a fundo

Hardware

- Potenciômetro e trimpot

Potenciômetros e trimpots são resistores variáveis e ajustáveis, portanto, são bastante utilizados para realizar o controle analógico de algumas funcionalidades de aparelhos eletrônicos, como por exemplo, o volume de um aparelho de som.

Geralmente, estes dispositivos possuem três pernas, de modo que, duas destas são ligadas às extremidades de um material resistivo resistência (A e B), que por sua vez, são ligadas em dois potenciais distintos, enquanto a terceira, é conectada a um cursor que se movimenta ao longo do material citado. Este deslocamento faz com que seja possível obtermos diferentes níveis de tensão, obviamente, entre os valores de potenciais citados anteriormente.

- Divisor de tensão

O princípio de funcionamento descrito na seção anterior corresponde ao conceito de divisor de tensão. Imagine a seguinte configuração:

Sabemos que, quando temos duas resistências são associadas em série e o conjunto é sujeito a uma diferença de potencial, ambas serão percorridas pela mesma corrente. A equação que rege o comportamento do conjunto citado é dada por:

Se aplicarmos uma tensão de 5V nos terminais do conjunto, teremos:

Onde a corrente é o resultado da razão entre a tensão pela soma dos valores das resistências. Observe que, apesar de termos a mesma corrente passando pelos resistores, os mesmos estão sujeitos a tensões diferentes em seus respectivos terminais.

e

Pelos cálculos realizados acima, podemos perceber que a queda de tensão será maior no resistor de maior resistência.

Um circuito divisor de tensão é justamente aquele em que podemos extrair apenas uma fração da tensão aplicada nos terminais do mesmo. Observe como podemos calcular a tensão em um dos resistores de forma direta:

O exemplo a seguir mostra como funciona o cálculo o para dois resistores.

- Em resumo

Quando estamos utilizando um potenciômetro, estamos recorrendo ao conceito de divisor de tensão para obter diferentes valores de tensão em virtude da rotação do mesmo, de modo que,  com a tensão total e a resistência total fixas, o divisor de tensão vai variar com a resistência entre A0 e GND (Considere no GIF que 0 a 100% é a posição inicial e final de rotação do potenciômetro. Teremos a tensão sobre o pino central variando conforme a posição angular do potenciômetro.)

Software

– Declarando as variáveis

O primeiro passo realizado neste código foi a declaração das variáveis que serão utilizadas ao longo do código do projeto. Observe que a declaração de uma variável é feita colocando-se o tipo da mesma (neste caso, as duas variáveis declaradas são do tipo unsigned int, pois, consistem apenas em números positivos) e em seguida, o seu nome (potenciometro e pwm).

A diferença entre os tipos int e unsigned int consiste no fato de que, no arduino UNO, uma variável do tipo int pode armazenar números que vão de  -32.768 a 32.767, portanto, perceba que neste tipo de variável é possível que haja a ocorrência de números negativos em seu conteúdo. Em contrapartida,  quando uma variável é do tipo unsigned int, ela pode armazenar números de 0 a 65.535, portanto, positivos.

unsigned int potenciometro
unsigned int pwm

– Definindo as configurações iniciais

Em seguida, devemos determinar o modo de operação do pino utilizado para acionar o led, fazendo com que o mesmo se comporte como uma saída digital. Para isso, dentro da função setup() (lembre-se que esta função é executada apenas quando o Arduino UNO é ligado) utiliza-se a função pinMode(), onde os parâmetros passados para a mesma são: o número do pino a ser utilizado e o modo de operação do mesmo (neste caso, definimos o pino 10 como uma saída digital através da palavra OUTPUT).

void setup() 
{
    pinMode(10,OUTPUT);
}

– Realizando a leitura de uma entrada analógica

Em primeiro lugar, como vimos no tutorial sobre grandezas digitais, analógicas e pwm, o Arduino UNO possui conversores A/D com resolução de 10 bits e que trabalham com intervalos de tensão de referência de 0 a 5V. Estes conversores são responsáveis por transformar o sinal de tensão aplicado nas suas entradas analógicas em informações digitais que possam ser interpretadas pelo Arduino UNO.

Basicamente, o que os conversores citados fazem é dividir o intervalo citado (0 a 5V) em 1024 (210, onde 10 é a resolução do conversor) pedaços, que por sua vez, estão distantes uns dos outros por 0,0048828 V (5/1024 V) e além disso, relacionar o sinal de tensão presente em uma determinada porta de entrada analógica com um destes pedaços.

 

Por exemplo: imagine que um potencial de 3,25V esteja presente em um pino de entrada analógica, neste caso, o valor retornado pela conversão será:

Como o resultado deve ser um número inteiro para que o conversor consiga representá-lo, o Arduino UNO escolhe o valor 666 (por ser o inteiro mais próximo) para representar o nível de tensão aplicado.

Sabendo disso, utilizamos a função analogRead() para que o Arduino UNO realize a leitura do valor entregue pelo potenciômetro à porta de entrada analógica A0, realize a conversão do mesmo e por fim, armazene ele na variável potenciometro . Esta função recebe apenas um parâmetro que consiste na porta de entrada analógica que está sendo utilizada na aquisição dos dados.

potenciometro = analogRead(A0);

– Convertendo intervalos de entrada em intervalos de saída

Para realizarmos a alteração na luminosidade do led, devemos relembrar o conceito de PWM. No nosso artigo sobre entradas digitais, analógicas e pwm explicamos que este recurso consiste na geração de uma onda quadrada, na qual, definimos a porcentagem do tempo em que a onda permanece em nível lógico alto (Duty cycle), provocando a mudança no valor médio da onda, que por sua vez, está relacionada com a potência entregue ao led e consequentemente com o brilho emitido pelo mesmo

Além disso, mostramos também que, no código, o Duty Cycle corresponde a um número inteiro de 8 bits, variando, portanto, de 0 (0% de Duty cycle) a 255 (100% de Duty cycle).

De posse destas informações, observe que, de um lado, temos uma sinal analógico de 0 a 5 V que é entendido pelo Arduino UNO como um número inteiro que vai de 0 a 1023 e de outro temos um sinal PWM que deve ser aplicado a um dispositivo cujo valor do Duty cycle corresponde, no código, a um valor que varia de 0 e 255.

Neste momento, você deve ter percebido temos a necessidade de elaborar algo para que seja possível estabelecer uma correspondência entre os valores de entrada e os valores de saída citados, conforme a figura abaixo.

Este procedimento pode ser realizado através da função map(), confira:

A função map() permite o mapeamento de um intervalo numérico em outro intervalo numérico. Basicamente, o que a função map() faz é pegar um intervalo possua os extremos X1 e X2 e transformar-lo em um outro intervalo cujos valores extremos são Y1 e Y2.

A utilização da função map() requer o uso de 5 parâmetros, onde, o primeiro diz respeito à variável cujo intervalo queremos converter, o segundo e a terceiro correspondem aos extremos mínimo e máximo do intervalo original e os dois últimos estão relacionados com os extremos mínimo e máximo do intervalo novo. Na linha de código abaixo, a variável pwm (criada anteriormente) recebe o valor resultante da conversão da posição do potenciômetro no valor adequado para utilização do PWM, isto é, um valor entre 0 e 255.

pwm = map(potenciometro,0,1023,0,255);

– Acionando o led através de um sinal PWM

Em seguida recorremos à função analogWrite() para aplicar o sinal PWM na saída em que o led está conectado. Esta função possui dois parâmetros, onde, o primeiro corresponde ao pino utilizado e o segundo diz respeito ao número inteiro que representa o Duty cycle (lembre-se que este número está armazenado na variável pwm) do sinal PWM que será entregue pelo Arduino UNO.

analogWrite(10,pwm);

Por fim, devemos lembrar que todo conteúdo apresentado anteriormente faz parta da função loop(), pois, desta maneira, é possível realizar de maneira contínua e constante tanto a leitura do potenciômetro quanto o acionamento do led através da utilização do sinal PWM.

void loop() {
  
  potenciometro = analogRead(A0);
  
  pwm = map(potenciometro,0,1023,0,255);
  
  analogWrite(10,pwm);

}

Considerações finais

Este conteúdo foi elaborado para que você possa compreender o básico para poder manipular as entradas analógicas bem como fazer a utilização do PWM para acionar uma infinidade de dispositivos. Esperamos que você tenha gostado deste tutorial e sinta-se à vontade para nos dar sugestões, críticas ou elogios. Lembre-se de deixar suas dúvidas nos comentários abaixo.

 

Apostila Arduino Básico

 


HC-SR04 - Sensor Ultrassônico com Arduino

HC-SR04 - Sensor Ultrassônico de distância com Arduino

O sensor ultrassônico HC SR04 é amplamente utilizado em aplicações onde se deseja medir distância ou evitar colisões, como na robótica móvel e de reabilitação. Neste tutorial aprenderemos como utilizar o Módulo Sensor HC-SR04 com Arduino.

Sensor Distância Ultrassônico HCSR04, HC-SR04 ou HC SR04
Sensor Distância Ultrassônico HC SR04

Sensor Ultrassônico HC-SR04

Tudo começa pela emissão de um pequeno pulso sonoro de alta frequência que se propagará na velocidade do som no meio em questão. Quando este pulso atingir um objeto, um sinal de eco será refletido para o sensor. A distância entre o sensor e o objeto pode então ser calculada caso saibamos o tempo entre a emissão e a recepção do sinal, além da velocidade do som no meio em questão. Afigura a seguir exemplifica o processo.

sensor ultrassônico HC-SR04 funcionamento
Sensor ultrassônico HC-SR04

Para uma melhor medição da distância, a área do objeto na qual a onda será refletida deve ser de pelo menos 0,5 m2.


Mãos à obra - Medindo distância com o HC-SR04

Componentes necessários:

Montando o projeto

Agora vamos conectar os componentes do projeto. Para isso, desligue o cabo USB de seu Arduino e monte seu circuito conforme a figura a seguir.

esquema de montagem do Arduino uno com Sensor ultrassonico HC-SR04, HCSR04

O HC SR04 possui 4 pinos sendo eles:

  • Vcc – Deve ser conectado a um pino 5V do Arduino.
  • Trig – Deve ser conectado a um pino digital configurado como saída. Utilizaremos o pino 8.
  • Echo – Deve ser conectado a um pino digital configurado como entrada. Utilizaremos o pino 7.
  • Gnd – Deve ser conectado a um pino GND do Arduino.

Programando

Crie um no programa (sketch) e salve com o nome de “programa_ultrassom_hcsr04”.

Nesse exemplo utilizaremos a biblioteca Ultrasonic.h. A utilização dessa biblioteca é bastante simples.

Clique aqui para baixa a biblioteca Ultrasonic.h
Clique aqui para baixar a biblioteca Ultrasonic.h

- Instalar a biblioteca pelo IDE do Arduino

Esse é o método mais fácil. Primeiramente, faça o download dos arquivos da biblioteca compactados no formato zip. Geralmente as bibliotecas já são distribuídas compactadas, porém às vezes é necessário fazer o download dos arquivos separadamente e compactá-los à parte. Em seguida, basta abrir o IDE e ir em “Sketch -> Incluir Biblioteca -> Adicionar biblioteca .ZIP” E selecionar o aquivo baixado:

Imagem explicando como adicionar uma biblioteca IDE Arduino

Com isso, a nova biblioteca foi instalada. Para utilizá-la, basta ir em “Sketch -> Incluir Biblioteca” e selecionar a biblioteca desejada.

Você pode ver mais detalhes sobre como adicionar uma biblioteca no tutorial Sensores DHT11 e DHT22 e o Uso de Bibliotecas.

- Código exemplo

Com o seu programa salvo, escreva nele o código abaixo:

//Leitura de distância com o sensor HC-SR04
#include <Ultrasonic.h>
 Ultrasonic ultrassom(8,7); // define o nome do sensor(ultrassom)
//e onde esta ligado o trig(8) e o echo(7) respectivamente

long distancia;

// Esta função "setup" roda uma vez quando a placa e ligada ou resetada
 void setup() {
 Serial.begin(9600); //Habilita Comunicação Serial a uma taxa de 9600 bauds.
 
 }

// Função que se repete infinitamente quando a placa é ligada
 void loop()
 {
   distancia = ultrassom.Ranging(CM);// ultrassom.Ranging(CM) retorna a distancia em
                                     // centímetros(CM) ou polegadas(INC)
   Serial.print(distancia); //imprime o valor da variável distancia
   Serial.println("cm");
   delay(100);
 }

Após escrever o código, salve e depois clique em Carregar (Upload) para que o programa seja transferido para seu Arduino.

Colocando para funcionar

Abra o Serial Monitor e coloque um obstáculo na frente do sensor ultrassônico. Se tudo deu certo, conforme você variar a distância do obstáculo em relação ao sensor, a distância medida aparecerá no serial monitor, tal como a figura a seguir.

monitor serial sensor ultrassônico HC-SR04 distância


Entendendo a fundo

Entendendo o Software

- Biblioteca Ultrasonic.h

Na elaboração do software utilizaremos a biblioteca Ultrasonic.h. Essa biblioteca implementa as funcionalidades do sensor ultrassom HC-SR04, tornando sua utilização extremamente simples.

- Declarando um Ultrassom

Para o uso dessa biblioteca devemos definir o nome do sensor e em quais pinos estão conectados os pinos trig e echo.

Ultrasonic nomesensor(trig,echo);

No exemplo a seguir, o nome do sensor é ultrassom, o pino do trig está conectado na porta 8 e o pino do echo na porta 7.

Ultrasonic ultrassom(8,7);

- Medindo a distância

Para ler a distância, basta chamar a função Ranging(CM). Para valor em centímetros, deve-se usar CM e para valor em polegadas, deve-se usar INC. Essa função retorna um valor de variável long.

long distancia = ultrassom.Ranging(CM); // distancia recebe o valormedido em cm

Observe que usamos o nome do sensor escolhido, no nosso caso ultrassom, seguido de ponto e o nome da função que queremos usar. Para o Arduino estamos falando que queremos usar determinada função do objeto mencionado, no nosso caso o ultrassom.

- Imprimindo na porta serial

Para imprimir o valor de distância lido usamos a função Serial.print().

Serial.print(distancia); //imprime o valor da variável distancia
Serial.println("cm");

Repare que na primeira linha imprimimos o valor da variável distância e na segunda linha imprimimos a palavra cm, que está entre aspas duplas. Sempre que quisermos imprimir um texto devemos colocá-lo dentro de aspas duplas, caso contrário o programa irá entender que o texto é o nome de uma variável.

Repare também que na segunda linha usamos o sufixo -ln depois de print. Esse sufixo informa que depois de escrito o texto, o programa deve pular uma linha.

Entendendo o Hardware

Como dito anteriormente, o sensor ultrassom mede a distância através da medição do tempo que uma onda leva para sair do emissor, colidir com um obstáculo e ser refletido, para, finalmente, ser detectado pelo receptor. Desta forma, podemos notar que nosso sensor ultrassom possui dois cilindros metálicos que se assemelham a olhos em sua placa. São, na realidade, dois altos falantes: um trabalha como o emissor do sinal ultrassom e o outro como receptor.

sensor ultrassônico HC-SR04
Sensor ultrassônico HC-SR04

- Fazendo a leitura do tempo

Para iniciarmos uma medição, o pino Trig, que funciona como gatilho do nosso sensor ultrassom, deve receber um pulso de 5V por pelo menos 10 microssegundos. Isso fará com que o sensor HC-SR04 emita 8 pulsos ultrassônicos em 40kHz (T piezzo) e o pino ECHO, que funcionará como nosso cronômetro, vai para 5V, iniciando assim a espera pelas ondas refletidas.

Assim que uma onda refletida for detectada, o pino Echo, que estava em 5V, será alterado para 0V. Desta forma, o período que o pino Echo fica em 5V é igual ao tempo que a onda emitida leva para ir até o obstáculo e voltar.

Veja a imagem abaixo para entender o que acontece no sensor HC-SR04.

gráfico de pulsos no sensor HCSR04, HC-SR04 ou HC SR04

Por fim, para sabermos quão longe nosso obstáculo está, basta contarmos quanto tempo (T) a tensão no pino Echo ficou em 5V. Em posse desse tempo, sabendo que ele é o dobro do tempo de ida e volta da onda do sensor ultrassônico até o obstáculo, e, considerando a velocidade do som igual a 340,29 m/s, temos:

formula som

Desta forma, temos que a distância até o obstáculo é igual a ΔS.

A função Ultrasonic.h faz exatamente o procedimento descrito, retornando apenas o valor da distância.

Outra opção de código

Poderíamos seguir o procedimento explicado usando o seguinte código:

// Leitura HC-SR04
const uint8_t trig_pin = 10;
const uint8_t echo_pin = 9;

uint32_t print_timer;

void setup() {
Serial.begin(9600); // Habilita Comunicação Serial a uma taxa de 9600 bauds.

// Configuração do estado inicial dos pinos Trig e Echo.
pinMode(trig_pin, OUTPUT);
pinMode(echo_pin, INPUT);
digitalWrite(trig_pin, LOW);
}

void loop() {
// Espera 0,5s (500ms) entre medições.
if (millis() - print_timer > 500) {
print_timer = millis();

// Pulso de 5V por pelo menos 10us para iniciar medição.
digitalWrite(trig_pin, HIGH);
delayMicroseconds(11);
digitalWrite(trig_pin, LOW);

/* Mede quanto tempo o pino de echo ficou no estado alto, ou seja,
o tempo de propagação da onda. */
uint32_t pulse_time = pulseIn(echo_pin, HIGH);

/* A distância entre o sensor ultrassom e o objeto será proporcional a velocidade
do som no meio e a metade do tempo de propagação. Para o ar na
temperatura ambiente Vsom = 0,0343 cm/us. */
double distance = 0.01715 * pulse_time;

// Imprimimos o valor na porta serial;
Serial.print(distance);
Serial.println(" cm");
}
}

Desafio

Sabendo como funciona um sensor ultrassônico, faça o programa que meça a distância sem o auxílio da biblioteca.

Fechamento

Esperamos que tenham gostado, deixe seu comentário com duvidas, sugestões ou com a foto ou vídeo de seu projeto!! Compartilhe à vontade.

 

Apostila Arduino Básico

 


DHT11 e DHT22 | Sensor de umidade e Temperatura com Arduino

DHT11 e DHT22,  Sensor de umidade e Temperatura com Arduino

Umidade e temperatura são duas grandezas que estão muito relacionadas quando o assunto é climatização. Nesse tutorial você aprenderá a medir essas duas grandezas através do sensor de umidade e temperatura DHT11 ou o DHT22 em conjunto com um Arduino.

[toc]

Sensores de umidade e temperatura DHT11 e DHT22

O sensor DHT11 e o sensor DHT22 são sensores básicos e de baixo custo que utilizam um termistor e um sensor capacitivo para medir a temperatura e a umidade do ar ambiente.

Esses sensores são bastante simples de usar, mas requer cuidado com o tempo entre duas leituras consecutivas, uma vez que é necessário um intervalo de, no mínimo, 1 segundo entre uma leitura e outra.

SensorDHT11 (azul) e DHT22 (branco)
Sensor DHT11 (azul) e DHT22 (branco)

Existem diferentes versões do DHT, similares na aparência e na pinagem, porém com características diferentes. As características do DHT11 e DHT22, dois modelos populares desse sensor, são:

Sensor DHT11

  • Muito baixo custo
  • Tensão de alimentação de 3V a 5V
  • 2.5mA de corrente máxima durante a conversão
  • Bom para medir umidade entre 20% e 80%, com 5% de precisão
  • Bom para medir temperaturas entre 0 e 50°C, com ±2°C de precisão
  • Taxa de amostragem de até 1Hz (1 leitura por segundo)
  • Dimensões: 15.5mm x 12mm x 5.5mm
  • 4 pinos com 0.1" de espaçamento entre eles

Sensor DHT22

  • Baixo custo
  • Tensão de alimentação de 3V a 5V
  • 2.5mA de corrente máxima durante a conversão
  • Bom para medir umidade entre 0% e 100%, com 2% a 5% de precisão
  • Bom para medir temperaturas entre -40 e 125°C, com ±0,5°C de precisão
  • Taxa de amostragem de até 0,5Hz (2 leituras por segundo)
  • Dimensões: 15.1mm x 25mm x 7.7mm
  • 4 pinos com 0.1" de espaçamento entre eles

Como pode ser observado, o DHT22 é um pouco mais preciso e trabalha em uma faixa um pouco maior de temperatura e umidade. Porém, ambos utilizam apenas um pino digital e são relativamente lentos, visto que é necessário um intervalo de tempo relativamente grande entre cada leitura.


Incluindo Bibliotecas

Uma grande vantagem das placas Arduino é a grande diversidade de bibliotecas disponíveis que podem ser usadas em seu programa. Isso faz com o trabalho pesado em programação seja abstraído e resumido em simples comandos.

Com isso, o desenvolvedor não precisa de conhecimento muito aprofundado em programação, podendo gastar menos tempo nisso, resultando em mais tempo para trabalhar com empenho na estratégia de controle.

A seguir, iremos aprender como adicionar uma biblioteca em sua IDE. Esse mesmo procedimento será usado para outros sensores ou módulos.

Incluindo a biblioteca DHT

Para trabalhar de forma fácil com o DHT, podemos baixar uma biblioteca para ele no GitHub do Rob Tillaart (https://github.com/RobTillaart/Arduino/tree/master/libraries/DHTlib).

Baixar biblioteca DHTlib - Atualizada em 24/08/2017
Baixar biblioteca DHTlib - Atualizada em 24/08/2017

Há mais de uma forma de incluir bibliotecas no seu programa, a principal é:

Instalar a biblioteca pelo IDE do Arduino

Esse é o método mais fácil. Primeiramente, faça o download dos arquivos da biblioteca compactados no formato zip. Geralmente as bibliotecas já são distribuídas compactadas, porém às vezes é necessário fazer o download dos arquivos separadamente e compactá-los à parte. Em seguida, basta abrir o IDE e ir em "Sketch -> Incluir Biblioteca -> Adicionar biblioteca .ZIP":

Imagem explicando como adicionar uma biblioteca

Na janela que abrir, selecione a biblioteca a ser adicionada:

inserindo biblioteca dht.h

Com isso, a nova biblioteca foi instalada. Para utilizá-la, basta ir em "Sketch -> Incluir Biblioteca" e selecionar a biblioteca desejada:

biblioteca dht.h na ide arduino

Observe que o IDE adicionou no início do seu código a linha incluindo a biblioteca no seu programa.:

#include <dht.h>

Outras opções:

Instalar manualmente a biblioteca

Para instalar manualmente uma biblioteca, feche o IDE do Arduino e em seguida descompacte os arquivos da biblioteca. Se os arquivos .cpp e .h não estiverem dentro de uma pasta, crie uma e mova os arquivos para lá. Em seguida, basta mover a pasta para o local:

Windows: "Meus documentos\Arduino\libraries"

Mac: "Documents/Arduino/libraries"

Depois desse processo, a biblioteca estará disponível em "Sketch -> Incluir Biblioteca" na próxima vez que o IDE for aberto.

Incluir a biblioteca sem instalá-la

É possível também utilizar a biblioteca sem instalá-la no IDE do Arduino. Para isso, basta descompactar a biblioteca e colocar os arquivos .h e .cpp no mesmo diretório do programa, incluindo no início do mesmo a linha:

#include "nome_da_biblioteca.h"

Mãos à obra – Usando o Sensor de umidade e temperatura DHT11 com Arduino

Componentes necessários

Montando o projeto

Agora vamos conectar os componentes do projeto. Para isso, desligue o cabo USB de seu Arduino e monte seu circuito conforme a figura a seguir.

Esquemático do circuito DHT11 com Arduino uno

Conectando o Arduino ao computador

Conecte seu Arduino ao computador e abra a IDE Arduino.

Antes de carregar um programa, você precisa selecionar qual porta você deseja usar para fazer carregar o programa no Arduino (upload). Dentro do Arduino IDE, clique no menu Ferramentas (tools) e abra o submenu Porta(Port). Clique na porta que seu Arduino está conectado, tal como COM3 ou COM4. Geralmente aparece o nome da placa Arduino : “COM3 (Arduino/Genuino Uno)”.

Você também precisa garantir que o tipo de placa apropriado está selecionado em Ferramentas(Tools) no submenu Placa (Board).

Programando

Crie um programa (sketch) e salve com o nome de “programa_dht11”.

Com o seu programa salvo, escreva nele o código conforme escrito abaixo.

#include <dht.h> // Inclui a biblioteca no seu código
 
dht DHT; // Cria um objeto da classe dht
uint32_t timer = 0;
 
void setup()
{
  Serial.begin(9600); // Inicializa serial com taxa de transmissão de 9600 bauds
}
 
void loop()
{
  // Executa 1 vez a cada 2 segundos
  if(millis() - timer>= 2000)
  {
 
    DHT.read11(A1); // chama método de leitura da classe dht,
                    // com o pino de transmissão de dados ligado no pino A1
 
    // Exibe na serial o valor de umidade
    Serial.print(DHT.humidity);
    Serial.println(" %");
 
    // Exibe na serial o valor da temperatura
    Serial.print(DHT.temperature);
    Serial.println(" Celsius");
 
    timer = millis(); // Atualiza a referência
  }
}

Após escrever o código, clique em Carregar (Upload) para que o programa seja transferido para seu Arduino.

Colocando para funcionar

Caso tenha ocorrido tudo conforme esperado, poderemos fazer a leitura da temperatura através do monitor serial. Abra o monitor serial para verificar o que está sendo lido na entrada A0.


Entendendo a fundo

Entendendo o Software

millis()

Retorna o número de milissegundos desde a placa Arduino começou a funcionar com programa atual. Este número irá saturar (voltar para zero), após, aproximadamente, 50 dias.

 timer = millis();         //Atualiza a referência

Veja que usamos o millis como nossa referência de tempo. Toda vez que a diferença entre o millis e o timer for de 2000 milissegundos, entraremos no if e o timer irá assumir o valor atual de millis.

Desta forma, o programa irá executar o que está dentro do if de 2000 em 2000 milissegundos, ou seja, 2 em 2 segundos.

Esse tipo de estrutura é muito comum e será usada em outras experiências.

Biblioteca dht.h

Na elaboração do software utilizamos a biblioteca dht.h. Esta biblioteca implementa as funcionalidades do sensor DHT11 e DHT22 tornando sua utilização extremamente simples.

Declarando um DHT

Ao usar essa biblioteca trataremos cada sensor DHT como um objeto, dessa forma precisamos declará-lo no início do código.

dht DHT; // Cria um objeto da classe dht

Depois de declarado, sempre que quisermos mexer em alguma função desse DHT, devemos usar o nome da função precedida do nome do DHT e ponto.

DHT.exemplo(); // chama função exemplo() para o objeto DHT

Lendo o sensor

Para ler o sensor basta chamar o método de leitura (read11 se estiver utilizando o DHT11, ou read22 se estiver utilizando o DHT22) e em seguida ler os valores nos atributos temperature e humidity.

Importante: O sensor demora no mínimo 1 segundo de intervalo entre uma leitura e outra.

DHT.read11(A1); // chama método de leitura da classe dht,
                    // com o pino de transmissão de dados ligado no pino A1

Temos o valor de umidade em porcentagem armazenado em:

float umidade = DHT.humidity

Temos o valor de temperatura em graus Celsius armazenado em:

float temperatura = DHT.temperature

Exemplo de aplicação:

    // Exibe na serial o valor de umidade
    Serial.print(DHT.humidity);
    Serial.println(" %");
 
    // Exibe na serial o valor da temperatura
    Serial.print(DHT.temperature);
    Serial.println(" Celsius");

Fechamento

Esperamos que tenham gostado, deixe seu comentário com duvidas, sugestões ou com a foto ou vídeo de seu projeto!! Compartilhe à vontade.

Tutorial feito em parceria com Ronan Largura

Apostila Arduino Básico

 


O que é Servomotor? | Controlando um Servo com Arduino

O que é Servomotor? Controlando um Servo com Arduino

Nesse tutorial aprenderemos o que é um servomotor e como controla-lo usando um Arduino, mais especificamente o Arduino Uno, usando a biblioteca nativa da IDE Arduino Servo.h. Para esse tutorial usaremos o Micro Servo motor SG90.

[toc]

O que é um Servomotor e como funciona?

Entre os atuadores temos um motor bem especial. Os servomotores, também chamados de servos, são muito utilizados quando o assunto é robótica. De forma simplificada, um servomotor é um motor na qual podemos controlar sua posição angular através de um sinal PWM.

Microservo servo SG90 9g
Micro servo motor SG90

Dessa forma, um servomotor é um atuador eletromecânico utilizado para posicionar e manter um objeto em uma determinada posição. Para isso, ele conta com um circuito que verifica o sinal de entrada e compara com a posição atual do eixo.

controle via PWM de um servo
controle via PWM de um servo

Como você pode ver na figura anterior, o ângulo do servomotor é proporcional ao Duty Cycle (tempo que o sinal é positivo) do sinal PWM.

Diferentemente dos motores de corrente continua ou motores de passo que podem girar indefinidamente, o eixo de um servo possui a liberdade de apenas 180º. Existem ainda alguns servos que são adaptados para girar indefinidamente, mas não entraremos nesse mérito aqui.

Servomotores geralmente possuem 3 pinos:

  • Alimentação positiva (vermelho) – 5V;
  • Terra (Preto ou Marrom) – GND;
  • (Amarelo, Laranja ou Branco) – Ligado a um pino digital de entrada e saída;

Atenção!!

Servomotores consomem uma corrente significativa ao se movimentarem. A utilização de uma fonte externa pode ser necessária e é recomendada. Lembre-se de conectar o pino GND da fonte externa ao GND do Arduino para que a referência seja a mesma.

Apesar de sua posição ser controlada através do duty cycle de um sinal PWM enviado ao pino de controle não é necessária a conexão do pino de controle a um pino que possua PWM, pois utilizaremos a biblioteca Servo.h.

A utilização de analogWrite produzirá um controle de menor precisão e poderá até danificar alguns servomotores por sua frequência (490 Hz) ser 10 vezes superior a frequência típica de controle de alguns servomotores.

Além de mais preciso e recomendado, o uso da biblioteca Servo.h faz com que o uso do servomotor seja mais fácil. Isso se dá pelo fato de você só precisar definir o ângulo que você deseja, não necessitando o uso dos valores de PWM (0 a 255).


Mãos à obra - Controlando um Servomotor com Arduino - Micro Servo motor SG90

Componentes necessários

Montando o projeto

Agora vamos conectar os componentes do projeto. Para isso, desligue o cabo USB de seu Arduino e monte seu circuito conforme a figura a seguir.

Esquema de montagem de um servo com Arduino Uno
Esquema de montagem de um servomotor com Arduino Uno

O microservo tem três fios saindo dele. Um será vermelho e irá para os +5 V. Outro, preto ou marrom, irá para o GND. O terceiro, branco, amarelo ou laranja, será conectado ao pino digital 8.

Monte o potenciômetro com os seus pinos externos conectados um no +5 V e o outro no GND e o pino do meio ao pino analógico A0.

Conectando o Arduino ao computador

Conecte seu Arduino ao computador e abra a IDE Arduino.

Antes de carregar um programa, você precisa selecionar qual porta você deseja usar para fazer carregar o programa no Arduino (upload). Dentro do Arduino IDE, clique no menu Ferramentas (tools) e abra o submenu Porta(Port). Clique na porta que seu Arduino está conectado, tal como COM3 ou COM4. Geralmente aparece o nome da placa Arduino : “COM3 (Arduino/Genuino Uno)”.

Você também precisa garantir que o tipo de placa apropriado está selecionado em Ferramentas(Tools) no submenu Placa (Board).

Programando

Crie um programa (sketch) e salve com o nome de “programa_servo”.

Nesse exemplo utilizaremos a biblioteca Senvo.h que já é nativa da IDE Arduino e deve ser adicionada em: Sketch > Incluir Biblioteca > Servo.

Com o seu programa salvo, escreva nele o código conforme escrito abaixo.

#include <Servo.h>
Servo servo1; // cria um objeto servo1

// Esta função "setup" roda uma vez quando a placa e ligada ou resetada
void setup() {
 servo1.attach(5); // anexa o servomotor (físico), no pino 5, ao objeto servo1 (lógico)
}

void loop() {
 int angulo = analogRead(0); // Lê o valor do potenciômetro
 angulo = map(angulo, 0, 1023, 0, 180); // Mudança de Escala
 servo1.write(angulo); // Escreve o ângulo para o servomotor
 delay(20); // Espera de 20ms, Suficiente para que o servomotor atinja a posição
}

Após escrever o código, salve e depois clique em Carregar (Upload) para que o programa seja transferido para seu Arduino.

Colocando para funcionar

Se tudo deu certo, conforme você variar a resistência do potenciômetro o servomotor irá se mover.


Entendendo a fundo

Entendendo o Software

Biblioteca Servo.h

Na elaboração do software utilizamos a biblioteca Servo.h. Esta biblioteca implementa as funcionalidades de um servomotor tornando sua utilização extremamente simples. Entretanto alguns cuidados devem ser tomados.

Importante:

A biblioteca suporta a ligação de até 12 servomotores na maioria das placas Arduino e 48 no Arduino Mega. O uso da biblioteca desabilita o uso da função analogWrite nos pinos 9 e 10  (*exceto no Arduino Mega). No Mega o uso de 12 a 23 servomotores desabilitará o a função analogWrite nos pinos 11 e 12.

Declarando um Servomotor

Ao usar essa biblioteca trataremos cada servomotor como um objeto, dessa forma precisamos declará-lo no início do código.

Servo servo1; // Cria um objeto servo1

Depois de declarado, sempre que quisermos mexer em alguma função desse servo, devemos usar o nome da função precedida do nome do servo e ponto.

servo1.exemplo(); // chama função exemplo() para o objeto servo1

Você poderá declarar quantos servos for usar, levando em conta a limitação física de sua placa Arduino. Cada servo pode ter qualquer nome, mas é aconselhável que se use nomes intuitivos.

Declarando porta de controle do Servomotor

Agora é preciso definir em que porta esta conectado o fio de controle do servo, para isso usamos a função attach(pino).

servo1.attach(5); // Anexa o servomotor (físico), no pino 5, ao objeto servo1 (lógico)

Controlando a Posição do Servomotor

A função write define em um servomotor padrão o ângulo em graus na qual ele deve se posicionar.

servo1.write(angulo); //angulo: posição em graus para servos comuns

Fechamento

Esperamos que tenham gostado, deixe seu comentário com duvidas, sugestões ou com a foto ou vídeo de seu projeto!! Compartilhe à vontade.

Apostila Arduino Básico

 


Leitura de Botões e o Bounce

Leitura de Botões e o Bounce

Botões são utilizados na criação de interfaces entre maquinas e humanos. Nesse tutorial veremos como fazer com que o Arduino reconheça o estado de um botão e entenderemos o que é o Bounce.

Esse tutorial requer conhecimento em assuntos explicados em posts anteriores. Caso tenha dificuldades em acompanhar os assuntos abordados aqui, confira alguns de nossos tutoriais anteriores:

[toc]

REALIZANDO A LEITURA DE UMA ENTRADA DIGITAL ACIONADA POR UM BOTÃO

Para que o Arduino consiga saber o estado na qual o botão se encontra devemos fazer com que cada um de seus estados defina um nível lógico diferente na entrada na qual ele esta conectado. Para isso podemos utilizar o pull up interno do Arduino como mostra o esquema da figura a seguir.

No esquema da Figura acima, quando o botão estiver pressionado o pino escolhido estará com 0V e quando não estiver pressionado estará com 5V.

A Figura abaixo mostra o esquema de ligação para os exemplos apresentados a seguir. O resistor de 1k é utilizado para proteger o pino 8 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á acontecendo. Vamos analisá-lo:

O QUE É O BOUNCE?

Ao pressionar um botão nós fazemos com que os seus contatos se choquem o que fará com 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 jogada contra ao chão, que quica algumas vezes antes de se estabilizar. A figura abaixo mostra a forma de onda do sinal produzido pelo botão ao ser pressionado.

Podemos observar que o botão varia entre 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: Detectando o Bounce.

O código abaixo implementa um contador, que conta o número de vezes que o botão mudou de estado. Essa quantidade é 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();
 }
}

Ao pressionarmos o botão com força uma única vez e soltarmos veremos que o contador será incrementado mais que duas vezes como mostra a Figura 4. Isso ocorre devido a trepidação do botão.

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 detectada. 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 checar 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;
}

Biblioteca auxiliar

A biblioteca Bounce2 possui uma implementação eficiente e de fácil uso para o tratamento de bounce. Confira!

#include <Bounce2.h>

Bounce debouncer = Bounce();

void setup() {
 pinMode(8, INPUT_PULLUP); // Configura pino 8 como entrada e habilita pull up interno;
 debouncer.attach(8); // Informa que o tratamento de debouce será feito no pino 8;
 debouncer.interval(10); // Seta o intervalo de trepidação;
}

void loop() {
 debouncer.update(); // Executa o algorítimo de tratamento;

 int value = debouncer.read(); // Lê o valor tratado do botão;

 if (value == HIGH) {
  Serial.println("Botao Nao Pressionado!");
 } else {
  Serial.println("Botao Pressionado!");
 }
}

FINALIZANDO

Este conteúdo foi totalmente voltado para esclarecer alguns pontos à respeito da leitura de botões. Esperamos que você tenha gostado deste conteúdo, sinta-se à vontade para nos dar sugestões, críticas ou elogios. Lembre-se de deixar suas dúvidas nos comentários abaixo.

Apostila Arduino Básico

 


Teclado Matricial e Multiplexação

Teclado Matricial e Multiplexação

Teclados são geralmente utilizados em aplicações na qual o usuário precisar interagir com um sistema, como computadores, calculadoras, controles remotos entre outros. Imagine que desejamos utilizar um teclado com 64 botões em nossa aplicação. Caso cada botão seja ligado diretamente a um pino do microcontrolador, gastaríamos 64 pinos o que tornaria a implementação dessa interface, em uma placa Uno por exemplo, impossível. Para evitar este problema podemos conectar as teclas no formato de matriz 8x8 gastando agora apenas 16 pinos e utilizar uma técnica chamada multiplexação para realizar a leitura das teclas. Para demonstrar essa técnica de leitura utilizaremos um teclado matricial de membrana 4x4 junto com um Arduino.

Esse tutorial requer conhecimento em assuntos explicados em posts anteriores. Caso tenha dificuldades em acompanhar os assuntos abordados aqui, confira alguns de nossos tutoriais anteriores:

[toc]

O Teclado Matricial

Este teclado como o nome indica é formado de botões organizados em linhas e colunas de modo a formar uma matriz. Quando pressionado, um botão conecta a linha com a coluna na qual está ligado. A figura 1 ilustra a ligação matricial.

Figura 1 - Ligação interna de um teclado matricial 4x4.
Figura 1 - Ligação interna de um teclado matricial 4x4.

O teclado matricial possui a seguinte pinagem:

  • Pino 1 (Esquerda) - Primeira Linha (L1)
  • Pino 2  - Segunda Linha (L2)
  • ...
  • Pino 5 - Primeira Coluna (C1)
  • ...
  • Pino 8 - Quarta Coluna (C4)
Figura 2 - Pinagem do teclado matricial de membrana.
Figura 2 - Pinagem do teclado matricial de membrana.

A Multiplexação

Essa técnica consiste no compartilhamento do mesmo barramento por vários dispositivos, entretanto apenas um deles utilizará o barramento por vez. No caso do teclado matricial, os barramentos serão as linhas do teclado e os dispositivos as colunas. Logo devemos permitir que apenas uma coluna se ligue as linhas por vez. Para desconectarmos as colunas que não devem ser lidas devemos configurá-las como entradas (alta impedância).


Mão à obra - Algoritmo de varredura simples

Componentes utilizados

Para esse projeto usaremos os seguintes componentes:

Programação

No início os pinos conectados as linhas serão configurados como entradas com pull up e as colunas como entradas (alta impedância). A varredura consiste em ativar uma coluna por vez (saída em nível lógico baixo) e checar se houve uma alteração nas linhas. Caso uma alteração em uma linha seja identificada, o bounce da tecla deve ser devidamente tratado para que possamos finalmente afirmar que o botão foi pressionado.

 

const uint8_t row_size = 4;                       // Quantidade de linhas.
const uint8_t col_size = 4;                       // Quantidade de colunas.
const uint8_t row_pin[row_size] = {4, 5, 6, 7};   // Pinos que estão ligados as linhas.
const uint8_t col_pin[col_size] = {8, 9, 10, 11}; // Pinos que estão ligados as colunas.
const char keys[row_size][col_size] = {           // Mapa de teclas do teclado.
 { '1', '2', '3', 'A' },
 { '4', '5', '6', 'B' },
 { '7', '8', '9', 'C' },
 { '*', '0', '#', 'D' }
};
 
bool stable[row_size][col_size];   // Guarda o último estado estável dos botões.
bool unstable[row_size][col_size]; // Guarda o último estado instável dos botões.
uint32_t bounce_timer;
 
// Executa o algoritmo de varredura simples.
void scan() {
  for (uint8_t e = 0; e < col_size; ++e) {   // Varre cada coluna.
    pinMode(col_pin[e], OUTPUT);
    digitalWrite(col_pin[e], 0);             // Habilita a coluna "c".
    for (uint8_t r = 0; r < row_size; ++r) { // Varre cada linha a procura de mudanças.
      if (changed(r, e)) {                   // Se houver uma mudança de estado.
        Serial.print(keys[r][e]);
        Serial.print(" : ");                 // Imprime a tecla que sofreu a alteração
        Serial.println(stable[r][e]);        // e seu estado atual.
      }
    }
    pinMode(col_pin[e], INPUT);              // Desabilita a coluna "c".
  }
}
 
// Checa se o estado do botão foi alterado além de tratar os efeitos de sua trepidação.
bool changed(const uint8_t& row, const uint8_t& col) {
  bool now = digitalRead(row_pin[row]);    // Lê o estado do botão na linha especificada.
  if (unstable[row][col] != now) {         // Checa se houve mudança.
    bounce_timer = millis();               // Atualiza timer.
    unstable[row][col] = now;              // Atualiza estado instável.
  }
  else if (millis() - bounce_timer > 10) { // Checa o tempo de trepidação acabou.
    if (stable[row][col] != now) {         // Checa se a mudança ainda persiste.
      stable[row][col] = now;              // Atualiza estado estável.
      return 1;
    }
  }
  return 0;
}
 
void setup() {
  Serial.begin(9600);
 
  // Configura o estado inicial das linhas como entradas com pull up.
  for (uint8_t r = 0; r < row_size; ++r) {
    pinMode(row_pin[r], INPUT_PULLUP);
  } 
 
  // Configura o estado inicial das linhas como entradas.
  for (uint8_t c = 0; c < col_size; ++c) {
    pinMode(col_pin, INPUT);
  }
 
  // Define estado inicial dos botões;
  for (uint8_t c = 0; c < col_size; ++c) {
    for (uint8_t r = 0; r < row_size; ++r) {
      stable[r] = 1;
    }
  }
}
 
void loop() {
  scan();
}

 


Pressionando várias teclas

Quando pressionamos 3 ou mais teclas um efeito conhecido como tecla fantasma pode ocorrer, vamos observar a animação a seguir para entender o porquê:

Figura 3 - Teclas fantasmas teclado matricial
Figura 3 - Teclas fantasmas

Infelizmente os problemas não acabam por aqui. Caso a tecla fantasma seja pressionada e em seguida uma das teclas anteriores for solta, a tecla que foi solta ainda será considerada como pressionada. Para solucionarmos este problema devemos adicionar um diodo em cada botão para evitar que estes caminhos indesejados sejam formados, como mostra a Figura 4.

Figura 4 - Solução para teclas fantasmas.

 


Bibliotecas

A biblioteca Keypad é uma biblioteca especializada no interfaceamento de teclados matriciais. Seu algoritmo de varredura  consegue detectar se uma tecla esta apertada, solta ou sendo segurada, entre outras funções.

Clique para baixar a biblioteca Keypad

Exemplo de aplicação

#include <Keypad.h>
 
const uint8_t row_size = 4;                       // Quantidade de linhas.
const uint8_t col_size = 4;                       // Quantidade de colunas.
const uint8_t row_pin[row_size] = {4, 5, 6, 7};   // Pinos que estão ligados as linhas.
const uint8_t col_pin[col_size] = {8, 9, 10, 11}; // Pinos que estão ligados as colunas.
const char keys[row_size][col_size] = {           // Mapa de teclas do teclado.
  { '1', '2', '3', 'A' },
  { '4', '5', '6', 'B' },
  { '7', '8', '9', 'C' },
  { '*', '0', '#', 'D' }
};
 
Keypad keypad = Keypad(makeKeymap(keys), row_pin, col_pin, row_size, col_size);
 
void setup() {
  Serial.begin(9600);
}
 
void loop() {
  char key = keypad.getKey();   // Retorna a última tecla que foi apertada.
  if (key != NO_KEY) Serial.println(key); // Imprime tecla na porta serial.
}

Fechamento

Esperamos que tenham gostado, deixe seu comentário com duvidas, sugestões ou com a foto ou vídeo de seu projeto!! Compartilhe à vontade.

 

Apostila Arduino Básico