Estacao Meteorologica: mudanças entre as edições

De Wiki Cursos IFPR Foz
Ir para navegaçãoIr para pesquisar
 
(52 revisões intermediárias pelo mesmo usuário não estão sendo mostradas)
Linha 7: Linha 7:
as áreas de conhecimento de Informática, Eletrônica, Física, Hidrologia e Aquicultura.
as áreas de conhecimento de Informática, Eletrônica, Física, Hidrologia e Aquicultura.


*[[Mídia:ProjetoEstacaoHidroMeteorologica2.pdf|Projeto da Estação Hidrometeorológica]], aprovado no programa PIBIC/CNPq IFPR 2016.
;[[Mídia:ProjetoEstacaoHidroMeteorologica2.pdf|Projeto da Estação Hidrometeorológica]]: Aprovado no programa PIBIC/CNPq, IFPR, 2016.


===Equipe===
===Equipe===
Linha 30: Linha 30:
*Pablo Souza dos Santos (Licenciatura em Física)
*Pablo Souza dos Santos (Licenciatura em Física)


==Estudos sobre Hidrometeorologia==
===Produções===
 
RIBEIRO, T. H. ; OLIVEIRA, B. H. ; SILVA, M. S. ; MOSCHKOWICH, F. N. ; MARTINES, M. M. ; SALLET, J. A. K. ; SILVA, J. M. ; BENACCHIO, A. ; BENEDUZZI, H. M. ; CANTÚ, E. . Estação hidrometeorológica automatizada com microcontrolador Arduíno. '''I Mostra de Inovação, Pesquisa, Ensino, Extensão e Cultura do IFPR''', Foz do Iguaçu, 2016.
 
RIBEIRO, T. H. ; OLIVEIRA, B. H. ; SILVA, M. S. ; MARTINES, M. M. ; CANTÚ, E. . Estação hidrometeorológica automatizada com microcontrolador Arduíno. '''V Seminário de Extensão, Ensino, Pesquisa e Inovação do IFPR''', Cascavel, 2016 ([[Mídia:EstacaoMeteorologica.pdf|Poster SEPIN2016]]).
 
RIBEIRO, T. H. ; OLIVEIRA, B. H.; MARTINES, M. M. Estação hidrometeorológica. '''Projeto Integrador II, Curso Superior de Tecnologia em Análise e Desenvolvimento de Sistemas, IFPR''', Foz do Iguaçu, 2016 ([[Mídia:PI_II_TADS-EstacaoMeteorologica.pdf|Documentação PI-II Estação Meteorológica]]).
 
Esposição '''Espaço Maker'''. PTI, Foz do Iguaçu, 2016.
 
[[Arquivo:EspacoMaker.jpg|300px]] [[Arquivo:EspacoMaker2.jpg|300px]]
 
==Estudos sobre Meteorologia==


;[[Estudos sobre Hidrometeorologia]]: Responsável: Matheus Santos  (Licenciatura em Física)
;[[Estudos sobre Hidrometeorologia]]: Responsável: Matheus Santos  (Licenciatura em Física)
Linha 45: Linha 57:
A '''Biruta''' ou '''sensor de direção do vento''' é fisicamente composto por oito chaves, ligadas a resistores variados. Quando o vento muda de direção um imã fecha um ou dois contatos, permitindo a medição de 16 resistências diferentes.
A '''Biruta''' ou '''sensor de direção do vento''' é fisicamente composto por oito chaves, ligadas a resistores variados. Quando o vento muda de direção um imã fecha um ou dois contatos, permitindo a medição de 16 resistências diferentes.


Na ligação em hardware, um resistor de 10k ohms é utilizado como '''divisor de tensão''',  produzindo uma tensão de saída que pode ser medido por um conversor analógico-digital.
Na ligação em hardware, um resistor de 10 kΩ é utilizado como '''divisor de tensão''',  produzindo uma tensão de saída que pode ser medido por um conversor analógico-digital.


[[Arquivo:biruta_sparkfun_resistores.png]]
[[Arquivo:biruta_sparkfun_resistores.png]]
Linha 56: Linha 68:
  !rowspan=2 | Direção (Graus)
  !rowspan=2 | Direção (Graus)
  !rowspan=2 | Resistencia (Ohms)
  !rowspan=2 | Resistencia (Ohms)
  !rowspan=2 | Tensão (Entrada=5V Resistencia=10ohms)
  !rowspan=2 | Tensão (Entrada=5V Resistencia=10 KΩ)
  !rowspan=2 | Binário (Saída porta Analógica)
  !rowspan=2 | Binário (Saída porta Analógica)
  !colspan=2 | Saída Leitura em Binário de 10 bits (0 - 1023)
  !colspan=2 | Saída Leitura em Binário de 10 bits (0 - 1023)
Linha 133: Linha 145:
--Jade Mathias 18h28min de 18 de novembro de 2015 (BRST)
--Jade Mathias 18h28min de 18 de novembro de 2015 (BRST)


;Anemômetro no Arduíno: A '''largura dos pulsos''' gerados pelo '''anemômetro''' serão medidos pelo Arduíno através da função '''[http://www.arduino.cc/en/Reference/PulseIn pulseln()]'''. O tempo da largura de pulso retornado pela função pulseln() é medido em microsegundos, portando a velocidade do vento será determinada pela expressão:
====Anemômetro no Arduíno====
 
;Medição por largura de pulsos: A '''largura dos pulsos''' gerados pelo '''anemômetro''' serão medidos pelo Arduíno através da função '''[http://www.arduino.cc/en/Reference/PulseIn pulseln()]'''. O tempo da largura de pulso retornado pela função pulseln() é medido em microsegundos, portando a velocidade do vento será determinada pela expressão:
  velocidadeVento = 2,4 * 10<sup>6</sup> / larguraPulso  
  velocidadeVento = 2,4 * 10<sup>6</sup> / larguraPulso  


:Conforme o hardware do anemômetro mostrado abaixo, a '''largura dos pulsos''' do anemômetro será medida durante o tempo que estiver em nível lógico baixo (LOW), entre dois fechamentos de contato.
:Conforme o hardware do anemômetro mostrado abaixo, a '''largura dos pulsos''' do anemômetro será medida durante o tempo que estiver em nível lógico baixo (LOW), entre dois fechamentos de contato.


;Anemômetro: Para um '''vento com velocidade de 2,4 km/h''' o fechamento da chave ocorre uma vez por segundo (1 Hz).  
;Medição por interrupção: Para um '''vento com velocidade de 2,4 km/h''' o fechamento da chave ocorre uma vez por segundo (1 Hz).  
:A rotina de interrupção apenas implementa um '''contador de pulsos'''. No programa principal, para uma dada '''base de tempo''' a '''velocidade''' é determinada pela expressão:
:Uma rotina de interrupção no Arduíno necessita apenas implementar um '''contador de pulsos'''. No programa principal, para uma dada '''base de tempo''' a '''velocidade''' é determinada pela expressão:
  Vel = ( contadorPulsos / baseTempo ) * 2,4
  Vel = ( contadorPulsos / baseTempo ) * 2,4
::Exemplo:
::Exemplo:
Linha 146: Linha 160:
  Vel = (10 / 10 ) * 2,4 = 2,4 km/h
  Vel = (10 / 10 ) * 2,4 = 2,4 km/h


Obs: A '''medição por interrupção''' se mostrou mais estável e é a forma implementada na última versão do programa.


--[[Usuário:Evandro.cantu|Evandro.cantu]] ([[Usuário Discussão:Evandro.cantu|discussão]]) 22h16min de 17 de abril de 2016 (BRT)
--[[Usuário:Evandro.cantu|Evandro.cantu]] ([[Usuário Discussão:Evandro.cantu|discussão]]) 22h16min de 17 de abril de 2016 (BRT)
Linha 164: Linha 179:
[[Arquivo:SensorDirVento.png|400px]]
[[Arquivo:SensorDirVento.png|400px]]


==Sensor de Temperatura e Humidade DHT11==
==Sensores de Temperatura e Humidade==
 
===Sensor de temperatura (LM35) ===


O DHT11 é um sensor de temperatura e humidade. Este sensor inclui um medidor de humidade resistivo e um sensor de temperatura tipo NTC conectado a um microcontrolador de 8 bits <ref> http://www.micro4you.com/files/sensor/DHT11.pdf</ref>.
;Funcionamento do sensor LM35: O '''LM35''' é um '''circuito integrado''' exclusivo para medir temperatura com uma tensão de saída variando linearmente com a temperatura em graus Célsius.  
:Na configuração básica este sensor mede temperaturas entre 2<sup>o</sup>C e 150<sup>o</sup>C, variando a saída em função da temperatura de 0 mV + 10mV por 1<sup>o</sup>C.  


O DHT11 possui uma biblioteca com funções prontas para seu funcionamento <ref>[http://playground.arduino.cc/main/DHT11Lib playground.arduino.cc/DHT11]</ref>. Para uso, baixe a biblioteca [[Mídia:DHT11.zip |DHT11.zip]] e insira no ambiente da IDE do Arduíno:
;Esquema de ligação com Arduíno:
            _______
            |      |
            | LM 35 |
            |_______|
              | | |
    (+5v) ----+ | +---- (Ground)
                |
          Analog Pin
        0mV + 10mV / <sup>o</sup>C
 
;Leitura pela entrada analógica do Arduíno: O valor de tensão (entre '''0V e 5V''') lido pelo Arduíno na '''entrada analógica'''  é convertido um número digital com '''10 bits de magnitude''', ou seja, 2<sup>10</sup> (1024) valores (entre 0 e 1023).
 
:Para obter o valor de tensão, para uso no cálculo da temperatura, multiplica-se o valor digital obtido na leitura por 5/1023.
 
:Como a tensão medida pelo sensor varia de 0 mV + 10mV/1<sup>o</sup>C, se multiplicarmos por 100, teremos o valor em graus Celsius:
 
;Programa Exemplo:
<syntaxhighlight lang="c">
//Sensor de temperatura LM35
float valorSensor;
float temperatura;
void setup() {
Serial.begin(9600);
}
void loop() {
  valorSensor = analogRead(A0) * 5.0 / 1023.0;
  temperatura = valorSensor * 100.0;
  Serial.print("Temperatura: ");
  Serial.println(temperatura);
  delay(2000); //Tempo entre as leituras em ms
}
</syntaxhighlight>
 
O '''sensor de temperatura''' '''LM35''' será utilizado para medir a '''tempetarura interna''' do módulo de campo da '''Estação Meteorolótica'''.
 
===Sensor de Temperatura e Humidade DHT11===
 
O DHT11 é um sensor de temperatura e humidade. Este sensor inclui um medidor de humidade resistivo e um sensor de temperatura tipo NTC conectado a um microcontrolador de 8 bits <ref> Sensor DHT11 http://www.micro4you.com/files/sensor/DHT11.pdf</ref>.
 
O DHT11 possui uma biblioteca com funções prontas para seu funcionamento <ref>Uso da biblioteca DHT11 para Arduino https://playground.arduino.cc/Main/DHT11Lib</ref>. Para uso, baixe a biblioteca [[Mídia:DHT11.zip |DHT11.zip]] e insira no ambiente da IDE do Arduíno:
  Sketch -> Import Library -> Add Library
  Sketch -> Import Library -> Add Library


Linha 199: Linha 257:
  }
  }
</source>
</source>
O '''sensor de temperatura e humidade''' '''DHT11''' será utilizado para medir a '''tempetarura externa''' e a '''humidade relativa do ar''' no módulo de campo da '''Estação Meteorolótica'''.


==Sensor de Pressão Barométrica BMP180==
==Sensor de Pressão Barométrica BMP180==


