Medindo Tensão AC com Módulo GBK P8 e Arduino

Medindo Tensão Elétrica AC com Módulo GBK P8 e Arduino

Neste tutorial vamos aprender como medir a tensão da rede elétrica utilizando o sensor de tensão GBK P8 em conjunto com um Arduino UNO.

[toc]

Módulo GBK P8

Em alguns projetos, é necessário medir grandezas elétricas em algum aparelho ou circuito, para monitorar condições de funcionamento, prevenir falhas, ou medir seu consumo de energia.

O módulo Sensor de Tensão GBK P8 é uma opção para medição de tensão elétrica. A placa é baseada num optoacoplador (TIL 116) e com ela é possível realizar a medição de tensões de 127 até 220 V.

Imagem do módulo GBK P8

kit robotica educacional com Arduino ESP ou Microbit


Mãos à obra - Medindo Tensão AC com Módulo Sensor de Tensão GBK P8

Componentes necessários

Neste projeto, vamos monitorar o valor de tensão de um equipamento para verificar se ele está ligado ou desligado. Para isso, precisaremos de:

Montando o projeto

A placa possui três terminais, que estão identificados, como a figura abaixo.

 

Pinagem do sensor de tensão AC

Os três terminais são:

  • +5Vcc, é o pino de alimentação, que é ligado ao 5 V do Arduino
  • gnd, é o terminal de 0 V, ligado no GND do Arduino
  • Out, que será conectado no do Arduino

ATENÇÃO! Ao realizar este projeto, você estará trabalhado diretamente com tensões maiores que o habitual. Nesse nível de tensão, um choque elétrico pode causar danos a você e ao seu equipamento.

Se você está em dúvida sobre como proceder nessa parte, peça ajuda a alguém que saiba como trabalhar com segurança.

A montagem fica assim:

 

Esquema de ligação sensor de tensão com Arduino

 

Programando

Após conectarmos o Arduino ao computador e abrirmos sua IDE, selecionamos o modelo da placa que estamos usando - no caso, Arduino UNO - e selecionamos a porta de conexão dele com o computador.

Escreva na IDE o seguinte código:

#define gbk A0

const int R1 = 220000;
const int R2 = 10000;
int valorLido = 0;
float acum = 0;
float v1 = 0;

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

void tensaoCalculo() {
  valorLido = analogRead(gbk);
  v1 = valorLido * 0.004882812;
  acum = v1 / (R2 / (R2 + R1));
  if(acum == 0) {
    Serial.println("Aparelho desconectado da tomada");
    Serial.println("");
  } else {
    Serial.println("Aparelho conectado a tomada");
    Serial.print("Tensao = ");
    Serial.print(acum);
    Serial.println(" V");
    Serial.println("");
  }
}

void loop() {
  tensaoCalculo();
  delay(1000);
}

Colocando pra funcionar

ATENÇÃO! Ao realizar este projeto, você estará trabalhado diretamente com tensões maiores que o habitual. Nesse nível de tensão, um choque elétrico pode causar danos a você e ao seu equipamento.

Se você está em dúvida sobre como proceder nessa parte, peça ajuda a alguém que saiba como trabalhar com segurança.

Após dar upload do código ao Arduino, conectamos o módulo em PARALELO ao dispositivo. No nosso caso, adaptamos uma extensão para ligar direto na rede elétrica em tensão AC.

IMAGEM LIGAÇÃO EXTENSÃO E SENSOR

Depois de concluir todos os passos, o Arduino deve imprimir a seguinte mensagem no monitor serial: "Aparelho desconectado da tomada". Agora conecte a extensão na tomada e veja o resultado no monitor serial.

IMAGEM MONITOR SERIAL

Através da saída analógica do sensor de tensão AC o Arduino consegue dizer quando o aparelho está conectado a tomada e informar a tensão elétrica.

Entendendo o Módulo GBK P8

Hardware

O módulo GBK é composto por um optoacoplador, resistores e um capacitor. O esquema de ligação pode ser visto logo abaixo.

(esquemático GBK P8)

Por estar conectado em paralelo com a tomada, entre os terminais de conexão da rede elétrica haverá uma diferença de potencial interligados por um resistor de 220 kΩ (como visto no esquemático acima), com isso, circulará uma corrente com valor bem reduzido por esse resistor. Essa corrente passará também pela entrada do optoacoplador TIL116.

Optoacoplador TIL116
O esquemático interno do TIL 116

Na entrada do optoacoplador existe um diodo infravermelho, que emite luz quando há corrente. Essa luz chega ao fototransistor do acoplador, chaveando corrente e criando um sinal de tensão em sua saída.

Forma de onda antes do capacitor

A forma de onda da saída do optoacoplador seria a um retificador de meia onda, permitindo corrente apenas nos ciclos positivos de corrente. Entretanto, a presença do capacitor no circuito altera o sinal, descarregando para o circuito no ciclo negativo, criando uma tensão de ripple com menos variação.

Forma de onda após o capacitor

Software

Vamos explicar os trechos do código, para que você entenda por completo o que está sendo feito, e possa modificar o que for necessário no seu projeto.

- Variáveis do programa

O programa inicia com a definição de uma constante para o compilador: onde aparecer gbk o compilador interpreta como A0, que é o pino da leitura analógica. A vantagem desse recurso é que se o pino for alterado fisicamente depois, basta fazer a alteração em apenas um lugar do código, o que é bem útil em programas muito grandes.

Depois são declaradas algumas variáveis e constantes que ficarão na memória. R1 e R2 são constantes que armazenam os valores das resistências do módulo. A variável valorLido armazena a leitura analógica do pino A0, que vem do módulo. As variáveis v1 e acum são utilizadas no cálculo da tensão.

#define gbk A0

const int R1 = 220000;
const int R2 = 10000;
int valorLido = 0;
float acum = 0;
float v1 = 0;

- As definições no setup

No setup acontece a inicialização da comunicação serial, para a utilização do monitor serial

Serial.begin(9600);

- A função de cálculo da tensão

A função que calcula a tensão, com base na leitura analógica, é chamada logo no início da função loop.

void tensaoCalculo() {
  valorLido = analogRead(gbk);
  v1 = valorLido * 0.004882812;
  acum = v1 / (R2 / (R2 + R1));
  if(acum == 0) {
    Serial.println("Aparelho desconectado da tomada");
    Serial.println("");
  } else {
    Serial.println("Aparelho conectado a tomada");
    Serial.print("Tensao = ");
    Serial.print(acum);
    Serial.println(" V");
   Serial.println("");
  }
}

Ela inicia fazendo a leitura analógica do pino A0 e armazenando na variável valorLido. Em sequência, faz a conversão da leitura, que vai de 0 a 1023, para um valor de tensão, que vai de 0 a 5 V. A conversão é feita multiplicando o valorLido por 0,004882812. Esse valor é equivalente a 5/1024, e representa quanto vale em volts cada inteiro da leitura analógica. A multiplicação então, converte a leitura analógica para um valor de tensão.

valorLido = analogRead(gbk);
v1 = valorLido * 0.004882812;

Depois, se faz o cálculo de quanto a tensão lida representa no valor real. A tensão lida no sensor é uma tensão de 0 a 5 V, na saída de um divisor de tensão. Para o valor real, a tensão faz o cálculo inverso ao do divisor de tensão:

acum = v1 / (R2 / (R2 + R1));

 

 

- Declarando a função tensaoCalculo()

Antes de iniciar o void loop(), é necessário declarar a função que será chamada por ele.

void tensaoCalculo()

- Lendo os dados do pino A0

É armazenado o valor lido no pino A0 na variável do tipo inteiro "valorLido".

valorLido = analogRead(A0);

- Convertendo para tensão

Multiplica-se o valor lido na entrada analógica por 0,00482812 para descobrir o valor da tensão da entrada analógica do arduino.

v1 = valorLido * 0.004882812;

Considerações finais

Esperamos que este tutorial tenha ajudado a entender como utilizar o Módulo Sensor de Tensão GBK P8, e como utilizá-lo em projetos para medir tensão da rede elétrica, ou de dispositivos ligados em tensão AC.

Deixe nos comentários suas dúvidas. Críticas e sugestões também são muito bem vindas.

Até o próximo!


Descobrindo o endereço I2c de dispositivos com Arduino

Descobrindo o endereço I2C de dispositivos com Arduino

Quando compramos equipamentos de lojas desconhecidas quase sempre nos deparamos com o problema de não termos disponível um datasheet ou algum tipo de documentação que auxilie na utilização dos mesmos.  Sabendo disso, neste tutorial nós iremos aprender a como identificar o endereço I2C de dispositivos com um Arduino.

[toc]

kit robotica educacional com Arduino ESP ou Microbit

Protocolo I2C

O protocolo I2C, ou Inter-Integrated Circuit é um protocolo de comunicação desenvolvido pela Philips, que teve como objetivo inicial, interconectar dispositivos de baixa velocidade e curta distância. A comunicação i2C funciona por meio de um barramento onde apenas um dispositivo, denominado mestre, é responsável por requisitar informações dos dispositivos conectados. A conexão I2C é feita através de dois fios, sendo eles:

  • sda: Transmitir dados entre receptor e transmissor via barramento.
  • scl: Temporizar e sincronizar unidades conectadas ao sistema.

É também interessante possuir um resistor pull-up nas trilhas sda e scl para estabilizar o barramento de comunicação

Protocolo I2C endereço I2c
Protocolo I2C

Como a comunicação I2C é feita via um barramento, cada dispositivo conectado ao sistema deve possuir um endereço único. Este código é composto por um valor de 7 bits, disponibilizando um total de 127 endereços onde apenas o intervalo 0x8 até 0 intervalo 0x77 está disponível para utilização.


Mãos à obra - Descobrindo o endereço I2C de dispositivos utilizando o seu Arduino

Componentes utilizados:

Montando o projeto

Como teste do nosso código de pesquisa, iremos conectar um dispositivo I2C ao nosso Arduino Nano. Para fazer isso basta conectar o pino SDA ao pino A4 do Arduino e o pino SCL ao pino A5 do Arduino, além é claro dos pinos utilizados para alimentação. A figura abaixo ilustra o processo de ligação dos fios de comunicação e alimentação.

montagem circuito com arduino nano e lcd para descobrir endereço I2c

 

Veja como ficou a montagem na prática.

Atenção, sempre monte o seu circuito com a alimentação do Arduino desligada. Para evitar possíveis curtos circuitos que possam vir a danificar o seu módulo ou até mesmo o microcontrolador.

 

Programando

Agora que temos conectado ao nosso sistema um módulo que supostamente não sabemos o seu endereço. Iremos utilizar  carregar o seguinte código em nossa placa para sua identificação.

#include <Wire.h>
#define TEMPOLEITURA 100
#define TEMPOESPERA 3000
byte endereco;
byte codigoResultado=0;
byte dispositivosEncontrados=0;

void setup() {
  Serial.begin(9600);
  Wire.begin();
  while (!Serial); 
  scanI2c();           
}

void scanI2c(){
    for (endereco=0; endereco<128; endereco++){
    Wire.beginTransmission(endereco);
    codigoResultado = Wire.endTransmission();
    if (codigoResultado==0){
      Serial.print ("Dispositivo I2c detectado no endereço: ");
      Serial.println(endereco,HEX);
      dispositivosEncontrados++;
      delay(TEMPOESPERA);

    }
    delay(TEMPOLEITURA);
  }
  if (dispositivosEncontrados>0){
    Serial.print("Foi encontrado um total de: ");
    Serial.print(dispositivosEncontrados);
    Serial.println(" dispositivos");
  }
  else{
    Serial.println("Nenhum dispositivo foi encontrado !!!");
  }
}


void loop() {

}

 


Entendendo a fundo

Software

- Incluindo as bibliotecas necessárias

De início, para ser possível a utilização da comunicação I2C no nosso Arduino, nós iremos precisar adicionar a biblioteca wire.h que pode ser feita através da seguinte sentença:

#include <Wire.h>

- Temporizadores de pesquisa e tempo de espera

Iremos também neste código criar dois temporizadores para definir de quanto em quantos milissegundos o nosso código deverá fazer a pesquisa em um novo endereço e por quanto tempo ele deve esperar após encontrar um dispositivo conectado ao barramento I2C. Para isso, iremos criar 2 diretivas define que serão responsáveis por armazenar estes valores, fazendo com que eles sejam facilmente parametrizáveis.

#define TEMPOLEITURA 100
#define TEMPOESPERA 3000

- Função setup

Na função setup, iremos inicializar a comunicação I2C para identificação de dispositivos e também iremos inicializar a comunicação serial, para que os dados sejam mostrados no serial monitor.

void setup() {
  Serial.begin(9600);
  Wire.begin();
  while (!Serial);
  scanI2c();          
}

Na versão Leonardo do Arduino, para utilização correta da porta serial, é importar adicionar o trecho:

 while (!Serial);

Pois assim iremos garantir que a comunicação serial está de fato funcionando corretamente.

- Variáveis de controle

Para deslocarmos entre os endereços, identificarmos se o dispositivo está realmente conectado ao barramento e contar quantos dispositivos estão conectados, nós iremos utilizar três variáveis do tipo byte. A utilização destas variáveis com este tipo deve-se ao fato de que como estes valores nunca serão maiores que 255(,) não existe a possibilidade de overflow. Sendo assim iremos economizar cerca de 3 bytes de memória, se utilizássemos por exemplo o tipo int para armazenar.

byte endereco;
byte codigoResultado=0;
byte dispositivosEncontrados=0;

- Função scanI2c

Dentro da função scanI2c nós iremos realizar todo o processo de busca por dispositivos conectados, que será feito da seguinte forma:

  1.  Através do comando for, percorrer todos os endereços disponíveis no protocolo I2C, partindo do 0 até o 127.
    for (endereco=0; endereco<128; endereco++);
  2. Utilizando o método  Wire.beginTransmission, iremos tentar estabelecer uma comunicação com o dispositivo conectado, utilizando como endereço a posição atual do for.
    Wire.beginTransmission(endereco);
  3. Logo em seguida iremos encerrar a transmissão através do método Wire.endTransmission. Este método possui um retorno que consiste em:
    1. Igual a 0 - Conexão fechada com sucesso
    2. Diferente de 0 - Falha na transmissão ou não existe dispositivo conectado
  4. Sabendo disso, iremos armazenar este valor de retorno em nossa variável codigoResultado
    codigoResultado = Wire.endTransmission();
    
  5. Logo em seguida verificamos se a variável codigoResultado é igual a zero, caso seja mostramos o código do dispositivo e contabilizamos a variável que mostra o total de dispositivos encontrados e aguardamos o tempo em milissegundos definido em TEMPOESPERA
    if (codigoResultado==0){
     Serial.print ("Dispositivo I2c detectado no endereço: ");
     Serial.println(endereco,HEX);
     dispositivosEncontrados++;
     delay(TEMPOESPERA);
    }
  6. Após cada tentativa de leitura também aguardamos um intervalo de tempo definido em TEMPOLEITURA.
    delay(TEMPOLEITURA);
    
  7. Ao fim do for verificamos se o número de dispositivos encontrados é maior que zero, caso seja mostramos este valor na serial, caso contrário informamos que nenhum dispositivo foi encontrado.
    if (dispositivosEncontrados>0){
      Serial.print("Foi encontrado um total de: ");
      Serial.print(dispositivosEncontrados);
      Serial.println(" dispositivos");
    }
    else{
      Serial.println("Nenhum dispositivo foi encontrado !!!");
    }

Vídeo Tutorial

Vocês também podem ver uma explicação do código em vídeo no canal abaixo:

https://www.youtube.com/watch?v=SaZYSTw627o


Desafio

Agora que você sabe como descobrir o endereço de dispotivos I2C. Tente conectar mais de um ao barramento e veja se o código consegue detectar todos. Tente também criar uma lógica para salvar o endereço dos dispositivos identificados pelo sistema.

Considerações Finais

Este tutorial, teve como objetivo mostrar uma forma bem simples para encontrar o endereço de dispositivos conectados via I2C. 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 queira saber mais sobre o Display LCD 16x2 com Adaptador I2C, acesse o tutorial: Display LCD 20×4 e LCD 16×2 com Adaptador I2C – Utilizando o display com Arduino

 


Display OLED 0.96" I2C com Arduino

Utilizando o Display OLED 0.96" I2C com Arduino

Neste tutorial, aprenderemos a utilizar o Display OLED 0.96" em conjunto com o  Arduino Micro, mas você pode fazer com qualquer Arduino, bastando apenas a troca dos pinos da comunicação I2C que o Display utiliza. Também é possível usar com Raspberry PI, PIC e até ESP8266 e ESP32!

[toc]

kit robotica educacional com Arduino ESP ou Microbit

Display OLED

OLED (organic light-emitting diode, diodo emissor de luz orgânico) é um Diodo emissor de luz (LED) em que a camada de emissão eletro-luminescente são filmes orgânicos que emitem luz em resposta a uma corrente elétrica que flui entre anodo e catodo. Esta camada de semicondutor orgânico fica situada entre dois eletrodos. Os OLEDs podem ter duas ou três camadas de material orgânico.

As telas OLED também são as melhores telas disponíveis atualmente no mercado e por conta disso, o preço é bem elevado em relação aos outros tipos.

O Display OLED possuem varias vantagens frente a outros tipos de telas:

  • Consome muito menos energia;
  • Mais leve;
  • Fino;
  • Ângulos de visão maiores;
  • Melhor brilho e contraste;
  • Reproduzir cores mais naturais.

Mas nem tudo são flores, devido ao fato de ele usar material orgânico, o Display OLED possui uma vida útil menor que outras telas. Outras desvantagem é a baixa resistência à água. Ainda assim, esse display tem vantagens surpreendentes que compensam suas desvantagens.

Display OLED 0.96" I2C

Display OLED 0.96"
Figura 1 - Display OLED 0.96"

Este Display OLED 0.96" é perfeito para prototipação e produtos, uma vez que utiliza apenas 2 pinos do MCU com a comunicação Serial I2C. Além disso, é pequeno e tem uma ótima aparência pelo fato de ser OLED.

Especificações do display

  • Tamanho: 128x64 pixels;
  • Tensão: 3-5V;
  • Comunicação: SPI ou I2C.

Mãos a obra - Escrevendo no Display

Componentes necessários

Você pode utilizar outras placas, tais como Arduino UNO e Arduino Mega, você apenas deverá se atentar para os pinos I2C da sua placa de desenvolvimento

Montando o projeto

Cuidado: alguns display tem o Vcc e GND invertido.

Display OLED 0.96"

  • Vcc: 3.3V ou 5V.
  • GND: GND.
  • SCL: 3.
  • SDA: 2.

Caso você venha a utilizar em outro microcontrolador, precisará verificar os pinos de I2C dele e fazer a ligação corretamente.

Bibliotecas utilizadas

Baixe ambas bibliotecas e instale no diretório padrão de suas bibliotecas. Normalmente esse diretório se encontra dentro da pasta "Arduino", localizada em "Meus documentos".

Figura 2 - Adicionando as bibliotecas ao diretório.

 Antes de começar

Precisamos alterar uma linha na biblioteca do display (SSD1306), onde é definido o tamanho em pixels do display. Nosso display é 128x64, você deve verificar isso do site onde comprou o display. Por padrão, a biblioteca vem com 128x32 definido, entretanto, nosso display é 128x64.

Se seu display já é 128x32, pode pular esta parte, caso contrario, efetue a troca mostrada abaixo

1-) Abra o arquivo "Adafruit_SSD1306.h", que se encontra dentro da pasta da biblioteca baixada.

2-) Procure pela definição do tamanho do display, que está próximo a linha 70.

3-) Comente a linha do display que esta definida por padrão

4-) Remova o comentário da linha respectiva ao seu display, veja como ficou o nosso:

Figura 3 - Linha alterada.

Código do projeto

#include <Adafruit_SSD1306.h>
#include <Adafruit_GFX.h>

Adafruit_SSD1306 dsp(-1);//cria o objeto do display para i2c 


void setup()
{
	dsp.begin(SSD1306_SWITCHCAPVCC, 0x3C);//inicia o display com endereco padrao
	dsp.clearDisplay();//limpa a tela


	dsp.setTextColor(WHITE);//define o texto para branco (no display ficara azul)

	dsp.setTextSize(1);//define o tamanho do texto
	dsp.println("Vida de silicio");//escreve na tela a mensagem

	dsp.setTextSize(3);
	dsp.println("2018");
	dsp.display();//mostra as alteracoes no display, sem isso nao ira mostrar nada!!
	delay(2000);
	dsp.clearDisplay();
}

void loop()
{
	for (int8_t i = 0; i < 64; i++)
	{
		dsp.drawLine(0, 0, 128, i, WHITE);//desenha uma linha
		dsp.display();//mostra na tela
		delay(1);
	}

	for (int8_t i = 63; i > -1; i--)
	{
		dsp.drawLine(0, 0, 128, i, BLACK);
		dsp.display();
		delay(1);
	}
}

Colocando para funcionar

Display OLED 0.96" - Testando o código.
Figura 4 - Testando o código.

Entendendo a fundo

Software

-Objeto SSD1306

Adafruit_SSD1306 dsp(-1);

Nosso display é I2C, entretanto, há outros com comunicação SPI e estes devem ter os pinos definidos junto ao objeto. No caso do I2C, é preciso colocar -1.

-Função .begin()

dsp.begin(SSD1306_SWITCHCAPVCC, 0x3C);

Inicia o display no endereço 0x3C do I2C e configura o Vcc interno.

-Função .clearDisplay()

dsp.clearDisplay();

Apaga tudo o que estiver escrito ou desenhado na tela.

-Função .display()

dsp.display();

Depois de escrever ou desenhar algo na tela, não será mostrado enquanto você não usar esta função, que faz o display "atualizar" os dados e mostrar as alterações


Conclusões finais

Este pequeno e incrível display permite a criação de uma interface IHM (Interface Homem máquina) perfeita para pequenos projetos e até produtos. Também podemos usufruir do I2C que utiliza apenas 2 pinos e caso seu projeto já esteja usando algum componente I2C, não será necessário a adição de novos fios.

Recomendamos ler o seguintes tutoriais para saber mais sobre IHM e sobre I2C:


Módulo ACS712 - Medindo Corrente Elétrica Alternada e Contínua com Arduino

Módulo ACS712 - Medindo Corrente Elétrica Alternada e Contínua com Arduino

Neste tutorial você aprenderá como medir corrente elétrica alternada utilizando o  módulo sensor de corrente ACS712 juntamente com um Arduino. Para isso, realizaremos a medição do valor de corrente de um motor universal monofásico, com o objetivo de monitorar seu consumo de energia. Recomendamos a você que leia os tópicos introdutórios do tutorial SCT-013 - Sensor de Corrente Alternada com Arduino, pois, além de serem abordados os conceitos à respeito da medição de corrente, também são vistos os conceitos relacionados à Potência Elétrica, os quais, que serão utilizados neste tutorial. 

Apesar de abordarmos como medir corrente alternada, a medição de corrente Contínua é muito semelhante e será comentada em um tópico ao final do tutorial.

[toc]

kit robotica educacional com Arduino ESP ou Microbit

Sensor de corrente ACS712

O ACS712 é um pequeno sensor de corrente invasivo para baixas e médias correntes com alta sensibilidade e baixo custo. Ele é capaz de medir valores de corrente continua e alternada.

O ACS712 é um sensor de efeito Hall que gera uma saída de tensão proporcional a corrente que flui entre os pinos IP+ e  IP- do sensor.

Chip sensor ACS712
Chip sensor ACS712

Por usar o efeito Hall, o circuito do sensor ficar isolado eletricamente do circuito cujo o qual se está aferindo a corrente.

Existem diversos modelos do ACS712 com diferentes limites de medição de corrente, como podemos ver na tabela abaixo.

Tabela de opções sensores de corrente ACS712

As informações que serão importantes para nós são: os modelos (Part Number), a temperatura de operação em graus Celsius (TA), a corrente máxima a ser medida em Ampères (Optimized Range) e a relação de mV/A (Sensitivity, Sens). As informações completas podem ser consultadas no datasheet do fabricante.

O Módulo sensor de corrente ACS712

O módulo ACS712 nada mais é que um placa com o ACS712 e tudo que é preciso para usá-lo de maneira mais simples. Lembrando que este é um sensor de corrente invasivo, onde é necessário interromper o circuito para que ele seja instalado. Para este tutorial, será utilizado o módulo ACS712 30A, que por sua vez, consegue ler valores de corrente de até 30 Ampères.

Caso esteja usando o módulo ACS712 5A você precisa levar em conta a sensibilidade dele e fazer a devida alteração no código do Arduino.

Imagem do Módulo sensor de corrente ACS712
Imagem do Módulo sensor de corrente ACS712

Efeito hall

O ACS712 utiliza do efeito Hall para realizar a interface entre a corrente real do circuito com o Arduino, no qual, segundo preleciona Thomazini no livro Sensores Industriais:

"O efeito Hall caracteriza-se basicamente pelo aparecimento de um campo elétrico transversal em um condutor percorrido por uma corrente elétrica, quando ele se encontra mergulhado em um campo magnético".

Os sensores por efeito Hall são constituídos por dispositivos semicondutores que sofrem influência de campo magnético. Quando colocamos esse dispositivo semicondutor em série com a fonte e a carga, ocorre a passagem de elétrons por meio dele.

Passagem de corrente elétrica por um material semicondutor

Ao adicionarmos um campo magnético perpendicular ao movimento dos elétrons, surge uma força magnética, chamada de força de Lorentz.

Adição de um campo magnético

Sob influência dessa força, os elétrons livres não se moverão mais de forma retilínea, mas se concentrarão na direção da força magnética.

Regra da mão direita, indicando o sentido da força magnética
Concentração dos elétrons livres na parte superior do material semicondutor

Essa concentração faz surgir um potencial negativo, logo, na parte onde houver falta desses elétrons, surgirá o potencial negativo. Dessa forma, haverá uma diferença de potencial entre essas extremidades que será proporcional ao valor de corrente que está passando pelo material semicondutor. Com isso, medindo a tensão entre essas extremidades e por meio de cálculos, é possível descobrir o valor de corrente.


Mãos à Obra - Medindo Corrente Elétrica Alternada com Módulo ACS712 30A

Componentes necessários

Para a realização deste tutorial serão necessários:

Além desses itens, utilizaremos um pequeno motor universal monofásico para realizar a medição da corrente inerente ao funcionamento da mesma e também da potência consumida estipulada.

Montando o projeto

Por se tratar de um sensor de corrente invasivo, é necessário realizar a interrupção do circuito para que o ACS712 possa ser conectado ao circuito, como vemos abaixo.

Após isso, conectamos a alimentação (5V e GND) do ACS712 no arduino, e o pino OUT conectamos ao pino analógico A0, de acordo com o diagrama abaixo.

Programando

Após concluir a montagem descrita acima, basta dar upload no código abaixo para o arduino, no qual a explicação detalhada de cada linha poderá ser vista no tópico "Entendendo a fundo/Software". Lembre-se de selecionar a placa e a porta que está utilizando corretamente.

float vetCorrente[300];

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

void loop()
{
  double maior_Valor = 0;
  double valor_Corrente = 0;  

  float tensao = 127;
  float potencia = 0;

  for(int i = 0; i < 300; i++)
  {
    vetCorrente[i] = analogRead(A0);
    delayMicroseconds(600);
  }  

  for(int i = 0; i < 300; i++)
  {
    if(maior_Valor < vetCorrente[i])
    {
      maior_Valor = vetCorrente[i];
    }
  }  

  maior_Valor = maior_Valor * 0.004882812;
  valor_Corrente = maior_Valor - 2.5;
  valor_Corrente = valor_Corrente * 1000;
  valor_Corrente = valor_Corrente / 66;         //sensibilidade : 66mV/A para ACS712 30A / 185mV/A para ACS712 5A
  valor_Corrente = valor_Corrente / 1.41421356;

  Serial.print("Corrente = ");
  Serial.print(valor_Corrente);
  Serial.println(" A");

  potencia = valor_Corrente * tensao;

  Serial.print("Potencia = ");
  Serial.print(potencia);
  Serial.println(" W");
  
  Serial.print(".");
  delay(500);
  Serial.print(".");
  delay(500);
  Serial.print(".");
  delay(500);

  Serial.println("");
}

Colocando pra funcionar

Código compilado e circuito montado! Veja o resultado abaixo.

Resultado da montagem prática
Valores mostrados no monitor serial

Entendendo a fundo

Neste tópico serão tratados o funcionamento de cada parte do projeto deste tutorial, onde veremos os cálculos realizados pelo arduino para chegar ao valor de corrente correto.

Hardware

O circuito integrado ACS712 é fabricado pela Allegro MicroSystems, no qual é possível visualizar sua pinagem na imagen logo abaixo.

Pinagem do circuito integrado ACS712
  • IP+ / IP- : são os terminais que serão conectados em série com a carga. É por onde a corrente elétrica irá fluir.
  • VIOUT: corresponde ao pino de saída do sensor. Ele irá representar a forma de onda da corrente proporcional a sua entrada, no qual a sua proporcionalidade é definida pelo modelo que será utilizado. A forma de onda em sua saída apresentará um offset de 2,5V.
  • FILTER: terminal no qual será conectado um capacitor que definirá a largura de banda.
  • VCC / GND: correspondem aos terminais de alimentação do circuito integrado.

Logo abaixo é mostrado o circuito típico de suas aplicações.

Circuito do sensor ACS712

Software

A programação será responsável por, primeiramente, realizar várias leituras do pino analógico, no qual o ACS712 está conectado, durante um período de tempo, assim, podemos ter uma noção dos valores que constituem a senoide da corrente. Com esses valores, o arduino poderá calcular o valor de pico da senoide, no qual o mesmo equivale ao maior valor da amostra encontrada, e após isso, basta dividir esse valor por √2, segundo a seguinte fórmula:

Irms = Ipico / √2

Assim, conseguiremos descobrir o valor rms (eficaz) da corrente passando pelo condutor no qual o ACS712 está conectado.

Agora será explicado a função de cada linha presente no código apresentado no tópico "Programando".

- Criando um vetor

Inicialmente é criado um vetor que será utilizado para armazenar 300 amostras de valores que serão lidos adiante.

float vetCorrente[300];

- Aquisição das amostras por meio de uma estrutura de repetição

É criado um "for" para que o arduino possa armazenar vários valores de corrente durante um determinado instante de tempo.

for(int i = 0; i < 300; i++)
{
  vetCorrente[i] = analogRead(A0);
  delayMicroseconds(600);
}

- Encontrando o maior valor de amostra do vetor "vetCorrente[300]"

Cria-se outro laço "for" para que o arduino possa encontrar, entre as 300 amostras, a que apresente o maior valor.

for(int i = 0; i < 300; i++)
{
  if(maior_Valor < vetCorrente[i])
  {
    maior_Valor = vetCorrente[i];
  }
}

- Calculando o valor da corrente

No primeiro instante é necessário converter o valor encontrado, que se encontra entre 0 e 1023, para o valor de tensão lido pelo arduino. Para isso, por meio de uma regra de 3 simples, é possível encontrar o valor de tensão.

1024     -     5

(valor da amostra)     -     x

Seguindo essa regra de 3, é possível descobrir que basta multiplicar o valor da amostra por 0,004882812 para encontrar o valor da tensão lido pelo arduino.

maior_Valor = maior_Valor * 0.004882812;

- Removendo o valor de offset das amostras

A forma de onda resultante na saída do módulo ACS712 equivale a uma senoide com uma tensão de offset, como podemos ver abaixo.

Exemplo da forma de onda da saída do módulo ACS712

Seguindo seu datasheet, o valor da tensão de offset (equivalente ao zero da forma de onda senoidal da corrente) é proporcional ao valor de VCC * 0,5, que no nosso caso seria:

Voffset = VCC * 0,5

Voffset = 5 * 0,5

Voffset = 2,5 V

Por esse motivo foi necessário diminuirmos o valor de tensão encontrado por 2,5, como é indicado logo abaixo.

valor_Corrente = maior_Valor - 2.5;

- Convertendo para mili

O datasheet deste módulo apresenta os valores de sensibilidade de mV/A, com isso, foi necessário converter os valores de V para mV, para que o arduino possa calcular o valor da corrente adiante.

valor_Corrente = valor_Corrente * 1000;

- Encontrando o valor de pico da corrente

Agora dividiremos o resultado pelo valor equivalente a sensibilidade do sensor. Como visto anteriormente, existem diferentes modelos de ACS712, no qual o que foi utilizado neste tutorial é o ACS712ELCTR-30A-T, conhecido como ACS712 30A, no qual consultando seu datasheet foi possível encontrar o valor de sensibilidade de mV/A, que corresponde a 66 mV/A.

valor_Corrente = valor_Corrente / 66;

Caso o seu ACS712 seja de outro modelo, substitua o valor "66" pelo valor que corresponda a sensibilidade do seu módulo. Para o ACS712 5A, por exemplo, você precisa mudar para 185.

- Calculando o valor rms da corrente

Achado o valor de pico, é possível calcular o valor rms da corrente, finalizando assim o código referente a corrente.

valor_Corrente = valor_Corrente / 1.41421356;

- Mostrando o resultado no monitor serial

