Estacao Meteorologica
Estação hidrometeorológica automatizada com microcontrolador 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
- Professor orientador
- Bolsistas PIBIC/IFPR
- Thiago Henrique Ribeiro (CST Análise e Desenvolvimento de Sistemas - 5o Semestre) (abr a jul)
- Bruno Henrique Oliveira (CST Análise e Desenvolvimento de Sistemas - 5o Semestre) (ago a dez)
- Alunos voluntários
- Matheus Santos (Licenciatura em Física - 5o Semestre)
- Frederik Nazario Moschkowich (CST Análise e Desenvolvimento de Sistemas - 5o Semestre)
- Matheus Marques Martinês (CST Análise e Desenvolvimento de Sistemas - 5o Semestre)
Estudos sobre Hidrometeorologia
- 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 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.
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=10ohms) | 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
- 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.
- Anemômetro
- 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:
Vel = ( contadorPulsos / baseTempo ) * 2,4
- Exemplo:
- Base de tempo = 10s
- Contador de pulsos = 10
- Exemplo:
Vel = (10 / 10 ) * 2,4 = 2,4 km/h
--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:
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
}
Sensor de Pressão Barométrica BMP180
O Sensor de Pressão Barométrica BMP180 [5] é 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 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:
- + (VDD): 3,3 V (Não alimentar com 5 V sob risco de danificar o compomente);
- - (GND): Terra;
- DA (SDA) (I2C data): Conectar ao pino A4 UNO
- CL (SCL) (I2C clock): Conectar ao pino A5 UNO
- IO: Não usado com Arduíno (serve para microcontroladores que operam em baixa voltagem)
- Para Arduíno Leonardo ou Mega, verificar o pino de conexão no tutorial Sparkfun BMP180.
- Instalação da biblioteca para o BMP180
- O sensor BMP180 possui uma biblioteca e exemplos que facilitam a comunicação com o sensor e o desenvolvimento de programas. Para uso com o Arduíno, baixar a biblioteca SFE_BMP180 e instalar na IDE do Arduíno com os comandos:
Scketch -> Import Library -> Add library
- 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 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
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:
- 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;
- 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 8)
- 5V - (Vermelho) (pino 4)
- 3,3V - (Laranja) (pino 6)
- Data - (Amarelo) (pino 3) -> A2
- DA - (Azul) (pino 10) -> A4
- CL - (Verde) (pino 9) -> A5
--Evandro.cantu (discussão) 10h35min de 25 de outubro de 2016 (BRST)
Código para Arduíno
/*
Estação Meteorológica com Microcontrolador Arduino
2015-2016 - Instituto Federal do Paraná
Programadores: José Sallet
Thiago Henrique Ribeiro
Orientador: Evandro Cantú
Mudanças em 2016:
12/04/2016 - Inclusão da função de leitura de vento por pulseIn()
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)
- Testes com anemômetro e biruta com soprador de ar
*/
//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>
//incluindo biblioteca do sensor de temperatura e pressao DHT11
#include <dht11.h>
//incluindo biblioteca do sensor de pressão
#include <SFE_BMP180.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
SFE_BMP180 sensorPressao; //inicializando sensor de temperatura e pressão
dht11 sensorUmidade; //inicializando sensor DHT11
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 = 1000; //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
//int Tensao; //tensão de leitura da biruta - comentado para invocar em loop()
float mmChuva = 0; //pluviômetro - Isto deveria ser gravado em EEPROM
//int contVento = 0; //contador de pulsos de vento - substituído por pulseIn
//float velVento; //velocidade do vento - comentado para invocar em loop
//--------------------------------------------------------------------------------------------------------------
// ROTINA DE INTERRUPÇÃO 0 - ANEMÔMETRO (obsoleta)
//--------------------------------------------------------------------------------------------------------------
//void vento(){
// contVento++;
// }
//--------------------------------------------------------------------------------------------------------------
// ROTINA DE INTERRUPÇÃO 1 - PLUVIÔMETRO
//--------------------------------------------------------------------------------------------------------------
void choveu() {
mmChuva = mmChuva + 0.2794;
if (mmChuva > 1000)
{
mmChuva = mmChuva - 1000;
}
}
//--------------------------------------------------------------------------------------------------------------
// ANEMÔMETRO (versão nova sem interrupção)
//--------------------------------------------------------------------------------------------------------------
float velVento(){
//Medição de largura do pulso em microsegundos
unsigned long larguraPulso = pulseIn(2, LOW, 2400000); //um pulso de 2400000 ms equivale a um vento de 1km/h
float _velVento = 0;
//calcular Velocidade de acordo com a largura do pulso; Largura de pulso mínima a ser calculada
if (larguraPulso <= 5000) {
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)
//--------------------------------------------------------------------------------------------------------------
String biruta(int Tensao)
{
String direcao;
if (Tensao >= 744 && Tensao <= 805) {
//Serial.println(F("Direcao do Vento: Leste"));
direcao = "L";
}
else if (Tensao >= 346 && Tensao <= 432) {
//Serial.println(F("Direcao do Vento: Leste-Norderste"));
direcao = "LNE";
}
else if (Tensao >= 433 && Tensao <= 529) {
//Serial.println(F("Direcao do Vento: Nordeste"));
direcao = "NE";
}
else if (Tensao >= 75 && Tensao <= 87) {
//Serial.println(F("Direcao do Vento: Norte-Nordeste"));
direcao = "NNE";
}
else if (Tensao >= 88 && Tensao <= 109) {
//Serial.println(F("Direcao do Vento: Norte"));
direcao = "N";
}
else if (Tensao >= 0 && Tensao <= 74) {
//Serial.println(F("Direcao do Vento: Norte-Noroeste"));
direcao = "NNO";
}
else if (Tensao >= 156 && Tensao <= 213) {
//Serial.println(F("Direcao do Vento: Noroeste"));
direcao = "NO";
}
else if (Tensao >= 110 && Tensao <= 155) {
//Serial.println(F("Direcao do Vento: Oeste-Noroeste"));
direcao = "ONO";
}
else if (Tensao >= 265 && Tensao <= 345) {
//Serial.println(F("Direcao do Vento: Oeste"));
direcao = "O";
}
else if (Tensao >= 214 && Tensao <= 264) {
//Serial.println(F("Direcao do Vento: Oeste-Sudoeste"));
direcao = "OSO";
}
else if (Tensao >= 615 && Tensao <= 665) {
//Serial.println(F("Direcao do Vento: Sudoeste"));
direcao = "SO";
}
else if (Tensao >= 530 && Tensao <= 614) {
//Serial.println(F("Direcao do Vento: Sul-Sudoeste"));
direcao = "SSO";
}
else if (Tensao >= 886 && Tensao <= 961) {
//Serial.println(F("Direcao do Vento: Sul"));
direcao = "S";
}
else if (Tensao >= 806 && Tensao <= 885) {
//Serial.println(F("Direcao do Vento: Sul-Sudeste"));
direcao = "SSE";
}
else if (Tensao >= 962 && Tensao <= 1023) {
//Serial.println(F("Direcao do Vento: Sudeste"));
direcao = "SE";
}
else if (Tensao >= 666 && Tensao <= 743) {
//Serial.println(F("Direcao do Vento: Leste-Sudeste"));
direcao = "LSE";
}
else{
Serial.println(F("[ERRO] Leitura na biruta fora da faixa!"));
direcao = "ERR";
}
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**
//--------------------------------------------------------------------------------------------------------------
// 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
//--------------------------------------------------------------------------------------------------------------
int freeRam () {
extern int __heap_start, *__brkval;
int v;
return (int) &v - (__brkval == 0 ? (int) &__heap_start : (int) __brkval);
}
//--------------------------------------------------------------------------------------------------------------
// SETUP (Preparação)
//--------------------------------------------------------------------------------------------------------------
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.
}
}
//--------------------------------------------------------------------------------------------------------------
// 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
*/
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(temperatura1);
Serial.println(F(" graus Celsius"));
Serial.print(F("Temperatura [LM35]\t\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: "));
Serial.print(tempo);
Serial.println(F("ms\n"));
// exibir memória livre pra determinar estabilidade
Serial.print(F("\nMemoria Livre: "));
Serial.print(freeRam());
Serial.println(F(" bytes\n"));
/*
* Versão anterior do programa principal
*
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
*/
}
--Thiago.ribeiro (discussão) 17h53min de 27 de abril de 2016 (BRT)
Formato CSV dos dados
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.
Id da estação; direçao do vento; chuva acumulada; velocidade do vento; temperatura; pressao atmosferica 1;N;0.5;13.3;32.8;990 1;S;0.7;17.2;30;1020 1;NO;0.4;12;19.7;980 1;NE;0.54;13.6;42.3;900
--Jade Mathias 17h59min de 9 de dezembro de 2015 (BRST)
Material técnico de referência
Materiais na Wiki
Tutoriais no Site Oficial do Arduíno
- Bibliotecas e exemplos
- Ethernet e Cartão SD:
- Pressão Barométrica Web Server
- Guardar dados de sensores no cartão SD
- Ler e escrever dados em arquivos no cartão SD
- Criar e remover arquivos no cartão SD