Estação meteorológica sem fio com Arduino

Tempo de leitura: 11 minutes

Neste artigo, irei mostrar a você como construir uma estação meteorológica sem fio com um grande display TFT colorido de 3,2 “usando Arduino. Construir uma estação meteorológica sem fio é uma ótima experiência de aprendizado. Quando terminar de construir este projeto, você terá um melhor entendimento de como a comunicação sem fio funciona, como funcionam os sensores e quão poderosa a plataforma Arduino pode ser. Com este projeto como base e a experiência adquirida, você poderá construir facilmente projetos mais complexos no futuro.

Uma estação meteorológica é um dispositivo que coleta dados relacionados ao clima e ao meio ambiente usando vários sensores diferentes. Podemos medir muitas coisas como:

  • Temperatura
  • Umidade
  • Vento
  • Pressão barométrica
  • índice UV
  • Chuva

Na estação meteorológica que vamos construir, vamos medir a temperatura e a umidade em dois locais e mostrar a data e a hora atuais. Construir uma estação meteorológica é extremamente fácil. Mas um fabricante pode construir uma unidade com um display TFT colorido e recursos que correspondem aos de uma unidade comercial? A resposta é sim! Com o poder do software e hardware de código aberto, pode-se construir facilmente esta impressionante estação meteorológica!

O projeto consiste em duas partes, o transmissor e o receptor.

O transmissor mede a temperatura e a umidade e envia os dados sem fio para o receptor.

O receptor, mede a temperatura e a umidade, recebe os dados do sensor remoto e exibe tudo em um grande display colorido.

Vamos construir esse projeto!

 

Etapa 1: obter todas as peças

As peças necessárias para construir este projeto são as seguintes:

Arduino DUE (1)
Arduino Nano (1)
3.2″ TFT display (1)
DHT22 ou Módulo DGHT22 (2x)
NRF24L01 (1)
DS3231 RTC (1)
ProtoBoard
Fios

O custo do projeto gira em torno de  125,17 R$. Você pode reduzir o custo do projeto em 15 R$ se usar o Arduino Mega em vez do Arduino Due. Escolhi usar o Arduino Due para o receptor porque é muito rápido e tem muita memória. Isso será muito útil no futuro, à medida que adicionarmos mais e mais recursos ao projeto.

Todos os itens são encontrados no MercadoLivre (Com custo variado)

 

Etapa 2: Sensor de Temperatura e Umidade – DHT22

O DHT22 é um sensor de temperatura e umidade muito popular. É barato, fácil de usar e a especificação garante boa precisão e exatidão.

Os sensores DHT são compostos por duas partes, um sensor capacitivo de umidade e um termistor. Há também um chip interno que faz algumas conversões de analógico para digital e emite um sinal digital com a temperatura e a umidade. O sinal digital é bastante fácil de ler usando qualquer microcontrolador.

Características do DHT22

  • Baixo custo
  • 3 a 5 V de potência e E/S
  • 2,5mA máximo de uso de corrente durante a conversão
  • Leituras de umidade de 0-100% com precisão de 2-5%
  • -40 a 125 ° C leituras de temperatura ± 0,5 ° C precisão
  • Lento

A conexão com o Arduino é extremamente fácil. Conectamos o pino do sensor com o sinal + à saída de 5 V ou 3,3 V do Arduino. Conectamos o pino do sensor com o sinal – ao TERRA. Por último, conectamos o pino OUT a qualquer pino digital do Arduino.

Para usar o sensor DHT22 com o Arduino, temos que usar a biblioteca DHT.

 

Etapa 3: O Módulo de Relógio em Tempo Real DS3231

O módulo de relógio de tempo real DS3231 é, como seu nome sugere, um relógio de tempo real. Usando sua bateria, ele pode manter o tempo por anos, pois tem consumo mínimo de energia.