O '''Sensor de Pressão Barométrica BMP180''' <ref>[https://learn.sparkfun.com/tutorials/bmp180-barometric-pressure-sensor-hookup- Tutorial Sparkfun BMP180] </ref> é um '''sensor de pressão barométrica''', o qual mede a '''pressão absoluta''' do ar ao seu redor. A pressão do ar varia com as '''condições do tempo''' e também com a '''altitude'''. Portanto, dependendo de como os dados medidos forem interpretados, pode-se tanto aferir mudanças nas condições do tempo como na altitude.
O '''Sensor de Pressão Barométrica BMP180''' <ref>Sensor BMP180 https://www.adafruit.com/product/391 </ref> mede a '''pressão absoluta''' do ar ao seu redor. A pressão do ar varia com as '''condições do tempo''' e também com a '''altitude'''. Portanto, dependendo de como os dados medidos forem interpretados, pode-se tanto aferir mudanças nas condições do tempo como na altitude.
 
;Interface I<sup>2</sup>C: O '''BMP180''' utiliza uma interface '''I<sup>2</sup>C''' para se comunicar com o microcontrolador do Arduíno. A interface I<sup>2</sup>C é padronizada para conectar dispositivos periféricos de baixa velocidade a uma placa mãe ou sistema embarcado e usa duas linhas para comunicação: Dados Seriais (''Serial Data'' - SDA) e Clock Serial (''Serial Clock'' - SCL). O clock é gerado pelo mestre e a linha de dados seriais é bidirecional.
 
;Conexões com o hardware do sensor: O sensor BMP180 possui 4 pinos para conexão com o Arduíno:
* '''+''' (Vcc): '''5 V''';
* '''-''' (GND): '''Terra''';
* '''SDA''' (SDA) (I<sup>2</sup>C data): Conectar ao pino '''A4''' UNO
* '''SCL''' (SCL) (I<sup>2</sup>C clock): Conectar ao pino '''A5''' UNO
 
;Instalação da biblioteca para o BMP180: Este sensor possui uma biblioteca e exemplo que facilitam a comunicação com o sensor e o desenvolvimento de programas. Para uso com o Arduíno, baixar a biblioteca [https://github.com/adafruit/Adafruit-BMP085-Library Adafruit_BMP085.h] e instalar na IDE do Arduíno com os comandos:
Scketch -> Import Library -> Add library
 
;Exemplos: Há um exemplo incluído junto com a biblioteca, que pode ser utilizado para testar o sensor BMP180 e também serem utilizados como referência para a construções de novos programas.
 
;Modificado em função da troca de sensor: --[[Usuário:Evandro.cantu|Evandro.cantu]] ([[Usuário Discussão:Evandro.cantu|discussão]]) 19h49min de 27 de novembro de 2017 (BRST)
<!-- Sensor BMP180 Sparkfun (Comentado por sensor foi substituido por outro)
O '''Sensor de Pressão Barométrica BMP180''' <ref>Tutorial Sparkfun BMP180 https://learn.sparkfun.com/tutorials/bmp180-barometric-pressure-sensor-hookup </ref> é um '''sensor de pressão barométrica''', o qual mede a '''pressão absoluta''' do ar ao seu redor. A pressão do ar varia com as '''condições do tempo''' e também com a '''altitude'''. Portanto, dependendo de como os dados medidos forem interpretados, pode-se tanto aferir mudanças nas condições do tempo como na altitude.


;Interface I<sup>2</sup>C: O '''BMP180''' utiliza uma interface '''I<sup>2</sup>C''' para se comunicar com o microcontrolador do Arduíno. A interface I<sup>2</sup>C é padronizada para conectar dispositivos periféricos de baixa velocidade a uma placa mãe ou sistema embarcado e usa duas linhas para comunicação: Dados Seriais (''Serial Data'' - SDA) e Clock Serial (''Serial Clock'' - SCL). O clock é gerado pelo mestre e a linha de dados seriais é bidirecional.
;Interface I<sup>2</sup>C: O '''BMP180''' utiliza uma interface '''I<sup>2</sup>C''' para se comunicar com o microcontrolador do Arduíno. A interface I<sup>2</sup>C é padronizada para conectar dispositivos periféricos de baixa velocidade a uma placa mãe ou sistema embarcado e usa duas linhas para comunicação: Dados Seriais (''Serial Data'' - SDA) e Clock Serial (''Serial Clock'' - SCL). O clock é gerado pelo mestre e a linha de dados seriais é bidirecional.
Linha 221: Linha 298:
;Exemplos: Há dois exemplos incluídos junto com a instalação da biblioteca, que podem ser utilizados para testar o sensor BMP180 e também serem utilizados como referência para a construções de novos programas:
;Exemplos: Há dois exemplos incluídos junto com a instalação da biblioteca, que podem ser utilizados para testar o sensor BMP180 e também serem utilizados como referência para a construções de novos programas:
#'''Medição de temperatura e pressão absoluta e relativa''': Este exemplo mostra a medição de '''temperatura''' e '''pressão barométrica absoluta e relativa''', calculada a partir da '''altitude''' fornecida para o lugar da medição.
#'''Medição de temperatura e pressão absoluta e relativa''': Este exemplo mostra a medição de '''temperatura''' e '''pressão barométrica absoluta e relativa''', calculada a partir da '''altitude''' fornecida para o lugar da medição.
#'''Medição de altitude''': Mostra como medir a '''altitude''' de um lugar, a partir da calibração do sensor para uma altitude conhecida e utilizando o barômetro para medir as variações de altitude.
#'''Medição de altitude''': Mostra como medir a '''altitude''' de um lugar, a partir da calibração do sensor para uma altitude conhecida e utilizando o barômetro para medir as variações de altitude.-->
 
===Medição de tempo e altitude===
===Medição de tempo e altitude===


Linha 280: Linha 356:
Os sensores são conectados da seguinte forma:
Os sensores são conectados da seguinte forma:


[[Arquivo:ConexaoSensores-FlatCable.png]]
[[Arquivo:ConexaoSensores-FlatCable2.png]]


<!-- Ligações do sensor BMP180 Sparkfun
Código de cores utilizados nos fios de conexão com o Arduíno:
Código de cores utilizados nos fios de conexão com o Arduíno:
*GND  - '''Preto'''    (pinos 2 e 8)
*GND  - '''Preto'''    (pinos 2 e 8)
Linha 288: Linha 365:
*Data - (<font color="yellow">'''Amarelo'''</font>)  (pino 3)  -> A2
*Data - (<font color="yellow">'''Amarelo'''</font>)  (pino 3)  -> A2
*DA  - (<font color="blue">'''Azul'''</font>)    (pino 10) -> A4
*DA  - (<font color="blue">'''Azul'''</font>)    (pino 10) -> A4
*CL  - (<font color="green">'''Verde'''</font>)    (pino 9)  -> A5
*CL  - (<font color="green">'''Verde'''</font>)    (pino 9)  -> A5-->
 
Código de cores utilizados nos fios de conexão com o Arduíno:
*GND  - '''Preto'''    (pinos 2 e 9)
*5V  - (<font color="red">'''Vermelho'''</font>) (pino 4 e 10)
*Data - (<font color="yellow">'''Amarelo'''</font>)  (pino 3)  -> A2
*DA  - (<font color="blue">'''Azul'''</font>)    (pino 7) -> A4
*CL  - (<font color="green">'''Verde'''</font>)    (pino 8)  -> A5
 
;Modificado em função da troca de sensor: --[[Usuário:Evandro.cantu|Evandro.cantu]] ([[Usuário Discussão:Evandro.cantu|discussão]]) 19h53min de 27 de novembro de 2017 (BRST)


--[[Usuário:Evandro.cantu|Evandro.cantu]] ([[Usuário Discussão:Evandro.cantu|discussão]]) 10h35min de 25 de outubro de 2016 (BRST)
==Código para Arduíno que controla a Estação Meteorológica==


==Código para Arduíno==
Código para leitura dos '''sensores de campo''', com resultados podendo ser apresentados no '''monitor serial''' da IDE do Arduíno, ou enviados via '''comunicação sem fio Xbee''' para armazenamento em '''banco de dados''' e '''servidor Web'''..


<source lang="c">
<source lang="c">
/*
/*
       Estação Meteorológica com Microcontrolador Arduino
       Estação Meteorológica com Microcontrolador Arduino
Linha 301: Linha 388:
       Programadores: José Sallet (V1 2015)
       Programadores: José Sallet (V1 2015)
                     Thiago Henrique Ribeiro (V2 2016)
                     Thiago Henrique Ribeiro (V2 2016)
 
                    Evandro Cantú (V3 2017)
       Orientador: Evandro Cantú
       Orientador:   Evandro Cantú


       Mudanças em 2016:
       Mudanças em 2016:
 
       Abr4/2016 - Inclusão da função de leitura de vento por pulseIn()
       12/04/2016 - Inclusão da função de leitura de vento por pulseIn()
                - Carregar strings literais da memória flash -> Serial.println(F("String literal));
      14/04/2016 - Carregar strings literais da memória flash -> Serial.println(F("String literal));
                - Inclusão dos sensores LM35 (temperatura) e DHT11 (temperatura, umidade)
                - Inclusão dos sensores LM35 (temperatura) e DHT11 (temperatura, umidade)
                - Testes com anemômetro e biruta com soprador de ar
                - Testes com anemômetro e biruta com soprador de ar
               
 
      Mudanças em 2017:
      Nov/2017: - Troca do sensor de Pressão Atmosférica
                - Inclusão de ventilador para resfrigeração
*/
*/
//Estacao de Testes - Baseado no codigo EstacaoMeteoCompleta
//Teste de adição de sensores LM35, DHT11 e nova rotina de leitura de vento baseada em PulseIn


#include<string.h>
#include<string.h>
//incluindo biblioteca do sensor de temperatura e pressao DHT11
//incluindo biblioteca do sensor de temperatura e pressao DHT11
#include <dht11.h>
#include <dht11.h>
//incluindo biblioteca do sensor de pressão
//incluindo biblioteca do sensor de pressão
#include <SFE_BMP180.h>
#include <Adafruit_BMP085.h>
 
//biblioteca do protocolo I2C
//biblioteca do protocolo I2C
#include <Wire.h>      // biblioteca de comunicação I2C - necessária para o sensor barométrico BMP180
#include <Wire.h>      // biblioteca de comunicação I2C - necessária para o sensor barométrico BMP180
 
#define ALTITUDE 180.0 // Altitude de Foz do Iguaçu, Parana, Brasil
#define ALTITUDE 180.0 // Altitude de Foz do Iguaçu, Parana, Brasil
#define BASETEMPO 10    // define o tempo de repeticao
#define BASETEMPO 10    // define o tempo de repeticao


SFE_BMP180 sensorPressao;     //inicializando sensor de temperatura e pressão
Adafruit_BMP085 bmp;         //inicializando sensor de temperatura e pressão
dht11 sensorUmidade;          //inicializando sensor DHT11
dht11 sensorUmidade;          //inicializando sensor DHT11


const int PINO_BIRUTA = A0;  //pino analógico A0 - Leitura da tensão da biruta
const int PINO_VENTILADOR = 13;  //pino digital  13 - Acionamento do ventilador interno
const int PINO_LM35   = A1;  //pino analógico A1 - Leitura do sensor LM35 (temperatura)
const int PINO_BIRUTA     = A0;  //pino analógico A0 - Leitura da tensão da biruta
const int PINO_DHT11 = A2;  //pino analógico A2 - Leitura do sensor DHT11 (temperatura + umidade)
const int PINO_LM35       = A1;  //pino analógico A1 - Leitura do sensor LM35 (temperatura)
                              //pino analógico A3 livre
const int PINO_DHT11     = A2;  //pino analógico A2 - Leitura do sensor DHT11 (temperatura + umidade)
                              //pino analógico A4 usado no BMP180 (temperatura + pressão)
                                  //pino analógico A3 livre
                              //pino analógico A5 usado no BMP180 (temperatura + pressão)
                                  //pino analógico A4 usado no BMP180 (temperatura + pressão)
                                  //pino analógico A5 usado no BMP180 (temperatura + pressão)


const int BUFFER_SIZE = 1000;                       //quantidade de leituras do sensor LM35 para fazer a média
const int BUFFER_SIZE = 100;     //quantidade de leituras do sensor LM35 para fazer a média
                                                    //para reduzir a margem de erro
                                //para reduzir a margem de erro
const float CONVERSAO_GRAUS_CELSIUS = 0.488758553;  //constante para calcular a temperatura do sensor LM35
const float CONVERSAO_GRAUS_CELSIUS = 0.488758553;  //constante para calcular a temperatura do sensor LM35


//int Tensao;            //tensão de leitura da biruta - comentado para invocar em loop()
//Váriáveis para dados da Estação Meteorológica
float mmChuva = 0;       //pluviômetro - Isto deveria ser gravado em EEPROM
float mmChuva = 0;         //chuva acumulada
//int contVento = 0;     //contador de pulsos de vento - substituído por pulseIn
int   contVento = 0;       //contador de pulsos de vento
//float velVento;         //velocidade do vento - comentado para invocar em loop
double altitude_local;      //altitude do local
float temperatura1;       //temperatura do sensor DHT11
float  umidade;            //umidade do sensor DHT11
int    tensaoBiruta;        //valor da tensão na biruta
String direcao;            //direção da biruta
float  velocidadeVento;    //velocidade do vento
float  temperatura2;        //temperatura do sensor LM35 interno da estação
double temperatura3;        //temperatura do sensor BMP180
double pressaoAbsoluta;    //pressão absolutado sensor BMP180
double pressaoRelativa;    //calculo pressão relativa
double altitudeCalculada;  //calculo da altitude
double pontoOrvalho;        //calculo do ponto de orvalho


//--------------------------------------------------------------------------------------------------------------
//Váriáveis para base de tempo para contagem de interrupções do anemômetro
//  ROTINA DE INTERRUPÇÃO 0 - ANEMÔMETRO (obsoleta)
float tempoAnterior = 0;
//--------------------------------------------------------------------------------------------------------------
float tempoAtual;
float baseTempo = 0;


//void vento(){
//Váriáveis para medida do tempo total de execução do programa
//  contVento++;
unsigned long inicio;  
//  }
unsigned long fim;
unsigned long tempo;


//--------------------------------------------------------------------------------------------------------------
//-----------------------------------------------------------
//  ROTINA DE INTERRUPÇÃO 1 - PLUVIÔMETRO
//  ROTINA DE INTERRUPÇÃO 1 - PLUVIÔMETRO
//--------------------------------------------------------------------------------------------------------------
//-----------------------------------------------------------


void choveu() {
void choveu() {
   mmChuva = mmChuva + 0.2794;
   mmChuva = mmChuva + 0.2794;
  if (mmChuva > 1000)
    mmChuva = mmChuva - 1000;
}


  if (mmChuva > 1000)
//-----------------------------------------------------------
  {
//  ROTINA DE INTERRUPÇÃO 0 - ANEMÔMETRO
    mmChuva = mmChuva - 1000;
//-----------------------------------------------------------
  }
 
void vento(){
  contVento++;
}
}


//--------------------------------------------------------------------------------------------------------------
//-----------------------------------------------------------
//  ANEMÔMETRO (versão nova sem interrupção)
//  ANEMÔMETRO
//--------------------------------------------------------------------------------------------------------------
//-----------------------------------------------------------


float velVento(){
float velVento(){
//Medição de largura do pulso em microsegundos
          tempoAtual = millis();
  unsigned long larguraPulso = pulseIn(2, LOW, 2400000); //um pulso de 2400000 ms equivale a um vento de 1km/h
          baseTempo = tempoAtual - tempoAnterior;
  float _velVento = 0;
          float _velVento = (contVento / (baseTempo/1000)) * 2.4;
 
          tempoAnterior = tempoAtual;
  //calcular Velocidade de acordo com a largura do pulso; Largura de pulso mínima a ser calculada
          contVento = 0;  
  if (larguraPulso <= 5000) {
    return _velVento;
    byte retry = 2;
    //se houver uma leitura inválida (valores absurdos devido a erros), mais duas tentativas são feitas.
    while((retry > 0) && (larguraPulso <= 5000)){
      retry--;
      larguraPulso = pulseIn(2,LOW, 2400000);
    }
   }
   }


  if(larguraPulso > 5000){
//-----------------------------------------------------------
    _velVento = 2.4 * (1000000 / (float) larguraPulso); 
  }else{
    _velVento = 0;
  }
 
  return _velVento;
}
//--------------------------------------------------------------------------------------------------------------
//  BIRUTA (Sparkfun)
//  BIRUTA (Sparkfun)
//--------------------------------------------------------------------------------------------------------------
//-----------------------------------------------------------
 


String biruta(int Tensao)
String biruta(int Tensao)
Linha 402: Linha 496:
   String direcao;
   String direcao;
   if (Tensao >= 744 && Tensao <= 805) {
   if (Tensao >= 744 && Tensao <= 805) {
    //Serial.println(F("Direcao do Vento:  Leste"));
     direcao = "Norte";
     direcao = "L";
   }
   }
   else if (Tensao >= 346 && Tensao <= 432) {
   else if (Tensao >= 346 && Tensao <= 432) {
    //Serial.println(F("Direcao do Vento:  Leste-Norderste"));
     direcao = "Norte-Nordeste";
     direcao = "LNE";
   }
   }
   else if (Tensao >= 433 && Tensao <= 529) {
   else if (Tensao >= 433 && Tensao <= 529) {
    //Serial.println(F("Direcao do Vento:  Nordeste"));
     direcao = "Nordeste";
     direcao = "NE";
   }
   }
   else if (Tensao >= 75 && Tensao <= 87) {
   else if (Tensao >= 75 && Tensao <= 87) {
     //Serial.println(F("Direcao do Vento:  Norte-Nordeste"));
     direcao = "Leste-Nordeste";
    direcao = "NNE";
   }
   }
   else if (Tensao >= 88 && Tensao <= 109) {
   else if (Tensao >= 88 && Tensao <= 109) {
    //Serial.println(F("Direcao do Vento:  Norte"));
     direcao = "Leste";
     direcao = "N";
   }
   }
   else if (Tensao >= 0 && Tensao <= 74) {
   else if (Tensao >= 0 && Tensao <= 74) {
    //Serial.println(F("Direcao do Vento:  Norte-Noroeste"));
     direcao = "Leste-Sudeste";
     direcao = "NNO";
   }
   }
   else if (Tensao >= 156 && Tensao <= 213) {
   else if (Tensao >= 156 && Tensao <= 213) {
    //Serial.println(F("Direcao do Vento:  Noroeste"));
     direcao = "Sudeste";
     direcao = "NO";
   }
   }
   else if (Tensao >= 110 && Tensao <= 155) {
   else if (Tensao >= 110 && Tensao <= 155) {
    //Serial.println(F("Direcao do Vento:  Oeste-Noroeste"));
     direcao = "Sul-Sudeste";
     direcao = "ONO";
   }
   }
   else if (Tensao >= 265 && Tensao <= 345) {
   else if (Tensao >= 265 && Tensao <= 345) {
    //Serial.println(F("Direcao do Vento:  Oeste"));
     direcao = "Sul";
     direcao = "O";
   }
   }
   else if (Tensao >= 214 && Tensao <= 264) {
   else if (Tensao >= 214 && Tensao <= 264) {
     //Serial.println(F("Direcao do Vento:  Oeste-Sudoeste"));
     direcao = "Sul-Sudoeste";
    direcao = "OSO";
   }
   }
   else if (Tensao >= 615 && Tensao <= 665) {
   else if (Tensao >= 615 && Tensao <= 665) {
    //Serial.println(F("Direcao do Vento:  Sudoeste"));
     direcao = "Sudoeste";
     direcao = "SO";
   }
   }
   else if (Tensao >= 530 && Tensao <= 614) {
   else if (Tensao >= 530 && Tensao <= 614) {
     //Serial.println(F("Direcao do Vento:  Sul-Sudoeste"));
     direcao = "Oeste-Sudoeste";
    direcao = "SSO";
   }
   }
   else if (Tensao >= 886 && Tensao <= 961) {
   else if (Tensao >= 886 && Tensao <= 961) {
    //Serial.println(F("Direcao do Vento:  Sul"));
     direcao = "Oeste";
     direcao = "S";
   }
   }
   else if (Tensao >= 806 && Tensao <= 885) {
   else if (Tensao >= 806 && Tensao <= 885) {
    //Serial.println(F("Direcao do Vento:  Sul-Sudeste"));
     direcao = "Oeste-Noroeste";
     direcao = "SSE";
   }
   }
   else if (Tensao >= 962 && Tensao <= 1023) {
   else if (Tensao >= 962 && Tensao <= 1023) {
    //Serial.println(F("Direcao do Vento:  Sudeste"));
     direcao = "Noroete";
     direcao = "SE";
   }
   }
   else if (Tensao >= 666 && Tensao <= 743) {
   else if (Tensao >= 666 && Tensao <= 743) {
    //Serial.println(F("Direcao do Vento:  Leste-Sudeste"));
     direcao = "Norte-Noroeste";
     direcao = "LSE";
   }
   }
   else{
   else{
     Serial.println(F("[ERRO] Leitura na biruta fora da faixa!"));
     Serial.println(F("[ERRO] Leitura na biruta fora da faixa!"));
     direcao = "ERR";
     direcao = "Erro de leitura da Biruta";
   }
   }
   
   return direcao;
   return direcao;
}
}