É mostrado os valores de corrente e potência no monitor serial, para que você possa visualizá-los.

Serial.print("Corrente = ");
Serial.print(valor_Corrente);
Serial.println(" A");

Serial.print("Potencia = ");
Serial.print(potencia);
Serial.println(" W");

É dado um tempo para a próxima atualização dos valores.

Serial.print(".");
delay(500);
Serial.print(".");
delay(500);
Serial.print(".");
delay(500);

Medindo corrente contínua

Uma vantagem deste sensor é que com ele você poderá medir também o valor da corrente de cargas DC, ou seja, do mesmo modo que ele pode ser empregado para medir corrente alternada, ele também pode ser empregado para medir corrente contínua.  Para isso, basta mudarmos algumas linhas da programação referentes ao vetor de amostras vetCorrente[300]. Abaixo é detalhado as alterações que deverão ser feitas.

Ao invés de encontrarmos o maior valor presente no vetor, como foi descrito no tópico Encontrando o maior valor de amostra do vetor "vetCorrente[300]" logo acima, teremos que realizar um cálculo de média aritmética com todos os valores.

Veja abaixo o código a ser retirado.

for(int i = 0; i < 300; i++)
{
  if(maior_Valor < vetCorrente[i])
  {
    maior_Valor = vetCorrente[i];
  }
}

maior_Valor = maior_Valor * 0.004882812;
valor_Corrente = maior_Valor - 2.5;

Em seu lugar, colocaremos o seguinte código.

int somaTotal;

for(int i = 0; i < 300; i++)
{
  somaTotal = vetCorrente[i] + somatorio;
}

valor_medio = somaTotal / 300;

valor_medio = valor_medio * 0.004882812;
valor_Corrente = valor_medio - 2.5;

Além disso, devemos retirar a seguinte linha do código:

valor_Corrente = valor_Corrente / 1.41421356;

Retirar essa linha se faz necessário pois ela converter o valor de pico da corrente para o valor rms, mas, por estarmos tratando de corrente contínua, isso não é necessário.

Essas modificações surtirão no seguinte efeito:

  • Por meio do laço for será realizado a soma de todos os valores presentes no vetor vetCorrente[300], e armazenando o resultado na variável somaTotal;
  • É realizado a divisão da variável somaTotal pelo número 300, encerrando assim o cálculo da média aritmética;
  • As linhas seguintes serão responsáveis por converter o valor achado até o momento no valor de corrente realmente lido.

O código final com essas alterações pode ser visualizado logo abaixo.

float vetCorrente[300];

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

void loop()
{
  double maior_Valor = 0;
  double valor_Corrente = 0;  

  float tensao = 127;
  float potencia = 0;

  for(int i = 0; i < 300; i++)
  {
    vetCorrente[i] = analogRead(A0);
    delayMicroseconds(600);
  }  



  int somaTotal = 0;

  for(int i = 0; i < 300; i++)
  {
    somaTotal = vetCorrente[i] + somaTotal;
  }
  valor_medio = somaTotal / 300;
  
  valor_medio = valor_medio * 0.004882812;
  valor_Corrente = valor_medio - 2.5;



  valor_Corrente = valor_Corrente * 1000;
  valor_Corrente = valor_Corrente / 66;         //sensibilidade : 66mV/A para ACS712 30A / 185mV/A para ACS712 5A

  Serial.print("Corrente = ");
  Serial.print(valor_Corrente);
  Serial.println(" A");

  potencia = valor_Corrente * tensao;

  Serial.print("Potencia = ");
  Serial.print(potencia);
  Serial.println(" W");
  
  Serial.print(".");
  delay(500);
  Serial.print(".");
  delay(500);
  Serial.print(".");
  delay(500);

  Serial.println("");
}

Com essas alterações, você poderá medir a corrente de sua carga DC tranquilamente.


Considerações finais

Esperamos que este tutorial tenha tanto trazido-lhe o entendimento a respeito do módulo ACS712 quanto tirado suas dúvidas sobre esse sensor de corrente.


Como utilizar o LED RGB com Arduino

Como utilizar o LED RGB

Neste tutorial, você aprenderá como utilizar o LED RGB integrado a uma placa Arduino Uno, utilizando as saídas PWM para demonstrar as cores emitidas do componente. Por meio do monitor serial, o Arduino lerá o nome da cor escrita pelo usuário e, por meio do LED RGB, a cor digitada será reproduzida.

Caso ainda não tenha conhecimento básico sobre como usar o monitor serial da Arduino IDE, sugerimos que você leia o tutorial Comunicação Serial Arduino, para compreender melhor o projeto a ser desenvolvido, principalmente na parte de software.

[toc]

kit robotica educacional com Arduino ESP ou Microbit

O que é um LED? O que significa o termo "LED"?

LED é uma sigla para Light Emitting Diode que em português significa Diodo Emissor de Luz. O LED é um componente eletrônico que, quando ocorre passagem de corrente elétrica, emite luz. Possui dois terminais, chamados de anodo (positivo) e catodo (negativo).

Identificação dos terminais e simbologia

Por que utilizar um LED?

É sempre bom termos um auxílio visual nos nossos projetos, seja como sinalizador ou alarme, indicando que algo está ligado ou não, como os encontrados em televisores, aparelhos de DVD, computadores, dentre outros, ou por opções de design de produto, como podemos ver logo abaixo.

Exemplo de aplicação do LED RGB

Ou seja, um LED é uma forma visual simples de um projeto conversar conosco. Outra forma visual de um projeto interagir é através de displays LCDs.

Falamos um pouco mais sobre a importância das interfaces homem maquina (IHM) no tutorial Display lcd 16x2 com Arduino.

O que é um LED RGB?

Assim como os LEDs tradicionais, o LED RGB emite luz por meio da passagem de corrente elétrica, mas ele apresenta a peculiaridade de ser composto por três LEDs de cores diferentes, sendo elas: vermelho (Red), verde (Green) e azul (Blue), surgindo daí o nome "RGB".

LED RGB
LED RGB

Cada LED pode ser controlado de maneira individual, conectando apenas os seus terminais em alguma fonte de energia, deixando os outros desconectados, mas o seu grande diferencial está em justamente utilizar os três ao mesmo tempo, no qual utilizando pulsos PWM (recomendamos que veja o tutorial Arduino - Grandezas digitais, analógicas e PWM) para realizar o controle de intensidade de cada cor individualmente, de modo que, a cor resultante será a mistura das cores emitidas por cada LED.

Demonstração do resultado da mistura de intensidades diferentes das cores: vermelho, verde e azul

Tipos de LED RGB

Por se tratar da associação de três LEDs distintos em um único LED, eles podem ser denominados de: catodo comum ou anodo comum, sendo o catodo comum o mais utilizado.

Descrição dos pinos LED RGB
Descrição dos pinos

O tipo catodo comum possui uma interligação entre os catodos dos três LEDs, fazendo com que se torne apenas um. Já o tipo anodo comum apresenta uma interligação entre os anodos dos três LEDs, tornando-o apenas um, como é possível visualizar na figura abaixo.

Tipos de LED RGB
Tipos de LED RGB

Para identificar o terminal que equivale ao comum, basta ver qual terminal é o maior, ou ver qual está conectado a maior "placa" presente no interior do LED, como é possível ver na ilustração abaixo.

Identificação de cada pino RGB
Identificação de cada pino

Mãos à obra - Comandando a cor a ser mostrada no LED RGB pelo Monitor Serial

O projeto deste tutorial visa integrar o monitor serial com o LED RGB, no qual o usuário enviará o nome de uma cor e o Arduino reproduzirá essa cor por meio do LED. Para este fim, serão necessários:

Montando o hardware

Com os componentes em mãos, montaremos o circuito abaixo.

Circuito montado em protoboard com Arduino Uno e LED RGB
Circuito montado em protoboard

Programando

Após montar o circuito na protoboard, damos início a parte de programação do arduino. Escreva em sua IDE o código apresentado abaixo. Não se preocupe, a explicação detalhada de cada linha será abordado logo abaixo.

const int azul = 9;
const int verde = 10;
const int vermelho = 11;

String cor;

void setup()
{
   Serial.begin(9600);
  
   pinMode(azul, OUTPUT);
   pinMode(verde, OUTPUT);
   pinMode(vermelho, OUTPUT);
}

//Funções responsáveis por executar o brilho selecionado
void vermelhoFuncao(){
  digitalWrite(azul, LOW);
  digitalWrite(verde, LOW);
  digitalWrite(vermelho, HIGH);
}
void azulFuncao(){
  digitalWrite(azul, HIGH);
  digitalWrite(verde, LOW);
  digitalWrite(vermelho, LOW);
}
void verdeFuncao(){
  digitalWrite(azul, LOW);
  digitalWrite(verde, HIGH);
  digitalWrite(vermelho, LOW);
}
void amareloFuncao(){
  analogWrite(azul, 0);
  analogWrite(verde, 50);
  analogWrite(vermelho, 255);
}
void roxoFuncao(){
  analogWrite(azul, 207);
  analogWrite(verde, 0);
  analogWrite(vermelho, 255);
}
void brancoFuncao(){
  digitalWrite(azul, HIGH);
  digitalWrite(verde, HIGH);
  digitalWrite(vermelho, HIGH);
}


void loop()
{
  if(Serial.available()){
    cor = Serial.readString();
    Serial.println(cor);
  }

  if(cor == "Vermelho"){
    vermelhoFuncao();
  }
  if(cor == "Azul"){
    azulFuncao();
  }
  if(cor == "Verde"){
    verdeFuncao();
  }
  if(cor == "Amarelo"){
    amareloFuncao();
  }
  if(cor == "Roxo"){
    roxoFuncao();
  }
  if(cor == "Branco"){
    brancoFuncao();
  } 
}

Depois de passar o código acima para a sua IDE, verifique se a porta no qual o arduino está conectado está selecionada. Com tudo pronto, basta carregar o código para o arduino.

Colocando para funcionar

Agora vamos conferir o resultado deste projeto!

Resultado da montagem prática

Entendendo a fundo

Hardware

- Como funciona

Quanto ao funcionamento específico do LED, recomendamentos que veja o artigo Como funcionam os LEDs, do Instituto Newton Braga, no qual ele explica o funcionamento dos LEDs de maneira geral comparando-o  com a lâmpada incandescente.

- Montagem na protoboard

Relacionado a montagem, é composto apenas por resistores e um LED RGB, no qual os resistores estão presentes apenas para limitar o valor da corrente que circulará pelo circuito, pois sem ele a corrente poderia danificar o LED, ocasionando falha no funcionamento. Logo abaixo está o esquema eletrônico do projeto desenvolvido no tutorial de hoje.

Esquema eletrônico

Software

Neste tópico abordaremos cada instrução realizada pelo nosso código citado acima.

- Declarando as variáveis

São criadas quatro variáveis no código, três do tipo inteiro e uma do tipo string. O termo "const" utilizado antes do termo "int" foi empregado para dizer ao programa que a variável não sofrerá modificação em seu valor, ou seja, ela permanecerá com o mesmo valor no programa. Isso foi utilizado para declarar os pinos responsáveis pelas saídas que comandarão os terminais do LED RGB.

A String cor foi criada com o objetivo de ser armazenado nela a palavra que for escrita no monitor serial.

const int azul = 9;
const int verde = 10;
const int vermelho = 11;

String cor;

Caso queira utilizar outros pinos para comandar seu LED RGB, lembre-se de utilizar somente os que possuem saída PWM.

- Configurações no void setup()

É iniciada a comunicação serial de 9600 bps (relembrando, caso você tenha dúvidas sobre como utilizar a comunicação serial, veja o tutorial Comunicação Serial Arduino). São declarados os pinos 'azul', 'verde' e 'vermelho' (no qual anteriormente foi atribuído a eles o valor que corresponde ao pino) como OUTPUT, ou seja, como saída.

void setup()
{
   Serial.begin(9600);
  
   pinMode(azul, OUTPUT);
   pinMode(verde, OUTPUT);
   pinMode(vermelho, OUTPUT);
}

- Criando funções para comandar o LED RGB

Nesta parte do código são criadas funções que tem por função comandar os terminais do LED RGB. Todas são iniciadas com void pois não retornarão nenhum valor para a função principal.

void vermelhoFuncao(){
  digitalWrite(azul, LOW);
  digitalWrite(verde, LOW);
  digitalWrite(vermelho, HIGH);
}
void azulFuncao(){
  digitalWrite(azul, HIGH);
  digitalWrite(verde, LOW);
  digitalWrite(vermelho, LOW);
}
void verdeFuncao(){
  digitalWrite(azul, LOW);
  digitalWrite(verde, HIGH);
  digitalWrite(vermelho, LOW);
}
void amareloFuncao(){
  analogWrite(azul, 0);
  analogWrite(verde, 50);
  analogWrite(vermelho, 255);
}
void roxoFuncao(){
  analogWrite(azul, 207);
  analogWrite(verde, 0);
  analogWrite(vermelho, 255);
}
void brancoFuncao(){
  digitalWrite(azul, HIGH);
  digitalWrite(verde, HIGH);
  digitalWrite(vermelho, HIGH);
}

- Recebendo e armazenando a string de entrada

É verificado se há algum termo a ser lido do monitor serial. Caso haja, o termo é armazenado na variável cor. Logo após o armazenamento, é realizado um print no monitor serial do que foi recebido.

if(Serial.available()){
   cor = Serial.readString();
   Serial.println(cor);
}

- Verificação do termo recebido

É realizada uma série de comparações para verificar o que foi recebido do monitor serial. As cores disponíveis para serem mostradas pelo LED RGB são: Vermelho, Azul, Verde, Amarelo, Roxo e Branco. Caso haja a confirmação que o que foi escrito corresponde a uma das opções, é chamada uma função específica para a realização do comando do LED RGB.

if(cor == "Vermelho"){
  vermelhoFuncao();
}
if(cor == "Azul"){
  azulFuncao();
}
if(cor == "Verde"){
  verdeFuncao();
}
if(cor == "Amarelo"){
  amareloFuncao();
}
if(cor == "Roxo"){
  roxoFuncao();
}
if(cor == "Branco"){
  brancoFuncao();
}

Considerações finais

Esperamos que este tutorial tenha lhe esclarecido sobre a utilização deste componente eletrônico tão utilizado na área de desenvolvimento eletrônico.

Obrigado pela atenção e continue buscando conhecimento no portal do Vida de Silício.


Shield display LCD TFT 2.4" Touchscreen - Descobrindo o drive

Shield display LCD TFT 2.4" Touchscreen - Descobrindo o drive

No desenvolvimento de qualquer tipo de projeto, é indispensável o uso de uma interface que permita ao usuário ver todo o funcionamento do sistema. Entretanto, essa não é uma tarefa fácil, principalmente quando dispomos de sistemas de baixo poder computacional, como é o caso dos microcontroladores tais como os Arduino. Sabendo disso, neste tutorial você aprenderá a utilizar o display TFT 2.4" com touchscreen embutido em conjunto a uma Placa Arduino Uno e descobriremos como resolver o problema da tela branca, comum ao usar esse LCD. Com esse display podemos criar interfaces interativas e supervisionar dados em tempo real.

É interessante ressaltar que uma das maiores dificuldade na utilização desse tipo de LCD se dá em achar a biblioteca adequada. Isso porque existe diversos modelos semelhantes o que gera uma grande confusão na hora de botar ele para funcionar. Pensando nisso, nesse conteúdo usamos uma biblioteca que faz a leitura do controlador usado pelo Display e nos informa qual é o driver através do monitor serial. Em seguida usamos o número do controlador para configurar a Biblioteca.

[toc]

kit robotica educacional com Arduino ESP ou Microbit

O Shield Display LCD TFT 2.4" Touchscreen

O shield Lcd 2.4" possui uma resolução de 240x320, além de possuir uma interface touchscreen resistiva por onde é possível interagir com a tela sem a necessidade de botões. A tela conta com um total de 13 pinos distribuídos entre alimentação, controle do touch e controle do display. Se você deseja adicionar sensores em conjunto com a tela, recomendo que utilize o Arduino Mega, pois ao acoplar o shield em um Arduino uno você não terá espaço nem pinos para conectar outros dispositivos.

Esse shield também possui uma interface para cartões SD em sua parte traseira. Tal interface é muito comum em LCDs coloridos, seu propósito é armazenar imagens prontas para serem exibidas no Display. Além disso, esse módulo SD  pode ser usado para armazenar outras informações que seja úteis ao seu projeto.

Shield lcd TFT 2.4" Touchscreen
Shield lcd 2.4" Touchscreen

Ao utilizar essa tela no Arduino uno, se certifique que a parte do conector USB do arduino NÃO esteja tocando no shield, caso contrário pode ocorrer um curto circuito capaz de danificar o shield ou até o Arduino.


Mãos à obra – Construindo um sistema de controle de acesso utilizando a shield LCD

O projeto é divido em duas partes, na primeira descobrimos qual o controlador do nosso LCD e em seguida configuramos a biblioteca para se adequar ao modelos de Display que temos em mão.

Componentes Utilizados:

Montando o projeto

Para realizar a montagem em um Arduino uno não existe muito segredo, basta encaixar o módulo em seu Arduino sempre deixando um espaço entre o conector usb e a shield. Tenha cuidado para não amassar uma das pernas de seu shield.

Caso tudo esteja funcionando corretamente o display deverá acender como mostra o gif abaixo:

encaixando Shield LCD TFT no Arduino uno
Ligando a tela pela primeira vez.

Instalando Biblioteca da Tela

A utilização destas telas nem sempre é uma tarefa fácil, isso ocorre devido a grande quantidade de controladores disponíveis no mercado para este tipo de tela. Sabendo disso, neste tutorial iremos utilizar uma biblioteca que abrange uma grande quantidade de controladores, no caso a MCUFRIEND. A instalação da biblioteca pode ser feita de maneira bem simples, bastando seguir os seguintes passos:

  • Clique em  Sketch e vá até a opção Incluir Biblioteca como mostra a figura abaixo:

  • Logo em seguida selecione a opção Gerenciar Bibliotecas, uma nova tela será aberta onde você pode gerenciar todas as bibliotecas disponíveis no repositório.
Gerenciador de bibliotecas
  • Por fim, para instalar  a biblioteca, basta digitar MCUF RIEND_kbv na barra de pesquisa e instalar a opção da imagem.
Biblioteca selecionada e baixada

Ao fim do processo de instalação, reinicie a IDE do Arduino para diminuir a possibilidade de problemas de compatibilidade.

Descobrindo o Driver do Display LCD TFT 2.4"

Agora que temos a nossa biblioteca instalada, iremos testar se da forma como ela está já conseguimos renderizar informações na tela. Para isso execute o seguinte código:

#include <MCUFRIEND_kbv.h>
MCUFRIEND_kbv tft;
#define VERDE   0x07E0
#define BRANCO 0xFFFF

void setup() {
  Serial.begin(9600);
  uint16_t ID = tft.readID(); 
  Serial.print("Identificador do display: ");
  Serial.println(ID,HEX);
  tft.begin(ID);
  tft.setRotation(1);
  tft.fillScreen(BRANCO);
  tft.setCursor(20,100);
  tft.setTextColor(VERDE);
  tft.setTextSize(3);
  tft.print("It's Alive !!!");
}

void loop() {

}

O código acima realiza uma leitura do registrador responsável por armazenar o código do circuito integrado que controla a tela através da função readID(). Com este código, a biblioteca sabe quais os registradores utilizados para entrada e saída de dados, podendo assim estabelecer uma comunicação com o display que é feita através da função begin(ID).  Além de fazer isso, no monitor serial e escreve a  mensagem "It's Alive" em verde caso o código esteja funcionando corretamente.

Se tudo estiver ok, você verá a seguinte mensagem escrita em seu display:

Shield LCD funcionando

Dessa forma, o nosso controlador é o driver LGPD4532.

Consertando bug da tela branca - Configurando a biblioteca para o nosso controlador

Caso a tela simplesmente continue branca, será necessário realizar uma modificação na biblioteca MCUFRIEND. Para isso você deve ir até a pasta onde a biblioteca está instalada:

  • Windows: C:\Program Files (x86)\Arduino\libraries
  • Linux: /home/Usuario/Arduino/libraries

Após encontrar a localização da biblioteca instalada, selecione a pasta MCUFRIEND_kbv e abra o arquivo MCUFRIEND_kbv.cpp com o seu editor de textos favorito

Pasta a ser aberta
Arquivo a ser modificado

A biblioteca MCUFRIEND possui praticamente todos os controladores disponíveis para esse display, porém algumas são desabilitadas devido a pequena quantidade de memória disponível. Sabendo disso, iremos através dessa modificação habilitar este controlador. Para fazer isso, iremos precisar do identificador do controlador do display, que pode ser obtido através do código de teste apresentado logo acima. Neste exemplo estou utilizando o controlador 4532, então devemos habilitar o suporte a este controlador

Controlador desabilitado por padrão na biblioteca

Na linha correspondente ao controlador que foi mostrado no código de testes, basta "descomentar" a linha do controlador desejado.

Controlador habilitado

Antes de realizar qualquer modificação em uma biblioteca, é altamente recomendado que se faça backup da versão anterior para que caso  ocorre algum problema seja possível retornar ao estado anterior.

Logo após realizar as modificações, salve o arquivo e reinicie a IDE do Arduino. Se tudo tiver sido feito corretamente a mensagem It's Alive irá aparecer na sua tela quando você fizer o upload do código novamente.

Programando

Agora que temos a biblioteca funcionando corretamente, iremos construir a interface do nosso controle de acesso. O código abaixo é responsável por renderizar todos os botões que iremos utilizar em nosso sistema.

#include "Adafruit_GFX.h" // Biblioteca Gráfica Adafruit
#include <MCUFRIEND_kbv.h> // Bibllioteca para controle do lcd 

// Cores que iremos utilizar em nosso projeto
#define PRETO   0x0000
#define VERMELHO     0xF800
#define VERDE   0x07E0
#define BRANCO 0xFFFF

//---------------------------------------------//

MCUFRIEND_kbv tft; // Objeto  de comunicação com  display

void setup() {
  uint16_t ID = tft.readID(); // Leitura do código de identificação do controlador
  tft.begin(ID); // Inicialização da tela
  telaInicial(); // Chamada da função responsável por renderizar o nosso painel de acesso
}
void telaInicial(){
  tft.setRotation(1); // Display é rotacionado para modo paisagem
  tft.fillScreen(BRANCO); // Tela  é preenchida pela cor Branca
  escreveTexto(50,0,"Controle de Acesso",2,PRETO); // Texto é escrito na posição (50,0)
  criarBotao(60,50,200,30,"",PRETO); // Criamos uma pequena caixa onde será mostrada a senha digitada
  criarBotao(50,100,30,30,"1",VERMELHO); // Criação do botão 1 do  sistema
  criarBotao(100,100,30,30,"2",VERMELHO); // Criação do botão 2 do sistema
  criarBotao(150,100,30,30,"3",VERMELHO); // Criação do botão 3 do sistema
  criarBotao(200,100,30,30,"4",VERMELHO); // Criação do botão 4 do sistema
  criarBotao(250,100,30,30,"5",VERMELHO); // Criação do botão 5 do sistema
  criarBotao(50,150,30,30,"6",VERMELHO); // Criação do botão 6 do sistema
  criarBotao(100,150,30,30,"7",VERMELHO); // Criação do botão 7 do sistema
  criarBotao(150,150,30,30,"8",VERMELHO); // Criação do botão 8 do sistema
  criarBotao(200,150,30,30,"9",VERMELHO); // Criação do botão 9 do sistema
  criarBotao(250,150,30,30,"0",VERMELHO); // Criação do botão 0 do sistema
  criarBotao(50,200,120,30,"Apagar",VERMELHO); // Criação do botão Apagar
  criarBotao(180,200,100,30,"Logar",VERMELHO); // Criação do botão Logar
}

void telaAcesso(bool acesso){ // Função que controla o acesso ao sistema
  if (acesso){ // Se o acesso for permitido
     tft.fillScreen(PRETO); // Tela é preenchida pela cor preta
     tft.setCursor(10,100); // Cursor é deslocado para pixel de posição (10,100)
     tft.setTextColor(VERDE); // Cor do texto é alterada para verde
     tft.setTextSize(3); // Tamanho da fonte do texto é alterada para o tamanho 3 ( Grande )
     tft.print("Acesso Autorizado"); // Texto é escrito em verde com mensagem Acesso Autorizado
     delay(3000); // Sistema aguarda 3 segundos
     telaInicial(); // Tela de acesso inicial é renderizada
  }
  else{ // Caso contrário
     tft.fillScreen(PRETO); // Tela é preenchida pela cor preta
     tft.setCursor(40,100); // Cursor é deslocado para pixel de posição (40,100)
     tft.setTextColor(VERMELHO); // Cor do texto é alterada para vermelho
     tft.setTextSize(3); // Tamanho da fonte do texto é alterada para o tamanho 3 ( Grande )
     tft.print("Acesso Negado"); // Texto é escrito em vermelho com mensagem Acesso Negado
     delay(3000); // Sistema aguarda 3 segundos
     telaInicial();  // Tela de acesso inicial é renderizada
  }
  
}

void escreveTexto(int posx,int posy, String texto,int tamanho,int cor){ // Função criada para facilitar escrita de texto
  tft.setCursor(posx,posy); // Cursor é deslocado para posição passada como parâmetro
  tft.setTextColor(cor); // Cor a ser escrita é alterada conforme valor recebido como parâmetro
  tft.setTextSize(tamanho); // Tamanho da fonte é  alterado conforme parâmetro recebido
  tft.print(texto); // Texto passado por parâmetro é escrito na tela
}

void criarBotao(int posx,int posy, int largura, int altura,String texto,int cor) //
{
    //Create Red Button
  tft.fillRect(posx,posy, largura, altura, cor); // um quadrado começando em (posx,posy) é renderizado conforme parâmetros passados
  tft.drawRect(posx,posy, largura, altura,PRETO); // um quadrado de cor preta é desenhado ao redor do quadrado vermelho 
  tft.setCursor(posx+8,posy+4); // Cursor é deslocado para o pixel de posição (posx+8,posy+4)
  tft.setTextColor(BRANCO); // Cor do texto é alterada para Branco
  tft.setTextSize(3); // Fonte é alterada para tamanho 3
  tft.print(texto); // Texto é escrito em posição determinada
}
void loop() { // Cada uma das três telas que compõem o sistema é chamada a cada dois segundos
telaInicial();
delay(2000);
telaAcesso(true);
delay(2000);
telaAcesso(false);  
delay(2000); 
}

Colocando pra funcionar


Entendendo a Fundo

Software

- Incluindo bibliotecas a serem adicionadas ao projeto

Inicialmente podemos observar que necessitamos adicionar penas duas bibliotecas ao nosso projeto. A biblioteca Adafruit_GFX fornece uma série de funções que permitem o desenho de figuras geométricas de forma transparente. Já a biblioteca MCUFRIEND_kbv fornece o objeto com o qual iremos nos comunicar com o display.

#include "Adafruit_GFX.h" // biblioteca com funções Gráficas
#include <MCUFRIEND_kbv.h> // biblioteca de acesso e comunicação com display

- Declarando objeto de comunicação com display

Para estabelecer uma comunicação com o nosso display, iremos criar um objeto de nome tft que ficará responsável por renderizar toda a informação que for requisitada pelo código.

MCUFRIEND_kbv tft; // Objeto de comunicação com a tela

O nome do objeto não precisa ser necessariamente tft, você pode nomear o objeto com o nome que preferir.

- Paleta de cores utilizada

Neste exemplo iremos utilizar um total de 4 cores, para desenhar botões e telas de acesso. Para facilitar o trabalho de digitar o código da cor utilizada, criaremos 4 defines contendo as cores utilizadas e seu respectivo código RGB.

#define PRETO 0x0000
#define VERMELHO 0xF800
#define VERDE 0x07E0
#define BRANCO 0xFFFF

- Função desenha botão

Para  facilitar o processo de desenhar botões na tela, foi  elaborada uma função que dada a posição inicial, dimensões, texto e cor um retângulo representando um botão é desenhado na tela. Seu funcionamento segue a seguinte lógica:

void criarBotao(int posx,int posy, int largura, int altura,String texto,int cor)
{
  tft.fillRect(posx,posy, largura, altura, cor); // Cria um quadrado com inicio na posição (posx,posy) com altura e largura definidas na função
  tft.drawRect(posx,posy, largura, altura,PRETO); // Cria uma borda ao redor do quadrado desenhado anteriormente
  tft.setCursor(posx+8,posy+4); // Cursor de escrita é deslocado para centro do quadrado desenhado
  tft.setTextColor(BRANCO); // Cor do texto é alterada para branco
  tft.setTextSize(3); // Tamanho do texto é alterado para tamanho 3
  tft.print(texto); // Texto é escrito na posição central da caixa desenhada
}

- Tft.fillRect()

Esse método recebe como parâmetros a posição inicial onde o quadrado deve começar, sua largura, altura e cor. Com todos esses dados o método irá renderizar na tela um quadrado da seguinte forma:

- Tft.drawRect

O método drawRect por sua vez, com  base nos mesmos parâmetros irá criar uma borda sobre o quadrado que foi renderizado anteriormente

- Escrevendo texto

O processo para escrever informações na tela segue o seguinte fluxo:

  1. Primeiro através da função setCursor() iremos selecionar a posição onde o nosso texto começará a ser Escrito

  2. Logo em seguida configuramos a cor da fonte e seu tamanho através dos métodos setTextColor() e setTextSize().
  1. Por fim escrevemos o texto desejado através do método print()

- Função escreveTexto

Como foi possível observar na etapa onde escrevemos o texto dentro do retângulo, uma grande quantidade de comandos é necessária até que se escreva o texto em si. Para reduzir a quantidade de código escrita foi também criada uma função que já encapsula todo esse processo. Seu uso consiste em basicamente fornecer o ponto de inicio do texto, o texto a ser escrito, seu tamanho, e a cor do texto.

void escreveTexto(int posx,int posy, String texto,int tamanho,int cor){ 
  tft.setCursor(posx,posy); // Move cursor para posição inicial onde o texto será escrito
  tft.setTextColor(cor); // Muda a cor do texto
  tft.setTextSize(tamanho); // Altera o tamanho da fonte
  tft.print(texto); // Escreve texto na tela
}

- Função setup

dentro da nossa função setup iremos basicamente inicializar a nossa tela seguindo o seguinte fluxo

  1. Lemos o código de identificação do display através do método readID()
    uint16_t ID = tft.readID();
  2. Inicializamos o nosso display através do método begin()
    tft.begin(ID);
    
  3. Mudamos o layout da tela para o modo paisagem através do método setRotation(1)

    tft.setRotation(1);
    
  4.  Por fim chamamos a função telaInicial() que irá renderizar na tela nosso painel de acesso
    telaInicial();
    

- Função telaInicial

A função tela inicial tem como função básica renderizar todos os botões e o campo de texto que será responsável por mostrar a senha digitada. Para isso a função executa os seguintes passos:

  1. Mudamos a tela para o modo paisagem através do método setRotation(1)
      tft.setRotation(1);
    

     

  2. Toda a tela é preenchida pela cor branca através do método fillScreen(BRANCO)
    tft.fillScreen(BRANCO);
    

  3. Utilizando a função escreveTexto iremos escrever o texto: "Controle de acesso" na cor preta na parte superior da tela
    escreveTexto(50,0,"Controle de Acesso",2,PRETO);
    

  4. Logo em seguida criamos uma caixa onde a senha digitada será armazenada conforme os botões forem clicados.
    criarBotao(60,50,200,30,"",PRETO);
    

  5. Sequencialmente, criamos todos os 10 botões que serão utilizados para que o usuário digite a senha para acesso ao sistema. Isso é feito através do método criarBotao(), onda cada botão será desenhado na tela com uma distância de 50 pixels entre um e outro.
      criarBotao(50,100,30,30,"1",VERMELHO);
      criarBotao(100,100,30,30,"2",VERMELHO);
      criarBotao(150,100,30,30,"3",VERMELHO);
      criarBotao(200,100,30,30,"4",VERMELHO);
      criarBotao(250,100,30,30,"5",VERMELHO);
      criarBotao(50,150,30,30,"6",VERMELHO);
      criarBotao(100,150,30,30,"7",VERMELHO);
      criarBotao(150,150,30,30,"8",VERMELHO);
      criarBotao(200,150,30,30,"9",VERMELHO);
      criarBotao(250,150,30,30,"0",VERMELHO);

  6. Por fim, criamos os dois botões responsáveis por apagar caracteres digitados incorretamente, e o botão responsável por validar a senha digitada.
      criarBotao(50,200,120,30,"Apagar",VERMELHO);
      criarBotao(180,200,100,30,"Logar",VERMELHO);

- Função telaAcesso(bool autorizacao)