O DS3231 é um relógio de tempo real I2C (RTC) extremamente preciso e de baixo custo com um oscilador de cristal com compensação de temperatura (TCXO) e cristal integrados. O dispositivo incorpora uma entrada de bateria e mantém uma cronometragem precisa quando a alimentação principal do dispositivo é interrompida. A integração do ressonador de cristal aumenta a precisão de longo prazo do dispositivo e também reduz a contagem de peças em uma linha de fabricação.

O RTC mantém informações de segundos, minutos, horas, dia, data, mês e ano. A data no final do mês é ajustada automaticamente para meses com menos de 31 dias, incluindo correções para ano bissexto. O relógio opera no formato de 24 ou 12 horas com um indicador AM / PM. São fornecidos dois alarmes programáveis ​​de hora do dia e uma saída de onda quadrada programável. O endereço e os dados são transferidos serialmente por meio de um barramento bidirecional I2C.

O custo do módulo é extremamente baixo, custa cerca de 2 $ incluindo a bateria! Vamos usá-lo para manter o tempo em nosso Projeto Estação Meteorológica.

 

Etapa 4: NRF24L01 +: Módulos sem fio

O módulo NRF24L01 é um módulo transceptor bidirecional de baixo custo. O custo é inferior a 3 $! Ele opera na banda de 2,4 GHz e pode atingir uma taxa de dados de 2 Mbits! Impressionante, não é? Ele usa a interface SPI para se comunicar com o Arduino, por isso é muito fácil de usar com ele. Temos que conectar 7 dos 8 pinos do módulo para fazê-lo funcionar com o Arduino.

Infelizmente, não podemos conectar o módulo na placa de ensaio, então usaremos fios macho para fêmea para conectar o módulo ao Arduino. O pino número 1 do módulo é GND. Você tem que conectá-lo ao Arduino Ground. O próximo pino é Vcc. Você deve conectá-lo à saída de 3,3 V do Arduino Uno. Seja cuidadoso! Não conecte em 5V ou você destruirá seu módulo! O terceiro pino é denominado CE e você pode conectá-lo a qualquer pino digital de sua preferência. Neste exemplo, vou conectá-lo ao pino digital 7. O pino 4 é CS e você pode conectar a qualquer pino digital também. Vou conectar ao pino digital 8. O próximo pino é SCK, que vai para o pino digital 13 do Arduino Uno. O próximo pino é MOSI, que vai para o pino digital 11 e o último pino do MISO, que vai para o pino digital 12. É isso!

Para ser fácil de usar o módulo com Arduino, temos que usar a seguinte biblioteca (Link):

 

Etapa 5: Construindo o Transmissor

Vamos primeiro construir o transmissor. É muito simples.

Para o transmissor, usamos:

  • Um Arduino Nano
    Um sensor DHT22
  • Um módulo sem fio NRF24L01+
  • Um ProtoBoard
  • Alguns fios

Conectamos o pino de saída do sensor ao pino digital 4 do Arduino Nano. Conectamos o Ground e VC e estamos prontos. Tudo o que precisamos fazer agora é conectar o módulo sem fio NRF24L01.

Anexe-o usando os pinos que são mostrados na terceira imagem. Para obter mais detalhes, assista ao vídeo detalhado que anexei na etapa anterior.

É isso, seu transmissor está pronto. Vamos agora passar para o receptor.

 

Etapa 6: Construindo o Receptor

Para construir o receptor, precisamos das seguintes partes:

  • Um Arduino Due ou um Mega
  • Um módulo de relógio em tempo real DS3231
  • Um sensor de temperatura e umidade DHT22
  • Um módulo sem fio NRF24L01+
  • Um display TFT colorido de 3,2 “
  • Um ProtoBoard
  • 7 pinos de canecão
  • Alguns fios