//--------------------------------------------------------------------------------------------------------------
//-----------------------------------------------------------
//  SENSOR DE TEMPERATURA LM35
//  SENSOR DE TEMPERATURA LM35
//--------------------------------------------------------------------------------------------------------------
//-----------------------------------------------------------
 


//ler temperatura do sensor LM35 uma única vez
//ler temperatura do sensor LM35 uma única vez
Linha 487: Linha 563:
float temperaturaLM35Buffer() {
float temperaturaLM35Buffer() {
   float buffer = 0;
   float buffer = 0;
   for (int i = 0; i < BUFFER_SIZE ; i++) {
   for (int i = 0; i < BUFFER_SIZE ; i++)  
     buffer += analogRead(PINO_LM35);
     buffer += analogRead(PINO_LM35);
  }
   return (buffer / BUFFER_SIZE) * CONVERSAO_GRAUS_CELSIUS;
   return ((buffer) / BUFFER_SIZE) * CONVERSAO_GRAUS_CELSIUS;
}
}


//--------------------------------------------------------------------------------------------------------------
//-----------------------------------------------------------
//  CÁLCULO DE PONTO DE ORVALHO
//  CÁLCULO DE PONTO DE ORVALHO
//  Funções de ponto de orvalho obtidas em http://playground.arduino.cc/Main/DHT11Lib
//  Funções de ponto de orvalho obtidas em http://playground.arduino.cc/Main/DHT11Lib
//  A fazer: Verificar e referenciar o código apropriadamente
//  A fazer: Verificar e referenciar o código apropriadamente
//  O código abaixo foi copiado e usado sem alterações
//  O código abaixo foi copiado e usado sem alterações
//--------------------------------------------------------------------------------------------------------------
//-----------------------------------------------------------


// dewPoint function NOAA
// dewPoint function NOAA
// reference (1) : http://wahiduddin.net/calc/density_algorithms.htm
// reference (1) : http://wahiduddin.net/calc/density_algorithms.htm
// reference (2) : http://www.colorado.edu/geography/weather_station/Geog_site/about.htm
// reference (2) : http://www.colorado.edu/geography/weather_station/Geog_site/about.htm
//
 