Agora que temos a nossa tela de controle de acesso criada, iremos precisar criar mais duas telas, uma para quando o acesso for permitido e outra para quando o acesso for negado. Para encapsular todo esse processo e deixa-lo mais transparente, foi criada uma função denominada telaAcesso que funciona da seguinte forma:

  • Caso o argumento recebido seja verdadeiro significa que o acesso foi autorizado, então
    • A Tela é preenchida pela cor preta através do método fillScreen()
      tft.fillScreen(PRETO);
      
    • O cursor é deslocado para o pixel de posição (10,100)
      tft.setCursor(10,100);
      
    • A cor do texto é alterada para verde
      tft.setTextColor(VERDE);
      
    • O tamanho da fonte do texto é alterada para o tamanho 3
      tft.setTextSize(3);
      
    • O texto acesso autorizado é escrito na tela
      tft.print("Acesso Autorizado");
      

    • Após 3 segundos o sistema volta para a tela inicial
  • Caso contrário uma mensagem de acesso negado será escrita em vermelho na tela

- Função Loop()

A função loop por sua vez apenas alterna entre as três telas criadas em nosso sistema sendo cada uma das telas chamadas a cada dois segundos.

void loop() { // Cada uma das três telas que compõem o sistema é chamada a cada dois segundos
telaInicial();
delay(2000);
telaAcesso(true);
delay(2000);
telaAcesso(false);  
delay(2000); 
}

Desafio

Agora que você sabe como construir uma tela para controle de acesso, tente alterar as cores da paleta de cores, para cores que sejam do seu agrado. Adicione também novos botões ao sistema para que ele possa ter uma maior quantidade de combinações possíveis.

Considerações Finais

Este tutorial teve como objetivo ensinar uma forma de elaborar interfaces utilizando a shield display TfT. Além disso foi possível também aprender a como resolver um problema bastante recorrente neste display devido a grande diversidade de controladores utilizados. Este tutorial foi dividido em duas partes devido a complexidade dos passos apresentados, então aguardem que logo logo iremos adicionar a parte touch ao projeto. 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.


Robô seguidor de linha

Robô seguidor de linha

Neste tutorial vamos aprender a fazer um robô seguidor de linha utilizando o sensor de obstaculo infravermelho (Você poderá usar o Módulo Segue Faixa - TCRT5000) em conjunto com um Arduino.

Robô seguidor de linha em competição

Para melhor entendimento deste tutorial é necessário que você já tenha um conhecimento prévio sobre Arduino e ponte H. Mas não se preocupe pois nossa equipe já produziu outros tutoriais sobre esse assuntos e você pode conferir alguns destes nos seguintes links: Entradas e Saídas Analógicas e Módulo Ponte H L298n .

[toc]

kit robotica educacional com Arduino ESP ou Microbit

A importância do robô seguidor de linha

O robô seguidor de linha, também conhecido como seguidor de faixa, é um projeto bem famoso entre os apaixonados por robótica. Quase sempre é o primeiro projeto de robótica móvel.

Em todo o mundo, competições de robótica possuem modalidades únicas  para o seguidor de linha, o que faz deste projeto algo que nunca irá deixar de ser melhorado.

Seu projeto envolve conceitos de dimensionamento de energia, controle de motores, programação de embarcados, entre outros.

Esses mesmos conceitos são levados para projetos maiores e mais complexos, tanto acadêmicos quanto industriais.

Robô seguidor de linha em uma industria
Exemplo de aplicação industrial de um robô seguidor de linha

Robôs seguidores de linha na industria

As aplicações industriais são bem diversificadas. Os robôs que gerenciam o estoque da grande rede de varejos Alibaba, começaram a funcionar com os princípios do seguidor de linha.

Eles manejavam as prateleiras de produtos dentro do estoque por meio de orientação de faixas no chão. Sua função era transportar os materiais de um lado para outro, seja para reajustar o estoque ou para levar para uma área de exportação.

Atualmente o Alibaba evoluiu os robôs, de forma que eles se comunicam, e se localizam, por meio de IA (Inteligência Artificial).

Centro de distribuição do Alibaba com uso de robô
Centro de distribuição do Alibaba

 


Como um robô seguidor de linha funciona ?

O funcionamento do robô seguidor de linha é simples. Ele deve seguir andando por cima de uma linha de cor preta (fita isolante) ou branca.

Os circuitos podem alternar entre as cores do campo e da faixa, no nosso caso iremos assumir que a pista é branca e a faixa é preta.

Usaremos 2 sensores infravermelho que detectam a presença ou não desta faixa. De acordo com a combinação dos sensores, o carrinho irá para frente ou virar para um dos lados.

Funcionamento do sensor infravermelho

O módulo sensor de obstáculo infravermelho IR é bem simples. Ele emite uma luz infravermelha por um LED negro e capta o reflexo com um LED receptor (LED claro).

Como sabemos, a luz reflete em superfícies claras e é absorvida em superfícies negras, como a fita isolante. Sendo assim o LED receptor irá detectar a luz infravermelha no branco e não detectar no preto.

Para uma melhor eficácia do sensor, a superfície em contraste com a faixa preta deve ser branca. Para ajustar a sensibilidade ao contraste, o modulo possui um potenciômetro de calibração.

sensor infravermelho
Funcionamento do sensor infravermelho

Diferença entre sensores infravermelho obstaculo e o TCRT5000

Você pode usar diferentes sensores infravermelhos para o projeto seguidor de linha, o que você precisa levar em conta é as especificações de cada um.

Um sensor infravermelho amplamente utilizado é o TCRT5000, que tem como vantagem seu tamanho e preço. Porem, ele precisa está próximo ao chão para que seja capaz de identificar a faixa, uma vez que seu alcance é de até 8mm. Entretanto, ele possui a vantagem de sofrer menos interferências de luzes infravermelhas externas.

Sensor de linha TCRT5000
Módulo Sensor de linha TCRT5000

Em contrapartida, a vantagem de usar o sensor de obstaculo é o seu maior alcance possuir ajuste, porem ele é mais suscetível a interferências das luzes ambientes.

Sensor de obstáculo infravermelho
Sensor de obstáculo infravermelho

Nesse tutorial, usaremos o sensor de obstaculo infravermelho. Dessa forma, caso esteja usando o TCRT5000, fique atento com a distância do chão. Ele precisa ficar com uma distância entre 1mm e 8mm para ser capaz de detectar a faixa.

Controlando motores com Ponte H

Quando lidamos com controle de cargas que consomem grande quantidade de energia, é importante que essas cargas sejam controladas com circuitos que separem o circuito de controle do circuito de potência.

Para controlar motores, é comum usarmos um circuito chamado ponte H, ele é capaz por controlar o sentido de giro do motor e a sua velocidade, usando o PWM.

PWM

PWM (Pulse Width Modulation – Modulação por Largura de Pulso) é uma técnica para obter resultados analógicos por meios digitais (Leia mais sobre Grandezas digitais e analógicas e PWM).

Essa técnica consiste na geração de uma onda quadrada em uma frequência muito alta em que pode ser controlada a porcentagem do tempo em que a onda permanece em nível lógico alto, alterando, assim, a tensão média.

Por exemplo, se a saída é de 5V, porem ela fica apenas 50% do tempo em 5V e outros 50% do tempo em nível lógico baixo, isso resulta em uma tensão média de 2,5V (50% x 5V).

Dessa forma, esta variável de tempo é capaz de controlar de velocidade do nosso carrinho alterando a tensão média aplicada no motor.

Os valores de PWM variam de 0 (parado) até 255 (velocidade máxima ou 5 V).

Controlando a velocidade do motor através da Ponte H

Existem varias opções de Ponte H, nesse tutorial usaremos o módulo Ponte H com CI L298N que dispões de duas pontes H, sendo capaz assim de controlar dois motores.

Cada ponte H possui um pino que ativa ou não a ponte H. Caso tenha um sinal de 5V aplicado nele, a ponte estará ligada, caso seja 0V a ponte estará desligada. Como temos 2 pontes H, temos o Enable A(Ativa A) e o Enable B (Ativa B).

Normalmente os Enables A e B ficam em curto com um sinal de 5V da placa através de um jumper.

Jumpers Enable A e B

Se retiramos esse jumper e inserimos um sinal PWM nessas entradas, modularemos a tensão que é enviada para o motor. Isso ocorre porque a ponte H só ira “funcionar” enquanto o sinal de Enable estiver com 5V, assim teremos o mesmo efeito de tensão média explicado anteriormente.

Apesar de a ponte H ser controlada por um sinal de 5V, elá pode chavear uma tensão diferente. Podemos, por exemplo, controlar uma tensão de 6V, vindo de um conjunto de 4 pilhas AA. Nesse caso, apesar de o sinal PWM ser de 5V ele modulará os 6V nos motores.

A descrição completa sobre como funciona uma ponte H L298N e como controlar a velocidade de um motor usando uma ponte H L298N pode ser visto nos nossos tutoriais sobre os respectivos assuntos.

 


Montado um robô seguidor de linha com sensor infravermelho

A partir de agora iremos mostrar como montar o seu próprio robô seguidor de linha.

Componentes Necessários

Para este projeto iremos utilizar:

 

Montando o projeto do robô seguidor de linha

Abaixo segue um esquema de ligações e montagem ELETRÔNICA do projeto:

Este projeto possui um procedimento de montagem complexo devido ao fato da necessidade de termos que passar vários fios por um espaço limitado ao tamanho do chassi do seu carrinho.

Calibração do Sensor infravermelho

Ao usar o sensor infravermelho, seja o sensor de obstaculo ou o TCRT5000, você precisa calibrar o sensor para que seja capaz de detectar adequadamente a mudança de cor entre preto e branco.

No vídeo a segui eu mostramos como fazer essa calibração.

Programando o controle do Robô seguidor de linha

A programação do projeto é bem simples. O carrinho precisa fazer a leitura dos sensores e definir pra qual  lado ele deve ir, somente isso, até por que um programa muito extenso pode prejudicar o rendimento.

/*DECLARAÇÃO DE VARIAVEIS*/
#define MotorA_sentido1 2
#define MotorA_sentido2 4
#define MotorB_sentido1 8
#define MotorB_sentido2 9
#define MotorA_PWM 3  
#define MotorB_PWM 10  

#define veloc0 0
#define veloc1 80
#define veloc2 180
#define veloc3 255

#define Sensor_direita 6
#define Sensor_esquerda 7

bool direita, esquerda;

void setup() {
  Serial.begin(9600);
  pinMode(MotorA_sentido1, OUTPUT);
  pinMode(MotorA_sentido2, OUTPUT);
  pinMode(MotorB_sentido1, OUTPUT);
  pinMode(MotorB_sentido2, OUTPUT);
  pinMode(MotorA_PWM, OUTPUT);
  pinMode(MotorB_PWM, OUTPUT);
  pinMode(Sensor_direita, INPUT);
  pinMode(Sensor_esquerda, INPUT);
  
}

void loop() {
   //Define o sentido de rotação dos motores
  digitalWrite(MotorA_sentido1, LOW);
  digitalWrite(MotorA_sentido2, HIGH);
  digitalWrite(MotorB_sentido1, HIGH);
  digitalWrite(MotorB_sentido2, LOW);
  
  //Leituras dos Sensores
  direita = digitalRead(Sensor_direita);
  esquerda = digitalRead(Sensor_esquerda);
  Serial.print(direita);
  Serial.print(" || ");
  Serial.println(esquerda);

  //Rodando os motores dependendo das leituras
 if(direita == false && esquerda == false){
 analogWrite(MotorA_PWM, veloc2);
 analogWrite(MotorB_PWM, veloc2);
 } else if(direita == false && esquerda == true){
 delay(400);
 analogWrite(MotorA_PWM, veloc2);
 analogWrite(MotorB_PWM, veloc1);
 delay(400);
 }else if(direita == true && esquerda == false){
 delay(400);
 analogWrite(MotorA_PWM, veloc1);
 analogWrite(MotorB_PWM, veloc2);
 delay(400);
 
 }else if(direita == true && esquerda == true){
 analogWrite(MotorA_PWM, veloc0);
 analogWrite(MotorB_PWM, veloc0);
 }
}

Colocando o Robô seguidor de linha para funcionar

Agora é só por o carrinho pra rodar na pista !

Robô seguidor de linha montado
Robô seguidor de linha montado

 

Problemas comuns e como resolver

Vale notar que ele pode não fazer o percurso de primeira, o que significa que ajustes devem ser feitos no código ou ate mesmo no hardware. Alguns problemas comuns de acontecer:

  • Bateria fraca - Os testes podem ter consumido a bateria e talvez seja necessário o uso de uma nova. Baterias abaixo de 6,5 Volts já começam a diminuir a eficiência do carrinho.
  • Carrinho saindo da pista - Isso pode acontecer por ele estar rápido de mais ou por falha do infravermelho. Em caso de ele estar muito rápido basta trocar a velocidade dos motores em cada situação, o nosso código já possui outras velocidades definidas no cabeçalho. Se o problema for com o contraste da pista (talvez parte dela esteja mais escura) use 2 LEDs de alto brilho na frente do carrinho para iluminar a pista próximo aos sensores. Os LEDs podem ir conectados diretos no 5 V do arduino (lembrando de por um resistor de 300Ohms).
  • Carrinho não roda - Este é um problema complexo, pois podem ser infinitas possibilidades. Tente isolar os componentes e testar 1 por 1, principalmente os motores e a ponte H. Em alguns casos pode ser problemas de aterramento da bateria também.

Entendendo a fundo o Software

Declaração de Variáveis

Na primeira parte do código é feita a declaração das variáveis a serem utilizadas. Nota-se que a existe um grande numero de variáveis utilizando #define, isto é por conta de serem apenas nomes associados a números, não precisamos fazer contas com essas variáveis, portanto elas não precisam ser do tipo INT, FLOAT, entre outras.

O fato de declarar algo por meio de #define ocupa menos espaço de memória, o que dá um ganho na velocidade de execução do programa. As únicas variáveis a serem definidas por um tipo são as que armazenarão os valores lidos dos sensores (direita e esquerda), essas variáveis são do tipo bool e portanto só assumem dois estados (FALSE e TRUE).

/*DECLARAÇÃO DE VARIAVEIS*/
#define MotorA_sentido1 2
#define MotorA_sentido2 4
#define MotorB_sentido1 8
#define MotorB_sentido2 9
#define MotorA_PWM 3  
#define MotorB_PWM 10  

#define veloc0 0
#define veloc1 80
#define veloc2 180
#define veloc3 255

#define Sensor_direita 6
#define Sensor_esquerda 7

bool direita, esquerda;

Cada motor possui 3 pinos: 2 para definir o sentido de rotação da roda (IN1 e IN2 / IN3 e IN4) e 1 pra definir a velocidade de rotação (Enable A / Enable B)por meio de valores PWM. Lembre-se de que os pinos de velocidade devem conter o "~" desenhado ao lado da porta na placa Arduino, caracterizando o pino como PWM.

Declaramos também 4 velocidades de PWM que podem ser interpretadas como PARADO, DEVAGAR, NORMAL e RÁPIDO, respectivamente. Os sensores foram definidos em suas respectivas portas digitais(6 e 7) e por fim, foram declaradas 2 variáveis do tipo BOOL para armazenar os valores dos sensores.

Função Void Setup()

A função void setup, que roda apenas uma vez, defini todas as configurações necessárias para funcionamento do sistema.

void setup() {
  Serial.begin(9600);
  pinMode(MotorA_sentido1, OUTPUT);
  pinMode(MotorA_sentido2, OUTPUT);
  pinMode(MotorB_sentido1, OUTPUT);
  pinMode(MotorB_sentido2, OUTPUT);
  pinMode(MotorA_PWM, OUTPUT);
  pinMode(MotorB_PWM, OUTPUT);
  pinMode(Sensor_direita, INPUT);
  pinMode(Sensor_esquerda, INPUT);
  
}

Nesta função declaramos as variáveis que definem os pinos utilizados no Arduino como sendo Entrada(INPUT) ou Saída(OUTPUT). Além disso colocamos a função Serial.begin() que inicializa a comunicação serial entre o Arduino e o computador.

MAS O CARRINHO NÃO RODA LIGADO NA BATERIA ?!?!?! Sim, porém precisamos fazer testes antes de executar a versão final, para isso utilizamos alguns comandos via serial para poder calibrar sensores, averiguar execução do programa, entre outros.

Função  Void Loop ()

Em seguida temos o loop do nosso programa onde o carrinho ira fazer suas principais funções.

- Definindo sentido de giro dos motores

Primeiro é necessário definir o sentido de rotação das rodas.

//Define o sentido de rotação dos motores
  digitalWrite(MotorA_sentido1, LOW);
  digitalWrite(MotorA_sentido2, HIGH);
  digitalWrite(MotorB_sentido1, HIGH);
  digitalWrite(MotorB_sentido2, LOW);

Nesta parte do código precisamos mandar um sinal alto e um sinal baixo entre os pares de portas IN1/IN2 e IN3/IN4. Como nosso carrinho não anda pra trás nós vamos setar essas configurações para que as rodas girem no mesmo sentido(pra frente no caso).

Veja que os pares no nosso código estão invertidos, isso acontece por que a montagem de hardware foi invertida entre os motores.

É como se os polos fossem trocados de lugar entre os motores, porém lembre-se que motores DC não possuem polaridade definida, logo podemos inverter a ligação + e - sem problemas. Isso altera apenas o sentido para o qual o motor gira. Essa é uma das partes que devem ser testadas antes da montagem final do carrinho.

- Leituras dos Sensores

Adiante, temos as leituras dos sensores infravermelhos e a impressão na serial dos valores lidos. Isso é apenas para verificar se os sensores estão funcionando corretamente, não interferindo no funcionamento final do projeto.

//Leituras dos Sensores
  direita = digitalRead(Sensor_direita);
  esquerda = digitalRead(Sensor_esquerda);
  Serial.print(direita);
  Serial.print(" || ");
  Serial.println(esquerda);

As variáveis do tipo BOOL são utilizadas para armazenar os valores digitais lidos pelos sensores.

- Controlando a direção do robô

Por fim, temos as condições de giro do motor com base no sensores infravermelhos.

//Rodando os motores dependendo das leituras
 if(direita == false && esquerda == false){
 analogWrite(MotorA_PWM, veloc2);
 analogWrite(MotorB_PWM, veloc2);
 } else if(direita == false && esquerda == true){
 delay(400);
 analogWrite(MotorA_PWM, veloc2);
 analogWrite(MotorB_PWM, veloc1);
 delay(400);
 }else if(direita == true && esquerda == false){
 delay(400);
 analogWrite(MotorA_PWM, veloc1);
 analogWrite(MotorB_PWM, veloc2);
 delay(400);
 
 }else if(direita == true && esquerda == true){
 analogWrite(MotorA_PWM, veloc0);
 analogWrite(MotorB_PWM, veloc0);
 }

Para isso, utilizamos as condições IF Else, que são mais comum. São 2 variáveis combinatórias que geram 4 possibilidades, porém a ultima condição é quase "impossível" (true e true), pois seria a leitura dos sensores detectando a faixa preta ao mesmo tempo (como é um erro estranho, o carrinho deve parar).

Os motores estão ligados em portas DIGITAIS mas lembre-se que estamos utilizando valores PWM, logo as funções de comando são do tipo analogWrite(porta, PWM). Para que o carrinho possa ter tempo de verificar o estado dos sensores novamente, alguns delays de curto período são utilizados, mas isso pode variar de projeto para projeto.

Entendendo a fundo o Hardware

O carrinho funciona com uma comunicação entre os sensores, o Arduino e a ponte H controlando os motores.

Através das leituras do sensores enviadas para o Arduino por meio das portas digitais, o controlador irá acionar um motor mais rápido ou mais devagar do que o outro. Os sensores emitem 5 V (faixa preta) ou 0 V(pista branca) para as portas digitais. O Arduino modula os valores de velocidade pelos valores PWM que variam de 0 volts (0) até 5 volts (255), fazendo isso ao longo de todo trajeto.

Observe que utilizamos apenas 1 bateria para todo o sistema. A bateria que alimenta o Arduino pelo pino P4 energiza não somente o controlador como também a ponte H dos motores por meio do pino Vin do Arduino. Esta porta é capaz de emitir valores maiores do que os 5 volts que o regulador de tensão da placa utiliza. Sendo assim a tensão de entrada no pino P4 é a mesma do pino Vin.


Conclusão

Este é um dos projetos mais simples de robótica móvel utilizando Arduino e claro que pode ser melhorando em muitos aspectos.

Algumas sugestões de melhorias são:  controle de velocidade PID, desvio de obstáculos, reconhecimento de pista, machining learning, etc.

Desafio

Crie uma função para o robô desviar de obstáculos e retornar para a pista. O sensor ultrassônico é uma ótima opção para ajudar nesse desafio.


Sensor de Distância Infravermelho Sharp GP2Y0A21YK0F

Sensor de Distância Infravermelho Sharp GP2Y0A21YK0F

Ao desenvolvermos projetos voltados a robótica ou sistemas para detecção de corpos, precisamos sempre utilizar sensores de distância. Estes dispositivos nos permitem detectar obstáculos que possam estar no caminho do nosso robô, ou até mesmo identificar se alguém, ou algum objeto passou, pelo local.  Já vimos em outro tutorial que é possível medir distancias através som, usando, por exemplo, o famoso sensor ultrassônico HC-SR04. Além do som, podemos usar a luz infravermelha para medir distancias, usando, por exemplo, o Sensor Sharp GP2Y0A21YK0F, que é pequeno, robusto e capaz de medir distância com precisão e velocidade surpreendentes. Outra vantagem desse sensor é o fato de sua implementação junto ao Arduino ou outro microcontrolador ser muito simples. Dessa forma, neste tutorial você aprenderá a utilizar o sensor de distância infravermelho da Sharp (10cm a 80cm) em conjunto com um Arduino.

[toc]

kit robotica educacional com Arduino ESP ou Microbit

Sensor infravermelho Sharp GP2Y0A21YK0F

O sensor infravermelho Sharp GP2Y0A21YK0F é um sensor de distância voltado a projetos em que precisamos de uma boa precisão na distância com resposta rápida.

Com uma interface de comunicação bem simples, esse sensor conta com apenas três pinos, sendo dois para alimentação e um para saída. O módulo Sharp GP2Y0A21YK0F é capaz de medir distâncias de 10 cm até 80 cm, fornecendo como saída de dados um valor analógico que é inversamente proporcional a distância lida ( quanto mais longe menor a tensão ).

  • Especificações:
    • Alimentação: 4,5 V até 5,5 Volts
    • Distância: 10 até 80cm
    • Sinal de Saída: Analógico
    • Consumo: Aproximadamente 30 mA

 

Sensor de distância infravermelho Sharp GP2Y0A21YK0F
Sensor infravermelho Sharp GP2Y0A21YK0F

Funcionamento do sensor

O sensor Sharp GP2Y0A21YK0F é composto por basicamente três componentes:

  • Unidade de controle do emissor infravermelho: Responsável por emitir a luz infravermelha. Este conjunto é composto pela unidade de controle e o led emissor. Unidade de processamento de sinais: Responsável por ler o sinal emitido pela unidade emissora. Este conjunto é composto pela unidade  de cálculo de distância e receptor infravermelho.
  • Circuito de saída analógica: Circuito responsável por converter o sinal vindo da unidade de processamento em uma onda analógica equivalente a distância lida.
Estrutura física do circuito responsável por calcular a distância

Para calcular a distância, executa-se o seguinte processo:

  • Inicialmente o módulo de controle do emissor infravermelho é ativo e o led infravermelho dispara um feixe de luz ( invisível ao olho humano) no objeto em questão
Processo de emissão
  • Quando a luz chega até um determinado objeto, uma parte costuma ser absorvida e uma outra parte refletida, sabendo disso, a unidade de processamento de  sinais é capaz de medir a distância baseada na quantidade de luz que foi refletida pelo objeto.
Reflexão
  • Através de cálculos com a luminosidade recebida pelo receptor e algoritmos de triangulação, a unidade de processamento de sinais é capaz de aferir a distância e com o auxílio de um circuito de saída, retornar um valor analógico equivalente a distância lida.
Distancia em valor analógico

 


Mãos à obra - Acionamento de leds baseado na distância

Para ilustrar o funcionamento desse sensor, vamos construir uma aplicação bem simples, onde utilizando dois leds ( azul e vermelho ) iremos definir se um objeto está próximo ou não.

Componentes Necessários

Montando o projeto

A montagem deste projeto é bem simples, pois neste tutorial iremos apenas utilizar duas portas digitais e uma analógica de nosso Arduino. Sabendo disso, a montagem será feita com base no o seguinte esquema de ligação:

Vejam só como ficou a montagem final :)

 

Antes de ligar o seu circuito, verifique se todas as conexões foram feitas corretamente. Um curto circuito causado por uma ligação errada pode danificar todo o seu projeto.

 

Programando

Agora que montamos o nosso projeto, iremos partir para a parte do código. Nesta versão não será necessário o uso de nenhuma biblioteca de terceiros, já que o sensor fornece uma saída analógica que pode ser lida através do método AnalogRead(). Porém, teremos  que fazer um pequeno estudo sob o comportamento do sinal analógico resultante da leitura do sensor, estimando com base em sua onda uma formula fechada que nos informe a distância aproximada com base na leitura realizada. O código abaixo ilustra todo o processo de leitura dos dados.

/* Nome: Acionamento de leds com sensor de distância IR
 * Feito por: Danilo Almeida
 * Data: 20/12/2017
 */

#define pinoAnalogico A0          // Definição do pino Analógico utilizado na leitura do sensor de distância
#define ledAzul 2                 // Definição do pino digital onde iremos ligar o led azul
#define ledVermelho 3             // Definição do pino digital onde iremos ligar o led vermelho
void setup() {
  Serial.begin(9600);             // Inicialização da comunicação serial ( Caso queira ver a distância em cm )
  pinMode(ledAzul,OUTPUT);        // Inicialização do led azul como saída
  pinMode(ledVermelho,OUTPUT);    // Inicialização do led vermelho como saída
  digitalWrite(ledAzul,LOW);      // Inicia o led azul em nível lógico baixo ( desligado )
  digitalWrite(ledVermelho,LOW);  // Inicia o led vermelho em nível lógico alto ( desligado)
}

void loop() {
   // Obtenção do valor em Volts através da formula ( valorAnalógico * (5/1023) )
   double valorVolts = analogRead(pinoAnalogico) * 0.0048828125; 

   // Formula para cálculo da distância levando em consideração o valor em volts
   double distancia = 4800/(valorVolts*200 - 20 ); 
  

   Serial.print(distancia);
   Serial.println(" CM");
   // Se a distância for maior que 20 CM ligamos o led azul e desligamos o led Vermelho
   if (distancia>=20){ 
     digitalWrite(ledAzul,HIGH);
     digitalWrite(ledVermelho,LOW);
   }
   // Caso contrário ligamos o led vermelho e desligamos o azul
   else{ 
     digitalWrite(ledAzul,LOW);
     digitalWrite(ledVermelho,HIGH);
   }

   // Bloqueio de execução por 100 ms
   delay(100); 

}

Colocando pra funcionar

 


Entendendo a Fundo

Software

- Declaração de pinos utilizados

Inicialmente  declaramos todos os pinos que utilizaremos, tanto para leitura do sensor quanto para ligar e delisgar leds. O trecho de código abaixo ilustra a definição dada a cada pino utilizado.

#define pinoAnalogico A0      // Definição do pino Analógico utilizado na leitura do sensor de distância
#define ledAzul 2             // Definição do pino digital onde iremos ligar o led azul
#define ledVermelho 3         // Definição do pino digital onde iremos ligar o led vermelho

- Função Setup

Na função setup iremos configurar os pinos utilizados para ligar e desligar os leds. Iremos também inicializar a comunicação serial para fins de depuração da distância calculada.

void setup() {
  Serial.begin(9600);            // Inicialização da comunicação serial ( Caso queira ver a distância em cm )
  pinMode(ledAzul,OUTPUT);       // Inicialização do led azul como saída
  pinMode(ledVermelho,OUTPUT);   // Inicialização do led vermelho como saída
  digitalWrite(ledAzul,LOW);     // Inicia o led azul em nível lógico baixo ( desligado )
  digitalWrite(ledVermelho,LOW); // Inicia o led vermelho em nível lógico alto ( desligado)
}

- Função loop

Já na função loop faremos todo o processo de leitura e cálculo da distância, baseados na saída analógica fornecida pelo sensor.  Na linha abaixo, realizamos uma conversão do valor vindo do circuito ADC do Arduíno em um valor de tensão equivalente a saída do sensor. Basicamente multiplicamos o valor lido do  ADC pela razão entre o nível de tensão utilizado como referência 5 Volts pela amplitude do circuito ADC, que no caso do Arduíno é 210 .

// Obtenção do valor em Volts através da formula ( valorAnalógico * (5/1023) )
  double valorVolts = analogRead(pinoAnalogico) * 0.0048828125; 

Com o valor em volts em mãos, podemos partir para a equação da distância, que é dada pela seguinte equação:

Onde V0 é o valor em  volts lido na porta analógica e  d é a distância em cm. Essa equação foi obtida através da análise da onda comportamental do circuito na figura abaixo:

Sinal resultante da distância lida pelo sensor.
double distancia = 4800/(valorVolts*200 - 20 ); // Formula para cálculo da distância levando em consideração o valor em volts

Por fim, com a distância calculada verificamos se existe um objeto a menos de 20 cm de distância, caso exista, o led vermelho é aceso e o azul é apagado, caso  contrário o led azul é aceso e o vermelho é apagado.

Serial.print ("Distancia: ");
Serial.println(distancia);  
if (distancia>=20){   // Se a distância  for maior que 20 CM ligamos o led azul e desligamos o led Vermelho
    digitalWrite(ledAzul,HIGH);
    digitalWrite(ledVermelho,LOW);
  }
  else{               // Caso contrário ligamos o led vermelho e desligamos o azul
    digitalWrite(ledAzul,LOW);
    digitalWrite(ledVermelho,HIGH);
  }
delay(100);

Desafio

Agora que você é capaz de acionar e apagar leds apenas com base na distância de um objeto, tente fazer com que outro tipo de dispositivo seja acionado ao se aproximar. Um tipo de acionamento largamente utilizado consiste em acionar um relé ao se aproximar de um sensor de distância, com base nisso, use o artigo Módulo relé - Acionando cargas com Arduino e tente fazer com que um relé acione ao detectar um objeto em uma determinada  distância.Considerações Finais

Este tutorial teve como objetivo apresentar uma ótima alternativa aos sensores ultrassônicos de distância. Através da utilização do sensor Sharp GP2Y0A21YK0F é possível medir pequenas distâncias com uma ótima precisão, o que facilita bastante a elaboração e controle de processos onde necessitamos que a distância medida tenha uma boa precisão e um baixo tempo  de resposta. 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.

Referências

Tudo que foi explicado neste tutorial pode ser encontrado no datasheet do dispositivo, que se encontra no seguinte link:


Conheça o que é o LilyPad e dê vida às suas roupas

Conheça o que é o LilyPad e dê vida às suas roupas

Uma das áreas relacionadas ao mundo maker que tem ganhado força é a wearable, área destinada ao estudo e aplicação das "tecnologias vestidas", onde componentes e circuitos eletrônicos são integrados à peças de roupas e acessórios para criar sistemas automáticos e interativos. No que se refere à essas soluções vestíveis, a placa de desenvolvimento LilyPad tem sido muito usada. Ela funciona como uma placa Arduino, só que foi projetada visando o uso em roupas e acessórios.

[toc]

Dando vida às roupas

A placa LilyPad é uma derivada das placas Arduino que visa atender projetos portáteis. Ela funciona conectada a baterias recarregáveis e pode ser integrada a projetos wearableEla foi desenhada e desenvolvida pela engenheira e designer Leah Buechley em conjunto com a SparkFun.

Vista frontal da placa LilyPad
Vista frontal da placa

A placa em questão foi desenvolvida de maneira que fosse de fácil instalação em tecidos, nos quais é possível montar circuitos utilizando-a integrada a outros módulos, costurando-os com uma linha condutora, como podemos ver abaixo.

Exemplo de aplicação - Wearable

O hardware da placa pode ser visualizado logo abaixo. Por utilizar o mesmo microcontrolador que o Arduino Uno, a pinagem acaba sendo semelhante.

Hardware do modelo utilizado neste tutorial

Exitem cerca de quatro modelos diferentes da família, que são:

  • LilyPad Arduino Simple;
  • LilyPad Arduino Main Board;
  • LilyPad Arduino USB;
  • LilyPad Arduino Simple Snap.

Vamos agora conhecer mais sobre cada uma, vendo suas características e vantagens.

LilyPad Arduino Simple

Possui ao todo 9 pinos que podem ser utilizados como INPUT / OUTPUT digitais, onde 5 deles podem ser utilizados para PWM e 4 podem ser utilizados como entrada analógica. Seu microcontrolador é o ATmega328p e sua tensão de operação é de 2,7 até 5,5V. Ela apresenta também um conector JST, no qual podem ser conectadas baterias de lítio de 3,7V. Para ser programado pela IDE do arduino, a placa em questão precisa ser conectado a um adaptador FTDI para com isso, ser conectado ao computador.

Imagem da LilyPad Arduino Simple

LilyPad Arduino Main Board

É a que apresenta o maior número de pinos em relação as outras, totalizando 14 pinos, no qual 6 podem ser utilizados para PWM e 6 podem ser utilizados como entrada analógica. Algumas versões possuem o ATmega168 como microcontrolador, enquanto outras possuem o ATmega328p. Sua tensão de operação está na faixa de 2,7 até 5,5V. Assim como o modelo anterior, necessita de um conversor FTDI.