Primeiramente, dobramos 7 pinos de conecão e os colocamos em alguns dos pinos do Arduino Due. Precisamos de um para aterramento e outro para 3,3V. Precisamos de dois nos pinos I2C. Precisamos dos 3 restantes para pinos digitais de 6 a 8. Também precisamos soldar três fios aos pinos SPI de hardware dos pinos do Arduino Due. Precisamos de MOSI, MISO e SCK. Verifique o diagrama com atenção. Conectamos os fios aos pinos do cabeçalho e estamos prontos para conectar a tela.

Conectando o DS3231
o pino VCC na saída de 3,3 V do Arduino

o pino GND para o GND do Arduino e

o pino SDA (Serial Data Line) para o pino SDA do Arduino e

o pino SCL (Serial Clock Line) para o pino SCL do Arduino

Conectando o Sensor DHT22
o pino VCC na saída de 3,3 V do Arduino

o pino GND para o GND do Arduino e

o pino de saída para o pino digital 8 do Arduino

Conectando o módulo NRF24L01
o pino GND para o GND do Arduino

o pino VCC para Arduino 3.3V

o terceiro pino para o pino digital 6 do Arduino

o quarto pino para o pino digital 7 do Arduino

o quinto pino para o pino SCK que soldamos

o 6º pino ao pino MOSI que soldamos

o 7º pino ao pino MISO que soldamos

 

Etapa 7: O Código do Transmissor

Em primeiro lugar, temos que fazer o download da biblioteca RF24 para facilitar nossa vida quando trabalhamos com os módulos wireless NRF24L01. Também precisamos da biblioteca DHT para o sensor DHT22.

Biblioteca NRF24L01: https://github.com/TMRh20/RF24

Biblioteca DHT22: https://github.com/adafruit/DHT-sensor-library

Vamos primeiro ver o código do transmissor. Ele envia uma estrutura de dados simples que contém dois flutuadores, a temperatura e a umidade.

Para estabelecer um elo de comunicação, temos que criar um “tubo” entre os dois módulos. Esse tubo precisa ter um endereço. Ambos os módulos precisam escrever e ler no mesmo tubo para se comunicarem. Essa é a primeira coisa que definimos em nosso código, definimos o endereço do tubo como “0”. Em seguida, definimos o canal no qual queremos nos comunicar com o outro módulo. O chip NRF24L01 suporta 126 canais diferentes. Ambos os módulos precisam usar o mesmo canal para se comunicarem. Neste exemplo, estou usando o canal 115. A seguir, defino que quero usar a potência máxima de transmissão que o módulo oferece. Ele usa mais energia, mas amplia o alcance da comunicação. Em seguida, definimos a taxa de dados da transmissão. Eu o defini para 250Kbs, que é a taxa de dados mais baixa possível, a fim de alcançar um melhor alcance. O próximo passo é abrir o pipe para escrever nele mais tarde.

Na função de loop, lemos os valores de temperatura e umidade do sensor, salvamos esses dados na estrutura de dados e, em seguida, enviamos a estrutura de dados gravando a estrutura de dados no tubo.

#include "DHT.h"
#include <SPI.h>  
#include "RF24.h"

#define DHTPIN 4  
#define DHTTYPE DHT22 

RF24 myRadio (7, 8);
byte addresses[][6] = {"0"};
const int led_pin = 13;

struct package
{
  float temperature ;
  float humidity ;
};

typedef struct package Package;
Package data;

DHT dht(DHTPIN, DHTTYPE);

void setup()
{
    Serial.begin(9600);
    pinMode(led_pin, OUTPUT);
    dht.begin();
    myRadio.begin();  
    myRadio.setChannel(115); 
    myRadio.setPALevel(RF24_PA_MAX);
    myRadio.setDataRate( RF24_250KBPS ) ; 
    myRadio.openWritingPipe( addresses[0]);
    delay(1000);
}

void loop()
{
  digitalWrite(led_pin, HIGH); // Pisca uma luz para mostrar a transmissão
  readSensor();
  Serial.println(data.humidity);
  Serial.println(data.temperature);
  myRadio.write(&data, sizeof(data)); 
  digitalWrite(led_pin, LOW);
  delay(1000);
}

