Station météo : capteur de température, humidité et pression (BME280)

Station météo : capteur de température, humidité et pression (BME280)

Il s’agit d’une station météo sans fil avec mesure de la température, de l’humidité et de la pression atmosphérique. Elle utilise un module avec un capteur BME280 et un module nrf24l01 + pour la transmission sans fil. Le cœur est un  atmega328p qui peut être programmé avec arduino.

Le BME280

Le BME280 est un capteur environnemental qui permet de mesurer la pression, l’humidité et la température avec une consommation de courant réduite (3,6 μA à 1Hz). En mode sommeil, il atteint une consommation de 0.1 μA. Niveau interface, il dispose de ports I²C et SPI.

Le module utilisé comporte  6 pins :

PIN I²C SPI
VCC +3.3v +3.3v
GND GND GND
SCK SCL (avec résistance pull-up vers VCC) SCK
SDI SDA (avec résistance pull-up vers VCC) MOSI
CSB +3.3v (par défault en mode I²C) Slave Select (SS)
SDO
  • GND : adresse 0x76(par défault)
  • +3.3v : adresse 0x77
MISO

Schéma du circuit

Le circuit s’articule autour d’un Atmega328p comme dans la plupart des circuits présentés sur ce blog. C’est le même que celui présent sur l’Arduino Uno. La partie sans fil est assurée par un module Nrf24l01+. Le BME280 est utilisé avec le mode I²C et l’adresse 0x76. Il est alimenté en 3.3V,  avec un accu LiFePO4 par exemple, qui, vu la faible consommation, peut tenir plusieurs mois.

C5,C1,C2,C3,C6 100nF
Q1 AO3401
IC1 ATMEGA328P-P + Support
R1 1.2MΩ
R2 470kΩ
R3 100kΩ
D1 LED
R8 560Ω
U2 BME280 + Support 1×6
C4 470µF
U1 nRF24L01 + Support 2×4
J1 ALIM 3.3v

Abri anti-rayonnement

L’abri protège le capteur des rayonnements du soleil et de la pluie tout en assurant la circulation d’air autour du capteur. Il est réalisé à l’imprimante 3D, pour l’instant en PLA pour le prototype, mais l’ASA (acrylonitrile styrene acrylate) sera plus résistant aux UV et aux intempéries. Il est réalisé avec OpenScad.

Le matériel nécessaire pour le boitier :

  • 4x Boulon M4x80
  • 5x écrous M4
  • 5x Vis à tôle 2.9×6.5 ou 2.9×9.5

Les écrous sont noyés dans le plastique, ainsi il est nécessaire de mettre l’impression en pause après la dernière couche des emplacements des écrous.

Les fichiers stl sont disponibles sur Thingiverse.

Le programme

#include <LowPower.h>
#include <nRF24L01.h>
#include <printf.h>
#include <RF24.h>
#include <RF24_config.h>
#include <Wire.h>
#include <stdint.h>
#include <Adafruit_Sensor.h>
#include <Adafruit_BME280.h>

/* -------CONFIG---------*/
#define LOGDEBUG  0
/* --------------------- */

#define NODE_ID  1
#define RF24_CH   25
/* --------------------- */


#define SLEEP_DATA   37    //5min , 8s par cycle
#define SLEEP_VOLT   450  //1h
/* --------------------- */


#define VT_PIN    14    //A0
#define RF24_ON   6
#define LED_PIN   5
/* --------------------- */

//DEBUG 
#if LOGDEBUG==1
#define DEBUG_PRINT(x)       Serial.print(x)
#define DEBUG_PRINTDEC(x)    Serial.print(x, DEC)
#define DEBUG_PRINTLN(x)     Serial.println(x)
#define DEBUG_RADIO()        radio.printDetails()
#else
#define DEBUG_PRINT(x)
#define DEBUG_PRINTDEC(x)
#define DEBUG_PRINTLN(x)
#define DEBUG_RADIO()
#endif
/* --------------------- */

uint16_t  nodeId = NODE_ID;
uint8_t   node_address[5]         = {"1Node"};
uint8_t   server_address[5]       = {"2Node"};
/* --------------------- */


Adafruit_BME280   bme280; 
RF24      radio(9,10);

uint8_t   radioBuffer[32]    = {0};

uint16_t  cntDATA = SLEEP_DATA;
uint16_t  cntVOLT = SLEEP_VOLT;

float     humidity       = 0;
float     temperature    = 0;
float     pressure       = 0;
float     voltage        = 0;


void radioSetup(){
  radio.begin();
  radio.setChannel(RF24_CH);
  radio.setDataRate(RF24_250KBPS);
  radio.setPALevel(RF24_PA_MAX);
  radio.setCRCLength(RF24_CRC_16);
  radio.setRetries(10, 15);  
  radio.setAutoAck(1);
  radio.openReadingPipe(1, node_address);
  radio.openWritingPipe(server_address);

  DEBUG_RADIO();
}