Imagem da LilyPad Arduino Main Board

LilyPad Arduino USB

Assim como a LilyPad Simple, essa também apresenta 9 pinos, onde 4 podem ser PWM e quatro podem servir como entrada analógica. Sua principal diferença para o modelo Simple, é que este possui um conector micro USB, onde ele poderá ser conectado diretamente ao computador, sem a necessidade de um adaptador FTDI. Seu microcontrolador é o ATmega32u4, e pode ser alimentado na faixa de 3,8 até 5V.

Imagem do LilyPad Arduino USB

LilyPad Arduino Simple Snap

No aspecto visual, esta é a placa que mais se difere das demais, por apresentar encaixes condutores ao invés de furos. Em questão de hardware, se assemelha muito com o LilyPad Simple, apresentando assim 9 pinos ao todo, onde 4 podem ser PWM, e 4 podem ser entradas analógicas. Seu microcontrolador é o ATmega328p. Como o modelo Simple e o Main Board, o Simple Snap também necessita de um adaptador FTDI para ser conectado ao computador, para assim ser programado.

Imagem do LilyPad Simple Snap

 


Mãos à obra - Começando com o tradicional Blink

Componentes necessário

Para este tutorial, tenha em mãos os seguintes itens:

Montando o projeto

Ensinaremos a você como passar a programação da IDE pro LilyPad por meio do Arduino Uno, sem a necessidade de se utilizar o conversor FTDI. O código que passaremos ao LilyPad será o nosso famoso e querido blink.

Primeiramente, precisamos preparar o arduino UNO para que ele seja o nosso "adaptador FTDI". O primeiro passo é remover o ATmega328p do seu arduino UNO, como pode-se ver abaixo.

Arduino com e sem o microcontrolador ATmega328p

AVISO: Cuidado ao remover o microcontrolador, pois há risco de se quebrar um terminal caso seja removido de maneira indevida.

Após isso, monte o circuito representado abaixo.

Ligações realizadas

Pronto! Agora você poderá programar sua LilyPad sem problemas por meio da IDE do Arduino!

Programando

O código que será passado já é conhecido por todos, no qual consiste em deixar o LED presente na placa acesso por 1 segundo, e apagado por mais 1 segundo.

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

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

Pelo fato dessa placa apresentar o microcontrolador ATmega328p, o mesmo presente no Arduino UNO, na opção de "Placa" podemos selecionar a opção "Arduino/Genuino Uno", sem a necessidade de ter que adicionar novas placas a IDE.

Colocando pra funcionar

Aqui podemos ver o resultado na prática, do blink.


Entendendo a fundo

Software

Relembrar é sempre bom, então falaremos o que irá ocorrer em cada linha do código.

Primeiramente inicia-se a programação configurando o pino 13 como saída (OUTPUT) no void setup().

pinMode(13, OUTPUT);

Após isso, é realizado os seguintes comandos no void loop():

  • Define o estado lógico do pino 13 como alto, ligando o LED presente na placa;
  • Ocorre uma espera de 1 segundo para a execução da próxima linha de programação;
  • Define o estado lógico do pino 13 como baixo, desligando o LED presente na placa;
  • Ocorre uma espera de 1 segundo para a execução da próxima linha de programação.
digitalWrite(13, HIGH);
delay(1000);
digitalWrite(13, LOW);
delay(1000);

Considerações finais

Esperamos que este tutorial tenha lhe esclarecido sobre como utilizar a placa LilyPad, principalmente a respeito de sua programação.


Módulo RF 433Mhz - Comunicação entre Arduinos

Módulo RF 433Mhz - Comunicação entre duas placas Arduino 

Na maioria das vezes em que falamos sobre comunicação sem fio, pensamos imediatamente no acesso à internet através de computadores ou celulares por meio de algum modem ou roteador que esteja disponibilizando o sinal para tal propósito, no entanto, existem muitos outros métodos de comunicação sem fio. Neste tutorial, demonstraremos como é possível estabelecer uma comunicação sem fio entre duas placas Arduino via radiofrequência, utilizando os módulos Receptor e Transmissor RF 433Mhz (Módulo RF 433Mhz).

[toc]

O que é radiofrequência?

Quando pesquisamos sobre o que vem a ser o conceito de radiofrequência, nos deparamos com várias definições, no entanto, a mais adequada é que afirma que a radiofrequência consiste em uma faixa de frequências que engloba valores de aproximadamente 3KHz (algumas referências trazem valores de 9KHz, 10KHz) até 300GHz, os quais, correspondem ao intervalo de frequências utilizadas por ondas de rádio.

O uso da radiofrequência permite o controle dos mais diversos dispositivos sem que seja necessária a utilização de qualquer tipo de fio. Podemos facilmente encontrar aplicações que utilizam a radiofrequência para atender os seus propósitos, como por exemplo, os portões eletrônicos de residências, os quais, através de um controle remoto operando dentro de uma determinada faixa de frequência, pode-se acionar o motor do portão a uma grande distância.

Controle de portão eletrônico

Os módulos Receptor e Transmissor RF433Mhz

Para realizar o projeto vamos utilizar dois módulos (apresentados na figura abaixo) para que possamos estabelecer uma comunicação sem fio entre duas placas Arduino e assim, comandar uma delas através da outra.

Módulos RF 433Mhz
Módulos RF 433Mhz

Estes módulos trabalham à uma frequência de 433MHz e tem um alcance de até 90 metros em espaços abertos. Através da utilização destes, é possível realizar transferência de dados em uma velocidade que pode variar até 9200 bits por segundo, de modo que, quanto maior for a distância entre o elemento transmissor e o elemento receptor, menor deve ser a velocidade na transmissão dos dados para diminuir a probabilidade de erros.

Na figura acima, o módulo apresentado do lado direito, é o módulo transmissor. Este contem três pinos: Um para alimentação, outro para o terra e o último para dados. Por outro lado, o módulo presente do lado esquerdo, é o módulo receptor e apesar de este conter 4 pinos, utilizamos apenas 3 deles (assim como o módulo transmissor, utilizamos um pino para alimentação, um para o terra e outro para dados.


Mãos à obra - Comunicando duas placas Arduino via radiofrequência

Nesta seção iremos demonstrar todos os passos que você deve seguir para aprender fazer com que duas placas Arduino se comuniquem via radiofrequência.

Componentes necessários

Montando o projeto

Neste tutorial temos dois hardwares que serão utilizados. O primeiro deles irá conter um Arduino Micro, que por sua vez, irá atuar em conjunto com um módulo Transmissor RF 433Mhz.

Módulo Transmissor RF 433Mhz com Arduino Micro
Módulo Transmissor RF 433Mhz com Arduino Micro

O segundo hardware irá conter um Arduino UNO, o qual, irá atuar em conjunto com um módulo Receptor RF 433Mhz.

Módulo RF 433Mhz - Módulo Receptor RF 433Mhz com Arduino UNO
Módulo Receptor RF 433Mhz com Arduino UNO

Programando

Conforme apresentado no tópico anterior, o projeto a ser desenvolvido neste tutorial utiliza duas placas Arduino, portanto, teremos a presença de dois códigos para serem gravados em ambas as placas. Primeiramente, apresentamos o código a ser gravado no Arduino Micro, que por sua vez, estará atuando no envio das informações.

#include <VirtualWire.h>
 
bool estado_led;
char data[2];
 
void setup()
{
  vw_set_tx_pin(5);
  vw_setup(2000);  
  
}
 
void loop()
{
  estado_led = !estado_led;
  itoa(estado_led, data, 2);
  vw_send((uint8_t *)data, strlen(data)); 
  vw_wait_tx(); 

  delay(2000);
  }  
 

Em seguida, apresentamos o código a ser gravado no Arduino UNO, que em nosso projeto, deverá receber as informações obtidas pelo Receptor RF433 Mhz.

#include <VirtualWire.h>
 
byte message[VW_MAX_MESSAGE_LEN];    // Armazena as mensagens recebidas
byte msgLength = VW_MAX_MESSAGE_LEN; // Armazena o tamanho das mensagens
 
 
void setup()   {

    vw_set_rx_pin(5); // Define o pino 5 do Arduino como entrada 
//de dados do receptor
    vw_setup(2000);             // Bits por segundo
    pinMode(13,OUTPUT);
    vw_rx_start();              // Inicializa o receptor

 
}
 
void loop()
{
    if (vw_get_message(message, &msgLength)) // Non-blocking
    {
        Serial.print("Recebido: ");
        Serial.write(message[0]);
        if(message[0] == '0'){
          digitalWrite(13, LOW);
        }
        else if(message[0] == '1'){
          digitalWrite(13,HIGH);
        }
    }
}

Entendendo a fundo

Software - Arduino Micro / Transmissor RF 433Mhz   

- Incluindo a biblioteca que será utilizadas

Primeiramente, para desenvolvermos uma aplicação como esta, devemos incluir a biblioteca que será utilizada no código, para que assim, o mesmo possa funcionar de maneira adequada. A biblioteca VirtualWire.h é responsável pela comunicação que será estabelecida entre o Arduino UNO e o Arduino Micro através do par Transmissor/Receptor RF 433Mhz.

#include <VirtualWire.h>

-Declarando as variáveis do projeto

Posteriormente, temos um bloco onde ocorre a declaração das variáveis que serão utilizadas no decorrer do programa. A variável estado_led (do tipo booleana) é responsável por armazenar o valor referente ao estado desejado do led (que será acionado na placa Arduino receptora) e a variável data, que por sua vez, é um vetor de caracteres, terá a função de armazenar o dado que será enviado (posteriormente explicaremos o motivo desta variável ter duas posições).

bool estado_led;
char data[2];

- Estabelecendo as configurações iniciais

Na função setup(), utilizamos duas funções de configuração do módulo transmissor. A primeira delas é a função vw_set_tx_pin(), que por sua vez, é responsável por determinar qual pino do Arduino Micro será utilizado para enviar os dados da placa para o módulo Transmissor RF 433Mhz.

A outra função existente neste bloco é a função vw_setup(), a qual, serve para inicializar a comunicação entre o Arduino Micro e o módulo Transmissor RF 433Mhz, de modo que, ao utilizarmos a mesma, devemos passar como parâmetro a velocidade de transmissão em bits por segundo.

void setup()
{
  vw_set_tx_pin(5);
  vw_setup(2000);  
}

- Enviando dados através do transmissor RF 433Mhz

Dentro da função loop() vamos estabelecer toda parte referente ao envio dos dados propriamente dito. O primeiro passo a ser realizado é a inversão do conteúdo armazenado na variável estado_led, de modo que, como esta variável é do tipo booleana, os valores irão sendo alternados entre 0 e 1 a cada passagem pelo ciclo da função loop().

estado_led = !estado_led;

Em seguida, utilizamos a função itoa() para transformar o valor contido na variável estado_led em uma string e armazenar este valor, já transformado, na variável data (como dissemos anteriormente, esta variável possui duas posições, pois, após o processo de conversão de um determinado número em string, além do mesmo, surge também como resultado, o caractere terminador de strings "\0") .

A função itoa() possui 3 parâmetros, dos quais, o primeiro refere-se à variável cujo valor queremos transformar em string. O segundo, é a variável na qual queremos guardar o resultado gerado e a terceira é o tipo de dado que estamos convertendo, logo, como estamos convertendo um valor binário, utilizamos o número 2 nesta posição.

itoa(estado_led, data, 2);

Posteriormente, utilizamos a função vw_send() para enviar os dados para o Transmissor RF433Mhz transmiti-los  (note que esta função possui 2 parâmetros, de modo que, o primeiro deles refere-se à variável que queremos enviar e o seguindo diz respeito ao tamanho da mesma. Sugerimos que utilize esta função neste formato, trocando apenas o nome da variável que você irá utilizar).

 vw_send((uint8_t *)data, strlen(data));

Por fim, utilizamos a função vw_wait_tx() para que o programa aguarde a transferência total da mensagem e a função delay() para estipular o tempo que o led levará para trocar de estado.

vw_wait_tx(); 
delay(2000);

Veja como ficou nossa função loop()

void loop()
{
  estado_led = !estado_led;
  itoa(estado_led, data, 2);
  vw_send((uint8_t *)data, strlen(data)); 
  vw_wait_tx(); 

  delay(2000);
  }

Software - Arduino UNO / Receptor RF 433Mhz   

- Incluindo a biblioteca que será utilizadas

Assim como no programa desenvolvido para o Arduino Micro, devemos incluir a biblioteca que será utilizada neste código, para que assim, o mesmo possa funcionar de maneira adequada. A biblioteca VirtualWire.h é responsável pela comunicação que será estabelecida entre o Arduino UNO e o Arduino Micro através do par Transmissor/Receptor RF 433Mhz.

#include <VirtualWire.h>

-Declarando as variáveis do projeto

Posteriormente, temos um bloco onde ocorre a declaração das variáveis que serão utilizadas no decorrer do programa. As variáveis tamanho_msg e msg, ambas do tipo byte, são responsáveis por armazenar informações referentes às mensagens que serão recebidas, para que, utilizando as mesmas, seja possível interpretá-las e tomar as ações necessárias com base no conteúdo recebido.

Apenas a título de curiosidade, o elemento VW_MAX_MESSAGE_LEN é próprio da biblioteca utilizada e armazena o valor referente ao tamanho da mensagem.

byte tamanho_msg = VW_MAX_MESSAGE_LEN; 
byte message[VW_MAX_MESSAGE_LEN];

- Estabelecendo as configurações iniciais

Na função setup(), utilizamos três funções para a configuração do módulo receptor. A primeira delas é a função vw_set_rx_pin(), que por sua vez, é responsável por determinar qual pino do Arduino UNO será utilizado para receber os dados enviados do módulo Receptor RF 433Mhz para a placa Arduino utilizada.

A segunda função existente neste bloco é a função vw_setup(), a qual, serve para inicializar a comunicação entre o Arduino UNO e o módulo Receptor RF 433Mhz, de modo que, ao utilizarmos a mesma, devemos passar como parâmetro a velocidade de transmissão em bits por segundo (note que esta informação deve ser igual à estabelecida no módulo Transmissor RF 433Mhz). Por fim, através da função vw_rx_start() inicializamos a função de recebimento de dados do Receptor RF 433Mhz. Além disso, definimos o modo de operação do pino 13 através da função pinMode().

void setup()   {
   vw_set_rx_pin(5); // Define o pino 5 do Arduino como entrada 
   vw_setup(2000);  
//Serial.begin(9600);
  //while(!Serial){}
    
//de dados do receptor
    vw_setup(2000);             // Bits por segundo
    pinMode(13,OUTPUT);
    vw_rx_start();              // Inicializa o receptor 
}

- Recebendo dados através do Receptor RF 433Mhz

Basicamente, o que fazemos na função loop() é conferir se houve o recebimento de algum dado através da função vw_get_message() e caso tenha, verificamos se este valor, em string, corresponde ao caractere 0, o qual, será responsável por fazer com que o led seja apagado. Em contrapartida, caso, o valor encontrado seja o caractere 1, o led deverá ser acionado.

void loop()
{
uint8_t message[VW_MAX_MESSAGE_LEN];    
uint8_t msgLength = VW_MAX_MESSAGE_LEN; 
 
  //display.setCursor(0, 0);  //Seta a posição do cursor
    if (vw_get_message(message, &msgLength)) // Non-blocking
    {
        Serial.print("Recebido: ");
        Serial.write(message[0]);
        if(message[0] == '0'){
          digitalWrite(13, LOW);
        }
        else{
          digitalWrite(13,HIGH);
        }
        
   
    Serial.println();
    }

Considerações finais

Neste tutorial, demonstramos como você pode utilizar o conceito de radiofrequência para fazer com que duas placas Arduino troquem informações entre si. Este foi apenas um conteúdo para que você tenha uma noção de como das os primeiros passos com esta tecnologia, portanto, esperamos que continue nos acompanhando e sinta-se à vontade para nos dar sugestões, críticas ou elogios. Lembre-se de deixar suas dúvidas nos comentários abaixo.


Shield Ethernet W5100 - Controlando saídas via servidor web

Shield Ethernet W5100 - Controlando saídas de um Arduino via navegador - Servidor Web

Neste tutorial iremos dar prosseguimento ao conteúdo relacionado à criação de Servidores Web utilizando o Arduino UNO juntamente com o Ethernet Shield W5100. Anteriormente, vimos quais eram os procedimentos básicos para criar um Servidor Web e também para efetuar a leitura de valores provenientes de elementos ligados tanto às entradas analógicas quanto às digitais. Neste tutorial você aprenderá como controlar as saídas digitais do Arduino UNO por meio do navegador acessando um Servidor Web implementado com seu Shield Ethernet W5100

É importante, para o pleno entendimento desse tutorial, que o leitor tenha lido os dois tutoriais anteriores:

[toc]


Mãos à obra - Acionando saídas digitais do Arduino UNO através de um Servidor Web

Componentes necessários

Para reproduzir este projeto, você irá precisar dos seguintes componentes:

Montando o projeto

Na figura abaixo você pode conferir o hardware pronto para ser utilizado.

Hardware para servidor web com o Ethernet Shield w5100 e leds
Hardware utilizado com o Ethernet Shield w5100 e leds

Gostaríamos de sugerir que você tenha bastante cuidado no momento em que for encaixar o Ethernet Shield W5100 no Arduino UNO, pois, além da possibilidade de entortar os pinos do shield, você também pode se machucar.

Lembre-se que o shield em questão possui uma série de pinos em sua parte inferior, tanto nas laterais como em sua parte dianteira, portanto, antes de pressionar o mesmo sobre o Arduino UNO, certifique-se de que os pinos estejam levemente posicionados em suas respectivas entradas para que então você possa ir realizando o encaixe lentamente.

Realizando as conexões

Para reproduzir este projeto, garanta que o seu Shield Ethernet W5100 esteja ligado corretamente a uma das portas LAN presentes no seu modem ou roteador.

Programando

Este programa foi elaborado a partir do código-exemplo da biblioteca Ethernet.h denominado WebServer.

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

byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };   
IPAddress ip(192, 168, 25, 26);                       
EthernetServer server(80);                             

String requisicao_do_navegador;
String parametro_da_requisicao;

void setup()
{
    Ethernet.begin(mac, ip); 
    server.begin();                 
    pinMode(2,OUTPUT);
    pinMode(7,OUTPUT);
}

void loop()
{
    EthernetClient client = server.available();

    if (client) { 
        boolean currentLineIsBlank = true;
        while (client.connected()) {
            if (client.available()) { 
                char c = client.read(); 
                requisicao_do_navegador += c;  
                
                if (c == '\n' && currentLineIsBlank ) 
                {     
                        if (definindo_a_requisicao(&requisicao_do_navegador)) {
                        parametro_da_requisicao = pegar_parametro_da_requisicao(&requisicao_do_navegador);
                        Serial.println(parametro_da_requisicao);
                                                 
                        client.println("HTTP/1.1 200 OK");
                        client.println("Content-Type: text/html");
                        client.println("Connection: close");
                        client.println();
                        
                        //Conteudo da Página HTML
                        client.println("<!DOCTYPE html>");
                        client.println("<html>");
                        client.println("<head>");
                        client.println("<title>Servidor Web VDS</title>");
                        client.println("</head>");
                        client.println("<body>");
                        client.println("<h1><font color=#4279c7>Servidor Web do Vida de Sil&iacute;cio</font></h1>");
                        client.println("<hr/>");                         
                        client.println("<h1>Sa&iacute;das digitais</h1>");
                        
                        client.println("<form method=\"get\">");

                        saida(client);
                        
                        client.println("<br/>");
                        saida2(client);
                        client.println("</form>");
                                                
                        
                        client.println("</body>");
                        client.println("</html>");
                        } else {
                        client.println("HTTP/1.1 200 OK");
                    }
                   
                    requisicao_do_navegador = "";    
                    break;
                }
                
                if (c == '\n') {
                    currentLineIsBlank = true;
                } 
                else if (c != '\r') {
                    currentLineIsBlank = false;
                }
            }
        } 
        delay(1);     
        client.stop(); 
    } 
}

void saida(EthernetClient cl)
{
        
        if (parametro_da_requisicao.indexOf("P2=1") > -1) 
        { 
           digitalWrite(2, HIGH);
           cl.println("<input type=\"checkbox\" name=\"P2\" value=\"1\" onclick=\"submit();\" checked > Pino digital 2");
        } 
        else 
        {
           digitalWrite(2, LOW);
           cl.println("<input type=\"checkbox\" name=\"P2\" value=\"1\" onclick=\"submit();\" > Pino digital 2");
        }
        
}

void saida2(EthernetClient cl)
{
        
        if (parametro_da_requisicao.indexOf("P7=1") > -1) 
        { 
           digitalWrite(7, HIGH);
           cl.println("<input type=\"checkbox\" name=\"P7\" value=\"1\" onclick=\"submit();\" checked > Pino digital 7");
        } 
        else 
        {
           digitalWrite(7, LOW);
           cl.println("<input type=\"checkbox\" name=\"P7\" value=\"1\" onclick=\"submit();\" > Pino digital 7");
        }
        
}

String pegar_parametro_da_requisicao(String *requisicao) {
int pos_inicial, pos_final;
String parametro;

  
  pos_inicial = (*requisicao).indexOf("GET") + 3;
  pos_final = (*requisicao).indexOf("HTTP/") - 1;
  parametro = (*requisicao).substring(pos_inicial,pos_final);
  parametro.trim();
 
  return parametro;
}

bool definindo_a_requisicao(String *requisicao) {
String parametro;
bool requisicao_desejada = false;

  parametro = pegar_parametro_da_requisicao(requisicao);

  if (parametro == "/") {
     requisicao_desejada = true;
  }

  if (parametro.substring(0,2) == "/?") {
     requisicao_desejada = true;
  }  

  return requisicao_desejada;
}

Colocando para funcionar

Veja como ficou nosso segundo Servidor Web.

Servidor Web com Ethernet Shield W5100
Servidor Web pronto.

Entendendo a fundo

Antes de começarmos com a explicação do código, gostaríamos de ressaltar que iremos apresentar apenas os detalhes dos tópicos não contemplados nos tutoriais anteriores, pois, desta maneira, será mais fácil focar nas partes referentes às atualizações feitas sobre o programa já existente, portanto, caso você tenha alguma dúvida sobre alguma parte do programa que não seja explicada neste momento, sugerimos que acesse o nossos materiais citados anteriormente.

Software

- Definindo os pré-requisitos para o funcionamento do código

Inicialmente, devemos incluir duas bibliotecas no código para que o mesmo pudesse funcionar corretamente. A biblioteca SPI.h, responsável pela comunicação dos módulos do shield com o Arduino UNO utilizando o protocolo SPI e a biblioteca Ethernet.h que atua possibilitando a conexão do conjunto, em um primeiro momento, com uma rede local.

Após a inclusão das bibliotecas citadas, devemos definir um endereço MAC (lembre-se que este pode ser qualquer um, desde que seja único em sua rede local) e um endereço IP (este deve ser um endereço válido  e disponível dentro da sua rede local). Além disso, devemos criar o objeto que será responsável por representar o Servidor Web no código (aqui, chamamos este de server) e relacioná-lo com a porta 80.

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

byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };   
IPAddress ip(192, 168, 25, 16);                       
EthernetServer server(80);

- Declarando as variáveis responsáveis pela manipulação da requisição do navegador

Em seguida, declaramos duas variáveis do tipo String , as quais, conforme veremos posteriormente, serão responsáveis por armazenar informações referentes à requisição feita pelo navegador.

String requisicao_do_navegador;
String parametro_da_requisicao;

- Definindo as configurações iniciais

Dentro da função setup(), devemos determinar o modo de operação dos pinos digitais que serão utilizados (estes terão o papel de saídas digitais) . Além disso, iniciamos a conexão com a rede local através da função Ethernet.begin() (passando como parâmetro os endereços MAC e IP definidos anteriormente) e também iniciamos o Servidor Web por meio da sentença server.begin() (lembre-se que server é o objeto criado para representar o Servidor Web no código).

void setup()
{
    Ethernet.begin(mac, ip); 
    server.begin();                 
    pinMode(2,OUTPUT);
    pinMode(7,OUTPUT);
}

- Entendendo as requisições do navegador

Nos tutoriais anteriores, ressaltamos o mecanismo básico de funcionamento dos códigos voltados para a criação de Servidores Web, o qual, começa através de um procedimento padrão, que por sua vez, consiste em utilizar uma variável para obter caractere por caractere da requisição feita pelo navegador até que esta seja completamente recebida pelo Arduino UNO, de modo que, apenas a partir deste ponto inicia-se o processo de elaboração da página.

Aqui, teremos uma nova condição que deve ser cumprida para que o Servidor Web entregue uma página como resposta para o navegador. Esta é função definindo_a_requisição(), cujo papel consiste em determinar se a requisição feita pelo navegador cumpre alguns requisitos para que então o Servidor Web possa entregar a página para o navegador. Repare que o parâmetro da função citada é o texto completo de requisição feita pelo navegador (armazenado na variável requisição_do_navegador) e que a mesma se encontra como parâmetro de uma função if(), ou seja, caso a função definindo_a_requisição() retorne um valor verdadeiro, o conteúdo da função if() será executado.

if(definindo_a_requisicao(&requisicao_do_navegador))
{
      ****** Conteúdo da função if() ******
}

Veja como é a função definindo_a_requisição():

bool definindo_a_requisicao(String *requisicao) {
String parametro;
bool requisicao_desejada = false;

  parametrofinal = pegar_parametro_da_requisicao(requisicao);

  if (parametrofinal == "/") {
     requisicao_desejada = true;
  }

  if (parametrofinal.substring(0,2) == "/?") {
     requisicao_desejada = true;
  }  

  return requisicao_desejada;
}

Primeiramente, como já era previsto, esta função retorna um valor booleano, ou seja, verdadeiro ou falso. O que esta função faz é basicamente chamar outra função, denominada pegar_parametro_da_requisicao(), que por sua vez, será responsável por pegar a requisição feita pelo navegador, manipulá-la e gerar um resultado a partir da mesma, de modo que, este resultado ficará armazenado na variável parametrofinal. Vamos observar o comportamento da função pegar_parametro_da_requisicao() para depois analisarmos o que ocorre com a variável citada anteriormente.

String pegar_parametro_da_requisicao(String *requisicao) {
int pos_inicial, pos_final;
String parametro;

  
  pos_inicial = (*requisicao).indexOf("GET") + 3;
  pos_final = (*requisicao).indexOf("HTTP/") - 1;
  parametro = (*requisicao).substring(pos_inicial,pos_final);
  parametro.trim();
 
  return parametro;
}

- Exemplificando com a primeira requisição feita pelo navegador

Por hora, vamos apenas analisar as requisições que o navegador pode fazer, sem nos aprofundarmos muito, para então ver como isso reflete no código. Primeiramente, imagine que você gravou o programa que disponibilizamos aqui, no seu Arduino UNO e posteriormente foi no seu navegador e digitou o endereço IP predefinido no código (no nosso caso 192.168.25.16).

Ao realizar este procedimento, o navegador enviará a seguinte requisição para o Servidor Web:

Veja o que irá acontecer com esta informação:

  1. O programa irá receber todo conteúdo da requisição e armazenar o mesmo na variável requisicao_do_navegador. 
  2. A função definindo_a_requisicao() será executada e a requisição armazenada na variável requisicao_do_navegador será o parâmetro desta função.
  3. Dentro da função definindo_a_requisicao() haverá  a execução de uma outra função chamada pegar_parametro_da_requisicao(), que por sua vez, também terá como parâmetro a requisição armazenada na variável requisicao_do_navegador.
  4. A função  pegar_parametro_da_requisicao() é responsável por retirar e armazenar (na variável parametro) o pedaço da primeira linha da requisição, que está entre as palavras GET e HTTPneste exemplo, será " / ". Entretanto, utilizando a função trim(), removemos os espaços antes e depois dos caracteres de fato, portanto, o conteúdo guardado na variável parametro será somente "/".
  5. O conteúdo da variável parametro da função pegar_parametro_da_requisicao() será levado para a variável parametrofinal da função definindo_a_requisicao(), de modo que, quando esta for testada na primeira função if() dentro desta (a que compara a variável parametrofinal com o caractere "/"), haverá uma resposta positiva, portanto, esta resposta, true, será utilizada na função if() cujo argumento é a função definindo_a_requisicao() e o servidor poderá entregar uma página como resposta à requisição feita.

- Exemplificando com as outras requisições feitas pelo navegador

Como veremos posteriormente, quando clicamos em um checkbox para acionar umas das nossa saídas digitais, o navegador irá fazer a seguinte requisição (suponha que o clique aconteceu no checkbox referente ao pino 2):

Neste caso, a variável parametrofinal da função definindo_a_requisicao() será preenchida com "/?P2=1". Repare que no primeiro if() existente nessa função terá como resultado, falso, já que o conteúdo da variável parametrofinal é diferente de "/", no entanto, no segundo if(), temos a função substring(), que por sua vez, irá pegar somente os dois primeiros caracteres da string "/?p2=1", ou seja, "/?" e irá comparar com "/?", gerando portanto, true, que será utilizado na função if() cujo parâmetro é a função definindo_a_requisicao(), permitindo assim, que o nosso Servidor Web responda à requisição com uma página.

O próximo tipo de requisição ocorre quando desmarcamos um checkbox, observe:

Nesta requisição ocorre algo semelhante ao que aconteceu anteriormente, de modo que, a variável parametrofinal da função definindo_a_requisicao() é justamente a string "/?", validando portanto, o segundo if() desta função e também o if() cujo parâmetro é a função definindo_a_requisicao(). Portanto, perceba que neste tipo de requisição, o Servidor Web tem permissão de responder à requisição com uma página.

- Exemplo de hipótese em que o servidor não deverá responder

Como vimos anteriormente, existem 3 requisições que o Servidor Web deverá responder através da criação de uma pagina, estas são: Primeiro acesso ao endereço IP do Servidor Web, quando um checkbox é marcado e quando um checkbox é desmarcado.

À título de curiosidade, existe uma requisição, que é comumente feita pelo google chrome (navegador que estou utilizando) a um servidor, relacionada ao ícone que deve aparecer na aba do navegador ao conectar-se com o servidor em questão. Esta requisição é da seguinte forma:

Note que quando este tipo de requisição for tratado, o conteúdo da variável parametrofinal será a string "/favicon.ico", que por sua vez, não se enquadra nas condições necessárias para que o programa responda através de uma pagina criada, portanto, a condição da função if() cujo parâmetro é a função definindo_a_requisicao(), não será satisfeita. Sendo assim, o que irá ocorrer é a execução do complemento else desta função if(), o qual, simplesmente envia uma mensagem de cabeçalho sem alterar o conteúdo da página enviada anteriormente.

if(definindo_a_requisicao(&requisicao_do_navegador))
{
      ****** Conteúdo da função if() ******
}
else 
{ 
      client.println("HTTP/1.1 200 OK"); 
}

- Construção da página

Após a permissão para o Servidor Web responder com uma página, utilizamos a variável parametro_da_requisicao para conter um dos 3 tipos parâmetros permitidos anteriormente ("/", "/?","/?P2=1"). Observe que, neste momento, estamos fazendo o uso apenas das strings entre os elementos GET e HTTP, sem os espaços antes e depois.

parametro_da_requisicao = pegar_parametro_da_requisicao(&requisicao_do_navegador);

Posteriormente, enviamos o cabeçalho padrão de uma pagina da Web em HTML.

client.println("HTTP/1.1 200 OK");
client.println("Content-Type: text/html");
client.println("Connection: close");
client.println();

Em seguida, começamos a construir, de fato, a página. Neste momento, utilizamos apenas os conceitos já apresentados nos tutoriais anteriores.

client.println("<!DOCTYPE html>");
client.println("<html>");
client.println("<head>");
client.println("<title>Servidor Web VDS</title>");
client.println("</head>");
client.println("<body>");
client.println("<h1><font color=#4279c7>Servidor Web do Vida de Sil&iacute;cio</font></h1>");
client.println("<hr/>");                         
client.println("<h1>Sa&iacute;das digitais</h1>");

Com esta porção de código, nossa página estará assim:

Servidor web com ethernet shield W5100
Adição de títulos na página

- Criação de formulários

O próximo passo que iremos fazer é criar um formulário através do par <form></form>.

Os formulários são seções de um documento que contém controles interativos, que por sua vez, permitem ao usuário submeter informações a um determinado Servidor Web.

Dentro da tag de abertura do formulário devemos declarar qual método que será utilizado para submeter o mesmo, de modo que, o método que será utilizado por nós será o método GET. Sendo assim, declaramos nosso formulário da seguinte maneira:

client.println("<form method=\"get\">");

      ***** Conteúdo do formulário *****

client.println("</form>");

Note que, no código acima, temos uma string sendo passada como parâmetro para a função println(), portanto, entre aspas duplas, no entanto, a palavra get também deve vir entre aspas duplas , por isso, utilizamos o conjunto \" para simbolizar aspas duplas dentro da string.

- Recebendo dados do formulário