void readSensor()
{
 data.humidity = dht.readHumidity();
 data.temperature = dht.readTemperature();
}

 

Etapa 8: O Código do Receptor

Vamos agora ver o código do receptor. Precisamos de 4 bibliotecas.

Primeiro, temos que baixar a biblioteca para a exibição deste link:

Biblioteca DISPLAY: https://github.com/Bodmer/TFT_HX8357_Due

Depois de baixar a biblioteca, você deve abrir a linha 13 de comentário do arquivo User_Setup.h e descomentar a linha 14 porque o monitor que temos está usando o driver HX8357C. Agora podemos continuar com as outras 3 bibliotecas. Precisamos de uma biblioteca para o relógio em tempo real, uma para o sensor DHT22 e por último uma para o módulo Wireless.

NRF24L01: https://github.com/TMRh20/RF24

DHT22: https://github.com/adafruit/DHT-sensor-library

DS3231: https://github.com/SodaqMoja/Sodaq_DS3231

Vamos dar uma olhada no código. A primeira coisa que temos que fazer é definir a hora para o módulo de relógio em tempo real, se ainda não estiver definido. Para fazer isso, insira a data e hora atuais na função setRTCTime, descomente a chamada setRTCTime da função na linha 54 e carregue o programa no Arduino. Agora a hora está definida. Mas, então, temos que comentar a chamada setRTCTime da função novamente e fazer o upload do programa para o Arduino mais uma vez.

O código do receptor funciona assim. Na função de configuração inicializamos todos os sensores e módulos e imprimimos a Interface do Usuário. Em seguida, na função de loop, verificamos continuamente se há novos dados sem fio. Se houver novos dados, salvamos esses dados em variáveis ​​e os imprimimos no display. Lemos a temperatura e a umidade uma vez por minuto e só atualizamos o display se houver uma alteração nos valores. Desta forma, reduzimos ainda mais a tremulação da tela! Também preparei uma versão do código com a temperatura exibida em graus Fahrenheit.

#include <TFT_HX8357_Due.h> // Hardware-specific library
#include <Sodaq_DS3231.h> //RTC Library https://github.com/SodaqMoja/Sodaq_DS3231
#include "DHT.h"
#include "RF24.h"

#define DHTPIN 8  

#define DHTTYPE DHT22 
DHT dht(DHTPIN, DHTTYPE);

RF24 myRadio (6, 7);
byte addresses[][6] = {"0"};

TFT_HX8357_Due tft = TFT_HX8357_Due();       // Invoke custom library

float remoteHumidity = 0.0;
float remoteTemperature = 0.0;

String dateString;
String hours;
int minuteNow=0;
int minutePrevious=0;

struct package
{
  float temperature ;
  float humidity ;
};

float previousIndoorHumidity = 0;
float previousIndoorTemperature = 10;

float previousRemoteHumidity = 0.1;
float previousRemoteTemperature = 0.1;

float indoorHumidity = 0;
float indoorTemperature = 0;

typedef struct package Package;
Package data;

void setup() {

  Serial.begin(9600);
  
  tft.init();
  tft.setRotation(1);
  tft.fillScreen(TFT_BLACK);
  tft.setTextFont(1);        // Select font 1 which is the Adafruit GLCD font
  delay(100);

  rtc.begin();
  dht.begin();
  delay(2000);
  //setRTCTime();

  startWirelessCommunication();
  printUI();

}

void loop() {

   checkForWirelessData();

   getAndPrintTime();
   
   printIndoorTemperature();
   printIndoorHumidity();

   printRemoteTemperature();
   printRemoteHumidity();
}

void startWirelessCommunication()
{
  myRadio.begin(); 
  myRadio.setChannel(115); 
  myRadio.setPALevel(RF24_PA_MAX);
  myRadio.setDataRate( RF24_250KBPS ) ; 
  myRadio.openReadingPipe(1, addresses[0]);
  myRadio.startListening();
  delay(100);
}