double dewPoint(double celsius, double humidity)
double dewPoint(double celsius, double humidity)
{
{
Linha 536: Linha 611:
//    **Fim das funções de orvalho copiadas**
//    **Fim das funções de orvalho copiadas**


//--------------------------------------------------------------------------------------------------------------
//-----------------------------------------------------------
//  SENSOR DE PRESSÃO E TEMPERATURA (BMP180)
//--------------------------------------------------------------------------------------------------------------
 
 
double temperaturaBMP180(SFE_BMP180 sensor) {
  double T;
  char  status = sensor.startTemperature();
  if (status != 0) {
    delay(status);
    status = sensor.getTemperature(T);
    if (status == 0) {
      Serial.println(F("[AVISO] Falha na aquisição de temperatura do sensor BMP180. Tentando novamente..."));
      return temperaturaBMP180(sensor); // recursivamente faz uma nova tentativa
    }
  } else {
    Serial.println(F("[AVISO] Falha na preparação do sensor de temperatura BMP180. Tentando novamente..."));
    return temperaturaBMP180(sensor); // recursivamente faz uma nova tentativa
  }
  return T;
}
 
double pressaoBMP180(double temperatura, SFE_BMP180 sensor) {
  double pressao;
  char status = sensor.startPressure(3);
  if (status != 0) {
    delay(status);
    status = sensor.getPressure(pressao, temperatura);
    if (status == 0) {
      //erro em getPressure
      Serial.println(F("[ERRO] Falha na aquisição da temperatura do sensor BMP180. Tentando novamente..."));
      return pressaoBMP180(temperatura, sensor);  //nova tentativa usando recursão
    }
  } else {
    //erro em startPressure
    Serial.println(F("[ERRO] Falha na preparação do sensor de pressão BMP180. Tentando novamente..."));
    return pressaoBMP180(temperatura, sensor); // nova tentativa usando recursão
  }
 
  return pressao;
}
 
//  cálculo da pressão relativa ao nível do mar
double pressaoNivelMar(double pressao, double altura, SFE_BMP180 sensor) {
  return sensor.sealevel(pressao, altura);
}
 
//  cálculo da altitude
double altitude(double pressao, double pressao_nivel_mar, SFE_BMP180 sensor) {
  return sensor.altitude(pressao, pressao_nivel_mar);
}
 
//--------------------------------------------------------------------------------------------------------------
//  TELEMETRIA - MEMÓRIA LIVRE NO SISTEMA
//  TELEMETRIA - MEMÓRIA LIVRE NO SISTEMA
//--------------------------------------------------------------------------------------------------------------
//-----------------------------------------------------------


int freeRam () {
int freeRam () {
Linha 598: Linha 621:
}
}


//--------------------------------------------------------------------------------------------------------------
//-----------------------------------------------------------
//  SETUP (Preparação)
//  Função para imprimir na serial: Estação em modo StandAlone
//--------------------------------------------------------------------------------------------------------------
//-----------------------------------------------------------
 
void setup()
{
  Serial.begin(9600); //define a frequencia
 
  attachInterrupt(1, choveu, RISING); // interrupcao do pluviometro
 
  Serial.print(F("\nInicializando sensor barometrico BMP180... "));
  // Initialize the sensor (it is important to get calibration values stored on the device).
  if (sensorPressao.begin())
    Serial.println(F("[OK]"));
  else
  {
    // Oops, something went wrong, this is usually a connection problem,
    // see the comments at the top of this sketch for the proper connections.
    Serial.println(F("[FAIL]\n\nA estação não pode ser inicializada. Verifique o sensor barométrico e reinicie o aparelho."));
    while (1); // Pause forever.
  }
}


//--------------------------------------------------------------------------------------------------------------
void imprimeSerial () {
//  PROGRAMA PRINCIPAL
  //  exibir dados na tela ou terminal serial
//--------------------------------------------------------------------------------------------------------------


//repeticao que imprime as informacoes do programa ao usuario
   Serial.println(F("================================================"));
//TODO: organizar a ordem de execução levando em consideração o tempo tolerado por cada sensor
void loop()
{
  /*
  *  Ações do programa:
  *  1.  Obter leitura do sensor de umidade (só pode ser lido a cada 2 segundos, são dois valores inteiros)
  *  2.  Obter leituras de tensão da biruta
  *  3.  Obter leituras do anemômetro
  *  4.  Obter leituras de temperatura do sensor LM35
  *  5.  Obter leituras de temperatura e pressão do sensor BMP180
  */
  unsigned long inicio = millis(); // millis() e micros() - medem o tempo corrido em milisegundos e microsegundos
 
  sensorUmidade.read(PINO_DHT11);
  double altitude_local = (double)ALTITUDE;                            //adquire a altitude do local
  float temperatura1 = (float) sensorUmidade.temperature;              //adquire temperatura do sensor DHT11
  float umidade = (float) sensorUmidade.humidity;                      //adquire umidade do sensor DHT11
  int tensaoBiruta = analogRead(PINO_BIRUTA);                          //adquire o valor da tensão na biruta
  String direcao = biruta(tensaoBiruta);                                //calcula a direção da biruta
  float velocidadeVento = velVento();                                  //adquire a velocidade do vento
  float temperatura2 = temperaturaLM35Buffer();                        //adquire temperatura do sensor LM35
  double temperatura3 = temperaturaBMP180(sensorPressao);              //adquire temperatura do sensor BMP180
  double pressaoAbsoluta = pressaoBMP180(temperatura3, sensorPressao);  //adquire pressão absolutado sensor BMP180
  double pressaoRelativa = pressaoNivelMar(pressaoAbsoluta, altitude_local, sensorPressao); //calcula pressão relativa
  double altitudeCalculada = altitude(pressaoAbsoluta, pressaoRelativa, sensorPressao);    //calcula altitude
  double pontoOrvalho = dewPoint(temperatura2, umidade);                                    //calcula ponto de orvalho
 
  unsigned long fim = millis();                                        //fim da cronometração da função
  unsigned long tempo = fim - inicio;                                  //cálculo do tempo de execução
 
  if(tempo < 2000){
    delay(2000 - tempo);                                                //cálculo do tempo de espera
  }                                                                    //(não pode ser menor que 2s)
 
//  exibir dados na tela ou terminal serial
   Serial.println(F("================================================================================================"));
    
    
   Serial.print(F("Temperatura [DHT11]:\t\t\t"));
   Serial.print(F("Temperatura [DHT11]:\t\t\t"));
Linha 667: Linha 634:
   Serial.println(F(" graus Celsius"));
   Serial.println(F(" graus Celsius"));


   Serial.print(F("Temperatura [LM35]\t\t\t"));
   Serial.print(F("Temperatura Interna [LM35]:\t\t"));
   Serial.print(temperatura2);
   Serial.print(temperatura2);
   Serial.println(F(" graus Celsius"));
   Serial.println(F(" graus Celsius"));


   Serial.print(F("Temperatura [BMP180]\t\t\t"));
   Serial.print(F("Temperatura [BMP180]:\t\t\t"));
   Serial.print(temperatura3);
   Serial.print(temperatura3);
   Serial.println(F(" graus Celsius"));
   Serial.println(F(" graus Celsius"));
Linha 708: Linha 675:
    
    
   //exibir tempo de execução
   //exibir tempo de execução
 
   Serial.print(F("\nTempo de execucao total:\t\t"));
   Serial.print(F("\nTempo de execucao total: "));
   Serial.print(tempo);
   Serial.print(tempo);
   Serial.println(F("ms\n"));
   Serial.println(F("ms\n"));


   // exibir memória livre pra determinar estabilidade
   // exibir memória livre pra determinar estabilidade
   Serial.print(F("\nMemoria Livre: "));
   Serial.print(F("Memoria Livre:\t\t\t\t"));
   Serial.print(freeRam());
   Serial.print(freeRam());
   Serial.println(F(" bytes\n"));
   Serial.println(F(" bytes\n"));
    
    
/*
}
  * Versão anterior do programa principal
 
  *
//-----------------------------------------------------------
        velVento = (contVento / BASETEMPO) * 2.4;   
//  Função para enviar PAYLOAD com dados via Xbee
        Tensao = analogRead(A0); //variavel tensao recebe valor digital do dispositivo de direcao de vento
//-----------------------------------------------------------
        Serial.print("Chuva acumalada (mm):  ");
        Serial.println(mmChuv1000a);
        Serial.print("Velocidade do Vento (km/h):  ");
        Serial.println(velVento);
        biruta(Tensao);
        altitudeEPressao();
   
        contVento = 0;
  Serial.println("");
        // PARA MODIFICAR O DELAY MODIFICAR A VARIAVEL "BASETEMPO"
        // NO CABECARIO DO PROGRAMA
        delay(BASETEMPO*1000); //Tempo entre as leituras em ms


   */
void enviaXbee () {
}
   //  Montar dados em formato Jason
     
  String payload = "{";
  payload += "\"a\":";
  payload += temperatura1;


  payload +=", \"b\":";
  payload += temperatura2;
 
  payload +=", \"c\":";
  payload += temperatura3;


</source>
  payload +=", \"d\":";
--[[Usuário:Thiago.ribeiro|Thiago.ribeiro]] ([[Usuário Discussão:Thiago.ribeiro|discussão]]) 17h53min de 27 de abril de 2016 (BRT)
  payload += velocidadeVento;
<!--
<source lang="c">
                                                                                                                                                                     
//incluindo biblioteca do sensor de temperatura e pressão
#include <SFE_BMP180.h>
#include <Wire.h>


SFE_BMP180 pressure;
  payload +=", \"e\":\"";
#define ALTITUDE 180.0 // Altitude de Foz do Iguaçu, Parana, Brasil
  payload += direcao;
#define BASETEMPO 10 // define o tempo de repeticao
 
int Tensao;  
  payload +="\", \"f\":";
float mmChuva = 0;  
  payload += pressaoAbsoluta;
int contVento = 0;  
 
float velVento;  
  payload +=", \"g\":";
  payload += pressaoRelativa;
 
  payload +=", \"h\":";
  payload += umidade;
 
  payload +=", \"i\":";
  payload += mmChuva;
 
  payload +=", \"j\":";
  payload += pontoOrvalho;


//rotina da interrupcao 1: pluviometro
  payload +=", \"k\":";
void choveu(){
   payload += "\"IFPR0001\"";
   mmChuva = mmChuva + 0.2794;
    
    
  if(mmChuva > 999)
//  payload += (fim/1000);
    {mmChuva = mmChuva - 999;}
  payload +="}";
 
  Serial.print(payload);    
}
}


//rotina da interrupcao 0: anemometro
//-----------------------------------------------------------
void vento(){
//  SETUP (Preparação)
  contVento++;
//-----------------------------------------------------------
}
 
void setup()
void setup()
{
{
    Serial.begin(9600); //define a frequencia
  pinMode(PINO_VENTILADOR, OUTPUT); //Saída digital para acionamento do ventilador
    attachInterrupt(1, choveu, RISING); // interrupcao do pluviometro
  Serial.begin(9600); //define a taxa de transmissão da serial
    attachInterrupt(0, vento, RISING); // interrupcao do anemometro
 
  attachInterrupt(0, vento, RISING); // interrupcao do anemometro
  attachInterrupt(1, choveu, RISING); // interrupcao do pluviometro


    if (pressure.begin())
  //Inicialização do sensor de pressão BMP180
        Serial.println("BMP180 iniciado com sucesso...");
  if (!bmp.begin()) {
    else
    Serial.println(F("[FAIL]\n\nA estação não pode ser inicializada. Verifique o sensor barométrico e reinicie o aparelho."));
    {
    while (1) {}
        Serial.println("BMP180 FALHOU...\n\n");
  }
          while(1); // nao executa programa.
    }
}
}


//funcao que define e imprime a direcao do vento
//-----------------------------------------------------------
String biruta(int Tensao)
//  PROGRAMA PRINCIPAL
  {
//-----------------------------------------------------------
    String direcao;
   
    if(Tensao >= 744 && Tensao <= 805){
          Serial.println("Direcao do Vento:  Leste");
          direcao = "L";}
    else if(Tensao >= 346 && Tensao <= 432){
          Serial.println("Direcao do Vento:  Leste-Norderste");
          direcao = "LNE";}
    else if(Tensao >= 433 && Tensao <= 529){
          Serial.println("Direcao do Vento:  Nordeste");
          direcao = "NE";}
    else if(Tensao >= 75 && Tensao <= 87){
  Serial.println("Direcao do Vento:  Norte-Nordeste");
          direcao = "NNE";}
    else if(Tensao >= 88 && Tensao <= 109){
  Serial.println("Direcao do Vento:  Norte");
          direcao = "N";}
    else if(Tensao >= 0 && Tensao <= 74){
  Serial.println("Direcao do Vento:  Norte-Noroeste");
          direcao = "NNO";}
    else if(Tensao >= 156 && Tensao <= 213){
  Serial.println("Direcao do Vento:  Noroeste");
          direcao = "NO";}
    else if(Tensao >= 110 && Tensao <= 155){
  Serial.println("Direcao do Vento:  Oeste-Noroeste");
          direcao = "ONO";}
    else if(Tensao >= 265 && Tensao <= 345){
  Serial.println("Direcao do Vento:  Oeste");
          direcao = "O";}
    else if(Tensao >= 214 && Tensao <= 264){
  Serial.println("Direcao do Vento:  Oeste-Sudoeste");
          direcao = "OSO";}
    else if(Tensao >= 615 && Tensao <= 665){
  Serial.println("Direcao do Vento:  Sudoeste");
          direcao = "SO";}
    else if(Tensao >= 530 && Tensao <= 614){
    Serial.println("Direcao do Vento:  Sul-Sudoeste");
          direcao = "SSO";}
    else if(Tensao >= 886 && Tensao <= 961){
  Serial.println("Direcao do Vento:  Sul");
          direcao = "S";}
    else if(Tensao >= 806 && Tensao <= 885){
  Serial.println("Direcao do Vento:  Sul-Sudeste");
          direcao = "SSE";}
    else if(Tensao >= 962 && Tensao <= 1023){
  Serial.println("Direcao do Vento:  Sudeste");
          direcao = "SE";}
    else if(Tensao >= 666 && Tensao <= 743){
  Serial.println("Direcao do Vento:  Leste-Sudeste");
          direcao = "LSE";}
    else
  Serial.println("[  Fora de Leitura!!!  ]");
 
    return direcao;
  }


//funcao que define altitude,  pressao e temperatura
//repeticao que imprime as informacoes do programa ao usuario
void altitudeEPressao()
//TODO: organizar a ordem de execução levando em consideração o tempo tolerado por cada sensor
void loop()
{
{
   char status;
   /*
   double T,P,p0,a;
  *  Ações do programa:
  *  1.  Obter leitura do sensor de umidade (só pode ser lido a cada 2 segundos, são dois valores inteiros)
  *  2.  Obter leituras de tensão da biruta
  *  3.  Obter leituras do anemômetro
  *  4.  Obter leituras de temperatura do sensor LM35
  *  5.  Obter leituras de temperatura e pressão do sensor BMP180
  */
 
  int espera = 5000;
   inicio = millis(); // millis() e micros() - medem o tempo corrido em milisegundos e microsegundos
    
    
   Serial.println();
   sensorUmidade.read(PINO_DHT11);
   Serial.print("Altitude: ");
   altitude_local = (double)ALTITUDE;                    //adquire a altitude do local
   Serial.print(ALTITUDE,0);
  temperatura1 = (float) sensorUmidade.temperature;    //adquire temperatura do sensor DHT11
   Serial.println(" metros, ");
  umidade = (float) sensorUmidade.humidity;            //adquire umidade do sensor DHT11
  tensaoBiruta = analogRead(PINO_BIRUTA);               //adquire o valor da tensão na biruta
   status = pressure.startTemperature();
   direcao = biruta(tensaoBiruta);                       //calcula a direção da biruta
   if (status != 0)
   velocidadeVento = velVento();                         //adquire a velocidade do vento
   {
  temperatura2 = temperaturaLM35Buffer();              //adquire temperatura do sensor LM35
    delay(status);
   temperatura3 = bmp.readTemperature();                 //adquire temperatura do sensor BMP180
   pressaoAbsoluta = (bmp.readPressure() / 100);        //adquire pressão absolutado sensor BMP180
  pressaoRelativa = (bmp.readSealevelPressure() / 100); //calcula pressão relativa
   altitudeCalculada = bmp.readAltitude();              //calcula altitude
  pontoOrvalho = dewPoint(temperatura1, umidade);       //calcula ponto de orvalho


    status = pressure.getTemperature(T);
  //Controle de temperatura interna para acionar ventilador
    if (status != 0)
  if(temperatura2 > 35.0)
     {
     digitalWrite(PINO_VENTILADOR, HIGH);
      Serial.print("Temperatura: ");
  else
      Serial.print(T,2);
    digitalWrite(PINO_VENTILADOR, LOW);
      Serial.println(" °C, ");
 
  //calcular e exibir tempo de execução
      status = pressure.startPressure(3);
  fim = millis();         //fim da cronometração da função
      if (status != 0)
  tempo = fim - inicio;   //cálculo do tempo de execução
      {
        delay(status);


        status = pressure.getPressure(P,T);
  if(tempo < espera){
        if (status != 0)
    delay(espera - tempo);               //cálculo do tempo de espera
        {
  }                                      //(não pode ser menor que 2s)
          Serial.print("Pressao Absoluta: ");
          Serial.print(P,2);
          Serial.println(" mbar: ");


          p0 = pressure.sealevel(P,ALTITUDE); // altitude em 180m - Foz do Iguaçu
//-----------------------------------------------------------
          Serial.print("Pressao Relativa(Nivel do Mar): ");
//Funções para mostrar dados:
          Serial.print(p0,2);
//- imprimeSerial: Imprime dados na serial -> Estação em modo StandAlone
          Serial.println(" mbar: ");
//- enviaXbee: Envia dados via Xbee para receptor remoto -> Estação em modo transmissão
//-----------------------------------------------------------


          a = pressure.altitude(P,p0);
// imprimeSerial ();
          Serial.print("Altitude Computada: ");
   enviaXbee ();
          Serial.print(a,0);
          Serial.println(" metros: ");
        }
        else Serial.println("erro na recuperacao da medida da pressao \n");
      }
      else Serial.println("erro na inicilizacao da medida da pressao\n");
    }
    else Serial.println("erro na recuperacao da medida da temperatura\n");
   }
  else Serial.println("erro na inicilizacao da medida da temperatura\n");
}


//repeticao que imprime as informacoes do programa ao usuario
//-----------------------------------------------------------
void loop()
{
        velVento = (contVento / BASETEMPO) * 2.4; 
        Tensao = analogRead(A0); //variavel tensao recebe valor digital do dispositivo de direcao de vento
        Serial.print("Chuva acumalada (mm):  ");
        Serial.println(mmChuv1000a);
        Serial.print("Velocidade do Vento (km/h):  ");
        Serial.println(velVento);
       
        biruta(Tensao);
        altitudeEPressao();


        contVento = 0;
Serial.println("");
        // PARA MODIFICAR O DELAY MODIFICAR A VARIAVEL "BASETEMPO"
        // NO CABECARIO DO PROGRAMA
        delay(BASETEMPO*1000); //Tempo entre as leituras em ms
}
}
       
</source>
</source>
--Jade Mathias 17h47min de 2 de dezembro de 2015 (BRST)
--[[Usuário:Evandro.cantu|Evandro.cantu]] ([[Usuário Discussão:Evandro.cantu|discussão]]) 08h58min de 12 de dezembro de 2017 (BRST)
-->
 
===Formato json para envio dos dados via serial===


===Formato CSV dos dados===
Os '''dados''' lidos pelos sensores da '''estação meteorológica''' serão concatenados em uma '''''string''''' em formato '''json''' e transmitidos de forma '''serial''' para o servidor que armazenará os dados, utilizando os módulos '''Xbee'''.


Os '''dados''' lidos pelos sensores da '''estação hidrometeorológica''' serão concatenados em uma '''''string''''' em formato '''CSV''' e transmitidos de forma '''serial''' para o servidor que armazenará os dados, utilizando os módulos '''Xbee'''.
O '''json''' (''JavaScript Object Notation'') <ref NAME=json>Formato Json https://pt.wikipedia.org/wiki/JSON</ref> é um formato de padrão aberto que utiliza texto legível a humanos para transmitir objetos de dados consistindo de '''pares atributo-valor''', bastante utilizados em '''''web services'''''.
 
Código jason utilizado na estação:
<source lang="JavaScript">
{ "a": temperatura1, "b": temperatura2,    "c": temperatura3,    "d": velocidadeVento,
  "e": direcao,      "f": pressaoAbsoluta, "g": pressaoRelativa, "h": umidade,
  "i": mmChuva,      "j": pontoOrvalho,   "k": "IFPR0001"
}
</source>
<!--
;Formato CSV proposto inicialmente:


  Id da estação; direçao do vento; chuva acumulada;
  Id da estação; direçao do vento; chuva acumulada;
Linha 935: Linha 838:
  1;NE;0.54;13.6;42.3;900
  1;NE;0.54;13.6;42.3;900


--Jade Mathias 17h59min de 9 de dezembro de 2015 (BRST)
--Jade Mathias 17h59min de 9 de dezembro de 2015 (BRST)-->
 
==Código para Arduíno que recebe dados via Xbee==
 
Código para recepção dos dados enviados pela '''Estação Meteorológica''' via comunicação '''Xbee''' e implementação de '''cliente Web''' para envio dos dados para armazenamento em '''banco de dados''' e '''servidor Web'''.
 
<source lang="c">
/*
      Estação Meteorológica com Microcontrolador Arduino
      2015-2016 - Instituto Federal do Paraná
      Versão: V2
      Programadores: Thiago Henrique Ribeiro (V2 2016)
                    Frederik Nazario Moschkowich
                    Matheus Marques Martines
      Orientador:    Evandro Cantú
*/
 
#include <SPI.h>
#include <Ethernet.h>
#include <stdlib.h>
 
String json;
 
byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };
IPAddress ip(192,168,40,99);        //Define o endereco IP
IPAddress subnet(255, 255, 252, 0); //Define a máscara de rede
IPAddress server(192,168,40,98);    //ip do webservice
//Inicializa biblioteca de cliente Ethernet
EthernetClient client;
 
String vetor;
char incomingByte;
 
void setup() {
  Serial.begin(9600);
  Serial1.begin(9600);
  Ethernet.begin(mac, ip);
  delay(1000);
  Serial.println("connecting...");
}
 
void loop() {
  if (Serial1.available() > 0) {
    Serial.println("Recebendo dados..>");
    incomingByte = Serial1.read();
    Serial.print(incomingByte);
 
    vetor += incomingByte;
  }
 
  if (incomingByte == '}') {
    incomingByte = ' ';
    client.stop();
    Ethernet.begin(mac, ip);
 
    json = vetor;
 
    vetor = "";
    Serial.println(json);
    //conecta ao WebService e envia os dados
    if (client.connect(server, 8080)) {
      Serial.println("connected");
      String request;
      request += "POST /WSEstacao/server/sensores HTTP/1.1\n";
      request += "Host: 192.168.40.98:8080\n";
      request += "Connection: close\n";
      request += "User-Agent: Arduino/1.0\n";
      request += "Content-Type: application/json\n";
      request += "Content-Length: ";
      request += String(request.length());
      request += "\n\n";
      request += json;
 
      client.println(request);
      client.stop();
    } else {
      Serial.println("connection failed");
    }
 
    if (client.available()) {
      char c = client.read();
      Serial.print(c);
    }
 
    // if the server's disconnected, stop the client:
    if (!client.connected()) {
      Serial.println();
      Serial.println("disconnecting.");
    }
  } else {
    //Serial.println("Problema de comunicacao");
  }
//  delay(5000);
}
 
</source>
 
===Detalhes do código===
 
Este código foi construído para '''Arduíno Leonardo''' com dois '''''shiels''''' adicionais:
*'''Shield Xbee''' <ref>Wireless shield Xbee https://store.arduino.cc/usa/arduino-wirelss-sd-shield</ref> para recepção dos dados remotos da '''Estação Meteorológica''';
*'''Shield Ethernet''' <ref NAME=Ethernet> Shield Ethernet https://www.arduino.cc/en/Tutorial/WebClient</ref> para conexão com a rede '''Internet''' e comunicação com o '''Web Service''' para armazenar dados no '''banco de dados'''.


==Material técnico de referência==
;Recepção de dados seriais via Xbee: A comunicação serial via Xbee utiliza a interface '''Serial1''' do '''Arduíno Leonardo''' e recebe os dados codificados em formato '''json'''. A interface '''Serial''', por sua vez,  é utilizada para impressão de informações no monitor serial da IDE do Arduíno visando acompanhamento da execução do programa.
===Materiais na Wiki===
;[[Arduíno]]:
*[[Sensores para Arduíno]]
*[[Comunicação e Shields para Arduíno]]


===Tutoriais no Site Oficial do Arduíno===
;Implementação de cliente Web para envio das informações a um Web Service: Através do shield '''Ethernet''' é implementado um '''cliente Web''' <ref NAME=Ethernet/> (endereço IP 192.168.40.99), o qual se conecta a um '''servidor Web''' (endereço IP 192.168.40.98) e envia informações dos dados meteorológicos utilizando o método '''POST''' do protocolo '''HTTP'''.
;Bibliotecas e exemplos: [https://www.arduino.cc/en/Tutorial/LibraryExamples Ethernet e Cartão SD]:
*[https://www.arduino.cc/en/Tutorial/BarometricPressureWebServer Pressão Barométrica Web Server]
*[https://www.arduino.cc/en/Tutorial/Datalogger Guardar dados de sensores no cartão SD]
*[https://www.arduino.cc/en/Tutorial/ReadWrite Ler e escrever dados em arquivos no cartão SD]
*[https://www.arduino.cc/en/Tutorial/Files Criar e remover arquivos no cartão SD]


==Referências==
==Referências==
Linha 955: Linha 950:
----
----


[[Categoria:Arduíno]] [[Categoria:LabMaker]]
[[Categoria:Arduíno]] [[Categoria:LabMaker]] [[Categoria:IoT]]

Edição atual tal como às 19h37min de 29 de outubro de 2021

Estação Meteorológica Automatizada com Arduíno

Objetivo

O objetivo deste projeto é construir uma estação hidrometeorológica automatizada no Campus Foz do Iguaçu, com o objetivo de dispor um banco de dados dinâmico de informações para uso em pesquisas e estudos sobre manejo da água, integrando as áreas de conhecimento de Informática, Eletrônica, Física, Hidrologia e Aquicultura.

Projeto da Estação Hidrometeorológica
Aprovado no programa PIBIC/CNPq, IFPR, 2016.

Equipe

Professores
2015
Estudos e testes preliminares
Alunos voluntários
  • Jade Mathias da Silva (CST Análise e Desenvolvimento de Sistemas)
  • José Antonio Kazienko Sallet (CST Análise e Desenvolvimento de Sistemas)
2016
Versão operacional incluindo sensores de campo, transmissão de dados via rede sem fio, banco de dados e Servidor Web.
Bolsistas PIBIC/IFPR:
  • Thiago Henrique Ribeiro (CST Análise e Desenvolvimento de Sistemas) (abr a jul)
  • Bruno Henrique Oliveira (CST Análise e Desenvolvimento de Sistemas) (ago a dez)
Alunos voluntários:
  • Matheus Santos (Licenciatura em Física)
  • Frederik Nazario Moschkowich (CST Análise e Desenvolvimento de Sistemas)
  • Matheus Marques Martinês (CST Análise e Desenvolvimento de Sistemas)
2017
Manutenção e aprimoramentos:
Alunos voluntários:
  • Pablo Souza dos Santos (Licenciatura em Física)

Produções

RIBEIRO, T. H. ; OLIVEIRA, B. H. ; SILVA, M. S. ; MOSCHKOWICH, F. N. ; MARTINES, M. M. ; SALLET, J. A. K. ; SILVA, J. M. ; BENACCHIO, A. ; BENEDUZZI, H. M. ; CANTÚ, E. . Estação hidrometeorológica automatizada com microcontrolador Arduíno. I Mostra de Inovação, Pesquisa, Ensino, Extensão e Cultura do IFPR, Foz do Iguaçu, 2016.

RIBEIRO, T. H. ; OLIVEIRA, B. H. ; SILVA, M. S. ; MARTINES, M. M. ; CANTÚ, E. . Estação hidrometeorológica automatizada com microcontrolador Arduíno. V Seminário de Extensão, Ensino, Pesquisa e Inovação do IFPR, Cascavel, 2016 (Poster SEPIN2016).

RIBEIRO, T. H. ; OLIVEIRA, B. H.; MARTINES, M. M. Estação hidrometeorológica. Projeto Integrador II, Curso Superior de Tecnologia em Análise e Desenvolvimento de Sistemas, IFPR, Foz do Iguaçu, 2016 (Documentação PI-II Estação Meteorológica).

Esposição Espaço Maker. PTI, Foz do Iguaçu, 2016.

Estudos sobre Meteorologia

Estudos sobre Hidrometeorologia
Responsável: Matheus Santos (Licenciatura em Física)

Sensores Meteorológicos Sparkfun

Conjunto de Sensores Meteorológicos Sparkfun [1] [2], contendo os seguintes elementos:

  • Sensor de Direção do Vento (Biruta)
  • Sensor de Volume de Chuva (Pluviômetro)
  • Sensor de Velocidade do Vento (Anemômetro)

Biruta

A Biruta ou sensor de direção do vento é fisicamente composto por oito chaves, ligadas a resistores variados. Quando o vento muda de direção um imã fecha um ou dois contatos, permitindo a medição de 16 resistências diferentes.

Na ligação em hardware, um resistor de 10 kΩ é utilizado como divisor de tensão, produzindo uma tensão de saída que pode ser medido por um conversor analógico-digital.

No Arduíno a tensão medida nas entradas analógicas (variando de 0V a 5V) é convertida internamente em um número digital de 10 bits (variando de 0 a 1023).

Para o sensor de direção do vento os 16 valores de resistência no divisor de tensão produzem as seguintes entradas no Arduino:

Direção (Graus) Resistencia (Ohms) Tensão (Entrada=5V Resistencia=10 KΩ) Binário (Saída porta Analógica) Saída Leitura em Binário de 10 bits (0 - 1023)
Mínimo Máximo
0 33k 3,84 786 744 805
22,5 6,57k 1,98 405 346 432
45 8,2k 2,25 460 433 529
67,5 891 0,41 84 75 87
90 1k 0,45 92 88 109
112,5 688 0,32 65 0 74
135 2,2k 0,9 184 156 213
157,5 1,41k 0,62 127 110 115
180 3,9k 1,4 286 265 345
202,5 3,14k 1,19 243 214 264
225 16k 3,08 630 615 665
247,5 14,12k 2,93 599 530 614
270 120k 4,62 945 886 961
292,5 42,12k 4,04 827 806 885
315 64,9k 4,78 978 962 1023
337,5 21,88k 3,43 702 666 743

--José Sallet 18h52min de 18 de novembro de 2015 (BRST)--

Rosa dos ventos
Códigos utilizados para apontar a direção do vento no Brasil.

Pluviômetro

O pluviômetro é um tipo de balde de auto esvaziamento. A cada 0.2794 mm de chuva causa um fechamento de contato momentâneo que pode ser gravado com um contador digital ou acionar uma interrupção de microcontrolador (Arduíno).

O interruptor do pluviômetro é conectado com dois condutores centrais anexados em um cabo RJ11.

--Jade Mathias 16h17min de 17 de novembro de 2015 (BRST)

Pluviômetro no Arduíno
A cada 0.2794 mm de chuva uma interrupção é gerada. A rotina de interrupção, portanto, apenas deverá soma 0.2794 a uma variável que guarda a chuva acumulada em mm.
O contador de chuva acumulada em mm foi construído com uma variável circular, de 0 a 999. Isto é, uma vez chegado a 999 mm a contagem da chuva acumulada volta a zero.
Interrupções no Arduíno
No Arduíno UNO as interrupções externas são acionadas pelo comando AttachInterrupt e são acionadas pelo pino 2 (interrupção 0) e/ou pino 3 (interrupção 1).
No Arduíno as interrupções externas podem ser acionadas de diferentes modos:
  • LOW: Quando o pino está baixo;
  • CHANGE: Quando o valor do pino muda;
  • RISING: Quando o valor do pino sobe de baixo para alto;
  • FALLING: Quando o valor do pino desce de alto para baixo;
  • HIGH: Quando o pino está alto.
A cada fechamento de contados ocasionado pelos sensores uma rotina de tratamento de interrupção será acionada.
Conforme ilustrado no tópico abaixo sobre o hardware para a chave do pluviômetro, será utilizado a borda de subida do pino (RISING) para acionar a interrupção e contar a chuva acumulada.

--Evandro.cantu (discussão) 22h16min de 17 de abril de 2016 (BRT)

Anemômetro

O anemômetro mede a velocidade do vento, fechando um contato com a ajuda de um ímã. Para uma velocidade do vento de 2.4 km/h o interruptor fecha uma vez por segundo.

O interruptor anemômetro está ligado a dois condutores internos do cabo RJ11 compartilhada pelo anemômetro e cata-vento (pinos 2 e 3).

--Jade Mathias 18h28min de 18 de novembro de 2015 (BRST)

Anemômetro no Arduíno

Medição por largura de pulsos
A largura dos pulsos gerados pelo anemômetro serão medidos pelo Arduíno através da função pulseln(). O tempo da largura de pulso retornado pela função pulseln() é medido em microsegundos, portando a velocidade do vento será determinada pela expressão:
velocidadeVento = 2,4 * 106 / larguraPulso 
Conforme o hardware do anemômetro mostrado abaixo, a largura dos pulsos do anemômetro será medida durante o tempo que estiver em nível lógico baixo (LOW), entre dois fechamentos de contato.
Medição por interrupção
Para um vento com velocidade de 2,4 km/h o fechamento da chave ocorre uma vez por segundo (1 Hz).
Uma rotina de interrupção no Arduíno necessita apenas implementar um contador de pulsos. No programa principal, para uma dada base de tempo a velocidade é determinada pela expressão:
Vel = ( contadorPulsos / baseTempo ) * 2,4
Exemplo:
  • Base de tempo = 10s
  • Contador de pulsos = 10
Vel = (10 / 10 ) * 2,4 = 2,4 km/h

Obs: A medição por interrupção se mostrou mais estável e é a forma implementada na última versão do programa.

--Evandro.cantu (discussão) 22h16min de 17 de abril de 2016 (BRT)

Hardware para chaves do pluviômetro e anemômetro

Circuito para conectar as chaves do pluviômetro e anemômetro nas entradas de Interrupção do Arduíno:

Conexão dos Sensores Meteorológicos Sparkfun ao Arduíno

Os Sensores Meteorológicos Sparkfun são conectados ao Arduíno segundo os seguintes diagramas e códigos de cores para os fios provenientes dos sensores:

Sensores de Temperatura e Humidade

Sensor de temperatura (LM35)

Funcionamento do sensor LM35
O LM35 é um circuito integrado exclusivo para medir temperatura com uma tensão de saída variando linearmente com a temperatura em graus Célsius.
Na configuração básica este sensor mede temperaturas entre 2oC e 150oC, variando a saída em função da temperatura de 0 mV + 10mV por 1oC.
Esquema de ligação com Arduíno
            _______
           |       |
           | LM 35 | 
           |_______|
             | | |
   (+5v) ----+ | +---- (Ground)
               |
          Analog Pin 
       0mV + 10mV / oC
Leitura pela entrada analógica do Arduíno
O valor de tensão (entre 0V e 5V) lido pelo Arduíno na entrada analógica é convertido um número digital com 10 bits de magnitude, ou seja, 210 (1024) valores (entre 0 e 1023).
Para obter o valor de tensão, para uso no cálculo da temperatura, multiplica-se o valor digital obtido na leitura por 5/1023.
Como a tensão medida pelo sensor varia de 0 mV + 10mV/1oC, se multiplicarmos por 100, teremos o valor em graus Celsius:
Programa Exemplo
 //Sensor de temperatura LM35
 float valorSensor;
 float temperatura;
 void setup() {
 Serial.begin(9600);
 }
 void loop() {
   valorSensor = analogRead(A0) * 5.0 / 1023.0;
   temperatura = valorSensor * 100.0;
   Serial.print("Temperatura: ");
   Serial.println(temperatura);
   delay(2000); //Tempo entre as leituras em ms
 }

O sensor de temperatura LM35 será utilizado para medir a tempetarura interna do módulo de campo da Estação Meteorolótica.

Sensor de Temperatura e Humidade DHT11

O DHT11 é um sensor de temperatura e humidade. Este sensor inclui um medidor de humidade resistivo e um sensor de temperatura tipo NTC conectado a um microcontrolador de 8 bits [3].

O DHT11 possui uma biblioteca com funções prontas para seu funcionamento [4]. Para uso, baixe a biblioteca DHT11.zip e insira no ambiente da IDE do Arduíno:

Sketch -> Import Library -> Add Library
Esquema de ligação com Arduíno
            _______
           |       |
           | DHT11 | 
           |_______|
             | | |
(Ground) ----+ | +---- (+5v)
               |
          Analog Pin 1
Programa exemplo
 //Sensor de temperatura LDHT11
 #include <dht11.h>
 dht11 sensor; //Inicializa sensor
 void setup() {
   Serial.begin(9600);
   delay(1000);
 }
 void loop() {
   sensor.read(A1);
   Serial.print("Temperatura (oC): ");
   Serial.println(sensor.temperature);
   Serial.print("Unidade (%): ");
   Serial.println(sensor.humidity);
   delay(2000); //Tempo entre as leituras em ms
 }

O sensor de temperatura e humidade DHT11 será utilizado para medir a tempetarura externa e a humidade relativa do ar no módulo de campo da Estação Meteorolótica.

Sensor de Pressão Barométrica BMP180

O Sensor de Pressão Barométrica BMP180 [5] mede a pressão absoluta do ar ao seu redor. A pressão do ar varia com as condições do tempo e também com a altitude. Portanto, dependendo de como os dados medidos forem interpretados, pode-se tanto aferir mudanças nas condições do tempo como na altitude.

Interface I2C
O BMP180 utiliza uma interface I2C para se comunicar com o microcontrolador do Arduíno. A interface I2C é padronizada para conectar dispositivos periféricos de baixa velocidade a uma placa mãe ou sistema embarcado e usa duas linhas para comunicação: Dados Seriais (Serial Data - SDA) e Clock Serial (Serial Clock - SCL). O clock é gerado pelo mestre e a linha de dados seriais é bidirecional.
Conexões com o hardware do sensor
O sensor BMP180 possui 4 pinos para conexão com o Arduíno:
  • + (Vcc): 5 V;
  • - (GND): Terra;
  • SDA (SDA) (I2C data): Conectar ao pino A4 UNO
  • SCL (SCL) (I2C clock): Conectar ao pino A5 UNO
Instalação da biblioteca para o BMP180
Este sensor possui uma biblioteca e exemplo que facilitam a comunicação com o sensor e o desenvolvimento de programas. Para uso com o Arduíno, baixar a biblioteca Adafruit_BMP085.h e instalar na IDE do Arduíno com os comandos:
Scketch -> Import Library -> Add library
Exemplos
Há um exemplo incluído junto com a biblioteca, que pode ser utilizado para testar o sensor BMP180 e também serem utilizados como referência para a construções de novos programas.
Modificado em função da troca de sensor
--Evandro.cantu (discussão) 19h49min de 27 de novembro de 2017 (BRST)

Medição de tempo e altitude

O BMP180 é um sensor de pressão barométrica e pode ser usado tanto aferir mudanças nas condições do tempo como na altitude [1].

Pressão atmosférica

A pressão é medida pela força por unidade de área. No Sistema Internacional é medida por newton por metro quadrado, ou pascal (Pa).

A pressão atmosférica é dada pela força exercida pelo ar que forma a atmosfera sobre a superfície da terra. Uma coluna de ar de um centímetro quadrado, ao nível do mar, pesa aproximadamente um quilograma, ou 101325 pascals. Em uma altitude de 3810 m, a pressão atmosférica é a metade da pressão ao nível do mar.

O BMP180 mede a pressão absoluta em pascal (Pa). Entretanto, um pascal é uma unidade muito pequena, sendo normalmente a pressão dada em hectopascals (1 hPa = 100 Pa). Outras unidades utilizadas para medir a pressão atmosférica são o bar e o atm:

  • 1 mbar = 1 hPa
Pressão atmosférica ao nível do mar
1 atm
  • 1 atm = 101 325 Pa = 1013,25 hPa = 1013,25 mbar = 1,01325 bar

Efeito da temperatura

A temperatura afeta a densidade de um gaz, a densidade de um gaz afeta a massa do gaz, e a massa do gaz afeta a pressão, portanto, a pressão atmosférica é bastante influenciada pela variação da temperatura.

Observações do tempo

A pressão atmosférica em um dado ponto da terra não é constante. Há uma interação complexa entre o movimento de rotação da terra, a inclinação do eixo da terra, e muitos outros fatores relacionados ao movimento das áreas de alta e baixa pressão. Todavia, observando a variação de pressão em um dado ponto é possível fazer previsões de curto prazo sobre o tempo. Por exemplo, quedas de pressão normalmente indicam mau tempo (chuva) ou tormenta se aproximando. Subida de pressão normalmente indica que o tempo bom (seco) está chegando.

Efeito da altitude

A pressão atmosférica também varia com a altitude. A pressão medida em um dado local é a pressão absoluta. Para comparar a pressão em dois lugares com altitude diferente, deve-se descontar os efeitos da altitude, gerando o que se chama pressão relativa.

Na biblioteca do BP180 a função seaLevel(P,A) utiliza como parâmetros a pressão absoluta (P) em hPa, e a altitude corrente (A) em metros, para devolver a pressão relativa. A partir da pressão relativa é possível comparar as pressões atmosféricas em diferentes pontos da terra.

Determinando a altitude

Uma vez que a pressão atmosférica varia com a altitude, é possível utilizar o medidor de pressão atmosférica para aferir a altitude de um local.

A pressão atmosférica média ao nível do mar é 1013.25 hPa e cai a zero no vácuo do espaço.

A variação da altitude entre duas medidas de pressão (p e p0) é dada pela fórmula:

Formas de utilizar esta equação:

  1. Se utilizarmos p0 como a pressão atmosférica ao nível do mar (1013.25 hPa), teremos a altitude acima do nível do mar do local;
  2. Se utilizarmos p0 como a pressão atmosférica do um local com altitude conhecida, teremos a altitude relativa, podendo ser positiva ou negativa, dependendo se subirmos ou descermos em relação a altitude conhecida.

Na biblioteca do BP180 a função altitude(P,P0) está pronta para realizar medições de altitude.


Tradução e adaptação
--Evandro.cantu (discussão) 10h33min de 23 de agosto de 2015 (BRT)

Conexão dos Sensores DHT11 e BMP180 ao Arduíno

Sensores DHT11 e BMP180
Os sensores de Temperatura e Unidade do Ar (DHT11) e Pressão Atmosférica (BMP180) são conectados ao Arduíno através de um flat cable de 10 vias:

Os sensores são conectados da seguinte forma:


Código de cores utilizados nos fios de conexão com o Arduíno:

  • GND - Preto (pinos 2 e 9)
  • 5V - (Vermelho) (pino 4 e 10)
  • Data - (Amarelo) (pino 3) -> A2
  • DA - (Azul) (pino 7) -> A4
  • CL - (Verde) (pino 8) -> A5
Modificado em função da troca de sensor
--Evandro.cantu (discussão) 19h53min de 27 de novembro de 2017 (BRST)

Código para Arduíno que controla a Estação Meteorológica

Código para leitura dos sensores de campo, com resultados podendo ser apresentados no monitor serial da IDE do Arduíno, ou enviados via comunicação sem fio Xbee para armazenamento em banco de dados e servidor Web..

/*
      Estação Meteorológica com Microcontrolador Arduino
      2015-2016 - Instituto Federal do Paraná
      Versão: V2
      Programadores: José Sallet (V1 2015)
                     Thiago Henrique Ribeiro (V2 2016)
                     Evandro Cantú (V3 2017)
      Orientador:    Evandro Cantú

      Mudanças em 2016:
      Abr4/2016 - Inclusão da função de leitura de vento por pulseIn()
                - Carregar strings literais da memória flash -> Serial.println(F("String literal));
                - Inclusão dos sensores LM35 (temperatura) e DHT11 (temperatura, umidade)
                - Testes com anemômetro e biruta com soprador de ar
                 
      Mudanças em 2017:
      Nov/2017: - Troca do sensor de Pressão Atmosférica
                - Inclusão de ventilador para resfrigeração
*/

#include<string.h>

//incluindo biblioteca do sensor de temperatura e pressao DHT11
#include <dht11.h>

//incluindo biblioteca do sensor de pressão
#include <Adafruit_BMP085.h>

//biblioteca do protocolo I2C
#include <Wire.h>       // biblioteca de comunicação I2C - necessária para o sensor barométrico BMP180
 
#define ALTITUDE  180.0 // Altitude de Foz do Iguaçu, Parana, Brasil
#define BASETEMPO 10    // define o tempo de repeticao

Adafruit_BMP085 bmp;          //inicializando sensor de temperatura e pressão
dht11 sensorUmidade;          //inicializando sensor DHT11

const int PINO_VENTILADOR = 13;   //pino digital   13 - Acionamento do ventilador interno
const int PINO_BIRUTA     = A0;   //pino analógico A0 - Leitura da tensão da biruta
const int PINO_LM35       = A1;   //pino analógico A1 - Leitura do sensor LM35 (temperatura)
const int PINO_DHT11      = A2;   //pino analógico A2 - Leitura do sensor DHT11 (temperatura + umidade)
                                  //pino analógico A3 livre
                                  //pino analógico A4 usado no BMP180 (temperatura + pressão)
                                  //pino analógico A5 usado no BMP180 (temperatura + pressão)

const int BUFFER_SIZE = 100;     //quantidade de leituras do sensor LM35 para fazer a média
                                 //para reduzir a margem de erro
const float CONVERSAO_GRAUS_CELSIUS = 0.488758553;  //constante para calcular a temperatura do sensor LM35

//Váriáveis para dados da Estação Meteorológica
float  mmChuva = 0;         //chuva acumulada
int    contVento = 0;       //contador de pulsos de vento
double altitude_local;      //altitude do local
float  temperatura1;        //temperatura do sensor DHT11
float  umidade;             //umidade do sensor DHT11
int    tensaoBiruta;        //valor da tensão na biruta
String direcao;             //direção da biruta
float  velocidadeVento;     //velocidade do vento
float  temperatura2;        //temperatura do sensor LM35 interno da estação
double temperatura3;        //temperatura do sensor BMP180
double pressaoAbsoluta;     //pressão absolutado sensor BMP180
double pressaoRelativa;     //calculo pressão relativa
double altitudeCalculada;   //calculo da altitude
double pontoOrvalho;        //calculo do ponto de orvalho

//Váriáveis para base de tempo para contagem de interrupções do anemômetro
float tempoAnterior = 0;
float tempoAtual;
float baseTempo = 0;

//Váriáveis para medida do tempo total de execução do programa
unsigned long inicio; 
unsigned long fim;
unsigned long tempo;

//-----------------------------------------------------------
//  ROTINA DE INTERRUPÇÃO 1 - PLUVIÔMETRO
//-----------------------------------------------------------

void choveu() {
  mmChuva = mmChuva + 0.2794;
  if (mmChuva > 1000) 
    mmChuva = mmChuva - 1000;
}

//-----------------------------------------------------------
//  ROTINA DE INTERRUPÇÃO 0 - ANEMÔMETRO
//-----------------------------------------------------------

void vento(){
   contVento++;
}

//-----------------------------------------------------------
//  ANEMÔMETRO
//-----------------------------------------------------------

float velVento(){
          tempoAtual = millis();
          baseTempo = tempoAtual - tempoAnterior;
          float _velVento = (contVento / (baseTempo/1000)) * 2.4;
          tempoAnterior = tempoAtual;
          contVento = 0;    
     return _velVento;
  }

//-----------------------------------------------------------
//  BIRUTA (Sparkfun)
//-----------------------------------------------------------

String biruta(int Tensao)
{
  String direcao;
  if (Tensao >= 744 && Tensao <= 805) {
    direcao = "Norte";
  }
  else if (Tensao >= 346 && Tensao <= 432) {
    direcao = "Norte-Nordeste";
  }
  else if (Tensao >= 433 && Tensao <= 529) {
    direcao = "Nordeste";
  }
  else if (Tensao >= 75 && Tensao <= 87) {
    direcao = "Leste-Nordeste";
  }
  else if (Tensao >= 88 && Tensao <= 109) {
    direcao = "Leste";
  }
  else if (Tensao >= 0 && Tensao <= 74) {
    direcao = "Leste-Sudeste";
  }
  else if (Tensao >= 156 && Tensao <= 213) {
    direcao = "Sudeste";
  }
  else if (Tensao >= 110 && Tensao <= 155) {
    direcao = "Sul-Sudeste";
  }
  else if (Tensao >= 265 && Tensao <= 345) {
    direcao = "Sul";
  }
  else if (Tensao >= 214 && Tensao <= 264) {
    direcao = "Sul-Sudoeste";
  }
  else if (Tensao >= 615 && Tensao <= 665) {
    direcao = "Sudoeste";
  }
  else if (Tensao >= 530 && Tensao <= 614) {
    direcao = "Oeste-Sudoeste";
  }
  else if (Tensao >= 886 && Tensao <= 961) {
    direcao = "Oeste";
  }
  else if (Tensao >= 806 && Tensao <= 885) {
    direcao = "Oeste-Noroeste";
  }
  else if (Tensao >= 962 && Tensao <= 1023) {
    direcao = "Noroete";
  }
  else if (Tensao >= 666 && Tensao <= 743) {
    direcao = "Norte-Noroeste";
  }
  else{
    Serial.println(F("[ERRO] Leitura na biruta fora da faixa!"));
    direcao = "Erro de leitura da Biruta";
  }  
  return direcao;
}

//-----------------------------------------------------------
//  SENSOR DE TEMPERATURA LM35
//-----------------------------------------------------------

//ler temperatura do sensor LM35 uma única vez
float temperaturaLM35() {
  return analogRead(PINO_LM35) * CONVERSAO_GRAUS_CELSIUS;
}

//ler temperatura do sensor LM35 (BUFFER_SIZE) vezes e calcular a média para obter uma medição mais precisa
//aumentar o valor de BUFFER_SIZE aumenta a precisão mas aumenta a carga do sistema
float temperaturaLM35Buffer() {
  float buffer = 0;
  for (int i = 0; i < BUFFER_SIZE ; i++) 
    buffer += analogRead(PINO_LM35);
  return (buffer / BUFFER_SIZE) * CONVERSAO_GRAUS_CELSIUS;
}

//-----------------------------------------------------------
//  CÁLCULO DE PONTO DE ORVALHO
//  Funções de ponto de orvalho obtidas em http://playground.arduino.cc/Main/DHT11Lib
//  A fazer: Verificar e referenciar o código apropriadamente
//  O código abaixo foi copiado e usado sem alterações
//-----------------------------------------------------------

// dewPoint function NOAA
// reference (1) : http://wahiduddin.net/calc/density_algorithms.htm
// reference (2) : http://www.colorado.edu/geography/weather_station/Geog_site/about.htm

double dewPoint(double celsius, double humidity)
{
  // (1) Saturation Vapor Pressure = ESGG(T)
  double RATIO = 373.15 / (273.15 + celsius);
  double RHS = -7.90298 * (RATIO - 1);
  RHS += 5.02808 * log10(RATIO);
  RHS += -1.3816e-7 * (pow(10, (11.344 * (1 - 1 / RATIO ))) - 1) ;
  RHS += 8.1328e-3 * (pow(10, (-3.49149 * (RATIO - 1))) - 1) ;
  RHS += log10(1013.246);

  // factor -3 is to adjust units - Vapor Pressure SVP * humidity
  double VP = pow(10, RHS - 3) * humidity;

  // (2) DEWPOINT = F(Vapor Pressure)
  double T = log(VP / 0.61078); // temp var
  return (241.88 * T) / (17.558 - T);
}

// delta max = 0.6544 wrt dewPoint()
// 6.9 x faster than dewPoint()
// reference: http://en.wikipedia.org/wiki/Dew_point
double dewPointFast(double celsius, double humidity)
{
  double a = 17.271;
  double b = 237.7;
  double temp = (a * celsius) / (b + celsius) + log(humidity * 0.01);
  double Td = (b * temp) / (a - temp);
  return Td;
}

//    **Fim das funções de orvalho copiadas**

//-----------------------------------------------------------
//  TELEMETRIA - MEMÓRIA LIVRE NO SISTEMA
//-----------------------------------------------------------

int freeRam () {
  extern int __heap_start, *__brkval;
  int v;
  return (int) &v - (__brkval == 0 ? (int) &__heap_start : (int) __brkval);
}

//-----------------------------------------------------------
//  Função para imprimir na serial: Estação em modo StandAlone
//-----------------------------------------------------------

void imprimeSerial () {
  //  exibir dados na tela ou terminal serial

  Serial.println(F("================================================"));
  
  Serial.print(F("Temperatura [DHT11]:\t\t\t"));
  Serial.print(temperatura1);
  Serial.println(F(" graus Celsius"));

  Serial.print(F("Temperatura Interna [LM35]:\t\t"));
  Serial.print(temperatura2);
  Serial.println(F(" graus Celsius"));

  Serial.print(F("Temperatura [BMP180]:\t\t\t"));
  Serial.print(temperatura3);
  Serial.println(F(" graus Celsius"));

  Serial.print(F("Velocidade do vento:\t\t\t"));
  Serial.print(velocidadeVento);
  Serial.println(F(" km/h"));

  Serial.print(F("Direcao do vento:\t\t\t"));
  Serial.print(direcao);
  Serial.println(F(""));
  
  Serial.print(F("Pressao absoluta (local):\t\t"));
  Serial.print(pressaoAbsoluta);
  Serial.println(F(" milibar"));
  
  Serial.print(F("Pressao relativa (nivel do mar):\t"));
  Serial.print(pressaoRelativa);
  Serial.println(F(" milibar"));
  
  Serial.print(F("Altitude:\t\t\t\t"));
  Serial.print(altitudeCalculada);
  Serial.println(F(" metros"));
  
  Serial.print(F("Chuva acumulada:\t\t\t"));
  Serial.print(mmChuva);
  Serial.println(F(" mm"));

  Serial.print(F("Umidade relativa do ar:\t\t\t"));
  Serial.print(umidade);
  Serial.println(F("%"));
  
  Serial.print(F("Ponto de orvalho:\t\t\t"));
  Serial.print(pontoOrvalho);
  Serial.println(F(" graus Celsius"));
  
  //exibir tempo de execução
  Serial.print(F("\nTempo de execucao total:\t\t"));
  Serial.print(tempo);
  Serial.println(F("ms\n"));

  // exibir memória livre pra determinar estabilidade
  Serial.print(F("Memoria Livre:\t\t\t\t"));
  Serial.print(freeRam());
  Serial.println(F(" bytes\n"));
  
}

//-----------------------------------------------------------
//  Função para enviar PAYLOAD com dados via Xbee
//-----------------------------------------------------------

void enviaXbee () {
  //  Montar dados em formato Jason
      
  String payload = "{";
  payload += "\"a\":";
  payload += temperatura1;

  payload +=", \"b\":";
  payload += temperatura2;
  
  payload +=", \"c\":";
  payload += temperatura3;

  payload +=", \"d\":";
  payload += velocidadeVento;

  payload +=", \"e\":\"";
  payload += direcao;
  
  payload +="\", \"f\":";
  payload += pressaoAbsoluta;
  
  payload +=", \"g\":";
  payload += pressaoRelativa;
  
  payload +=", \"h\":";
  payload += umidade;
  
  payload +=", \"i\":";
  payload += mmChuva;
  
  payload +=", \"j\":";
  payload += pontoOrvalho;

  payload +=", \"k\":";
  payload += "\"IFPR0001\"";
  
//  payload += (fim/1000);
  payload +="}";

  Serial.print(payload);     
}

//-----------------------------------------------------------
//  SETUP (Preparação)
//-----------------------------------------------------------

void setup()
{
  pinMode(PINO_VENTILADOR, OUTPUT); //Saída digital para acionamento do ventilador
  Serial.begin(9600);  //define a taxa de transmissão da serial

  attachInterrupt(0, vento,  RISING); // interrupcao do anemometro
  attachInterrupt(1, choveu, RISING); // interrupcao do pluviometro

  //Inicialização do sensor de pressão BMP180
  if (!bmp.begin()) {
    Serial.println(F("[FAIL]\n\nA estação não pode ser inicializada. Verifique o sensor barométrico e reinicie o aparelho."));
    while (1) {}
  }
}

//-----------------------------------------------------------
//  PROGRAMA PRINCIPAL
//-----------------------------------------------------------

//repeticao que imprime as informacoes do programa ao usuario
//TODO: organizar a ordem de execução levando em consideração o tempo tolerado por cada sensor
void loop()
{
  /* 
   *  Ações do programa:
   *  1.  Obter leitura do sensor de umidade (só pode ser lido a cada 2 segundos, são dois valores inteiros)
   *  2.  Obter leituras de tensão da biruta
   *  3.  Obter leituras do anemômetro
   *  4.  Obter leituras de temperatura do sensor LM35
   *  5.  Obter leituras de temperatura e pressão do sensor BMP180
  */
  
  int espera = 5000;
  inicio = millis(); // millis() e micros() - medem o tempo corrido em milisegundos e microsegundos
  
  sensorUmidade.read(PINO_DHT11);
  altitude_local = (double)ALTITUDE;                    //adquire a altitude do local
  temperatura1 = (float) sensorUmidade.temperature;     //adquire temperatura do sensor DHT11
  umidade = (float) sensorUmidade.humidity;             //adquire umidade do sensor DHT11
  tensaoBiruta = analogRead(PINO_BIRUTA);               //adquire o valor da tensão na biruta
  direcao = biruta(tensaoBiruta);                       //calcula a direção da biruta
  velocidadeVento = velVento();                         //adquire a velocidade do vento
  temperatura2 = temperaturaLM35Buffer();               //adquire temperatura do sensor LM35
  temperatura3 = bmp.readTemperature();                 //adquire temperatura do sensor BMP180
  pressaoAbsoluta = (bmp.readPressure() / 100);         //adquire pressão absolutado sensor BMP180
  pressaoRelativa = (bmp.readSealevelPressure() / 100); //calcula pressão relativa
  altitudeCalculada = bmp.readAltitude();               //calcula altitude
  pontoOrvalho = dewPoint(temperatura1, umidade);       //calcula ponto de orvalho

  //Controle de temperatura interna para acionar ventilador
  if(temperatura2 > 35.0)
    digitalWrite(PINO_VENTILADOR, HIGH);
  else
    digitalWrite(PINO_VENTILADOR, LOW);
  
  //calcular e exibir tempo de execução
  fim = millis();          //fim da cronometração da função
  tempo = fim - inicio;    //cálculo do tempo de execução

  if(tempo < espera){
    delay(espera - tempo);               //cálculo do tempo de espera
  }                                      //(não pode ser menor que 2s)

//-----------------------------------------------------------
//Funções para mostrar dados:
//- imprimeSerial: Imprime dados na serial -> Estação em modo StandAlone
//- enviaXbee: Envia dados via Xbee para receptor remoto -> Estação em modo transmissão
//-----------------------------------------------------------

//  imprimeSerial ();
  enviaXbee ();

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

}

--Evandro.cantu (discussão) 08h58min de 12 de dezembro de 2017 (BRST)

Formato json para envio dos dados via serial

Os dados lidos pelos sensores da estação meteorológica serão concatenados em uma string em formato json e transmitidos de forma serial para o servidor que armazenará os dados, utilizando os módulos Xbee.

O json (JavaScript Object Notation) [6] é um formato de padrão aberto que utiliza texto legível a humanos para transmitir objetos de dados consistindo de pares atributo-valor, bastante utilizados em web services.

Código jason utilizado na estação:

{ "a": temperatura1, "b": temperatura2,    "c": temperatura3,    "d": velocidadeVento,
  "e": direcao,      "f": pressaoAbsoluta, "g": pressaoRelativa, "h": umidade,
  "i": mmChuva,      "j": pontoOrvalho,    "k": "IFPR0001"
}

Código para Arduíno que recebe dados via Xbee

Código para recepção dos dados enviados pela Estação Meteorológica via comunicação Xbee e implementação de cliente Web para envio dos dados para armazenamento em banco de dados e servidor Web.

/*
      Estação Meteorológica com Microcontrolador Arduino
      2015-2016 - Instituto Federal do Paraná
      Versão: V2
      Programadores: Thiago Henrique Ribeiro (V2 2016)
                     Frederik Nazario Moschkowich 
                     Matheus Marques Martines
      Orientador:    Evandro Cantú
*/

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

String json;

byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };
IPAddress ip(192,168,40,99);        //Define o endereco IP
IPAddress subnet(255, 255, 252, 0); //Define a máscara de rede
IPAddress server(192,168,40,98);    //ip do webservice
//Inicializa biblioteca de cliente Ethernet
EthernetClient client;

String vetor;
char incomingByte;

void setup() {
  Serial.begin(9600);
  Serial1.begin(9600);
  Ethernet.begin(mac, ip);
  delay(1000);
  Serial.println("connecting...");
}

void loop() {
  if (Serial1.available() > 0) {
    Serial.println("Recebendo dados..>");
    incomingByte = Serial1.read();
    Serial.print(incomingByte);

    vetor += incomingByte;
  }

  if (incomingByte == '}') {
    incomingByte = ' ';
    client.stop();
    Ethernet.begin(mac, ip);

    json = vetor;

    vetor = "";
    Serial.println(json);
    //conecta ao WebService e envia os dados 
    if (client.connect(server, 8080)) {
      Serial.println("connected");
      String request;
      request += "POST /WSEstacao/server/sensores HTTP/1.1\n";
      request += "Host: 192.168.40.98:8080\n";
      request += "Connection: close\n";
      request += "User-Agent: Arduino/1.0\n";
      request += "Content-Type: application/json\n";
      request += "Content-Length: ";
      request += String(request.length());
      request += "\n\n";
      request += json;

      client.println(request);
      client.stop();
    } else {
      Serial.println("connection failed");
    }

    if (client.available()) {
      char c = client.read();
      Serial.print(c);
    }

    // if the server's disconnected, stop the client:
    if (!client.connected()) {
      Serial.println();
      Serial.println("disconnecting.");
    }
  } else {
    //Serial.println("Problema de comunicacao");
  }
//  delay(5000);
}

Detalhes do código

Este código foi construído para Arduíno Leonardo com dois shiels adicionais:

  • Shield Xbee [7] para recepção dos dados remotos da Estação Meteorológica;
  • Shield Ethernet [8] para conexão com a rede Internet e comunicação com o Web Service para armazenar dados no banco de dados.
Recepção de dados seriais via Xbee
A comunicação serial via Xbee utiliza a interface Serial1 do Arduíno Leonardo e recebe os dados codificados em formato json. A interface Serial, por sua vez, é utilizada para impressão de informações no monitor serial da IDE do Arduíno visando acompanhamento da execução do programa.
Implementação de cliente Web para envio das informações a um Web Service
Através do shield Ethernet é implementado um cliente Web [8] (endereço IP 192.168.40.99), o qual se conecta a um servidor Web (endereço IP 192.168.40.98) e envia informações dos dados meteorológicos utilizando o método POST do protocolo HTTP.

Referências