Em seguida, chamamos uma função denominada saida(), que por sua vez, será responsável por criar e controlar o checkbox referente à saída digital do pino 2.

saida(client);

O que a função saida() faz é basicamente pegar o conteúdo da variável parametro_da_requisicao e através da função indexOf(), ver se nele existe a porção de texto "P2=1".

A função indexOf() retorna um número inteiro referente à posição do primeiro caractere do conjunto de caracteres buscado em uma determinada string, portanto, caso o primeiro caractere do conjunto citado esteja no começo da string, a função retornará o número 0, logo, se compararmos o retorno desta função com -1 , estaremos apenas verificando se existe o tal conjunto de caracteres na string (isso é o que importa para nós).

- Acionando as saídas

Caso exista o conjunto de caracteres "P2=1", o led presente na saída digital 2 é acionado e o servidor incluirá na programação da página, a linha referente à criação de um objeto de entrada de dados, do tipo checkbox. O que você deve entender neste momento é o seguinte:

  1. Na declaração do checkbox, existe dois parâmetros, name e value.
  2. Quando o checkbox é marcado, o navegador irá associar estes dois parâmetros e enviar esta associação na requisição, por exemplo, quando o checkbox referente ao pino digital 2 for marcado, o navegador associará o name P2 ao value 1 e irá anexar o conjunto sob a forma /?P2=1 na requisição, conforme vimos anteriormente.
  3. Esta requisição chega ao servidor e ele analisa, se existe algum elemento que comece, por exemplo, com /?.
  4. Na presença do elemento citado anteriormente, o servidor é autorizado a responder com uma página da web, porém ele deve identificar por inteiro como é o elemento que começa com /?, de modo que, se este for /?P2=1, o servidor irá perceber que o checkbox referente ao pino de saída digital 2 que foi marcado.
  5. Quando o servidor constata que o checkbox citado que foi marcado, o led é acionado e permanecerá assim até que o checkbox em questão seja desmarcado.
void saida(EthernetClient cl)
{
        
        if (parametro_da_requisicao.indexOf("P2=1") > -1) 
        { 
           digitalWrite(2, HIGH);
           cl.println("<input type=\"checkbox\" name=\"P2\" value=\"1\" onclick=\"submit();\" checked > Pino digital 2");
        } 
        else 
        {
           digitalWrite(2, LOW);
           cl.println("<input type=\"checkbox\" name=\"P2\" value=\"1\" onclick=\"submit();\" > Pino digital 2");
        }
        
}

O mesmo procedimento é realizado para o outro pino de saída digital utilizado, no entanto, este é identificado nas requisições por /?P7 = 1.

Além disso, vamos supor que você marque o checkbox referente ao pino 2, de modo que, a requisição do navegador para o servidor traga /?P2 = 1. Em um determinado momento, você também marcou o checkbox referente ao pino 7, logo, é válido pensar que, na nova requisição haverá somente o conjunto /?P7 = 1no entanto, como o checkbox referente ao pino 2 ainda está marcado, o elemento que virá na requisição será /?P2=1&P7=1

Servidor Web com Ethernet Shield W5100
Resultado final

Considerações finais

Neste tutorial, demonstramos como você pode fazer para controlar as saídas digitais do seu Arduino UNO através de um  navegador. Para isto, utilizamos um Arduino UNO em conjunto com um Ethernet Shield W5100. Esta foi a terceira parte de uma série de artigos sobre a criação de Servidores Web, portanto, esperamos que continue nos acompanhando e sinta-se à vontade para nos dar sugestões, críticas ou elogios. Lembre-se de deixar suas dúvidas nos comentários abaixo.


EEPROM - Armazenando dados na memória não volátil do Arduino

Armazenando dados de forma não volátil no Arduino - EEPROM

A necessidade de se armazenar informações é algo bastante recorrente no desenvolvimento de projetos embarcados. Sejam elas um conjunto de variáveis para configurar o seu sistema, ou até  mesmos dados que você queira visualizar após um intervalo de tempo, o armazenamento de informações é muito importante em praticamente todos os tipos de projetos. Porém nem sempre dispomos de um cartão SD, seja por limitações de custo ou até mesmo pinos de I/O, impossibilitando  assim que a utilização de um cartão SD resolvesse o problema. Sabendo disso, neste tutorial, você aprenderá como utilizar a memória EEPROM existente nos microcontroladores Atmega das placas Arduino para armazenar dados permanentemente.

[toc]

Memória EEPROM

A memória EEPROM ou Electrically-Erasable Programmable Read-Only Memory, consiste em um modelo de memória onde diferente da memória RAM, podemos manter dados armazenados após desligarmos o nosso equipamento. Desta forma, é possível salvar informações que podem ser necessárias para o funcionamento do sistema após o seu desligamento, como por exemplo:

  • Configurações
  • Dados de difícil obtenção
  • Dados  estáticos

A utilização de memórias EEPROM, possibilitam com que o desenvolvedor seja capaz de armazenar diversas informações do sistema para uso posterior. Porém, este tipo de  memória possui um ciclo muito pequeno de escritas, o que torna o seu uso viável apenas para o armazenamento de informações que serão pouco modificadas.

Memória eeprom i2c com encapsulamento dip.

O processo de leitura e escrita neste tipo  de memória pode ser feito de duas formas:

  • Paralelo: Cada byte é escrito de forma paralela na memória, sendo  este escrito com base no endereço definido no barramento. Mais rápida, porém gasta uma maior quantidade de pinos para I/O

  • Serial: Cada byte é escrito de forma serializada (normalmente utilizando o protocolo i2c) na memória eeprom. Mais lenta, porém gasta uma menor quantidade de pinos para I/O

Memória EEPROM no Arduino

Os microcontroladores ATmega possuem em sua arquitetura uma pequena memória eeprom, que pode ser utilizada como uma unidade de armazenamento. Cada microcontrolador possui uma de tamanho específico,  segmentada em 1 byte por endereço. A lista abaixo ilustra a quantidade de memória disponível para a microcontroladores utilizados em plataformas como Arduino Nano, Arduino Uno e Arduino Mega:

  • ATmega8,ATmega168 - 512 Bytes
  • ATmega326 - 1024 Bytes
  • ATmega1280, ATmega2560 - 4096 Bytes

Mãos à obra – Armazenando dados na memória EEPROM do Arduino

Neste projeto iremos apenas aprender a como manipular e realizar leituras e escritas na memória EEPROM do Arduino, desta forma iremos precisar apenas de um Arduino com algum dos microcontroladores citados acima.

Componentes Utilizados

Neste projeto iremos utilizar um Arduino Nano, porém praticamente todos os  microcontroladores ATmega dispõem de uma memória eeprom nativa.

Programando

- Bibliotecas

Como iremos apenas aprender como armazenar e ler dados da memória EEPROM do Arduíno, iremos utilizar apenas a biblioteca EEPROM.h que já é nativa da ide que pode ser importada ao seu código da seguinte forma:

#include <EEPROM.h>

- Código Utilizado

Agora que temos o nosso sistema montado, e as bibliotecas adicionadas ao projeto, podemos partir para o código. Observem o código a seguir que utilizaremos como base para o nosso manipulador de memória.

#include <EEPROM.h> // Biblioteca para acesso e manipulação da EEPROM
void setup()   
{
  Serial.begin(115200); // Inicialização da comunicação serial

  Serial.print("Espaco Disponivel em Bytes: "); // Mostra a quantidade  de memória da EEPROM do seu microcontrolador
  Serial.println(EEPROM.length()); // Mostra a quantidade de memória da EEPROM do seu microcontrolador
  escreveByte(0,254); // Escreve o valor 255 na posição 0 da memória  
  byte valor = leByte(0); // Lê o endereço 0 da memória ( onde escrevemos 255 )
  Serial.print("Byte Armazenado: "); // Mostra o Byte Armazenado
  Serial.println(valor); // Mostra o Byte Armazenado
  escreveInt(1,2,1200); // Escreve o valor 1200 na EEPROM ( por ser um int de 2 bytes precisamos utilizar 2 endereços para armazenar)
  Serial.print ("Inteiro Armazenado: "); // Mostra o inteiro Armazenado
  Serial.println(lerInt(1,2)); // Mostra o inteiro Armazenado
  escreveString(3,"Vida de Silício"); // Escreve a String Vida de Silício na EEPROM, começando no  endereço 3
  Serial.println("String Armazenada: "+leString(3)); // Mostra a String armazenada
}

void loop(){
  
}

byte leByte (int endereco1){
  return EEPROM.read(endereco1); // Realizamosa leitura de 1 byte  e retornamos
}

void escreveByte (int endereco1, byte valor){ // Escreve um byte na EEPROM no endereço especificado
  byte valorAtual = leByte(endereco1); // Lemos o byte que desejamos escrever
  if (valorAtual == valor){ // Se os valores forem iguais não  precisamos escrever ( economia de ciclos de escrita )
    return;
  }
  else { // Senão escrevemos o byte no endereço especificado na função
    EEPROM.write(endereco1,valor); // Escreve o byte no endereço especificado na função
  }
  
}



void escreveInt(int endereco1, int endereco2, int valor){ // Escreve um inteiro de 2 bytes na EEPROM
  int valorAtual = lerInt(endereco1,endereco2); // Lemos o valor inteiro da memória
  if (valorAtual == valor){ // Se o valor lido for igual ao que queremos escrever não é necessário escrever novamente
    return;
  }
  else{ // Caso contrário "quebramos nosso inteiro em 2 bytes e escrevemos cada byte em uma posição da memória
      byte primeiroByte = valor&0xff; //Executamos a operação AND de 255 com todo o valor, o que mantém apenas o primeiro byte
      byte segundoByte = (valor >> 8) &0xff; // Realizamos um deslocamento de 8 bits para a direita e novamente executamos um AND com o valor 255, o que retorna apenas o byte desejado
      EEPROM.write(endereco1,primeiroByte); // Copiamos o primeiro byte para o endereço 1
      EEPROM.write(endereco2,segundoByte); // Copiamos o segundo byte para o endereço 2
  }
}

int lerInt(int endereco1, int endereco2){ // Le o int armazenado em dois endereços de memória
  int valor = 0; // Inicializamos nosso retorno
  byte primeiroByte = EEPROM.read(endereco1); // Leitura do primeiro byte armazenado no endereço 1
  byte segundoByte = EEPROM.read(endereco2); // Leitura do segundo byte armazenado no endereço 2
  valor = (segundoByte << 8) + primeiroByte; // Deslocamos o segundo byte 8 vezes para a esquerda ( formando o byte mais significativo ) e realizamos a soma com o primeiro byte ( menos significativo )
  return valor; // Retornamos o valor da leitura

}

void escreveString(int enderecoBase, String mensagem){ // Salva a string nos endereços de forma sequencial
  if (mensagem.length()>EEPROM.length() || (enderecoBase+mensagem.length()) >EEPROM.length() ){ // verificamos se a string cabe na memória a partir do endereço desejado
    Serial.println ("A sua String não cabe na EEPROM"); // Caso não caiba mensagem de erro é mostrada
  }
  else{ // Caso seja possível armazenar 
    for (int i = 0; i<mensagem.length(); i++){ 
       EEPROM.write(enderecoBase,mensagem[i]); // Escrevemos cada byte da string de forma sequencial na memória
       enderecoBase++; // Deslocamos endereço base em uma posição a cada byte salvo
    }
    EEPROM.write(enderecoBase,'\0'); // Salvamos marcador de fim da string 
  }
}

String leString(int enderecoBase){
  String mensagem="";
  if (enderecoBase>EEPROM.length()){ // Se o endereço base for maior que o espaço de endereçamento da EEPROM retornamos uma string vazia
    return mensagem;
  }
  else { // Caso contrário, lemos byte a byte de cada endereço e montamos uma nova String
    char pos;
    do{
      pos = EEPROM.read(enderecoBase); // Leitura do byte com base na posição atual
      enderecoBase++; // A cada leitura incrementamos a posição a ser lida
      mensagem = mensagem + pos; // Montamos string de saídaa
    }
    while (pos != '\0'); // Fazemos isso até encontrar o marcador de fim de string
  }
  return mensagem; // Retorno da mensagem
}


Colocando pra funcionar

Se nada tiver sido modificado no código e sua EEPROM ainda possuir ciclos de escrita, a seguinte mensagem será apresentada no monitor serial:


Entendendo a Fundo

Software

- Incluindo bibliotecas necessárias

Para este sistema, iremos precisar apenas da biblioteca EEPROM.h que já é  nativa do Arduíno e será utilizada como interface entre a EEPROM e o nosso código, desta forma ela pode ser adicionada  da seguinte forma:

#include <EEPROM.h>

- Função Setup

Em nossa função setup, iremos basicamente escrever e ler as variáveis que desejamos armazenar na EEPROM, foram definidos um conjunto de 6 funções, sendo três para escrita e três para leitura de tipos de dados normalmente utilizados, sendo eles:

  • Int
  • Byte
  • String

Sendo assim, no setup iremos apenas utilizar estas funções, da seguinte forma:

- Função escreve byte

Escreve um valor em byte no endereço especificado, neste exemplo estamos escrevendo o valor 254 no endereço 0 da memória.

  escreveByte(0,254); // Escreve o valor 255 na posição 0 da memória

- Função lê byte

Realiza a leitura de um único byte no endereço especificado pelo usuário, neste exemplo estamos lendo o endereço 0.

byte valor = leByte(0);

- Função escreve int

Escreve um valor inteiro composto por 2 bytes, em duas posições quaisquer da eeprom, neste exemplo estamos escrevendo o valor 1200 utilizando os endereços 1 e 2.

escreveInt(1,2,1200);

- Função lê int

Realiza a leitura de dois endereços especificados pelo usuário, reconstruindo o valor inteiro que elas representam, neste exemplo estamos lendo os endereços 1 e 2 da memória.

Serial.println(lerInt(1,2));

- Função escreve string

Escreve uma determinada string de forma sequencial na EEPROM, neste exemplo estamos utilizando um total de 15 endereços (começando do endereço 3) para escrever a string "Vida de Silício" em nossa memória.

escreveString(3,"Vida de Silício");

- Função lê string

Dado um endereço base fornecido, esta função lê sequencialmente toda a string armazenada.

leString(3);

Entendendo cada função implementada

Cada função implementada possui um grau complexidade devido a realização de operações lógicas para quebra de bytes e armazenamento sequencial, desta forma iremos mostrar a forma como cada função é capaz de salvar e recuperar seus respectivos tipos de dados. Porém antes vamos entender um pouco a forma como a nossa memoria funciona.

Imagine a sua  memória como um um conjunto de blocos onde podemos armazenar valores em um intervalo de 0 até 255, e cada um desses intervalos está associado a um endereço, sendo assim, podemos imaginar a nossa memória da seguinte forma: Com essa estrutura de memória podemos salvar qualquer tipo de informação, desde  que o espaço seja suficientemente grande para armazenar todos os valores.

- Função escreveByte

A função escreveByte recebe como argumentos o endereço  e o valor a ser escrito naquela  posição, verificando apenas se o byte que desejamos escrever já não está lá, desta forma economizamos uma escrita que seria feita desnecessariamente, prologando assim a vida útil de nossa memória.

void escreveByte (int endereco1, byte valor){
  byte valorAtual = leByte(endereco1);
  if (valorAtual == valor){
    return;
  }
  else {
    EEPROM.write(endereco1,valor);
  }
}

Estruturalmente, podemos dizer que esta função executa a seguinte operação:

- Função leByte

Já a função leByte, basicamente realiza a leitura do endereço especificado em seu argumento, retornando assim o valor que está armazenado naquele endereço.

byte leByte (int endereco1){
  return EEPROM.read(endereco1);
}

Utilizando o nosso modelo de memória, podemos dizer que estamos realizando a seguinte operação:

- Função escreveInt

Nos microcontroladores ATmega, uma variável  do tipo int, é representada por um total de 2 bytes, sendo estes divididos entre mais significativos (HB) e menos significativos (LB), como a nossa memória permite apenas o armazenamento de 1 byte por endereço. Sabendo disso, é necessário que a nossa função seja capaz de "quebrar" o nosso  valor inteiro de 2 bytes, em duas variáveis de 1 byte cada, para que assim seja possível armazenar esta informação na memória. Para que isso seja feito, iremos utilizar dois tipos de operações lógicas existente em praticamente todas as arquiteturas de computadores, que são as operações rigth shift e and bitwise.

void escreveInt(int endereco1, int endereco2, int valor){
  int valorAtual = lerInt(endereco1,endereco2);
  if (valorAtual == valor){
    return;
  }
  else{
      byte primeiroByte = valor&0xff;
      byte segundoByte = (valor >> 8) &0xff;
      EEPROM.write(endereco1,primeiroByte);
      EEPROM.write(endereco2,segundoByte);
  }
}

 

Sabendo disso o algoritmo funciona da seguinte forma:

  1. Inicialmente verificamos se o valor que desejamos inserir é igual ao que está na memória ( se for economizamos duas escritas na memória )
  2. Caso não seja executamos a seguinte operação:
    1. Dado o nosso valor de exemplo 1001, serão executadas as seguintes operações:
    2.  Aplicamos uma operação AND bit a bit sob o valor que desejamos quebrar com o número 255, desta forma iremos preservar apenas os bits da primeira cadeia de byte que desejamos armazenar. A figura abaixo ilustra como o processo é feito e o resultado obtido através da operação realizada.
    3. Para o segundo byte, realizaremos o mesmo processo do passo 2, porém ao invés apenas aplicar a operação lógica AND, iremos antes deslocar os bits que estão na camada superior. Para que dessa forma, cheguem a posição dos bits menos significativos para a aplicação da  máscara.
    4.  Por fim, com os bytes separados, a  função salva cada um deles no endereço especificado como mostra a figura abaixo:

- Função leInt

O processo de leitura segue praticamente a lógica inversa do processo de escrita, onde iremos ler cada byte e montar o nosso valor da seguinte forma:

  1. Relizamos uma leitura do endereço de valor mais significativo, este  valor é deslocado 8 bits a esquerda para que volte a sua posição de bit mais significativo.
  2. Realizamos uma leitura do endereço de valor menos significativo, este valor é somado ao  valor deslocado para que volte a posição de bit menos significativo.
  3. Temos o nosso  valor montado novamente.

 

int lerInt(int endereco1, int endereco2){
  int valor = 0;
  byte primeiroByte = EEPROM.read(endereco1);
  byte segundoByte = EEPROM.read(endereco2);
  valor = (segundoByte << 8) + primeiroByte;
  return valor;
}

- Função escreveString

A função escreve string por sua vez, não utiliza de recursos de deslocamento de bits, devido ao fato de que cada caractere, é um único byte. Ou seja, uma string nada mais é do que um vetor de bytes alocados sequencialmente. Sabendo disso, o nosso algoritmo de salvar uma string na memória segue a seguinte lógica:

  1. Dado um endereço base, e o tamanho da string verificamos se é possível o armazenamento ou não.
    1. Caso não seja possível, o  valor não é salvo.
    2. Caso seja possível, a string é alocada sequencialmente na memória começando com o endereço base e terminando sempre com um ''\0''
void escreveString(int enderecoBase, String mensagem){
  if (mensagem.length()>EEPROM.length() || (enderecoBase+mensagem.length()) >EEPROM.length() ){
    Serial.println ("A sua String não cabe na EEPROM");
  }
  else{
    for (int i = 0; i<mensagem.length(); i++){
       EEPROM.write(enderecoBase,mensagem[i]);
       enderecoBase++;
    }
    EEPROM.write(enderecoBase,'\0');
  }
}

- Função leString

A função leString por sua vez, realiza praticamente o mesmo processo que a leitura, porém ao invés de armazenar os bytes como na função escreveString, ela utiliza a função read, para ler cada byte armazenado sequencialmente. Desta forma podemos dizer que o algoritmo funciona da seguinte forma:

  • Com base no endereço inicial, a função lê cada byte lido, até que o caractere de fim de texto '\0', seja encontrado. Quando encontrado uma string montada é retornada pela função.
String leString(int enderecoBase){
  String mensagem="";
  if (enderecoBase>EEPROM.length()){
    return mensagem;
  }
  else {
    char pos;
    do{
      pos = EEPROM.read(enderecoBase);
      enderecoBase++;
      mensagem = mensagem + pos;
    }
    while (pos != '\0');
  }
  return mensagem;
}

Desafio

Agora que sabemos como manipular a memória EEPROM do nosso Arduino, tente adicionar esta funcionalidade a algum projeto que seja necessária a configuração de uma variável em tempo real.  Um exemplo de sistema desse tipo são os dataloggers, onde  precisamos configurar informações como tempo de leitura e configuração de sensores.

Considerações finais

Este tutorial, teve como objetivo mostrar como manipular a memória EEPROM, interna do seu Arduino, funcionando como uma pequena unidade de armazenamento para informações importantes. 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.


Shield Ethernet W5100 - Monitorando sensores com um Servidor Web

Shield Ethernet W5100 - Monitorando Sensores com um Servidor Web

Se você gostou do nosso tutorial inicial sobre a criação de Servidores Web utilizando o Arduino UNO juntamente com o Shield Ethernet W5100, prepare-se, pois, neste tutorial vamos dar sequência ao conteúdo citado, apresentando novos conceitos para que você possa incrementar a sua aplicação. Neste tutorial você aprenderá como a monitorar as informações de seu Arduino, como por exemplo, temperatura, através de um navegador com o auxilio de um Servidor Web implementado com o Shield Ethernet W5100

É importante, para o pleno entendimento desse tutorial, que o leitor tenha lido o tutorial anterior: Shield Ethernet W5100 - Criando um Servidor Web com Arduino

[toc]


Mãos à obra - Monitorando sensores com um Servidor Web

Nesta seção iremos demonstrar todos os passos que você deve seguir para aprender a monitorar sensores com um Servidor Web. De maneira mais específica, vamos desenvolver um projeto em que o usuário consiga monitorar valores de temperatura provenientes de um sensor LM35 (não esqueça de conferir nosso tutorial sobre o sensor de temperatura LM35 clicando aqui) e também o estado de um botão, ou seja, se o mesmo está pressionado ou não.

Componentes necessários

Para reproduzir este projeto, você irá precisar dos seguintes componentes:

Montando o projeto

Na figura abaixo você pode conferir o hardware pronto para ser utilizado.

Projeto Shield Ethernet W5100 - Monitorando sensores com um Servidor Web
Projeto com Shield Ethernet W5100, Arduino Uno e LM35

Gostaríamos de sugerir que você tenha bastante cuidado no momento em que for encaixar o Shield Ethernet W5100 no Arduino UNO, pois, além da possibilidade de entortar os pinos do shield, você também pode se machucar.

Lembre-se que o shield em questão possui uma série de pinos em sua parte inferior, tanto nas laterais como em sua parte dianteira, portanto, antes de pressionar o mesmo sobre o Arduino UNO, certifique-se de que os pinos estejam levemente posicionados em suas respectivas entradas para que então você possa ir realizando o encaixe lentamente.

Realizando as conexões

Para reproduzir este projeto, garanta que o seu Shield Ethernet W5100 esteja ligado corretamente a uma das portas LAN presentes no seu modem ou roteador.

Programando

Este programa foi elaborado a partir do código-exemplo da biblioteca Ethernet.h denominado WebServer.

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

byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };
IPAddress ip(192, 168, 25, 16); 
EthernetServer server(80);     

void setup() 
{
    pinMode(5,INPUT);
    Ethernet.begin(mac, ip);  
    server.begin();           
} 


void loop() {

    EthernetClient client = server.available();  

    if (client) 
    {    
        boolean currentLineIsBlank = true;
        while (client.connected()) 
        {
            if (client.available()) 
            {   
                char c = client.read(); 
                
                if (c == '\n' && currentLineIsBlank) {
                  
                    client.println("HTTP/1.1 200 OK");
                    client.println("Content-Type: text/html");
                    client.println("Connection: close");
                    client.println("Refresh: 2");
                    client.println();
                    
                    client.println("<!DOCTYPE html>");
                    client.println("<html>");
                    client.println("<head>");
                    client.println("<title>Servidor Web VDS</title>");
                    client.println("</head>");
                    client.println("<body>");
                    client.println("<h1><font color=#4279c7>Servidor Web do Vida de Sil&iacute;cio</font></h1>");
                    client.println("<hr/>");
                    client.println("<h1>Temperatura</h1>");
                    porta_analogica(client);   
                    client.println("<br/>");
                    client.println("<h1>Entrada digital</h1>");
                    porta_digital(client); 
                    client.println("</body>");
                    client.println("</html>");
                    break;
                }
                
                if (c == '\n') 
                {    
                    currentLineIsBlank = true;
                } 
                else if (c != '\r') 
                {
                    currentLineIsBlank = false;
                }
            } 
        } 
        
        delay(1);      
        client.stop(); 
        
    } 
} 

void porta_analogica(EthernetClient client_aux)
{
  client_aux.print("LM35:");
  int valor = analogRead(A0);
  float temperatura = (((valor*5)/1023)-0.5)*100;
  if(temperatura >=50)
  {
      client_aux.println("<font color=#FF0000>");
      client_aux.println(temperatura);
      client_aux.println("graus");
      client_aux.println("</font>");
  }
  else
  {
      client_aux.println("<font color=#000000>");
      client_aux.println(temperatura);
      client_aux.println("graus");
      client_aux.println("</font>");
  }
}


void porta_digital(EthernetClient client_aux)
{
  client_aux.print("Pino digital 5:");
  bool valor = digitalRead(5);
  if(valor == HIGH)
  {
      client_aux.println("<font color=#FF0000> Ligado</font>");
  }
  else
  {
      client_aux.println("<font color=#000000> Desligado</font>");
  }
}

Colocando para funcionar

Veja como ficou nosso segundo Servidor Web.

Shield Ethernet W5100 - Monitorando sensores com um Servidor Web
Acessando Servidor web do Shield Ethernet W5100 através de um navegador

Entendendo a fundo

Antes de começarmos com a explicação do código, gostaríamos de ressaltar que iremos apresentar os detalhes apenas dos tópicos não contemplados no tutorial anterior, pois, desta maneira, será mais fácil focar nas partes referentes às atualizações feitas sobre o programa já existente, portanto, caso você tenha alguma dúvida sobre alguma parte do programa que não seja explicada neste momento, sugerimos que acesse o nosso material citado anteriormente.

Software

- Definindo os pré-requisitos para o funcionamento do código

Inicialmente, devemos incluir duas bibliotecas no código para que o mesmo pudesse funcionar corretamente. A biblioteca SPI.h, responsável pela comunicação dos módulos do shield com o Arduino UNO utilizando o protocolo SPI e a biblioteca Ethernet.h que atua possibilitando a conexão do conjunto, em um primeiro momento, com uma rede local.

Após a inclusão das bibliotecas citadas, devemos definir um endereço MAC (lembre-se que este pode ser qualquer um, desde que seja único em sua rede local) e um endereço IP (este deve ser um endereço válido  e disponível dentro da sua rede local). Além disso, devemos criar o objeto que será responsável por representar o Servidor Web no código (aqui, chamamos este de server) e relacioná-lo com a porta 80.

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

byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };
IPAddress ip(192, 168, 25, 16); 
EthernetServer server(80);

- Definindo as configurações iniciais

Dentro da função setup(), devemos determinar o modo de operação do pino digital que será utilizado (este terá o papel de uma entrada digital) . Além disso, iniciamos a conexão com a rede local através da função Ethernet.begin() (passando como parâmetro os endereços MAC e IP definidos anteriormente) e também iniciamos o Servidor Web por meio da sentença server.begin() (lembre-se que server é o objeto criado para representar o Servidor Web no código).

void setup() 
{
    pinMode(5,INPUT);
    Ethernet.begin(mac, ip);  
    server.begin();           
}

- Criando a página para responder à requisição do navegador

No artigo anterior foi possível compreender como devemos proceder para elaborar uma página bem simples, contendo apenas elementos escritos e também estáticos, ou seja, que não sofriam nenhum tipo de alteração. Neste momento, iremos incrementar o programa criado anteriormente, portanto, vamos deixar de lado a parte referente ao processo de requisição do navegador (já explicado) e iremos focar apenas na elaboração da página que cumpra o objetivo proposto neste material.

Você se lembra do cabeçalho padrão que enviamos para o navegador antes de enviarmos a página propriamente dita? Para ajudar, vamos colocá-lo aqui.

client.println("HTTP/1.1 200 OK");
client.println("Content-Type: text/html");
client.println("Connection: close");
client.println();

Definindo tempo de atualização da página 

A primeira modificação que faremos neste momento será a inclusão de uma linha de código que faça com que a página seja atualizada em intervalos de tempo definidos. Isto é importante para este projeto em virtude de estarmos trabalhando com aquisição de variáveis, portanto, devemos atualizar a página periodicamente para que seja possível visualizarmos sempre os valores atuais das variáveis envolvidas. Sendo assim, utilizamos a seguinte sentença para que a página seja atualizada de 2 em 2 segundos.

client.println("Refresh: 2");

Veja como ficará o nosso cabeçalho padrão

client.println("HTTP/1.1 200 OK");
client.println("Content-Type: text/html");
client.println("Connection: close");
client.println("Refresh: 2");
client.println();

A estrutura da página em HTML

O próximo passo que faremos será construir, de fato, a página que será enviada ao navegador. Com uma breve recapitulação, devemos lembrar que todo conteúdo que compõe a página deve estar dentro da seguinte estrutura:

client.println("<!DOCTYPE HTML>");
client.println("<html>");
           . 
           .
***** Conteúdo da página *****
           .
           .
client.println("</html>"); 

Como ressaltado anteriormente, dentro desta estrutura temos o conteúdo da página que queremos enviar para o navegador, de modo que, nesta, devemos ter pelo menos dois blocos, um responsável pelas informações gerais do documento, limitado pelo uso do par <head></head> e o outro, por sua vez, deve conter o corpo da página e está entre as tags <body> e </body>.

client.println("<!DOCTYPE HTML>");
client.println("<html>");
client.println("<head>");
           .
           .
   ***** Bloco 1 *****
           .
           .
client.println("</head>");
client.println("<body>");
           .
           .
   ***** Bloco 2 *****
           .
           .
client.println("</body>");
client.println("</html>");

Definido o título para a página

Neste momento, vamos utilizar apenas uma tag dentro do bloco 1, denominada <title>, cuja função consistirá em definir um título para a página (este título aparecerá na aba do navegador). Para executarmos a ação proposta, devemos colocar o título desejado entre o par <title></title>.

client.println("<!DOCTYPE HTML>");
client.println("<html>");

client.println("<head>");
client.println("<title>Servidor Web VDS</title>"); 
client.println("</head>");

client.println("<body>");
           .
           .
   ***** Bloco 2 *****
           .
           .
client.println("</body>");
client.println("</html>");

Veja como ficou o título da nossa página:

servidor Shield Ethernet W5100 - Monitorando sensores com um Servidor Web
Título da página.

Escrevendo o corpo da página web

Quanto ao corpo da página (entre o par <body></body>), a primeira coisa que faremos será colocar um título visível na própria página. Para realizar este procedimento, utilizaremos a tag <h1>, que por sua vez, consiste em uma tag para apresentar um determinado texto em um modelo predefinido. Além disso, utilizaremos também a tag <font>, através da qual, poderemos fazer alterações no título produzido.

client.println("<h1><font color=#4279c7>Servidor Web do Vida de Sil&iacute;cio</font></h1>");

Alguns pontos no trecho de código acima devem ser ressaltados:

  1. Tudo que estiver escrito entre o par <h1></h1> estará pré formatado no estilo deste cabeçalho.
  2. A tag <font> é responsável por modificar algum atributo relativo à formatação de uma determinada porção de texto. Para isto, devemos colocar o nome do atributo que queremos modificar, após a palavra font (apenas na tag de abertura), sendo assim, quando escrevemos <font color=#4279c7>, estamos indicando que a porção de texto entre o par <font color=#4279c7></font> deverá está colorida em um certo tom de azul (dado pelo código RGB em hexadecimal #4279c7).
  3. Repare que a palavra Silício foi escrita no código como Sil&iacute;cioEsta forma de escrita é necessária sempre que temos a utilização de algum tipo de acento, pois, nem todos os dispositivos estão configurados para apresentar caracteres acentuados da mesma forma. Sendo assim, utilizamos o comando &iacute; para colocar o acento agudo na letra da palavra Silício.

Veja o resultado deste procedimento na figura abaixo:

acessando Servidor Web Shield Ethernet W5100

Posteriormente, vamos inserir uma barra horizontal para separar o título criado no passo anterior dos textos que ainda serão criados, através do comando <hr/>.

client.println("<hr/>");

Após a inserção da barra citada, nossa página ficará da seguinte maneira:

Imprimindo a tempertatura

Em seguida, escrevemos outro texto utilizando o modelo de cabeçalho h1 referente ao valor que será obtido pelo sensor de temperatura LM35.

client.println("<h1>Temperatura</h1>");

Com este passo, a página será apresentada assim:

O próximo passo consiste em apresentar o valor de temperatura obtido através da conversão do sinal proveniente do sensor de temperatura utilizado. Obviamente, existem várias formas de fazer isso, no entanto, nós criamos uma função própria para isso, chamada porta_analogica() e passamos a variável client como parâmetro da mesma.