void checkForWirelessData()
{
    if ( myRadio.available()) 
  {
    while (myRadio.available())
    {
      myRadio.read( &data, sizeof(data) );
      previousRemoteTemperature = remoteTemperature;
      previousRemoteHumidity = remoteHumidity;
      remoteTemperature = Celcius2Fahrenheit(data.temperature);
      remoteHumidity = data.humidity;
    }
    Serial.print("\nPackage:");
    Serial.print("\n");
    Serial.println(data.temperature);
    Serial.println(data.humidity);
  } 
}

void printUI()
{
  
tft.drawRoundRect(5,5,470,71,5,TFT_WHITE);
tft.drawRoundRect(6,6,470,71,5,TFT_WHITE);

tft.drawRoundRect(5,90,220,225,5,TFT_WHITE);
tft.drawRoundRect(6,91,220,225,5,TFT_WHITE);

tft.drawRoundRect(250,90,220,225,5,TFT_WHITE);
tft.drawRoundRect(251,91,220,225,5,TFT_WHITE);
  
tft.fillRect(26,90,180,40,TFT_GREEN);
tft.fillRect(270,90,180,40,TFT_CYAN);

tft.setCursor(62,100);
tft.setTextColor(TFT_BLACK);
tft.setTextSize(3);
tft.print("REMOTE");

tft.setCursor(312,100);
tft.setTextColor(TFT_BLACK);
tft.setTextSize(3);
tft.print("INDOOR");

tft.setCursor(162,165);
tft.setTextColor(TFT_GREEN);
tft.setTextSize(6);
tft.print("%");

tft.setCursor(412,165);
tft.setTextColor(TFT_CYAN);
tft.setTextSize(6);
tft.print("%");

tft.setCursor(162,230);
tft.setTextColor(TFT_GREEN);
tft.setTextSize(6);
tft.print("F");

tft.setCursor(145,230);
tft.setTextColor(TFT_GREEN);
tft.setTextSize(2);
tft.print("o");

tft.setCursor(412,230);
tft.setTextColor(TFT_CYAN);
tft.setTextSize(6);
tft.print("F");

tft.setCursor(395,230);
tft.setTextColor(TFT_CYAN);
tft.setTextSize(2);
tft.print("o");

}

void getAndPrintTime()
{
  
   delay(100);
   DateTime now = rtc.now(); //get the current date-time
   minuteNow = now.minute();
   if(minuteNow!=minutePrevious)
   {
      readSensor();
      dateString = getDayOfWeek(now.dayOfWeek())+" ";
      dateString = dateString+String(now.date())+"/"+String(now.month());
      dateString= dateString+"/"+ String(now.year()); 
      minutePrevious = minuteNow;
      hours = String(now.hour());
    if(now.minute()<10)
    {
      hours = hours+":0"+String(now.minute());
    }else
    {
      hours = hours+":"+String(now.minute());
    }
    printTime();
   }
}

void printTime()
{
  String dateAndTime = dateString+" "+hours;
  
  tft.setTextSize(2);
  char charBuf[25];
  dateAndTime.toCharArray(charBuf, 25);
  
  tft.setTextColor(TFT_WHITE, TFT_BLACK);
  tft.drawCentreString(charBuf,240,25,2);
}

void setRTCTime()
{
  DateTime dt(2016, 6, 7, 13, 40, 30, 2); // Year, Month, Day, Hour, Minutes, Seconds, Day of Week
  rtc.setDateTime(dt); //Adjust date-time as defined 'dt' above 
}

String getDayOfWeek(int i)
{
  switch(i)
  {
    case 1: return "Monday";break;
    case 2: return "Tuesday";break;
    case 3: return "Wednesday";break;
    case 4: return "Thursday";break;
    case 5: return "Friday";break;
    case 6: return "Saturday";break;
    case 7: return "Sunday";break;
    default: return "Monday";break;
  }
}