void setup() {
  delay(500);

  #if LOGDEBUG==1
  Serial.begin(115200);
  printf_begin();
  #endif

  pinMode(RF24_ON, OUTPUT);
  digitalWrite(RF24_ON, HIGH);

  pinMode(LED_PIN, OUTPUT);
  digitalWrite(LED_PIN, LOW);   

  //flash led
  digitalWrite(LED_PIN, HIGH);
  delay(250);
  digitalWrite(LED_PIN, LOW);
  
  //1.1V internal voltage reference
  analogReference(INTERNAL);

  bme280.begin(0x76);
  bme280.setSampling( Adafruit_BME280::MODE_FORCED,
                      Adafruit_BME280::SAMPLING_X1, // temperature
                      Adafruit_BME280::SAMPLING_X4, // pressure
                      Adafruit_BME280::SAMPLING_X1, // humidity
                      Adafruit_BME280::FILTER_OFF   );  

  //flash led
  delay(500);
  digitalWrite(LED_PIN, HIGH);
  delay(1000);
  digitalWrite(LED_PIN, LOW);
}

void loop() {
  DEBUG_PRINTLN("Start loop");

  if( (cntDATA >= SLEEP_DATA) || (cntVOLT >= SLEEP_VOLT)){
    //power on radio
    digitalWrite(RF24_ON, LOW);
    
    delay(100);
    radioSetup();
    
    DEBUG_PRINTLN("Radio up");

    if(cntDATA >= SLEEP_DATA){
      bme280.takeForcedMeasurement();
      temperature  = bme280.readTemperature();
      humidity     = bme280.readHumidity();      
      pressure     = bme280.readPressure();

      //sea level correction, sensor altitude is 104m above sea level
      pressure = bme280.seaLevelForAltitude(104.0, pressure);

      DEBUG_PRINT("T=");
      DEBUG_PRINT(temperature);
      DEBUG_PRINT(", H=");
      DEBUG_PRINT(humidity);
      DEBUG_PRINT(", P=");
      DEBUG_PRINTLN(pressure);  
	  
	  
	  memcpy(radioBuffer,     &nodeId,             2);
      memcpy(radioBuffer+2,   "DATA",              4);
    
      memcpy(radioBuffer+6,   &temperature,        4);
      memcpy(radioBuffer+10,   &humidity,          4);
      memcpy(radioBuffer+14,  &pressure,           4);

      memset(radioBuffer+18,  0,                  14);    

      if(radio.write(radioBuffer, 32)){
        cntDATA = 0;
      }
      else{
        if(cntDATA >= (SLEEP_DATA+5)){
          //retry up to 5 cycles of 8s.
          cntDATA = 0;
        }
      }
    }

    delay(250);
    radio.flush_tx();

    if(cntVOLT >= SLEEP_VOLT){
      voltage = analogRead(VT_PIN);
      voltage = voltage * 1.1 * ((1670000.0)/470000.0) / 1024.0;
    
      DEBUG_PRINT("V=");
      DEBUG_PRINTLN(voltage);

     
      memcpy(radioBuffer,     &nodeId,           2);
      memcpy(radioBuffer+2,   "VOLT",            4);
    
      memcpy(radioBuffer+6,   &voltage,          4);

      memset(radioBuffer+10,  0,                 22);
    

      if(radio.write(radioBuffer, 32)){
        cntVOLT = 0;
      }
      else{
        if(cntVOLT >= (SLEEP_VOLT+5)){
          //retry up to 5 cycles of 8s.
          cntVOLT = 0;
        }
      }
    }   

    delay(50);
    
    //power down radio
    radio.powerDown();
    digitalWrite(RF24_ON, HIGH);
  }
  
   
  ++cntDATA;
  ++cntVOLT;
  
  //flash led
  digitalWrite(LED_PIN, HIGH);
  delay(1);
  digitalWrite(LED_PIN, LOW);

  DEBUG_PRINTLN("Sleep for 8 seconds"); 

  LowPower.powerDown(SLEEP_8S, ADC_OFF, BOD_OFF);

}

4 réactions au sujet de « Station météo : capteur de température, humidité et pression (BME280) »

    1. Hello,
      Sorry, it was a copy paste mistake, I forgot a #define : #define NODE_ID 1 before.
      Any number can be defined here, it’s to identify which node send the message.

  1. Je ne suis qu’un débutant. S’il vous plaît aider. Ce qui devrait être indiqué dans les lignes:
    uint16_t nodeId = NODE_ID;
    uint8_t node_address [5] = {« 1Node »};
    uint8_t adresse_serveur [5] = {« 2Node »};

    peut un exemple

    1. node_address [5] is the current node address on five bytes.
      adresse_serveur [5] is the receiver node address. Another node on the network must have this address and must be in listen mode. Soon, a new article will explain how to make an ethernet gateway tu listen data packets.

Laisser un commentaire

Votre adresse de messagerie ne sera pas publiée. Les champs obligatoires sont indiqués avec *