porta_analogica(client);

A função porta_analogica() será responsável por fazer a aquisição do valor de tensão na porta analógica A0 proveniente do sensor de temperatura LM35. Repare que nesta função utilizamos um conjunto if()/else para testar se o valor de temperatura é superior a um determinado valor, de modo que, caso seja, apresentaremos este valor na cor vermelha e caso não seja, na cor preta.

void porta_analogica(EthernetClient client_aux)
{
  client_aux.print("LM35:");
  int valor = analogRead(A0);
  float temperatura = (((valor*5)/1023)-0.5)*100;
  if(temperatura >=50)
  {
      client_aux.println("<font color=#FF0000>");
      client_aux.println(temperatura);
      client_aux.println("graus");
      client_aux.println("</font>");
  }
  else
  {
      client_aux.println("<font color=#000000>");
      client_aux.println(temperatura);
      client_aux.println("graus");
      client_aux.println("</font>");
  }
}

A apresentação do valor de temperatura ficará conforme a figura abaixo:

imprimindo valores de temperatura do servidor web no navegador

Imprimindo o estado da entrada digital - Botão

Após chamar a função porta_analogica(), utilizamos o comando <Br/> para fazer com que a próxima sentença utilizada na construção da página ocorra na próxima linha da tela.

client.println("<br/>");

Neste momento escrevemos um outro texto utilizando o modelo de cabeçalho h1. Este irá definir o título da seção em que o estado do botão será apresentado.

 client.println("<h1>Entrada digital</h1>");

Confira em que estágio nossa página está:

Por fim, chamamos a função porta_digital() cuja função consiste realizar os procedimentos necessários para apresentar o estado da nossa variável digital. Repare que, assim como na função porta_analogica(), também passamos a variável cliente como parâmetro.

porta_digital(client);

No bloco de código abaixo demonstramos o funcionamento da função porta_digital(), que por sua vez, apresentará a palavra Ligado, na cor vermelha, caso o botão esteja pressionado e a palavra Desligado, na cor preta, caso o botão esteja solto

void porta_digital(EthernetClient client_aux)
{
  client_aux.print("Pino digital 5:");
  bool valor = digitalRead(5);
  if(valor == HIGH)
  {
      client_aux.println("<font color=#FF0000> Ligado</font>");
  }
  else
  {
      client_aux.println("<font color=#000000> Desligado</font>");
  }
}

Veja o nosso resultado final:

Os procedimentos citados anteriormente servem para elaborar a página que será exibida no navegador em resposta a requisição feita pelo mesmo, de modo que, caso você queira entender partes do código externas ao que foi apresentado, verifique nosso primeiro tutorial.


Considerações finais

Neste tutorial, demonstramos como você monitorar as variáveis envolvidas no seu projeto, em uma página criada para ser exibida no seu navegador, utilizando um Arduino UNO e um Shield Ethernet W5100. Esta foi a segunda parte de uma série de artigos sobre a criação de Servidores Web, portanto, esperamos que continue nos acompanhando e sinta-se à vontade para nos dar sugestões, críticas ou elogios. Lembre-se de deixar suas dúvidas nos comentários abaixo.


Protocolo I2C - Comunicação entre Arduinos

Protocolo I2C - Comunicação entre Arduinos

É indiscutível que os protocolos de comunicação são alguns dos elementos mais importantes de um sistema dotado de dispositivos que possuem a necessidade de interagir entre si para que um determinado resultado possa ser obtido, pois, estes possibilitam a troca de informações entre os mesmos através do estabelecimento de regras, padrões e modelos que visam permitir a conexão entre os dispositivos citados. Neste tutorial, você aprenderá sobre um protocolo de comunicação suportado pelas placas Arduino e também por diversos módulos para Arduino, o protocolo de comunicação I2C. Além de apresentá-lo, iremos utilizar o mesmo para estabelecer uma comunicação entre 2 placas Arduino.

[toc]

O protocolo de comunicação I2C

O modo de funcionamento do protocolo I2C é baseado na interação entre elementos seguindo a hierarquia mestre/escravo, ou seja, quando temos vários dispositivos se comunicando segundo esta premissa, pelo menos um destes deve atuar como mestre e os demais serão escravos. A função do mestre consiste em realizar a coordenação de toda a comunicação, pois, ele tem a capacidade de enviar e requisitar informações aos escravos existentes na estrutura de comunicação, os quais, devem responder às requisições citadas.

A estrutura na qual o protocolo I2C atua é uma estrutura de barramento, que por sua vez, consiste em um arranjo em que todos os elementos encontram-se conectados a um ramal principal.

 

 

Na figura acima pode-se ver um modelo simplificado da estrutura de barramento citada anteriormente. Note que, neste arranjo, o barramento de comunicação I2C pode ser dividido em dois barramentos. Um deles é denominado SDA (Serial Data), o qual, é responsável pela troca de dados entre os dispositivos do arranjo e o outro barramento, denominado SCL (Serial Clock), possui a função de sincronizar os dispositivos e garantir a confiabilidade do sistema.

Na prática, como o protocolo I2C funciona?

Segundo a literatura, podemos ter a presença de até 127 dispositivos escravos anexados no barramento citado, no entanto, algumas fontes ressaltam que este valor, embora fornecido pela literatura oficial, é apenas teórico, alegando que, na prática, é possível utilizar apenas 112 dispositivos em um barramento I2C. Isso se deve o fato de que dos 128 endereços possíveis, 16 estão reservados, os quais vão de 0x00 a 0x07 e 0x78 a 0x7F, em outras palavras, os endereços possíveis estão localizados no intervalo de 0x08 a 0x77.

Exemplo prático de barramento I2C
Exemplo prático de barramento I2C

A vantagem da utilização deste tipo de estrutura é nítida quando levamos em conta o número de pinos utilizados pelos elementos e por consequência, a quantidade de fios, além de promover uma organização maior do conjunto quando temos muitos dispositivos interagindo entre si.

Endereço

Para que o mestre converse com cada escravo ele precisa saber qual o endereço do escravo a ser contactado. É importante frisar que o endereço de cada integrante de um barramento I2C deve ser único.

Geralmente, cada módulo possui um endereço padrão que em alguns casos pode ser alterado por algumas opções.

É muito comum que haja mais de um módulo, mesmo com funcionalidades totalmente diferentes, com o mesmo endereço padrão. Quando for assim, pesquise se é possível e como mudar o endereço de pelo menos um deles.

No tutorial Display LCD 20×4 e LCD 16×2 com Adaptador I2C, mostramos que existem módulo I2C para LCD que permitem que o endereço seja alterado dentro de 8 opções. Clique aqui para entender mais sobre o endereço do módulo I2C para LCD.

Comunicação entre Arduinos

Você pode conectar ao barramento diversos Arduinos. Tal como os módulos que suportam I2C, o Arduino também precisa ter um endereço cujo o qual você definirá via software.

Nesse tutorial aprenderemos como criar uma comunicação entre dois Arduinos usando I2C. Tal aplicação pode gerá infinitas opções de projetos práticos, podendo integrar varias placas Arduino e módulos compatíveis com o protocolo I2C para montar um sistema de automação.


Mãos à obra - Utilizando um Arduino Micro para fazer um Arduino UNO acionar um led 

Nesta seção iremos demonstrar todos os passos que você deve seguir para aprender a utilizar o protocolo I2C.

Componentes necessários

Para reproduzir este projeto, você irá precisar dos seguintes componentes:

Montando o projeto

 

Hardware utilizado com 2 placas Arduino comunicando através do protocolo I2C, um mestre e outro escravo
Hardware utilizado.

 

Na montagem deste hardware devemos garantir que os pinos SDA, SCL e GND de ambos os dispositivos estejam respectivamente conectados entre si. No Arduino UNO, os pinos SDA e SCL são os pinos analógicos A4 e A5 respectivamente, ao passo que, no Arduino Micro, estes são os pinos D2 e D3.

Programando

Conforme apresentado no tópico anterior, o projeto a ser desenvolvido neste tutorial utiliza duas placas Arduino, portanto, teremos a presença de dois códigos para serem gravados em ambas as placas. Primeiramente, apresentamos o código a ser gravado no Arduino Micro, que por sua vez, será o mestre do barramento

#include <Wire.h>

bool estado_LED;

void setup() {
  Wire.begin();
}

void loop() {
  Wire.beginTransmission(0x08); 
  wire.write(estado_LED);            
  Wire.endTransmission();
  
  estado_LED = !estadoLED;   

  delay(1000);
}

Em seguida, apresentamos o código a ser gravado no Arduino UNO, que em nosso projeto, se comportará como escravo.

#include <Wire.h>

void setup() {
  Wire.begin(0x08);                
  Wire.onReceive(receiveEvent);     
  pinMode(4,OUTPUT);     
}

void loop() {
  delay(100);
}


void receiveEvent(int leitura) {
  
  bool estado = Wire.read();    // receive byte as an integer

  if (estado == 1){
    digitalWrite(4,HIGH);
  }
  else{
    digitalWrite(4,LOW);
  }
}

 


Entendendo a fundo

Software - Arduino Micro (Mestre)

Neste momento, iremos demonstrar o passo a passo como funciona o código que deve ser gravado no Arduino Micro, que por sua vez, atuará como mestre no barramento

- Incluindo a biblioteca que será utilizada

Primeiramente, devemos incluir a biblioteca que será utilizada no código, portanto, através da diretiva #include, dizemos ao Arduino Micro que iremos utilizar a biblioteca Wire.h, responsável por conter as funções necessárias para gerenciar a comunicação entre os dispositivos através do protocolo I2C.

#include <Wire.h>

- Declarando a variável do projeto

Em seguida, declaramos uma variável booleana, isto é, que pode armazenar apenas dois valores (0 ou 1) , com o intuito de que esta seja responsável por conter a informação que será enviada ao Arduino UNO através do protocolo I2C para que o LED seja acionado.

bool estado_LED;

- Inicializando a comunicação através do protocolo I2C

Dentro da função Setup() utilizamos a sentença Wire.begin() para que a comunicação através do protocolo I2C seja iniciada. Como este dispositivo será o elemento mestre, não é necessário adicionar parâmetro algum à função citada (veremos adiante como proceder quando o dispositivo se comportar como escravo).

void setup() {
  Wire.begin();
}

- Iniciando a transmissão de dados

Será dentro da função loop() que iremos proceder com a transmissão de dados entre as placas Arduino. O primeiro passo que deve ser realizado para que uma informação possa ser enviada de um dispositivo mestre para um dispositivo escravo é a inicialização da transmissão com o elemento-alvo. Para isto, utilizamos a sentença Wire.beginTransmission(), tendo como parâmetro, o endereço do escravo com o qual queremos que o mestre se comunique (na configuração do dispositivo escravo veremos como pode-se definir o endereço do mesmo).

Wire.beginTransmission(0x08);

- Enviando os dados desejados

Para enviar os dados para o escravo definido pelo endereço determinado na utilização da função anterior devemos utilizar a sentença Wire.write(). O parâmetro desta função é justamente a informação que nós queremos que o mestre envie para o escravo, neste caso, o valor armazenado na variável estado_LED.

wire.write(estado_LED);

- Finalizando a transmissão

Após o envio da informação, finalizamos a transmissão utlilizando a sentença Wire.endTransmission().

Wire.endTransmission();

- Atualização da variável estado_LED

Por fim, atualizamos a variável estado_LED fazendo com que o seu valor seja o inverso do que era anteriormente, ou seja, caso seu valor seja 0, na próxima iteração (lembrando que o conteúdo da função loop() é executado repetidamente) ele deverá ser 1. Além disso, utilizamos a função delay() para que este envio de informações aconteça a cada 1 segundo.

estado_LED = !estadoLED;
delay(1000);

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

void loop() {
  Wire.beginTransmission(0x07); 
  wire.write(estado_LED);            
  Wire.endTransmission();
  
  estado_LED = !estadoLED;   

  delay(1000);
}

Software - Arduino UNO (Escravo)

Agora iremos demonstrar o passo a passo como funciona o código que deve ser gravado no Arduino UNO, que por sua vez, atuará como escravo no barramento

- Incluindo a biblioteca que será utilizada

Assim como no caso anterior, devemos incluir a biblioteca que será utilizada no código, portanto, através da diretiva #include, dizemos ao Arduino Micro que iremos utilizar a biblioteca Wire.h, responsável por conter as funções necessárias para gerenciar a comunicação entre os dispositivos através do protocolo I2C.

#include <Wire.h>

- Definindo as configurações iniciais

Dentro da função setup() utilizamos a sentença Wire.begin() para inicializar a comunicação do Arduino UNO através do protocolo I2C, no entanto, desta vez, utilizamos o valor 0x07 como parâmetro, em outras palavras, quando fazemos isto, estamos dizendo que a placa Arduino em questão estará presente no barramento como escravo e que o endereço do mesmo será 0x07.

 Wire.begin(0x08);

Além disso, através da sentença Wire.onRecieve() determinamos qual função deverá ser executada quando chegar alguma informação proveniente do elemento-mestre do barramento. Neste caso, quando ocorrer a situação prevista, a função chamada será a receiveEvent() (note que esta função pode ter qualquer nome, utilizamos este somente pelo fato de que na literatura oficial esta é denominada desta forma na maioria das vezes).

Wire.onReceive(receiveEvent);

Por último, determinando que o pino 4 do Arduino UNO atue como uma saída digital através da função pinMode().

 pinMode(4,OUTPUT);

Veja como ficou nossa função setup()

void setup() {
  Wire.begin(0x07);                
  Wire.onReceive(receiveEvent);   
  pinMode(4,OUTPUT);     
}

- Lendo os dados recebidos

Em um primeiro momento, devemos ressaltar que não foi necessário utilizar nenhum procedimento dentro da função loop(), pois, o tratamento dos dados recebido será demonstrado posteriormente. Sendo assim, utilizamos apenas a função delay() em virtude de este procedimento ser aconselhado nos exemplos oficiais do Arduino

void loop() {
  delay(100);
}

No final do código apresentamos a função receiveEvent(), que por sua vez, será chamada sempre que houver alguma informação proveniente do mestre, chegando. Nesta função utilizamos a sentença Wire.read() para obter o valor relativo ao estado do led (enviado pelo mestre) e armazená-lo na variável estado, de modo que, conforme o conteúdo da mesma, optamos através de uma função if() se devemos acender ou apagar o led.

void receiveEvent(int leitura) 
{  
  bool estado = Wire.read();   

  if ( estado == 1){
    digitalWrite(4,HIGH);
  }
  else{
    digitalWrite(4,LOW);
  }
}

Considerações finais

Neste tutorial, demonstramos como você pode utilizar o protocolo de comunicação I2C para fazer com que duas placas Arduino troquem informações entre si. Este foi apenas um conteúdo para que você tenha uma noção de como das os primeiros passos com o protocolo citado, portanto, esperamos que continue nos acompanhando e sinta-se à vontade para nos dar sugestões, críticas ou elogios. Lembre-se de deixar suas dúvidas nos comentários abaixo.


Módulo relé - Acionando cargas com Arduino

Módulo relé - Acionando cargas com Arduino

Ao se trabalhar com sistemas inteligentes, é comum a necessidade de se controlar cargas das mais diversas potências, tal como: lâmpadas, motores, resistências, etc. O componente mais usado para ligar e desligar esses aparelhos são o relés. O relés são responsáveis por ligar e desligar equipamentos através de comandos. Neste tutorial você entenderá a importância dos relés, como funcionam. Aprenderá, também, a usar um módulo relé com seu Arduino.

[toc]

Para que servem os Relés?

Os microcontroladores, tais como Atmega, PIC e MSP, são dispositivos lógicos. Eles são usados com o intuito de ser a inteligência do circuito, o cérebro de nosso sistema inteligente.

Por isso, um microcontrolador usa tensões e correntes baixas para funcionar e não são produzidos para suportar grandes tensões e correntes. O Arduino UNO, por exemplo, que usa o Atmega328, suporta um máximo de 40mA em suas portas I/O e fornece uma tensão de 5V. Além disso, é sempre aconselhável separar o sistema de inteligência do sistema de acionamento, para que curtos ou problemas no sistema de acionamento não danifique sua placa Arduino.

Quando queremos acionar cargas com valores de corrente ou tensão maiores precisamos utilizar algum dispositivo que suporte tal carga. Por exemplo: Queremos acender uma lâmpada de 127V quando estiver escuro. Sabemos que o Arduino não é capaz de fornecer tal tensão, para isso iremos precisar de algum dispositivo capaz de ligar e desligar a lâmpada através do comando do nosso Arduino, uma boa pedida é o relé.

Para entender melhor o relé, vamos ver a diferença e semelhança entre ele e um interruptor residencial.

- Entendendo um interruptor

Diariamente ligamos e desligamos lâmpadas através de um dispositivo muito eficaz, o interruptor. Tal como o nome já diz, ele tem a capacidade de interromper o fluxo de energia e vice-versa. Veja na figura abaixo como um interruptor trabalha. O fio vermelho, que é o positivo e traz a energia, passa pelo interruptor e depois vai para a lâmpada que já possui o negativo conectado. Quando o interruptor está aberto, não temos passagem de energia, quando mudamos o estado dele e fechamos o contato, a lâmpada liga.

Interruptor residencial
Interruptor residencial

- Entendendo um Relé

Um relé é semelhante a um interruptor, com uma diferença, não precisamos usar nosso dedo para fechar ou abrir o contato. Para essa função, usamos um sistema engenhoso que quando alimentado, fecha o contato.

Esse sistema engenhoso possui um eletroímã, ou seja. Uma bobina que quando energizada criará um campo eletromagnético, se tornando um imã. Devido a força de atração magnética do eletroímã teremos a movimentação do interruptor. Veja a imagem a baixo para que possa entender melhor:

Dentro de um relé
Dentro de um relé

Quando alimentamos os terminais 3 e 4 da bobina, ela gera um campo eletromagnético que atrai a haste conectada ao terminal 2, que vence a força exercida pela mola conectada a ela. Isso faz com que essa haste se mova até encostar na haste conectada ao terminal 1. Com isso, teremos o contato fechado.

Quando paramos de alimentar a bobina através dos terminais 3 e 4, a força magnética exercida sobre a haste conectada ao terminal 2 deixa de existir e a mola puxa a haste de volta ao seu lugar inicial, abrindo o contato. Portanto, agora temos um interruptor acionado por uma bobina.

Usando um relé, podemos controlar um dispositivo, tal como a lâmpada de 127V que possui uma corrente e tensão alta, através da alimentação de uma bobina. A corrente e a tensão que essa bobina precisa varia com a especificação do relé.

Módulo Relé

Apesar de a bobina relé demandar uma corrente e uma tensão baixa, ainda assim o relé precisa de mais energia do que uma porta digital da sua placa Arduino pode fornecer.

Por conta disso, precisamos de um circuito auxiliar para o acionamento do relé. Esse circuito, que usa uma fonte de alimentação que pode ser a própria saída de 5V do seu Arduino, não é trivial, mas já pode ser encontrado pronto nos módulos relés muito usados com Arduino. Esse tipo de módulo poupa tempo e é muito simples de usar.

Módulo relé de 1 canal.
Módulo relé de 1 canal.

Veja que esse módulo relé possui 3 pinos. São eles:

  • Vcc - Pino para alimentação 5V
  • GND - Pino para Terra 0v
  • IN - Pino de comando do módulo. Esse é o pino responsável por ligar ou desligar o relé.

Existem vários modelos de módulos relés com diversas quantidades de canais, indo até 16 relés em uma só placa:

Módulo relé de 16 canais.
Módulo relé de 16 canais.

Veja algumas opções de módulos relés nesse link do Vida de Silício


Mãos à obra – Detectando elementos

Cuidado!

Nesse tutorial iremos mexer com tensões e correntes maiores. Tome cuidado ao manusear seu projeto, risco de choque!!

Tome cuidado para não energizar seu Arduino com a tensão da tomada. Isso irá queimá-lo.

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.

Vamos separar essa montagem em duas partes:

- Circuito de controle

Essa parte do projeto representa o Arduino e seus periféricos de baixa potência. Para montar seu circuito, use a figura a seguir. Garanta que seu Arduino esteja desligado durante a montagem.

O pino de entrada do botão é o 8 e o pino de saída do relé é o 13.

- Circuito de potência

Nessa parte iremos montar a parte de maior potência do nosso circuito. Para esse projeto iremos precisar de uma extensão que você não usará mais, ou você pode fazer a sua.

Quando lidamos com energia elétrica temos que tomar muito cuidado! Então monte seu projeto com segurança.  Não queremos transformar nossa diversão em dor de cabeça, não é mesmo?

Por isso, vamos montar uma extensão segura. Caso você já tenha uma que possa cortar os seus fios, você poderá usá-la. Basta executar apenas os três últimos passos.

Para nossa extensão você vai precisar de:

  • Um adaptador de tomada macho
  • Um adaptador de tomada fêmea
  • 4 metros de Fio de cobre (Fique à vontade em relação ao tamanho).
Adaptadores e fio para fazer a extensão
Adaptadores e fio para fazer a extensão

Vamos montar nossa extensão:

  • Divida seu fio de cobre em dois fios de 2 metros (ou metade do tamanho que você tiver). Dessa forma, você terá dois fios iguais;
  • Com seu alicate, descasque a ponta de cada fio;
Descasque a ponta do fio.
Descasque a ponta do fio.
  • Parafuse a ponta dos dois no adaptador macho;
Parafuse os fios dentro dos adaptadores.
Parafuse os fios dentro dos adaptadores.
  • Parafuse a outra ponta dos dois no adaptador fêmea;
Extensão pronta.
Extensão pronta.
  • Agora vamos conectá-la ao nosso circuito.
  • Corte um dos dois fios em um ponto onde ficará nosso módulo relé, verifique o melhor ponto para coloca-lo. (É para corta apenas um dos fios!)
contando 1 dos fios para colocarmos o módulo relé
Contando 1 dos fios para colocarmos o módulo relé
  • Descasque as duas pontas do fio cortado;
  • Parafuse uma no comum (COM) e outra no contato normalmente aberta (Pode está escrito nessa porta a sigla NA ou NO);
Parafuse os fios no módulo relé
Parafuse os fios no módulo relé.

Agora, volte, e confira se você realmente montou tudo como explicado.

Seu circuito ficará semelhante ao da foto a seguir:

Sistema montado.

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

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

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

#define RELE 13 
#define BOTAO 8

void setup() 
{
    pinMode(BOTAO, INPUT_PULLUP);
    pinMode(RELE, OUTPUT);
    estavel = digitalRead(BOTAO);
    estadoRele= 0; 
}

bool changed() 
    {
         bool now = digitalRead(BOTAO);   
         if (instavel != now) 
         {       
              bounce_timer = millis();   
              instavel = now;            
         }
         else if (millis() - bounce_timer > 10) 
         {  
              if (estavel != now) 
              {           
                  estavel = now;                  
                  return 1;
         }
    }
    return 0;
}