void readSensor()
{
  previousIndoorTemperature = indoorTemperature;
  previousIndoorHumidity = indoorHumidity;
  
  indoorHumidity = dht.readHumidity();
  indoorTemperature = Celcius2Fahrenheit(dht.readTemperature());
  Serial.println(indoorTemperature);
  Serial.println(indoorHumidity);
}

void printIndoorTemperature()
{
  String temperature;
  if(indoorTemperature != previousIndoorTemperature)
  {

    if(indoorTemperature>=100)
    {
      temperature = String(indoorTemperature,0);
    }else
    {
      temperature = String(indoorTemperature,1);
    }

    tft.fillRect(270,232,120,40,TFT_BLACK);
  
    tft.setCursor(270,234);
    tft.setTextColor(TFT_CYAN);
    tft.setTextSize(5);
    tft.print(temperature);

    previousIndoorTemperature = indoorTemperature;
  }
}

void printRemoteHumidity()
{
  String humidity;
  if(remoteHumidity != previousRemoteHumidity)
  {
    if(remoteHumidity == 0.0 && remoteTemperature == 0.0) //We just booted up
    {
      humidity = "---";
    }else
    {
          humidity = String(remoteHumidity,1);
    }
    
    tft.fillRect(20,167,120,40,TFT_BLACK);
  
    tft.setCursor(20,167);
    tft.setTextColor(TFT_GREEN);
    tft.setTextSize(5);
    tft.print(humidity);

    previousRemoteHumidity = remoteHumidity;
  }
}

void printRemoteTemperature()
{
  String temperature;
  if(remoteTemperature != previousRemoteTemperature)
  {
    if(remoteHumidity == 0.0 && remoteTemperature == 0.0) //We just booted up
    {
      temperature = "---";
    }else if(remoteTemperature>=100)
    {
      temperature = String(remoteTemperature,0);
    }else
    {
        temperature = String(remoteTemperature,1);
    }
    
    tft.fillRect(20,232,120,40,TFT_BLACK);
  
    tft.setCursor(20,234);
    tft.setTextColor(TFT_GREEN);
    tft.setTextSize(5);
    tft.print(temperature);

    previousRemoteTemperature = remoteTemperature;
  }
}

void printIndoorHumidity()
{
   if(indoorHumidity != previousIndoorHumidity)
  {

    String humidity = String(indoorHumidity,1);

    tft.fillRect(270,167,120,40,TFT_BLACK);
  
    tft.setCursor(270,167);
    tft.setTextColor(TFT_CYAN);
    tft.setTextSize(5);
    tft.print(humidity);

    previousIndoorHumidity = indoorHumidity; 
  }
}

float Celcius2Fahrenheit(float celsius)
{
  return 1.8 * celsius + 32;
}


Etapa 9: Testando o Projeto

A última etapa para ligar tudo e ver se tudo está funcionando conforme o esperado. Nesse caso, na parte superior do visor a data e a hora atuais são exibidas. Na parte inferior da tela, você pode ver a temperatura e a umidade do sensor remoto e local.

Se não houver dados exibidos para o sensor remoto, mova o transmissor para mais perto, ele estará fora do alcance. Se o problema persistir, verifique todas as conexões mais uma vez, deve haver algo errado aí.

Como você pode ver, este projeto é uma grande demonstração do que o hardware e software de código aberto são capazes. Em poucas horas, pode-se construir um projeto tão impressionante! Claro, isso é apenas o começo. Podemos adicionar muitos mais recursos ao projeto. Em breve adicionarei um botão, para que possamos exibir gráficos e ter diferentes modos. Também podemos adicionar mais sensores, registro de dados, conexão à Internet e assim por diante. Estamos usando o Arduino Due, portanto, temos bastante memória para implementar muito mais coisas.

 

Eu adoraria ouvir sua opinião sobre este projeto. Como você quer ver isso evoluir? Por favor, poste seus comentários ou ideias na seção de comentários abaixo!

 

Visits: 3 Visits: 1199241