Estacao Meteorologica

De Wiki Cursos IFPR Foz
Revisão de 21h58min de 10 de agosto de 2016 por Evandro.cantu (discussão | contribs) (→‎Equipe)
Ir para navegaçãoIr para pesquisar

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.

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)
  • Thiago Henrique Ribeiro (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)

Estação Meteorológica Sparkfun

Responsável: Thiago Henrique Ribeiro (CST Análise e Desenvolvimento de Sistemas)

Referências: [1], [2]

Sensor de Direção do Vento

O 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.


--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:

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

Sensor de Pressão Barométrica BMP180

Sensor de Pressão Barométrica BMP180

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)

Estação de Energia Solar

Responsável: José Antonio Kazienko Sallet (CST Análise e Desenvolvimento de Sistemas)

Material técnico de referência

Materiais na Wiki

Arduíno

Tutoriais no Site Oficial do Arduíno

Bibliotecas e exemplos
Ethernet e Cartão SD:

Referências