void loop() 
{
     if (changed()) { //verifica se houve mudança de estado
     { 
          if (digitalRead(BOTAO))
          {   
               estadoRele=!estadoRele;  //se mudou o estado e o botão está pressionado muda o valor de set
          }
     }
     digitalWrite(RELE,estadoRele);
}

Depois de escrever o código, clique em Upload para que o programa seja transferido para seu Arduino.

Colocando para funcionar

Conecte algum aparelho em sua extensão (que tenha uma coerente menor que 10A), um ventilador por exemplo. Então ligue seu Arduino e em seguida ligue a tomada de sua extensão.

Cuidado!

Só ligue seu sistema na tomada quando tiver a certeza que está tudo corretamente conectado.

Tome cuidado para não tomar um choque ou energizar seu Arduino com a tensão da tomada. Isso irá te machucar ou queimar seu Arduino.

Se tudo deu certo, quando você apertar o botão uma vez, o dispositivo que estiver ligado na tomada deverá ligar.

Sistema com relé acendendo lampada depois de apertado o botão pela primeira vez
Sistema depois de apertado o botão pela primeira vez

Quando apertar uma segunda vez, o dispositivo deverá desligar.

Sistema depois de apertado o botão pela segunda vez
Sistema depois de apertado o botão pela segunda vez

Entendendo a fundo

Software

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

Primeiramente, utilizamos a diretiva #define para associar o pino de entrada digital 13 ao nome RELE e o pino digital 8 ao nome BOTAO (vale ressaltar que isso é apenas um recurso para facilitar a didática da programação, portanto, não obrigatório).

#define RELE 13
#define BOTAO 8

– Declarando as variáveis a serem utilizadas no projeto

Em seguida, temos um bloco onde ocorre a declaração das variáveis que serão utilizadas no decorrer do programa. As variáveis estavel instavel (ambas booleanas) e a variável bounce_timer (tipo unsigned long) são responsáveis por coordenar o processo de tratamento do bounce existente ao utilizarmos um push-button. Além disso, temos a variável estadoRele, também booleana, cuja função é acionar e desacionar o relé.

Um ponto importante que deve ser ressaltado aqui é que neste tipo de projeto torna-se fundamental o tratamento citado anteriormente, portanto, caso você tenha dúvidas no procedimento, sugerimos a leitura do nosso tutorial Leitura de botões e o Bounce.

bool estavel;    // Guarda o último estado estável do botão;
bool instavel;   // Guarda o último estado instável do botão;
unsigned long bounce_timer;
bool estadoRele;

– Definindo as configurações iniciais do projeto

Dentro da função setup(), temos a definição dos modos de operação dos pinos que serão utilizados neste projeto, isto é, do pino 13 como um pino de saída digital e do pino 8 como um pino de entrada digital. Além desta configuração, por meio da função digitalRead(), fazemos com que a variável estavel armazene o estado em que o botão se encontra no começo do programa e por fim, carregamos a variável estadoRele com o valor 0.

void setup() {
  pinMode(BOTAO, INPUT_PULLUP);  
  pinMode(RELE, OUTPUT); 
  estavel = digitalRead(botao);
  estadoRele= 0;
}

– Acionando o relé

O procedimento de acionamento do relé é bem simples, de modo que, a única coisa que fazemos é verificar o retorno gerado através da execução da função changed(), o qual, será verdadeiro ou falso. Caso o retorno da mesma seja verdadeiro, quer dizer que o usuário do projeto deseja efetuar uma mudança no estado do relé, sendo assim, verifica-se posteriormente se o botão está pressionado, para que, por fim, o conteúdo da variável estadoRele seja atualizado com o inverso do seu valor e possa ser utilizado na manipulação do relé através da função digitalWrite().

void loop() 
{
     if (changed()) 
     { 
          if (digitalRead(botao))
          {   
               estadoRele=!estadoRele; 
          }
     digitalWrite(RELE,estadoRele);
}

Conforme ressaltamos anteriormente, utilizamos a função changed() para conferir se houve alguma mudança do estado do relé, desejada pelo operador. Esta função é a responsável por atuar no tratamento do bounce quando houver um aperto do botão. Basicamente, o que ocorre neste ponto é a verificação do estado do botão após a passagem de uma quantidade de tempo julgada necessária para garantirmos que o sinal não sofre mais alterações em virtude da trepidação inerente ao seu funcionamento.

Novamente ressaltamos que, caso você tenha alguma dúvida neste ponto, consulte nosso tutorial sobre o tratamento do bounce, clicando aqui.

bool changed() 
    {
         bool now = digitalRead(BOTAO);   
         if (instavel != now) 
         {       
              bounce_timer = millis();   
              instavel = now;            
         }
         else if (millis() - bounce_timer > 10) 
         {  
              if (estavel != now) 
              {           
                  estavel = now;                  
                  return 1;
         }
    }
    return 0;
}

Desafio

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

Faça isso:

  • Ligue uma lâmpada quando detectar movimento no ambiente (Tutorial HC-SR501) ;
  • Ligue um ventilador caso a temperatura esteja muito alta (Tutorial LM35).

Dica: Leia nosso tutorial ensinando como controlar um Módulo Relé através de seu celular utilizando um Módulo Bluetooth:

Considerações finais

Neste tutorial demonstramos como você deve proceder para utilizar relés no acionamento de cargas cujas especificações de tensão e corrente não permitem que as mesmas sejam feitas diretamente por uma placa Arduino. 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.


Módulo RFID RC522 Mifare com Arduino

Módulo RFID RC522 Mifare com Arduino

Neste tutorial entenderemos um como funciona um sistema RFID e aprenderemos como utilizar o módulo RFID RC522 Mifare através do Arduino.

[toc]

Entendendo o RFID

A tecnologia de RFID (Radio Frequency IDentification – identificação por radiofrequência) é um método de identificação através de sinais de rádio. Existem diversos métodos de identificação, mas o mais comum é armazenar um número de série que identifique uma pessoa ou um objeto, ou outra informação em um microchip.  

Tal tecnologia permite a captura automática de dados para identificação de objetos com dispositivos eletrônicos conhecidos como etiquetas eletrônicas, RF tags, cartões RF ou transponders, que emitem sinais de radiofrequência para leitores que captam estas informações. Tal tecnologia existe desde a década de 40 e veio para complementar a tecnologia de código de barras, bastante difundida no mundo.

O RFID pode ser utilizado em diferentes aplicações, inclusive na parte de segurança, onde podemos citar como exemplos de sua utilização o controle de acesso em catracas, alarmes contra furtos em lojas e até mesmo para o desbloqueio de computadores. Outra função muito comum que é atribuída a essa tecnologia são os cartões de utilização de transporte público.

Aplicação comum do RFID no controle de acesso
Aplicação comum do RFID no controle de acesso

Como funciona os sistemas RFID

Um sistema de RFID é composto, basicamente, de:

  • Um transceptor com decodificador e uma antena;
  • Um transponder (chamado também de Tag) que é eletronicamente programado com informações.

O transceptor emite, através de uma antena, sinais de rádio para ativar o Tag, que por sua vez, reponde uma mensagem ao receptor com a informações armazenadas em seu chip.

Uma tag é composta, basicamente, por um chip, que armazena informações, e uma antena.

Transponder RFID
Transponder RFID

Os transponders RFID são divididos em dois tipos : passivos e ativos.

Os transponders passivos utilizam a energia da onda de rádio frequência emitida pelo leitor para transmitir o seu sinal de resposta. Geralmente vêm com suas informações gravadas permanentemente quando são fabricadas. Contudo, em algumas é possível alterar as informações armazenadas em seu chip.

A grande vantagem dos transponders passivos é a facilidade de usa-lo em diversas aplicações, tais como: etiquetas, passaportes, chaveiros, cartões, etc.

Exemplo de aplicação de uma tag RFID passiva em uma etiqueta
Exemplo de aplicação de uma tag RFID passiva em uma etiqueta

Os transponders ativos contam com uma fonte de energia própria para transmitir seu sinal de resposta, aumentando o alcance. Esse tipo de Tag pode contar com memória RAM, capaz de armazenar até 32 KB de informação.

Exemplo de transponder RFID ativo usado para identificação de um veículo.
Exemplo de transponder RFID ativo usado para identificação de um veículo. Eles são muito usados nesse tipo de aplicação devido ao seu maior alcance.

Outra característica importante dos sistema RFID é a frequência de operação. A frequência interfere na taxa de transferência de dados entre a etiqueta e o leitor e em seu alcance.

As três frequências mais utilizadas para o sistema RFID passivo são: baixa frequência (LF), de 125kHz, alta frequência (HF), 13,56 MHz, e ultra alta frequência (UHF), operando na faixa de 860 a 960MHz.

Quanto maior a frequência, maior será o alcance máximo, mas esse não é o único fator. Também influenciam no alcance do sistema RFID: potencia e sensibilidade do transceptor e o tipo de transponder.

Módulo RFID-RC522 13,56MHz Mifare

Este módulo RFID usa o chip MFRC522 da empresa NXP, que por sua vez, pode ser usado em comunicações a uma frequência de 13,56MHz, permitindo, por exemplo, sem contato, a leitura e escrita em cartões que seguem o padrão Mifare.

Módulo RFID MFRC522 Mifare - Tansceptor

Para usar a tecnologia RFID precisamos de um receptor e de um emissor. Geralmente o módulo leitor RFID RC522 acompanha um kit com uma tag e um cartão RFID o qual usaremos nesse projeto.

Exemplo de cartão e tag RFID MFRC522 Mifare
Exemplo de cartão e tag RFID MFRC522 Mifare - Transponders

Mão à obra - Usando o Módulo Leitor RFID-RC522 13,56MHz Mifare com Arduino

Componentes necessários

Montando o projeto

 

Esquema de montagem do Módulo RFID RC522 Mifare com Arduino
Esquema de montagem do Módulo RFID RC522 Mifare com Arduino

Programando

- Biblioteca

Para desenvolver o projeto proposto com o Módulo RFID RC522 utilizou-se a biblioteca MFRC522.h. Esta biblioteca foi produzida por Miguel Balboa e está disponível neste link.

Você pode expandir o tutorial abaixo para aprender como instalá-la.

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.

Como baixar a biblioteca RFID
Como baixar a biblioteca RFID

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

Não ligar o módulo RFID-RC522 em 5V, o mesmo deve ser ligado em 3,3V.

//Vida de Silício
//Felipe Gbur

#include <SPI.h>
#include <MFRC522.h>

#define SS_PIN 10
#define RST_PIN 9
#define LED_R 2//LED Vermelho
#define LED_G 3 //LED Verde
char st[20];

MFRC522 mfrc522(SS_PIN, RST_PIN);

void setup()
{
  // Inicia a serial
  Serial.begin(9600);
  // Inicia  SPI bus 
  SPI.begin();
  // Inicia MFRC522    
  mfrc522.PCD_Init();
  Serial.println("Aproxime o seu cartao/TAG do leitor");
  Serial.println();
  pinMode(LED_R, 2);
  pinMode(LED_G, 3);
}

void loop()
{
  digitalWrite (LED_G, LOW);
  digitalWrite (LED_R, HIGH);

  // Busca novos cartões 
  if ( ! mfrc522.PICC_IsNewCardPresent())
  {
    return;
  }
  // Seleciona um catão a ser lido
  if ( ! mfrc522.PICC_ReadCardSerial())
  {
    return;
  }
  //Mostra ID na serial
  Serial.print("ID da tag:");
  String conteudo = "";
  byte letra;
  for (byte i = 0; i < mfrc522.uid.size; i++)
  {
    Serial.print(mfrc522.uid.uidByte[i] < 0x10 ? " 0" : " ");
    Serial.print(mfrc522.uid.uidByte[i], HEX);
    conteudo.concat(String(mfrc522.uid.uidByte[i] < 0x10 ? " 0" : " "));
    conteudo.concat(String(mfrc522.uid.uidByte[i], HEX));
  }
  Serial.println();
  Serial.print("Mensagem : ");
  conteudo.toUpperCase();

  if (conteudo.substring(1) == "D6 35 19 7E") //ID CARTÃO
  {
    Serial.println("Acesso autorizado !");
    Serial.println();
    digitalWrite (LED_G, HIGH);
    digitalWrite (LED_R, LOW);
    delay(5000);//Delay apagar LED Verde
    digitalWrite (LED_G, LOW);
    digitalWrite (LED_R, HIGH);
  }
}

Colocando para funcionar

- Descobrindo o endereço do cartão ou tag

Depois de carregar o código para seu Arduino você deve entrar no monitor serial e verificar a UID de sua tag que esta sendo detectada pelo modulo e esta sendo impressa no monitor serial,  posteriormente você deve substituir a UID que já esta no código para a UID de sua tag. É possível ver na imagem a baixo Duas tag diferentes sendo utilizadas, sendo que uma delas não esta cadastrada.

Descobrindo a ID do cartão.

- Projeto com Cartão cadastrado

Resultado final.


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 SPI.h é a responsável pela comunicação utilizando o protocolo SPI enquanto a biblioteca MFRC522.h atua sobre a biblioteca SPI.h simplificando o processo de comunicação através do protocolo citado, para que assim, o usuário possa utilizar o Módulo Leitor RFID-RC522 de maneira mais fácil.

#include <SPI.h> 
#include <MFRC522.h>

– Nomeando os pinos de entrada e saída através da diretiva #define

Em seguida, utilizamos a diretiva #define para associar os pinos digitais 10 e 9 para serem usado na comunicação SPI. Também nomeamos o pinos digitais que serão usados para acionar os LED's.

#define SS_PIN 10 
#define RST_PIN 9 
#define LED_R 2   //LED Vermelho 
#define LED_G 3   //LED Verde

Vale ressaltar que isso é apenas um recurso para facilitar a didática da programação, portanto, não obrigatório.

– Declarando o objeto mfrc522

Em seguida, cria-se o objeto chamado  que irá representar o módulo RFID

Lembre-se:mfrc522 é apenas um nome que escolhemos, sendo assim, é importante ressaltar que, o objeto identificado por mfrc522 poderia ser chamado de qualquer outro nome, como por exemplo, moduloRFID.

MFRC522 mfrc522(SS_PIN, RST_PIN);

– 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 UNO com o computador  (onde será possível ver o resultado do projeto)

Serial.begin(9600);

Em seguida, utiliza-se a função SPI.begin() para inicializar a comunicação.

// Inicia SPI bus 
SPI.begin();

Posteriormente, recorre-se à função mfrc522.PCD_Init() para inicializar o RFID-MFRC522.

// Inicia MFRC522 
mfrc522.PCD_Init();

A função mfrc522.PICC_IsNewCardPresent() inserida dentro de um laço de repetição, faz com que o modulo fique buscando por um novo cartão a ser lido.

// Busca novos cartões 
  if ( ! mfrc522.PICC_IsNewCardPresent())
  {
    return;
  }

Suscetivamente a função mfrc522.PICC_ReadCardSerial() tem como objetivo ler a TAG ler o cartão que foi encontrado anteriormente.

// Seleciona um catão a ser lido
  if ( ! mfrc522.PICC_ReadCardSerial())
  {
    return;
  }

Esta parte do código tem como finalidade imprimir no monitor serial a UID da TAG que foi lido.

 //Mostra ID na serial
  Serial.print("ID da tag:");
  String conteudo = "";
  byte letra;
  for (byte i = 0; i < mfrc522.uid.size; i++)
  {
    Serial.print(mfrc522.uid.uidByte[i] < 0x10 ? " 0" : " ");
    Serial.print(mfrc522.uid.uidByte[i], HEX);
    conteudo.concat(String(mfrc522.uid.uidByte[i] < 0x10 ? " 0" : " "));
    conteudo.concat(String(mfrc522.uid.uidByte[i], HEX));
  }

Aqui é onde você define a UID do seu cartão/tag if (conteudo.substring(1) == "Sua tag"), onde no código é usada como exemplo a seguinte TAG: 75 25 17 CB.

Nesta parte também é onde esta definida a função do projeto, em nosso caso, quando o tag for lido o LED verde deve se acender para sinalizar que o acesso foi autorizado.

É importante ressaltar que caso queira registrar mais de uma tag você deve copiar o código a partir do if e posteriormente registrar a UID da nova tag.

Serial.print("Mensagem : ");
  conteudo.toUpperCase();

  if (conteudo.substring(1) == "75 25 17 CB") //UID CARTÃO
  {
    Serial.println("Acesso autorizado !");
    Serial.println();
    digitalWrite (LED_G, HIGH);
    digitalWrite (LED_R, LOW);
    delay(5000);//Delay apagar LED Verde
    digitalWrite (LED_G, LOW);
    digitalWrite (LED_R, HIGH);
  }

Desafio

  1. Implemente um projeto que imprima em um Display LCD 16x2, ou no monitor serial caso não tenha o LCD, o nome do portador do Cartão;
  2. Faça um controle de ponto identificando o horário de saída e de entrada de uma pessoa usando o RTC DS3231.

Tutoriais vão de ajudar nesses desafios:

Considerações finais

Hoje aprendemos um pouco sobre a tecnologia RFID, e como utilizamos o módulo RFID-RC522 13,56MHz. Comente o que achou da postagem, e compartilhe conosco  como pretende utilizar desta tecnologia em seu projeto.


Shield Ethernet W5100 - Criando um Servidor Web com Arduino

Shield Ethernet W5100 - Primeiros passos na criação de um Servidor Web com Arduino

Em uma das nossas publicações anteriores ensinamos como você deve proceder para criar um Servidor Web com o NodeMCU. Neste tutorial, iremos utilizar um Shield Ethernet W5100 para criar um Servidor Web que terá como função fornecer uma página web contendo informações enviadas pelo Arduino UNO.

Respostar do servidor web - Página feita através do Arduino Uno em conjunto com o Ethernet Shield W5100
Resultado deste projeto.

[toc]

O que é um Servidor Web?

Ao navegarmos pelo gigante universo de possibilidades da internet, podemos não nos dar conta do que existe por trás disso tudo.

A internet é uma união de redes de computadores em nível mundial conversando entre si através de um conjunto próprio de protocolos de comunicação, como por exemplo, o TCP/IP, que por sua vez, consiste em um protocolo para transmissão de informações orientado à conexão, ou seja, cuja função consiste em permitir que as maquinas se comuniquem e gerenciem o estado atual da transmissão.

- Os Servidores

Um dos protagonistas desse universo são os servidores. A grosso modo, esses servidores são computadores responsáveis por fornecer e receber dados dos diversos clientes, atuando como centralizadores de informação.

servidor cliente
Conexão cliente/servidor

Indo um pouco a fundo, um servidor consiste em um software dentro um computador centralizador. Através de uma rede particular ou da internet,  esse servidor pode receber dados de clientes bem como fornecê-los.

O estabelecimento das relações entre o conjunto Servidor/Cliente é baseado em um sistema de recebimento, processamento e resposta, no qual, o servidor recebe, processa e responde a requisições feitas por um Cliente através de algum protocolo de comunicação.

- O HTTP - Protocolo de Transferência de Hipertexto

Um dos principais exemplos da relação Servidor/Cliente é a relação entre os computadores que atuam como servidores hospedando sites e os navegadores que utilizamos em nossos computadores ou celulares, os clientes. Neste tipo de relação, utiliza-se para estabelecer a comunicação, o procotolo o HTTP (Hypertext Transfer Protocol), o qual, é responsável pelo tratamento dos pedidos e respostas entre cliente e servidor na World Wide Web ou em uma rede localNesse contexto, chamamos os servidores de Servidores Web.

Comunicação requisição http servidor web
Utilização do protocolo HTTP.


- HTML - Linguagem de Marcação de Hipertexto

As informações que o Servidor Web envia para seu navegador a partir de uma requisição HTTP feita pelo mesmo, pode ocorrer em alguns determinados formatos que precisarão ser interpretados. Um desses formatos é o HTML (HyperText Markup Language), que por sua vez, é uma linguagem utilizada na construção de páginas na Web.

Por trás de uma Página web
Linguagem HTML.

O Shield Ethernet W5100

Como sabemos, os shields compatíveis com o Arduino UNO são placas de circuito que podem ser conectadas sobre o mesmo, encaixando-se perfeitamente, com o intuito de expandir suas capacidades em determinada vertente.

Neste tutorial, apresentamos o Shield Ethernet W5100, que por sua vez, consiste em um shield dotado de dois módulos, um módulo Ethernet que irá permitir a conexão do Arduino UNO, em um primeiro momento, com uma rede local e um módulo para cartão SD.

Sendo assim, perceba que é perfeitamente possível utilizar este módulo somente para ler/escrever dados em um cartão de memória ou apenas para conectar o Arduino UNO a uma rede local.

Shield Ethernet W5100 servidor web arduino
Shield Ethernet W5100.

Neste tutorial iremos utilizar apenas o módulo Ethernet do shield em questão, pois, iremos elaborar uma pagina simples para ser apresentada ao usuário através do navegador, no entanto, o módulo de cartão SD é muito útil para conter arquivos necessários para a construção de uma página mais rica em informações, como por exemplo, imagens.


Mãos à obra - Criando um Servidor Web com o Arduino UNO e o Shield Ethernet W5100

Nesta seção iremos demonstrar todos os passos que você deve seguir para aprender a criar um Servidor Web.

Componentes necessários

Para reproduzir este projeto, você irá precisar dos seguintes componentes:

Montando o projeto

Shield Ethernet W5100 no Arduino uno
Hardware utilizado.

Gostaríamos de sugerir que você tenha bastante cuidado no momento em que for encaixar o Shield Ethernet W5100 no Arduino UNO, pois, além da possibilidade de entortar os pinos do shield, você também pode se machucar.

Lembre-se que o shield ethernet W5100 possui uma série de pinos em sua parte inferior, tanto nas laterais como em sua parte dianteira, portanto, antes de pressionar o mesmo sobre o Arduino UNO, certifique-se de que os pinos estejam levemente posicionados em suas respectivas entradas para que então você possa ir realizando o encaixe lentamente.

Realizando as conexões

Para reproduzir este projeto, garanta que o seu Shield Ethernet W5100 esteja ligado corretamente a uma das portas LAN presentes no seu modem ou roteador.

Programando

Este programa foi elaborado a partir do código-exemplo da biblioteca Ethernet.h denominado WebServer.

Antes de utilizar este código, leia a seção Entendendo a fundo para adaptar os trechos necessários para o funcionamento da sua aplicação.

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

byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };
IPAddress ip(192, 168, 25, 16); 
EthernetServer server(80);     

void setup() 
{
    Ethernet.begin(mac, ip);  
    server.begin();           
} 

void loop() 
{
    EthernetClient client = server.available();  

    if (client) 
    { 
      
        boolean currentLineIsBlank = true;
        while (client.connected()) 
        {
            if (client.available())
            {   
                char c = client.read(); 
                
                if (c == '\n' && currentLineIsBlank) 
                {
                  
                    client.println("HTTP/1.1 200 OK");
                    client.println("Content-Type: text/html");
                    client.println("Connection: close");
                    client.println();
                    client.println("<!DOCTYPE html>");
                    client.println("<html>");
                    client.println("<head>");
                    client.println("<title>Servidor Web VDS</title>");
                    client.println("</head>");
                    client.println("<body>");
                    client.println("<h1>Meu primeiro Servidor Web</h1>");
                    client.println("<p>Esperamos que voce tenha gostado deste tutorial</p>");
                    client.println("</body>");
                    client.println("</html>");
                    break;
                }
                
                if (c == '\n') 
                {
                    currentLineIsBlank = true;
                } 
                else if (c != '\r') 
                {
                    currentLineIsBlank = false;
                }
            } 
        }
        
        delay(1);      
        client.stop(); 
        
    } 
}

Colocando para funcionar

Veja como ficou nosso primeiro Servidor Web.

Respostar do servidor web - Página feita através do Arduino Uno em conjunto com o Shield Ethernet W5100
Página da web criada.

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 SPI.h é a responsável pela comunicação dos módulos do Shield Ethernet W5100 com o Arduino UNO utilizando o protocolo SPI e a biblioteca Ethernet.h atua possibilitando a conexão do conjunto, em um primeiro momento, com uma rede local.

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

- 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.

Na prática, o endereço MAC pode ser qualquer um, desde que seja único na rede. Como sugestão, copie a sentença abaixo.

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

- Definindo o endereço IP do Arduino UNO

Além do endereço MAC definido anteriormente, torna-se necessário definir um endereço IP para o nosso Arduino UNO. Isso é imprescindível para que seja possível estabelecer a conexão entre o mesmo e a rede.

Este endereço deve estar disponível na sua rede local para que possa ser utilizado

Existem várias maneiras de encontrar um endereço válido na sua rede local, de modo que, demonstraremos uma forma bastante simples de realizar este procedimento, confira abaixo:

  1. Acesse um computador que esteja conectado na sua rede local
  2. Abra o Prompt de Comando do Windows (supondo que o sistema operacional seja Windows)
  3. Digite ipconfig

Neste momento, um conjunto de informações será disponibilizado, no entanto, o dado que requer sua atenção é justamente o endereço IP da máquina que você está utilizando (ele estará apresentado pelo nome IPV4).

Verificando o ip a ser usado pelo ethernet shield w5100

Primeiramente, repare que o endereço IP destacado possui quatro partes separadas por pontos. Para encontrarmos um possível endereço disponível em nossa rede local, basta modificarmos a última parte do endereço encontrado, como por exemplo, o endereço 192.168.25.16 . Geralmente, este procedimento é suficiente para encontrar possíveis endereços disponíveis em redes locais pequenas, como as das nossas casas.

IPAddress ip(192, 168, 25, 16);

- Criando o objeto server

Neste momento, cria-se um objeto chamado server, que por sua vez, será responsável por representar o Servidor Web no código do Arduino UNO.

Note que ao criarmos o objeto, passamos o número 80 como parâmetro, pois estamos determinando a porta que o Servidor Web utilizará para enviar as páginas web que serão criadas posteriormente.

A título de curiosidade, quando digitamos o endereço de algum site no navegador, ele automaticamente procura a porta 80 do servidor no qual está se conectando, de modo que, se o serviço responsável por disponibilizar as páginas da web para o cliente estiver em outra porta, devemos especificar esta no endereço do site citado, por exemplo: www.exemplo.com.br:1234

EthernetServer server(80);

- Iniciando a comunicação com a rede local e o Servidor Web

Na função setup() iniciamos a conexão com a rede local através da função Ethernet.begin() (passando como parâmetro os endereços MAC e IP definidos anteriormente) e também iniciamos o Servidor Web por meio da sentença server.begin() (lembre-se que server é o objeto criado para representar o Servidor Web no código).

Ethernet.begin(mac, ip);
server.begin();  

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

void setup() 
{
   Ethernet.begin(mac, ip);
   server.begin();
}

- Respondendo as requisições de um navegador

Verificando se existe requisição de conexão

Primeiramente, na função loop(), temos a sentença server.available() que verifica se existe tem algum cliente tentando fazer uma conexão. Como dito anteriormente, vamos chamar de cliente, o navegador que está tentando fazer a conexão com o Servidor Web através do endereço IP do mesmo. Repare que foi criada uma variável para conter o valor retornado pela função server.available().

EthernetClient client = server.available();

Em seguida, temos uma função if() cujo conteúdo será executado apenas no caso de termos um cliente tentando se conectar ao Servidor Web criado e iniciado anteriormente.

if (client)
{
   ***** Conteúdo da função if() *****
}

Supondo que temos um cliente tentando se conectar com o nosso Servidor Web, primeira sentença do conteúdo da função if() apresentada anteriormente consiste na declaração de uma variável de controle booleana que será utilizada na leitura da requisição feita pelo navegador.

boolean currentLineIsBlank = true;

Posteriormente, temos uma função while(), que por sua vez, fará com que a execução do programa fique restrita ao seu conteúdo enquanto o parâmetro passado para mesma for verdadeiro. O parâmetro citado corresponde à sentença client.connected(), responsável por retornar verdadeiro ou falso, caso o cliente esteja conectado ou não com o Servidor Web, respectivamente.

Portanto, enquanto o cliente estiver conectado com o nosso servidor, o programa ficará preso na função while().

while (client.connected())
{
       ***** Conteúdo da função while()
}

Imagine que a conexão do cliente (navegador) com o nosso Servidor Web tenha sido estabelecida. Neste momento o programa irá se preparar para receber a requisição feita pelo cliente, que por sua vez, é dada em forma de um grande texto, logo, utilizamos a função if() juntamente com a sentença client.available() para verificar se ainda existe alguma informação proveniente do navegador para ser lida. Caso exista, o conteúdo desta função será executado.

if (client.available())
{
      ***** Conteúdo da função if() *****
}

Lendo a requisição do cliente

Caso exista alguma informação para ser lida, utilizamos a sentença client.read() para ler caractere por caractere do grande texto de requisição citado anteriormente, de modo que, a cada passagem por esta sentença (lembre-se que isso é feito de maneira cíclica), um novo caractere será armazenado na variável do tipo char c.

 char c = client.read();

Após preenchermos a variável c com um determinado caractere da requisição, fazemos uma série de comparações deste com alguns parâmetros específicos para saber se o Arduino UNO recebeu o pacote de informações inteiro ou não.

O objetivo aqui não é entender tudo que esta vindo do cliente mas simplesmente entender que existe uma solicitação acontecendo e que após o término da mesma, vamos devolver como resposta uma pagina da web, sendo assim, devemos esperar que venha o texto completo de solicitação, até a ultima linha.

Caso a condição desta primeira função de tratamento da variável c seja verdadeira, quer dizer que recebemos o pacote completo e que o conteúdo desta função if() será executado.

if (c == '\n' && currentLineIsBlank)
{
      ***** Conteúdo da função if() *****
}

Enviando informações para o navegador

Neste momento, nós iremos criar as funções necessárias para que o nosso Arduino UNO envie uma página da web como resposta à solicitação do navegador. As instruções que utilizaremos para enviar informações ao navegador serão baseadas na sentença client.println().

Primeiramente, enviamos um cabeçalho padrão informando ao navegador que estamos mandando uma página da web utilizando o protocolo HTTP, feita utilizando a linguagem HTML.

                     client.println("HTTP/1.1 200 OK");
                     client.println("Content-Type: text/html");
                     client.println("Connection: close");  
                     client.println();

- Usando HTML para montar a página web

HTML é uma linguagem, porém, não exatamente uma linguagem de programação mas sim uma linguagem de marcação, ou seja, através desta nós enviamos comandos para um navegador, que por sua vez, irão orientar o mesmo na montagem da pagina.

Uso de tags em HTML

Em um primeiro momento, nós devemos saber que a linguagem HTML é composta por elementos que iremos chamar de tags. Estes consistem em comandos que são enviados para o navegador para informarmos alguma coisa ao mesmo, para pedirmos que ele mostre algo, para definirmos o formato de fonte que queremos, se é negrito, qual cor, entre outros.

Todos as tags em HTML são declaradas entre os sinais de maior e menor <nome_da_tag>. Torna-se importante ressaltar que muitas tags possuem uma abertura e um fechamento (este possui o mesmo nome da tag, porém, com uma "/" antes do respectivo nome, por exemplo, </nome_da_tag>), de modo que, tudo o que está entre a abertura e o fechamento de uma determinada tag será afetado pelo comando gerado pela função da mesma.

A estrutura da página em HTML

Vamos começar a entender a estrutura de uma pagina em HTML. Primeiramente, qualquer pagina em HTML precisa possuir a tag <html> cuja função é indicar para o navegador que estamos começando um bloco de programação utilizando a linguagem HTML (opcionalmente podemos utilizar também a tag <!DOCTYPE HTML> para informar o tipo documento, de modo que, se não colocarmos isto, o navegador entenderá da mesma forma) e o fechamento da mesma </html>, que por sua vez, indica o fim do bloco citado.

client.println("<!DOCTYPE HTML>");
client.println("<html>");
           . 
           .
***** Conteúdo da página *****
           .
           .
client.println("</html>"); 
 

Dentro do bloco citado anteriormente, temos o conteúdo da página que queremos enviar para o navegador, de modo que, neste, devemos ter pelo menos dois blocos, um responsável pelas informações gerais do documento, limitado pelo uso do par <head></head> e o outro, por sua vez, deve conter o corpo da página e está entre as tags <body> e </body>.

client.println("<!DOCTYPE HTML>");
client.println("<html>");
client.println("<head>");
           .
           .
   ***** Bloco 1 *****
           .
           .
client.println("</head>");
client.println("<body>");
           .
           .
   ***** Bloco 2 *****
           .
           .
client.println("</body>");
client.println("</html>"); 

Definido o título para a página

Neste momento, vamos utilizar apenas uma tag dentro do bloco 1, denominada <title>, cuja função consistirá em definir um título para a página (este título aparecerá na aba do navegador). Para executarmos a ação proposta, devemos colocar o título desejado entre o par <title></title>.

client.println("<!DOCTYPE HTML>");
client.println("<html>");

client.println("<head>");
client.println("<title>Servidor Web VDS</title>"); 
client.println("</head>");

client.println("<body>");
           .
           .
   ***** Bloco 2 *****
           .
           .
client.println("</body>");
client.println("</html>"); 

Veja como ficou o título da nossa página:

endereço IP do servidor web
Título da página.

Escrevendo o corpo da página web

Quanto ao corpo da página, a primeira coisa que faremos será colocar um título visível na própria página. Para realizar este procedimento, utilizaremos a tag <h1>, que por sua vez, consiste em uma tag de cabeçalho, cuja função consiste em apresentar um determinado texto em um modelo predefinido. Lembre-se que os textos que tiverem fora do par <h1></h1> serão apresentados fora do padrão citado.

client.println("<!DOCTYPE HTML>");
client.println("<html>");

client.println("<head>");
client.println("<title>Servidor Web VDS</title>"); 
client.println("</head>");

client.println("<body>");
client.println("<h1>Meu primeiro Servidor Web</h1>");  
client.println("</body>");

client.println("</html>");

Veja como está nossa página até agora

Shield Ethernet W5100 - tela acessada via navegardor
Primeiro texto da página.

Opções de cabeçalhos

Devemos ressaltar que não há nenhum problema em utilizar vários cabeçalhos iguais, portanto, você pode tranquilamente criar vários textos utilizando o cabeçalho h1, pois, ele apenas indica uma certa formatação. Além do cabeçalho que já utilizamos, temos também os cabeçalhos h2,h3,h4,h5,h6, os quais, nesta ordem, possuem fontes cada vez menores.

Escrevendo um texto simples

Por fim, utilizaremos uma tag voltada para a escrita de textos simples. Esta pode ser referenciada no código pelo par <p></p>.

client.println("<!DOCTYPE HTML>");
client.println("<html>");

client.println("<head>");
client.println("<title>Servidor Web VDS</title>"); 
client.println("</head>");

client.println("<body>");
client.println("<h1>Meu primeiro Servidor Web</h1>");  
client.println("<p>Esperamos que voce tenha gostado deste tutorial</p>");
client.println("</body>");

client.println("</html>"); 

Veja nosso resultado final:

Página da web criada.

- Verificando se a requisição foi finalizada

Após o desenvolvimento da nossa página, saímos da função if() utilizada para saber se a requisição foi finalizada e encontramos outras duas funções if() que cumprem o teste das condições não contempladas pela primeira, ou seja, atuam no tratamento da variável enquanto a requisição não foi finalizada.

if (c == '\n') 
{
    currentLineIsBlank = true; 
} 
else if (c != '\r')
{
    currentLineIsBlank = false;
}

Por fim utilizamos a função delay() para garantir que o navegador receba esta informação que estamos mandando e também a sentença client.stop() para parar a conexão.

delay(1);     
client.stop();

Considerações finais

Neste tutorial, demonstramos como você pode dar os primeiros passos na criação de um Servidor Web utilizando um Arduino UNO e um Shield Ethernet W5100. Esta foi apenas a primeira parte de uma série de artigos sobre a criação de Servidores Web, portanto, esperamos que continue nos acompanhando e 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 umidade do solo com Arduino - Higrômetro

Sensor de umidade do solo com Arduino - Higrômetro

Neste tutorial daremos o primeiro passo para desenvolver um sistema inteligente voltado para o monitoramento e controle das variáveis existentes em uma plantação. Começaremos aprendendo como usar o sensor de umidade do solo, também chamado de Higrômetro, em conjunto com um Arduino Nano.

[toc]

Sistemas automáticos na Agricultura

Plantas precisam de um solo de boa qualidade para crescerem de forma saudável e com qualidade, porém, existem vários tipos de situações ambientais que dificultam o seu crescimento, sendo algumas delas:

  • Irradiação solar excessiva;
  • Falta de nutrientes no solo;
  • Solo com baixa umidade;
  • Pragas;
  • Entre outros.

Todas as situações descritas anteriormente podem gerar prejuízo. Por este motivo, faz-se necessária a utilização de, sistemas automáticos os quais vêm sendo cada vez mais explorados que auxiliem o agricultor no monitoramento de seus cultivos visando obter uma eficiência cada vez maior e consequentemente a redução da ocorrência de situações indesejadas

Sensor umidade do solo - Higrômetro

Neste tutorial, iremos utilizar o sensor de umidade do solo, para aferir a condutividade do solo através de uma haste com dois eletrodos existentes no mesmo. O princípio de funcionamento deste circuito é bem simples, pois, resume-se ao fato de que, através da aplicação de uma determinada corrente X nos eletrodos citados, é possível estimar o quão úmido ou seco o solo estará em virtude da condutividade do solo em ambos os casos. Basicamente, quando o solo estiver úmido, teremos uma condutividade melhor devido a absorção da água e isso resultará em um fluxo maior de corrente entre os dois eletrodos. Entretanto se o solo estiver seco, teremos pouca ou até nenhuma corrente entre os eletrodos.

O sensor é composto basicamente duas hastes que ficaram presas ao solo que iremos monitorar e um circuito comparador que irá nos retornar o nível de condutividade do solo. Este circuito é composto por um total de 6 pinos, sendo dois destes utilizados para conectar a haste de metal ao circuito de comparação. As outras 4 entradas possuem as funções de alimentar o circuito e retornar o nível de umidade do solo.

A determinação do nível de umidade do solo pode ser feita de duas formas, sendo elas:

  • Um sinal digital que basicamente informa se o solo está seco ou não ( Menor precisão, porém não depende de um circuito ADC )
  • Um sinal analógico que pode ser utilizado para estimar o quão úmido o solo está ( Maior precisão, porém dependerá de um circuito ADC )
Sensor de umidade do solo com Arduino Higrômetro
Sensor de umidade do solo - Higrômetro

Especificações do dispositivo

  • Tensão de Operação: 3,3-5v
  • Sensibilidade ajustável via potenciômetro
  • Saída Digital TTL (D0) e Analógica(A0)
  • Led indicador de detecção de umidade

Mãos à Obra - Medindo a umidade do solo utilizando o Arduino - Higrômetro

Componentes utilizados

Montando o projeto

Nesta primeira parte do tutorial, iremos apenas conectar o sensor de umidade, desta forma,  iremos utilizar o seguinte esquema de ligação:

Mapa de ligação dos pinos

A montagem final do nosso sistema deve ser semelhante ao modelo abaixo

Sensor de umidade do solo com Arduino Higrômetro
Diagrama de montagem do sensor de umidade do solo - Higrômetro

Veja só como ficou o nosso sistema inicial.

Sensor de umidade do solo com Arduino Higrômetro
Montagem do circuito - sensor de umidade do solo - Higrômetro

Antes de ligar o seu circuito, verifique se todas as conexões foram feitas corretamente. Um curto circuito causado por uma ligação errada pode danificar todo o seu projeto.

Programando

Com a parte física do nosso projeto montada, iremos agora partir para a parte de codificação do sistema. Nesta primeira versão não iremos utilizar nenhuma biblioteca em especial, porém iremos utilizar funções para leitura de dados analógicos e também iremos construir o nosso sistema de leituras de uma forma um pouco diferente como pode ser visto no código abaixo:

/* Nome: Sistema de aferição de umidade de solo - Higrômetro
 * Feito por: Danilo Almeida
 * Data: 7/11/2017
 */
#define sensorUmidade A0 // Sensor de umidade de solo do módulo
unsigned long tempoAnterior = 0; // Variável utilizada para guardar o tempo anterior
unsigned long intervalo = 1000; // Intervalo de tempo em MS para cada leituraa
void setup() {
  Serial.begin(9600); // Inicialização da comunicação serial

}
void loop() {
  unsigned long tempoAtual = millis(); // Realizamos a leitura atual do tempo em que o nosso Arduino Nano está ligado
  if (tempoAtual-tempoAnterior > intervalo){ // Pequena lógica para realizar leituras temporizadas sem parar o microcontrolador
      tempoAnterior =tempoAtual; // Guardamos o tempo anterior como o ultimo intervalo de tempo lido
      int leitura = analogRead(sensorUmidade); // Leitura dos dados analógicos vindos do sensor de umidade de solo

      if (leitura<=1023 && leitura>=682){ // Se a leitura feita for um valor entre 1023 e 682 podemos definir que o solo está com uma baixa condutividade, logo a planta deve ser regada
        Serial.println("Nível de Umidade Baixo");
      }else{
        if (leitura<=681 && leitura>=341){ // Se a leitura feita for um valor entre 681 e 341 podemos definir que o solo está com um nível médio de umidade, logo dependendo da planta pode ou não ser vantajoso regar
        Serial.println("Nível de Umidade Médio");
        }
        else{
          if (leitura<=340 && leitura>=0){ // Se a leitura feita for um valor entre 0 e 340 podemos definir que o solo está com um nível aceitável de umidade, logo talvez não seja interessante regar neste momento
            Serial.println("Nível de Umidade Alto");
          }
        } 
      }
  }
}

Entendendo a Fundo

Software

- Definições e variáveis utilizadas no projeto

Inicialmente definimos todas as variáveis que iremos utilizar tanto para controlar as leituras que serão efetuadas quanto para realizar a leitura da entrada analógica do  sistema. Neste trecho de código definimos as variáveis  intervalo, tempoAnterior e criamos uma definição para o pino A0 do Arduino com o nome de sensorUmidade.

#define sensorUmidade A0 // Sensor de umidade de solo do módulo
unsigned long tempoAnterior = 0; // Variável utilizada para guardar o tempo anterior
unsigned long intervalo = 1000; // Intervalo de tempo em MS para cada leitura

- Função Setup - Inicialização da comunicação serial

Nesta primeira versão, iremos apenas verificar o nível de umidade do solo e com base nesta medição informar se o solo está úmido ou não. Para isso iremos utilizar a comunicação serial. Logo neste trecho de código basicamente inicializamos a comunicação serial do nosso Arduino.

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

}

- Função Loop - Usando a função millis para contar o tempo

Nossa função loop tem como objetivo realizar o processo de leitura dentro de cada  intervalo de tempo definido na variável intervalo, porém diferente de como fazemos na maioria das implementações, não iremos utilizar o comando delay para sincronizar cada leitura realizada. Isso ocorre pois o comando  delay "congela" o microcontrolador o impedindo de executar outras ações, como por exemplo ler um outro sensor, ou receber dados da porta serial. Com isso neste projeto iremos utilizar a função millis para sincronizar as leituras e não "congelar"o microcontrolador, possibilitando assim com que ele faça outras tarefas enquanto aguarda o tempo de realizar uma nova leitura.

O processo de sincronizar a leitura de forma não bloqueante é feito de uma maneira bem simples:

  1. Inicialmente armazenamos o tempo atual ( que é retornado pela função millis ).
      unsigned long tempoAtual = millis(); // Realizamos a leitura atual do tempo em que o nosso Arduino Nano está ligado
    
  2. Com o tempo atual do microcontrolador armazenado, iremos agora realizar uma operação de subtração entre o tempo atual lido e o último tempo que armazenamos.
    if (tempoAtual-tempoAnterior > intervalo)
  3. Se a subtração entre o tempo atual do microcontrolador e o último tempo armazenado for maior que o intervalo de tempo para cada leitura, significa que já  é hora de realizar a leitura desejada, porém antes devo atualizar o meu tempo anterior já que realizei uma leitura.
    tempoAnterior =tempoAtual; // Guardamos o tempo anterior como o ultimo intervalo de tempo lido
    
  4.  Recomeçamos o processo no passo 1

- Leitura do nosso medidor de umidade de solo

Agora iremos realizar a leitura do nosso sensor de umidade de solo através da porta A0, esta leitura é feita através da função analogRead como mostra o código abaixo:

      int leitura = analogRead(sensorUmidade); // Leitura dos dados analógicos vindos do sensor de umidade

Esta função basicamente retorna um valor numérico entre 0 e 1023, que representa o valor tem Volts lido do sensor de umidade. O valor está entre 0 e 1023 devido a resolução do circuito ADC que já vem integrado ao Arduíno, se você precisar de uma resolução maior, pode também utilizar circuitos ADC's dedicados.

- Tomada de decisão baseada no valor medido pelo sensor de umidade

Já por fim ( porém não menos importante ), iremos mostrar através da porta serial, em qual intervalo de valores a sua leitura está contida. Para isso, basicamente dividimos o valor da resolução máxima do circuito ADC do Arduino 1024 valores por três, o que resulta em três estados chamados: umidade baixa, umidade média, umidade alta.

      if (leitura<=1023 && leitura>=682){ // Se a leitura feita for um valor entre 1023 e 682 podemos definir que o solo está com uma baixa condutividade, logo a planta deve ser regada
        Serial.println("Nível de Umidade Baixo");
      }else{
        if (leitura<=681 && leitura>=341){ // Se a leitura feita for um valor entre 681 e 341 podemos definir que o solo está com um nível médio de umidade, logo dependendo da planta pode ou não ser vantajoso regar
        Serial.println("Nível de Umidade Médio");
        }
        else{
          if (leitura<=340 && leitura>=0){ // Se a leitura feita for um valor entre 0 e 340 podemos definir que o solo está com um nível aceitável de umidade, logo talvez não seja interessante regar neste momento
            Serial.println("Nível de Umidade Alto");
          }
        } 
      }

Desafio

Agora que temos o nosso projeto montado e funcionando tente melhorar um pouco o nível de medição do sistema. Divida o valor máximo do conversor ADC por um valor maior que três e crie mais ifs para que você seja capaz de identificar melhor o nível de umidade do solo.

Considerações Finais

Este tutorial teve como objetivo apresentar e ilustrar o funcionamento do sensor de umidade do solo, que por sua vez, tem uma aplicação bastante interessante e importante que é identificar em qual momento uma planta deve ser regada, para que dessa forma ela tenha uma qualidade de vida melhor e seja capaz de produzir e aumentar a qualidade de sua produção. Como dito anteriormente, este projeto será uma série onde iremos construir um sistema de monitoramento em tempo real do solo e do ambiente onde nossa plantação está. 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.


ATtiny85 - Primeiros passos

ATtiny85 - Primeiros Passos

Precisa criar projetos pequenos e com baixo consumo energético? Neste tutorial vamos apresentar o ATtiny85, um pequeno Microcontrolador (MCU) de 8 pinos, que pode ser programado pela Arduino IDE!

ATtiny85
ATtiny85

[toc]

O ATtiny85

Este pequeno MCU, apesar de ser inferior em relação ao desempenho quando comparado diretamente ao existente em uma placa Arduino UNO (ATmega328P). O ATtiny85 é útil em diversos projetos, entre eles, os portáteis, os de baixo consumo energético, os que utilizam poucos pinos, robôs e até em pequenos módulos separados de uma central, que por sua vez, se comunicaria com o ATtiny85 através de I2C, SPI ou UART (Serial), para controlar itens específicos, como por exemplo, uma placa de reles.

Comparando o tamanho de placas famosas e do ATtiny85

Características

  • Tensão: 1,8V a 5,5V.
  • Clock interno: 1MHz - 8MHz.
  • Flash: 8KB.
  • RAM: 512B.
  • EEPROM: 512B.
  • Digital Pins: 6.
  • Analog Input (ADC): 4 canais de 10bit.
  • PWM: 3 canais de 8bit.
  • UART: 0.
  • I2C: 1.
  • SPI: 1.

Mapa de pinos

Pinagem do ATtiny85
Pinagem do ATtiny85

Em muitos projetos simples que fazemos, não usamos nem metade dos pinos do Arduino UNO por exemplo. Assim desperdiçando um imenso hardware. Quando pensamos em algo portátil, qualquer consumo desnecessário é ruim ao projeto, porém, o ATtiny85 pode nos ajudar com isso.

Para efeitos de comparação, o Arduino UNO funcionando normalmente, consome aproximadamente ~50mA. Já o ATtiny85, consome aproximadamente ~1mA! Em relação ao Arduino UNO podemos melhorar isso usando Sleeps, no entanto, devido a existência de um LED indicando que a placa esta ligada e a diversos outros itens, portanto, mesmo com Deep Sleep, o Arduino UNO consome aproximadamente ~15mA. Já o ATtiny85, por não conter nada além do MCU, no modo Deep-Sleep consome ~0,0001mA ou ~100nA! Seus projetos portáteis irão melhorar muito na questão de autonomia, pois, é possível liga-lo com uma simples bateria CR2032 que encontramos em placa-mãe de CPUs.

Um dos problemas mais comuns é a falta dos pinos físicos de UART ,logo, se você for usar o Serial Monitor para algum debug ou até a comunicação com outros MCUs via UART (Serial), será necessário o uso da Software Serial. Esta biblioteca emula a comunicação Serial (UART) em qualquer pino do MCU e visto que o ATtiny85 não há pinos físicos para UART, devemos usa-la. Entretanto, a biblioteca ocupa uma imensa quantidade de Flash e RAM.

Podemos trabalhar, satisfatoriamente, com o Clock interno, que vai de 1MHz até 8MH. No entanto, Se for preciso mais velocidade, é necessário adicionar um cristal externo de até 20MHz.


Instalando na Arduino IDE

A Arduino IDE não suporta o ATtiny85 nativamente, portanto,  precisamos adicionar o Core do ATtiny85  a ela para conseguir usar o ATtiny85.

1-) Entre em https://github.com/SpenceKonde/ATTinyCore e copie o link .JSON que esta descrito dentro do arquivo "Installation" . Com este link iremos baixar os arquivos na Arduino IDE.

2-) Vá em "Preferências", adicione o link copiado em "URLs adicionais" e clique em "OK".

3-) Vá em "Ferramentas" -> "Placa" -> "Gerenciador de Placas...". Procure pelo ATtinyCore na lista e instale.

4-) Volte em "Ferramentas" -> "Placa" e veja que apareceu o ATtiny!


Mãos a obra - Piscando o primeiro LED no ATtiny85

Componentes necessários

Montando o projeto

O ATtiny85 não conta com conversor Serial e muito menos uma porta USB, portanto, devemos dar upload a ele através de um gravador que neste caso será o Arduino UNO. A explicação estará logo abaixo em "Entendendo a fundo: Hardware".

Para gravar o "Bootloader" (definição dos Fuses) e o código em si, devemos utilizar um gravador externo. Iremos usar o Arduino UNO como ISP.

1-) Abra o exemplo "ArduinoISP" no menu de exemplos , e faça o upload deste código no seu Arduino UNO. Não esqueça de selecionar a porta COM e a placa "Arduino UNO" no menu de ferramentas, caso não esteja selecionado.

2-) Após efetuar o upload do "ArduinoISP" no Arduino UNO, ele está apto a gravar códigos em Microcontroladores ISP sem Bootloader. Podemos agora concluir as ligações necessárias para upload do código e gravação dos Fuses ("Bootloader") no ATtiny85.

Muita atenção na posição do ATtiny85! Deixamos a "bolinha indicadora" para a esquerda, se você inverter, consequentemente irá inverter os pinos de alimentação e queimar seu tiny85! Sempre confira as ligações com o Mapa de pinos.

Os pinos utilizados são os mesmos de uma comunicação SPI e alimentação.

  • 5V.
  • GND.
  • CLOCK (13).
  • MISO (12).
  • MOSI (11).
  • CS (10).

3-) Plugue o Arduino UNO no computador e abra um novo Sketch (projeto). Precisamos selecionar as configurações de "Bootloader" (Fuses) para depois gravar o código no tiny85. Entre no menu de ferramentas e indicamos que deixe igual o da imagem, apenas altere se souber o que esta fazendo!

Obs: Altere a porta COM para a porta que seu Arduino UNO estiver conectado.

Após arrumar todos itens, clique em "Gravar Bootloader". Isso irá apenas configurar os Fuses do ATtiny85, ainda não é o upload do nosso código. Você só precisa fazer isso para o primeiro upload ou se for alterar alguma dessas configurações futuramente.

Agora que gravamos o "Bootloader", podemos finalmente dar upload de nossos códigos. Basta manter as configurações selecionadas anteriormente, escrever o código e dar upload.

Veja como ficou nossa montagem:

 ATtiny85 montado no protoboard junto ao Arduino Uno
ATtiny85 montado no protoboard junto ao Arduino Uno

Código do projeto

void setup()
{
    pinMode(4, OUTPUT);//Define o pino 4 (PB4) como saida.
}

void loop()
{
    digitalWrite(4, !digitalRead(4));//Inverte o estado do pino.
    delay(200);//Espera 200mS.
}

Colando para funcionar

Após a gravação do "Bootloader" e do código, podemos ver essa mini-maravilha funcionando! Removemos os fios de upload e deixamos apenas a alimentação (5V e GND) juntamente com o LED no pino PB4.

ATtiny85 com led


Entendendo a fundo

Software

-Função pinMode

 pinMode(4, OUTPUT);//Define o pino 4 (PB4) como saida.

Como podemos ver no Mapa de pinos, as opções em verde são os pinos que podemos usar normalmente. Estes estão descritos como PB0 ao PB5 e podemos usar o número para programar. Usamos o pino 4, que é referente ao PB4 (localizado ao lado do GND).

-Blink

digitalWrite(4, !digitalRead(4));//Inverte o estado do pino.
delay(200);//Espera 200mS.

Efetuamos um Blink (inversão de estado) no pino 4, para que vejamos o LED piscando.

Desafio

Como citado anteriormente, podemos utilizar esse pequeno MCU para fazer sub-módulos de controle, que estará conectado em uma central (um Arduino MEGA por exemplo). Tente fazer a comunicação Serial (UART) entre o Arduino UNO com o ATtiny85 para fazer o LED piscar a partir de comandos recebidos pela Serial (UART). Também citamos que não há pinos físicos para UART no tiny85, então você precisa usar a biblioteca Software Serial.

Fechamento

Com esse  minúsculo Microcontrolador, podemos fazer diversos projetos onde tamanho e consumo energético são essenciais e importantes. Entretanto, a pouca RAM e Flash comparada ao UNO, pode ser fatal se seus modos de programação não forem os melhores. Não se esqueça de "boas práticas" para programa-lo e bons estudos.

 


SCT-013 - Sensor de Corrente Alternada com Arduino

SCT-013 - Sensor de Corrente Alternada com Arduino

Neste tutorial ensinaremos a você como medir corrente alternada e estipular a potência instantânea de um circuito utilizando o Sensor de corrente alternada não invasivo SCT-013 juntamente com Arduino. Para este projeto, iremos medir a corrente e a potência de um ferro de solda.

Esse tutorial é dividido em três partes.

  1. Introdução: Nessa parte você conhecerá um pouco mais o sensor SCT013
  2. Mãos à obra: Aqui você aprenderá a usar o Sensor de corrente SCT-013 na prática
  3. Entendendo a fundo: Por fim você entenderá como funciona o software e hardware usado na experiência da parte 2

[toc]

Sensor de corrente não invasivo SCT-013

O sensor de corrente SCT-013 é muito versátil e tem como principal vantagem o fato de não precisar de contato elétrico com o circuito para medir a corrente elétrica alternada. Ou seja, não precisamos abrir o circuito para ligá-lo em série com a carga, basta apenas "abraçar" um dos fios ligados ao equipamento a ser monitorado.

SCT013 sensor de corrente ac
Sensor de corrente SCT013

Um pouco de física

Para fazer a medição da corrente sem a necessidade de contato elétrico com o circuito esse sensor de corrente alternada utiliza as propriedades magnéticas da corrente elétrica.

- Lei de Ampère

A Lei de Ampère diz que todo condutor por onde flui uma corrente elétrica induz ao seu redor um campo magnético proporcional à corrente.

Linhas de campo geradas pela corrente elétrica
Linhas de campo geradas pela corrente elétrica

- Corrente Alternada

A corrente alternada tem uma peculiaridade de se comportar como uma senoide, sendo assim sua intensidade varia ao longo do tempo indo do máximo positivo ao máximo negativo. Esse comportamento oscilatório tem uma frequência que pode ser de 50Hz ou de 60Hz conforme o país ou região. No Brasil é adotado a frequência de 60Hz, ou seja: a corrente elétrica varia entre positivo e negativo 60 vezes em 1 segundo.

Corrente Alternada
Corrente Alternada

Como o campo magnético é proporcional ao valor de corrente, o campo magnético gerado ao redor do condutor percorrido por uma corrente alternada irá variar ao logo do tempo conforme a variação da mesma.

- Lei de Faraday - lei da indução eletromagnética

A lei de Faraday diz que um campo magnético que varia ao longo do tempo induz em uma espira uma força eletromotriz que gera um corrente elétrica proporcional a intensidade do campo magnético.

Lei de Faraday
Lei de Faraday

Na figura acima podemos entender essa lei na prática. Veja que ao aproximar o imã das espiras estamos variando o campo magnético e está sendo indicado uma tensão no voltímetro (força eletromotriz) chegando quase a 20V. Depois, ao afastar o imã temos a tensão indo quase a 20V no sentido contrário.

- Resumo

  1. Lei de Ampère: Um condutor percorrido por uma corrente induz a formação de um campo magnético ao seu redor de valor proporcional à corrente;
  2. Corrente Alternada: A corrente alternada varia ao longo do tempo gerando um campo magnético também variante ao longo do tempo;
  3. Lei da indução de Faraday: Um campo magnético variante no tempo induz numa espira uma tensão, e por consequência um corrente elétrica, proporcional à intensidade do campo magnético

Levando em conta essas três propriedades, podemos montar um transformador de corrente.

Transformadores de corrente

Existe uma grande gama de sensores de corrente que usam essas propriedades magnéticas. Esse sensores são conhecidos com TC (Transformador de Corrente), que em inglês é CT (Current Transformer).

Um transformador de corrente, nada mais é que um conjunto de espiras que são colocadas ao redor de um condutor ao qual queremos medir a corrente. O transformador de corrente (TC) terá em seus polos uma corrente alternada induzida Is, que é proporcional a corrente alternada Ic que percorre o condutor ao qual pretendemos medir a corrente elétrica.

 Esquema para exemplificar o SCT-013
Esquema para exemplificar o SCT-013

A corrente induzida no TC também será inversamente proporcional ao número de espiras de sua bobina.

Esse sensores são divididos em 2 modelos: Os split-core (núcleo dividido) e os solid-core (núcleo sólido).

Solid-core CT - Transformador de núcleo sólido ou núcleo anel - Não possui possibilidade de abertura
Split-core CT - Transformador de corrente de núcleo dividido - Permite a abertura

Transformador de corrente SCT-013

SCT é a sigla para Split-core Current Transformer, ou seja, Transformador de corrente de núcleo dividido. Para fazer fazer a medição da corrente elétrica o SCT-013 possui uma bobina interna em sua estrutura, como podemos ver na figura abaixo.

Bobina do Sensor de corrente não invasivo SCT-013
Bobina do Sensor de corrente não invasivo SCT013

Podemos ver essa bobina com mais detalhes na foto a seguir

Dentro do Sensor de corrente SCT-013
Dentro do Sensor de corrente SCT013

O circuito é bem simples:

Circuito interno do SCT-013
Circuito interno do SCT-013

- Os Modelos de SCT-013

Com base nesse princípio de funcionamento, foram criados diferentes tipos de sensores não-invasivos, como pode ser observado em seu datasheet, com o objetivo de atenderem os mais diversos cenários, de forma que não exista um "melhor", mas sim o mais recomendado para a aplicação recorrente.

Tabela com os diferentes modelos do sensor de corrente não-invasivo

As duas principais diferenças são a Corrente eficaz máxima a ser medida (Input current) -  e o Tipo de saída do sensor (Output type).

É possível observar que somente o modelo SCT-013-000 apresenta uma variação de corrente em sua saída de 0-50mA, já os outros modelos apresentam uma variação tensão de 0-1V, onde por meio destas variações é possível mensurar a corrente elétrica.

Para sabermos qual será a taxa variação tanto de corrente quanto de tensão basta dividirmos o valor máximo  da saída pelo valor máximo a ser medido. Abaixo temos alguns exemplos deste cálculo:

  • SCT-013-000:
    • 0,05 / 100 = 0,5mA. A cada um Ampere a mais ou a menos, sua saída será de 0,5mA para mais ou a menos;
  • SCT-013-005:
    • 1 / 5 = 0,2V. A cada um Ampere a mais ou a menos, sua saída será de 0,2V para mais ou a menos;
  • SCT-013-050:
    • 1 / 50 = 0,02V. A cada um Ampere a mais ou a menos, sua saída será de 0,02V para mais ou a menos.

- SCT-013-000 - 100A / 0-50mA

Para esse tutorial usaremos o SCT-013-000. Ele poder medir valores de 0 até 100A de corrente alternada. Em sua saída teremos valores entre 0 a 50mA proporcionais ao valor de corrente percorrido no condutor principal.

Como nosso Arduino só lê valores de tensão, iremos precisar montar um circuito auxiliar para que essa corrente percorra um resistor e assim possamos converter os valores de correntes gerado pelo sensor em valores de tensão. Explicaremos o passo a passo de como dimensionar esse circuito no tópico Entendendo o Hardware.


Mãos à Obra - Monitorando a corrente AC com o Sensor de corrente SCT-013

Componentes necessários

Serão necessários os seguintes componentes para a execução deste projeto:

Utilizaremos o SCT-013 100A e o Arduino Uno, além de um aparelho que terá sua corrente elétrica medida, no nosso caso, um ferro de solda. Você poderá medir a corrente elétrica de outros dispositivos.

O resistor de 330Ω foi dimensionado por meio de uma sequência de cálculos com o propósito de aumentar a precisão das medidas deste sensor de corrente. Os cálculos poderão ser visto na sessão "Entendendo o SCT-013".

*Caso o seu SCT-013 seja de outro modelo ao invés de 100A, o passo a passo será diferente.

sct013 sensor de corrente

Montando o projeto

Esse sensor de corrente normalmente vem com um plugue P2 do tipo macho em sua ponta. Para esse tutorial nós removemos ele e conectamos os dois fios presentes no interior do cabo diretamente na protoboard. Caso você não queira remover o plugue P2, recomendamos que você adquira um plugue P2 do tipo fêmea para poder utilizar esse sensor de corrente.

Com os componentes em mãos, montaremos o seguinte circuito na protoboard:

Após realizar esta montagem, é necessário conectar o SCT-013 ao condutor por onde a corrente elétrica a ser medida passará.

AVISO: Não conecte este sensor de corrente de acordo com a imagem abaixo, pois não será possível medir a corrente elétrica. A explicação do por quê será feita mais abaixo.

Como a corrente elétrica produz campo magnético conforme seu sentido e o sentido da corrente em um fio é o oposto ao sentido do outro fio, os campos magnéticos produzido pelos dois acabam se anulando. Se não há campo magnético, não há indução magnética no transformador do sensor de corrente, fazendo com que não circule a corrente Is necessária para a medição da corrente Ic consumida. Por esse motivo não podemos conectar este sensor aos dois fios de alimentação.

Com isso finalizamos o hardware do nosso projeto. Agora, bora programar!

Programando

- Bibliotecas necessária

É necessário baixar a biblioteca EmonLib (download). Após baixar, descompacte e mova para a pasta libraries da IDE do Arduino. A EmonLib será utilizada para nos auxiliar a calcular o valor da corrente elétrica consumida.

- Código utilizado

Para sabermos quantos Amperes estão passando pelo condutor, basta realizar a seguinte programação:

#include "EmonLib.h"

EnergyMonitor SCT013;

int pinSCT = A0;   //Pino analógico conectado ao SCT-013

int tensao = 127;
int potencia;

void setup()
{
    SCT013.current(pinSCT, 6.0606);

    Serial.begin(9600);
}

void loop()
{
    double Irms = SCT013.calcIrms(1480);   // Calcula o valor da Corrente
    
    potencia = Irms * tensao;          // Calcula o valor da Potencia Instantanea    

    Serial.print("Corrente = ");
    Serial.print(Irms);
    Serial.println(" A");
    
    Serial.print("Potencia = ");
    Serial.print(potencia);
    Serial.println(" W");
   
    delay(500);

    Serial.print(".");
    delay(500);
    Serial.print(".");
    delay(500);
    Serial.println(".");
    delay(500);
}

Após compilar e enviar o código ao Arduino, os valores de corrente elétrica e potência instantânea serão mostrados no Monitor Serial da IDE do Arduino, e serão atualizados a cada 2 segundos.

Colocando para funcionar

Código compilado e circuito montado! Veja abaixo o resultado.

Circuito montado na prática
Circuito montado na prática
Monitor Serial aberto

Entendendo a fundo

Software

– Incluindo as bibliotecas a serem utilizadas no projeto

Inicialmente, observe que foi necessário incluir uma biblioteca no código para que o mesmo pudesse funcionar corretamente. A biblioteca EmonLib.h é a responsável por realizar os cálculos para encontrar o valor eficaz da corrente a ser medida, baseando-se nas amostras colhidas no pinSCT.

#include "EmonLib.h"

– Declarando o objeto SCT013

Em seguida, cria-se um objeto que será utilizado posteriormente para representar o sensor de corrente SCT-013 no código.

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

EnergyMonitor SCT013;

– Definindo as configurações iniciais

Declaramos pinSCT = A0 para poder facilitar e tornar intuitivo o uso da porta analógica do arduino.

int pinSCT = A0;    //Pino analógico conectado ao SCT-013

Declaramos duas variáveis, uma chamada Tensao, e atribuímos o valor de 127, que equivale a tensão da rede aqui no nosso estado, e outra chamada Potencia, que será utilizada para reservar o resultado da multiplicação da tensão e da corrente.

int tensao = 127;
int potencia;

No void setup(), chamamos a função SCT013.current(pinSCT, 6.0606) da biblioteca EmonLib, para que seja realizado o cálculo do valor eficaz da corrente, onde ele se baseará nas amostras lidas do pinSCT, e é empregado um valor de calibração de 6.0606 que ensinaremos como encontra-lo mais abaixo.

SCT013.current(pinSCT, 6.0606);

Habilitamos também a comunicação serial entre o arduino e o computador por meio do comando Serial.begin(9600).

Serial.begin(9600);

Caso você tenha dúvidas sobre como utilizar a comunicação serial do arduino, recomendamos que veja o tutorial Comunicação Serial Arduino (clique aqui), presente no portal.

– Aquisição do valor de corrente

Na função void loop(), utiliza-se primeiramente a função SCT013.calcIrms() para atribuir o valor de corrente à variável Irms. O valor entre parênteses representa o número de amostras que a função irá ler do pinSCT.

    double Irms = SCT013.calcIrms(1480);

Veja que SCT013 é o nome que definimos para o objeto. Para usar uma função ligada a esse objeto, colocamos seu nome seguido de ponto e o nome da função. Ex: nomeobjeto.calcIrms().

- Cálculo da potência instantânea

Por meio da multiplicação da corrente Irms pela tensão estipulada, conseguimos descobrir a potência do dispositivo.

    potencia = Irms * tensao;

Em seguida imprimimos o valor de corrente e da potência no monitor serial:

    Serial.print("Corrente = ");
    Serial.print(Irms);
    Serial.println(" A");

    Serial.print("Potencia = ");
    Serial.print(potencia);
    Serial.println(" W");

Esperamos um tempo para a próxima medição.

    delay(500);
    Serial.print(".");
    delay(500);
    Serial.print(".");
    delay(500);
    Serial.println(".");
    delay(500);

Hardware

- Corrente gerada pelo sensor

O sensor é calibrado para medir a corrente alternada máxima de 100A AC. Esse valor de 100A é o valor RMS, que também é chamado de valor eficaz. O valor RMS é igual ao máximo valor que a corrente pode alcançar (corrente de pico) dividido pela raiz quadrada de dois. 

sensor de corrente SCT013

Então, temos que a corrente de pico máxima medida é de 141.4A:

i (medido) = √2 * i (rms) = 1,414 * 100A = 141,4 A

Sabendo que para uma corrente de 100A no primário, ele produz 50mA no secundário, é só jogarmos na fórmula de relação de transformação. O resultado será:

N1 / N2 = I2 / I1

  • I1 = corrente no primário (corrente a ser medida);
  • I2 = corrente no secundário;
  • N1 = número de votas do primário (no caso deste sensor, N1 será igual a 1);
  • N2 = número de voltas do secundário.

N2 = 2000 espiras.

A corrente na saída do sensor é inversamente proporcional ao número de voltas (aqui é 2000):

i (sensor) = i (medido) / numero_de_espiras = 141,4A / 2000 = 0,0707A

Teremos na saída do sensor o sinal da corrente induzida semelhante ao da figura a seguir:

Sinal na saída do sensor de corrente SCT para um valor de corrente eficaz máxima de 100A
Sinal na saída do SCT013 para um valor de corrente eficaz  de 100A

- Transformando corrente em tensão - Calculando a resistência de carga

O Arduino UNO só realiza, em seus pinos de entrada analógica, a leitura de níveis de tensão (entre 0V a 5V). Dessa forma, precisamos converter o sinal de corrente alternada do SCT-013 para um valor de tensão que seja legível para o Arduino.

O primeiro passo é adicionar um resistor de carga entre os polos do sensor de corrente:

Sensor sct013 esquema de ligação

Como a corrente alterna em torno de zero, vamos escolher um resistor que de na saída um valor máximo de tensão de 2,5V.

R(carga) = U(sensor)/I(sensor) = 2,5V / 0,0707A = 35,4Ω

 

O resistor de carga ideal é de 35,4Ω para uma corrente de até 100A, nesse caso usariamos um resistor de 33Ω. Dessa forma teremos o seguinte sinal de tensão sobre o resistor de carga:

Sinal de tensão sobre o resistor de 33
Sinal de tensão sobre o resistor de carga de 33Ω para uma corrente eficaz de 100A

OBS: Para nosso projeto, não iremos medir valores maiores que 10A. Dessa forma, podemos considerar que nossa corrente máxima é 10 vezes menor. Logo:

i (sensor) = i (medido) / numero_de_espiras = 14,14A / 2000 = 0,00707A

R(carga) = U(sensor)/I(sensor) = 2,5V / 0,00707A = 354Ω

Portanto, para nosso projeto adotamos o resistor de 330Ω.

Ou seja, você pode calcular o resistor ideal para a faixa de operação que você precisa. Se for 100A, você pode adotar o de 33Ω, se for de 10A você pode usar um resistor de 330Ω. Para outros valores, basta você calcular.

Seguiremos essa explicação considerando a faixa de operação de 100A, que é o máximo para nosso sensor.

- Convertendo sinal de tensão AC para DC

Agora temos um sinal de tensão alternada variando entre 2,5V positivo e 2,5V negativo. O Arduino não pode medir tensão negativa, então precisamos somar 2,5 V ao sinal para que ele varie entre 0V a 5V.

O primeiro passo para isso é montar um divisor de tensão usando a alimentação de 5V que a placa Arduino fornece.  Assim, consideramos R1 e R2 iguais a 10kΩ, e com isso, a tensão sobre eles será igual, pois os 5V provenientes do Arduino se dividirá igualmente entre eles.

Circuito divisor de tensão
Circuito divisor de tensão

Em seguida adicionamos um capacitor entre o GND e a saída de 2,5V no meio do divisor de tensão:

Circuito de offset

Esse circuito funcionará como uma bateria de 2,5V adicionando essa tensão à fonte AC. Este valor de tensão que acrescentamos a forma de onda é chamado de offset.

Forma de onda da tensão no resistor de carga

 

Forma de onda com offset

Veja como vai fica nosso circuito:

Sensor sct013 esquema de ligação completo

Na figura a seguir mostramos o circuito com seus respectivos sinais:

Como explicado, o circuito de offset funciona como uma fonte tensão de 2,5V DC, somando essa tensão à senoide do SCT-013. O circuito poderia ser ilustrado como a figura a seguir:

- Calibrando o software

Agora que sabemos o sensor carga, modificamos a função SCT013.current onde definimos o pino de entrada e o valor de calibração.

SCT013.current(pinSCT, Valor_de_Calibracao);

Este valor é de calibração, destinado justamente para caso queiramos mudar o valor do resistor de carga. Para descobrir ele, basta dividir o número total de voltas (espiras) do secundário pelo valor do resistor de carga dimensionado:

  • Valor_de_Calibração = 2000 / 33
  • Valor_de_Calibração = 60,606

Dessa forma, teremos:

SCT013.current(pinSCT, 60,606);

obs: Para nosso projeto prático nosso resistor escolhido foi de 330Ω devido ao fato de trabalharmos com uma faixa de operação de 10A. Dessa forma o valor de calibração usado no projeto prático foi de 6,0606.

Valor_de_Calibração = 2000 / 330 = 6,0606

Mudando o range de medição

Calculamos até aqui o valor de uma resistência de carga e valor de calibração do software que possibilita nosso software medir valores de corrente eficazes de até 100A, que é o máximo valor de projeto do sensor. Só que conforme a aplicação, nunca chegaremos a correntes tão altas. Por isso, podemos calibrar nosso software e circuito para ler valores de máxima corrente distintos, desde que estejam dentro do permitido para esse sensor.

Talvez você tenha percebido inclusive que o valor de resistência encontrado em nossos cálculos (33Ω) foi 10 vezes menor que o usada em nossa experiencia (330Ω). Para nosso projeto adotamos uma corrente máxima de 10A, visto que a maiorias dos eletrodomésticos consomem correntes menores que esse valor.

Para calcular a resistência de carga adequada basta repetirmos os seguintes passos:

- Passo 1 - Escolher a corrente rms máxima que será medida pelo circuito

imax (rms) = 10A

- Passo 2 - Converter esta corrente para o valor de pico:

i (medido) = √2 * imax (rms) = 1,414 * 10A = 14,14 A

- Passo 3 - Descobrir o número total de espiras da bobina do secundário:

Sabendo que para uma corrente de 100A no primário, ele produz 50mA no secundário, é só jogarmos na fórmula de relação de transformação. O resultado será:

N1 / N2 = I2 / I1

  • I1 = corrente no primário (corrente a ser medida);
  • I2 = corrente no secundário;
  • N1 = número de votas do primário (no caso deste sensor, N1 será igual a 1);
  • N2 = número de voltas do secundário.

N2 = 2000 espiras.

- Passo 4 - Calcular a corrente de pico máxima do secundário do SCT-013:

i (sensor) = i (medido) / numero_de_espiras = 14,14A / 2000 = 0,00707A

- Passo 5 - Dimensionar o resistor de carga:

R(carga) = U(sensor)/I(sensor) = 2,5V / 0,00707A = 354Ω

Para o projeto, arredondamos este valor para 330Ω, que é um valor comercial de resistor.

R(carga) = 330Ω

- Passo 6 - Colocando o valor de calibração no software:

Agora que sabemos o sensor carga, modificamos a função SCT013.current onde definimos o pino de entrada e o valor de calibração.

SCT013.current(pinSCT, Valor_de_Calibracao);

Este valor é de calibração, destinado justamente para caso queiramos mudar o valor do resistor de carga. Para descobrir ele, basta dividir o número total de voltas (espiras) do secundário pelo valor do resistor de carga dimensionado:

Valor_de_Calibração = N2 / R(carga)

Valor_de_Calibração = 2000 / 330

Valor_de_Calibração = 06,0606

Dessa forma, teremos:

SCT013.current(pinSCT, 6.0606);

 

Pronto, agora você sabe como adaptar o hardware para o seu projeto.


Desafio

Desenvolva um projeto em que seja possível medir a potência requisitada por um determinado equipamento. Para isto, utilize o sensor de corrente SCT-013 (tratado com detalhes neste material) em conjunto com, por exemplo, o sensor de tensão GBK P8.

Considerações finais

Esperamos que este tutorial tenha esclarecido algumas dúvidas sobre os procedimentos necessários para realizar monitoramento das correntes elétricas utilizadas nos acionamentos dos seus equipamentos. Obrigado pela atenção e continue buscando conhecimento no portal do Vida de Silício.