Go Down

Topic: Capteur BME280 - amplification data possible ? (Read 408 times) previous topic - next topic

fitness04

Bonjour à tous,

J'ai un projet en cours de station météo utilisant plusieurs capteurs (Anemo Davis, température par DS18b20) dont un BME280 pour la Pression et l'humidité.

J'utilise une Arduino Mega et un shield Ethernet.

Tout allait bien quand je testais le montage avec des fils connecteurs courts (10 cm).

Pour raccorder les capteurs qui sont sur mon toit avec le module Arduino, j'utilise 10 m de câble 8 conducteurs issus d'une rallonge RJ45. (Multimedia Connect B99 -  24/15 TX200-P4 - 4 Pairs AWG 26/7 - u/FTP 100 ohms)

Le problème, c'est que les données (SDA) du BME280 n'arrivent plus sur l'Arduino méga. Je pense que le signal est trop faible avec les 10 m de câble même si j'ai utilisé une paire entière pour la liaison SDA.


J'ai comme pistes :

- essayer d'optimiser la longueur de câble, mais je peux gagner 2 m au maxi et ne sais si ça sera
suffisant ?

- Changer la section du câble et quelle section choisir ?

- Peut-on amplifier le signal de la sortie SDA ?

- Utiliser un module Wifi

- Laisser tomber la mesure d'humidité et de pression... mais ça réduit l'intérêt d'une station météo...

Avez vous d'autres solutions ?

Merci.

Fitness04 - Newby!

hbachetti

Salut

Je ne dis pas que c'est  techniquement infaisable mais I2C = Inter-Integrated Circuit.
C'est un bus prévu pour dialoguer entre composants sur une même carte.

@+
Linux is like a wigwam: no Windows, no Gates, and an Apache inside ...

hbachetti

Je complète ma réponse.

Il est beaucoup plus rationnel de développer des couples ARDUINO PRO MINI + capteur et de transmettre par radio ou liaison filaire les informations à la MEGA.

Si le câblage est possible, les capteurs peuvent transmettre leurs informations en RS232.
La MEGA possède 3 ports supplémentaires il me semble.

Sinon, il est possible de s'orienter sur des capteurs sur batterie. Une ARDUINO PRO MINI 8MHz 3.3V est capable de fonctionner sur batterie pendant un an si l'on utilise le mode veille.
La transmission des données peut avoir lieu tous les 1/4 d'heure par exemple. La consommation sera de quelques dizaines de mA pendant quelques dizaines de millisecondes, ensuite l'ARDUINO entrera en mode veille et ne consommera plus que 5µA.
L'avantage est bien sûr l'absence de câblage et le positionnement très libre des capteurs, sur une cloison, un mur, sur ou sous un toit, une cheminée, etc.

La MEGA reste alimentée sur le secteur en permanence et écoute les capteurs.

Le WIFI est un peu lourd pour ce genre d'application. J'utiliserais plutôt des NRF24L01, qui consomment 12mA en émission.
Il faut un module radio pour chaque capteur et un autre pour la MEGA.

@+
Linux is like a wigwam: no Windows, no Gates, and an Apache inside ...

fitness04

Merci pour ta réponse hbachetti,

Je vais étudier tout ça.

La transmission par radio semble une bonne option pas trop compliquée à mettre en oeuvre.

Je n'ai que 6 mois de pratique sur Arduino et j'avance pas à pas. La réalisation d'une balise météo "filaire" était un premier but.

J'avais déjà l'idée de faire à terme, une station autonome, alimentée par un panneau solaire et une batterie...

Concernant l'architecture d'une station "radio" :

- pourquoi faut il une carte arduino pro mini par capteur et non pas une arduino mega qui regroupe toutes les données des 4 capteurs (anémo, girouette, température, pression+Humidité) et un seul module radio (consommation ?)?
- Concernant la mesure de la vitesse et de la direction du vent, je fais une moyenne et je stocke donc les données (une mesure toutes les 2.5 secondes).  Si j'envoie les données tous les 1/4 d'heure, il va falloir que je stocke 360 données. Une carte Arduino pro mini n'aura certainement pas assez de mémoire (j'étais déjà passé de la UNO à la méga en moyennant sur 2mn pour ça).

Peux tu encore m'éclairer ?

Du coup, en attendant, je retarde l'installation de la balise filaire. Si je peux éviter de faire des trous !

Merci.
Fitness04 - Newby!

hbachetti

Quote
- pourquoi faut il une carte arduino pro mini par capteur et non pas une arduino mega qui regroupe toutes les données des 4 capteurs (anémo, girouette, température, pression+Humidité) et un seul module radio (consommation ?)?
Tout dépend de l'endroit où sont situés les capteurs.
Si tous les capteurs sont situés au même endroit, tu peux parfaitement les regrouper sur un seul ARDUINO MINI + 1 module radio.
L'ARDUINO MEGA reçoit les données avec son propre module radio.
Sur chaque émetteur il y a forcément un processeur et un module radio.

Quote
- Concernant la mesure de la vitesse et de la direction du vent, je fais une moyenne et je stocke donc les données (une mesure toutes les 2.5 secondes).  Si j'envoie les données tous les 1/4 d'heure, il va falloir que je stocke 360 données.
1/4 d'heure est une durée acceptable pour une température ou un degré d'humidité.
Tu peux même envoyer les données uniquement si elles ont changé par rapport à la mesure précédente.

Tu peux parfaitement envoyer les données de l'anémomètre toutes les 2.5s par radio. Cela ne devrait pas être très consommateur d'énergie.
En fait tout dépend de la consommation de ton anémomètre, en particulier de la partie direction du vent qui semble être un potentiomètre. Il se peut que tu sois obligé d'alimenter ce capteur par une alimentation sur secteur.
Tu peux aussi envoyer les données vitesse et direction du vent uniquement si elles ont changé par rapport à la mesure précédente.

@+
Linux is like a wigwam: no Windows, no Gates, and an Apache inside ...

fitness04

Rebonjour hbachetti,

Les capteurs sont effectivement regroupés sur un même mât et une boîte de dérivation.

Donc, une seule carte arduino et un module radio devraient être suffisant pour la partie émetteur.

Si je ne m'abuse, pour le choix de la carte Arduino de l'émetteur,:

- soit je prend une carte de faible capacité mémoire et j'envoie les données toutes les 2.5 s au récepteur à base d'Arduino Méga,

- soit je choisi une Arduino méga pour l'émetteur, qui traite toutes les données, et les envoie tous les 1/4 d'heure au récepteur qui transmets les données sur un site dédié, comme ThingSpeak et affiche ces mêmes données sur un écran. Dans ce cas, le récepteur peut être une Uno, non?

A ton avis, quelle est la meilleure solution ?

Ci joint, une photo du montage futur les éléments de la station météo sur un mât.

Et, pour info, le code... en deux fois...

Code: [Select]



//Capteur anémomètre-Girouette DAVIS
//Inspiré du site ci dessous
//http://cactus.io/hookups/weather/anemometer/davis/hookup-arduino-to-davis-anemometer-software

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

#include "TimerOne.h"
#include <math.h>

#include "cactus_io_DS18B20.h"
#include "cactus_io_BME280_I2C.h"


#define TX_Pin 8
#define DS18B20_Pin 9
#define WindSensor_Pin (2)
#define WindVane_Pin (A2)
#define VaneOffset 0

volatile unsigned long tipCount;
volatile unsigned int timerMinCount;    // used to determine 1 minute count
volatile unsigned long contactTime;

volatile unsigned int  timerCount;
volatile unsigned long rotations;
volatile unsigned long contactBounceTime;

float totalRainfall;

const float DEG2RAD = 3.14156 / 180.0; // convert degrees to radian
const float RAD2DEG = 180 / 3.14156; //convert radian to degrees
const int numReadings = 48;//2mn
int winDir[numReadings];
float sinSum = 0;
float cosSum = 0;

volatile float windSpeed;
volatile float xMin;
int vaneValue;
int vaneDirection;
int calDirection;
int lastDirValue;

float minTemp;
float maxTemp;

int readings[numReadings];
int readIndex = 0;
int total = 0;
int windDirection = 0;
int windSpeedMax = 0;
int averageSpeed = 0;

//int readingsDir[numReadingsDir];
int readingsDir[numReadings];
int readIndexDir = 0;
int avg_windDirection = 0;
int avgWinDir = 0;
String girouette = "";

float t = 0;
float h = 0;
float p = 0;
float v = 0;
float d = 0;

DS18B20 ds(DS18B20_Pin); // on digital pin 9
BME280_I2C bme; // I2C using address 0x76

// Local Network Settings
byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED }; // Must be unique on local network
IPAddress ip(192, 168, 1, 40);
// ThingSpeak Settings
char server[] = "api.thingspeak.com";
String writeAPIKey = "HBDG84UP7TIGVSNV";
const int updateThingSpeakInterval = 30 * 1000; // Time interval in milliseconds to update ThingSpeak (number of seconds * 1000 = interval)
// Variable Setup
long lastConnectionTime = 0;
boolean lastConnected = false;
int failedCounter = 0;
// Initialize Arduino Ethernet Client
EthernetClient client;

void setup() {

  Serial.begin(115200);
  lastDirValue = 0;
  rotations = 0;
  timerCount = 0;
  timerMinCount = 0;

  ds.readSensor();
  delay(3000); // allow 3 seconds for sensor to settle down
  ds.readSensor(); // read again to avoid weird values for defaults
  minTemp = ds.getTemperature_C();
  maxTemp = ds.getTemperature_C();

  // disable the SD card by switching pin 4 high
  pinMode(4, OUTPUT);
  digitalWrite(4, HIGH);

  if (!bme.begin()) {
    Serial.println("Could not find BME280 sensor, check wiring!");
    while (1);
  }

  for (int readIndex = 0; readIndex < numReadings; readIndex++) {
    readings[readIndex] = 0;
  }

  for (int readIndexDir = 0; readIndexDir < numReadings; readIndexDir++) {
    winDir[readIndexDir] = 0;
  }

  pinMode(TX_Pin, OUTPUT);
  pinMode(WindSensor_Pin, INPUT);
  attachInterrupt(digitalPinToInterrupt(WindSensor_Pin), isr_rotation, FALLING);

  // Setup the timer interupt for 0.5 second (500 000 microSecondes)
  Timer1.initialize(500000);
  Timer1.attachInterrupt(isr_timer);

  sei();

  startEthernet();

}

void loop() {

    // Read value from Analog Input Pin 0
    String analogPin0 = String(analogRead(A0), DEC);
    // Print Update Response to Serial Monitor
    if (client.available())
    {
      char c = client.read();
      Serial.print(c);
    }
  bme.readSensor();
  ds.readSensor();
  // update min and max temp values
  if (ds.getTemperature_C() < minTemp) {
    minTemp = ds.getTemperature_C();
  }
  if (ds.getTemperature_C() > maxTemp) {
    maxTemp = ds.getTemperature_C();
  }
  float t = ds.getTemperature_C();
  float h = bme.getHumidity();
  float p = bme.getPressure_MB();
  float v = windSpeed;
  float d = calDirection;
  float as = averageSpeed;
  //    float ad = avg_windDirection;

  // Disconnect from ThingSpeak
  if (!client.connected() && lastConnected)
  {
    Serial.println("...disconnected");
    Serial.println();
    client.stop();
  }
  // Update ThingSpeak
  if (!client.connected() && (millis() - lastConnectionTime > updateThingSpeakInterval))
  {
    // reset the timer and rain tip count
    cli();  // disable interrupts
    timerMinCount = 0;
    tipCount = 0;
    sei();  // enable interrupts
    getWindDirection();
//    Serial.print("test");
    int ad = avg_windDirection;
    String data1 = "&field1=";
    data1 += String(t);
    data1 += "&field2=";
    data1 += String(h);
    data1 += "&field3=";
    data1 += String(p);
    data1 += "&field4=";
    data1 += String(v);
    data1 += "&field5=";
    data1 += String(d);
    data1 += "&field6=";
    data1 += String(as);
    data1 += "&field7=";
    data1 += String(ad);

    updateThingSpeak (data1);
    //             updateThingSpeak("field1=" + String(t) + "&field2=" + String(h) + "&field3=" + String(p) + "&field4=" + String(v) + "&field5=" + String(d) + "&field6=" + String(as) + "&field7=" + String(ad));
  }
  // Check if Arduino Ethernet needs to be restarted
  if (failedCounter > 3 ) {
    startEthernet();
  }
  lastConnected = client.connected();

}

Fitness04 - Newby!

fitness04

La deuxième partie du code :

Code: [Select]

// isr routine for timer interrupt
void isr_timer() {

  timerCount++;
  if (timerCount == 5)//5 x .5 = 2.5 s
  {
    // convert to mp/h using the formula V=P(2.25/T)- Davis Anemometer
    // V = P(2.25/2.5) = P * 0.9
    //en Km/h = P * 0.9 * 1.60934
    windSpeed = rotations * 0.9 * 1.60934;

    // ************Calcul moyenne sur 2 mn************
    total = total - readings[readIndex];
    readings[readIndex] = windSpeed;
    total = total + readings[readIndex];
    readIndex = readIndex + 1;
    if (readIndex >= numReadings) {
      readIndex = 0;
    }
    averageSpeed = total / numReadings;
    if (windSpeed >= windSpeedMax ) {
      windSpeedMax = windSpeed;
    }
    rotations = 0;
    timerCount = 0;
    timerMinCount++;
  }
}

// interrupt handler to increment the rotation count for wind speed
void isr_rotation ()   {

  if ((millis() - contactBounceTime) > 15 ) {
    rotations++;
    contactBounceTime = millis();
  }
}

// Get Wind Direction
void getWindDirection() {

  vaneValue = analogRead(WindVane_Pin);
  //  Serial.print(vaneValue);
  //  Serial.println();
  vaneDirection = map(vaneValue, 0, 1023, 0, 360);
  calDirection = vaneDirection + VaneOffset;
  if (calDirection > 360)
    calDirection = calDirection - 360;
  if (calDirection < 0)
    calDirection = calDirection + 360;
  //*********Calcul Moyenne Direction**************
  winDir[readIndexDir] = calDirection;
  readIndexDir = readIndexDir + 1;
  if (readIndexDir == numReadings ) {
    for (readIndexDir = 0; readIndexDir < numReadings; readIndexDir++)
    {
      sinSum += sin((winDir[readIndexDir]) * DEG2RAD);
      cosSum += cos((winDir[readIndexDir]) * DEG2RAD);
    }
    float avgWinDir = atan2(sinSum, cosSum);
    avgWinDir = avgWinDir / DEG2RAD;
    if ( avgWinDir < 0 )
    {
      avgWinDir += 360;
    }
    int windDirection = (int)avgWinDir % 360;
    avg_windDirection = windDirection;
//    Serial.println(avg_windDirection);
    sinSum = 0;
    cosSum = 0;
    readIndexDir = 0;
  }
}
// Converts compass direction to heading
void getHeading(int direction) {
  if (direction < 22)
    girouette = (" N");
  else if (direction < 67)
    girouette = (" NE");
  else if (direction < 112)
    girouette = (" E");
  else if (direction < 157)
    girouette = (" SE");
  else if (direction < 202)
    girouette = (" S");
  else if (direction < 247)
    girouette = (" SO");
  else if (direction < 292)
    girouette = (" O");
  else if (direction < 337)
    girouette = (" NO");
  else
    girouette = (" N");
}
void updateThingSpeak(String data)
{
  if (client.connect(server, 80))
  {
    client.print("POST /update HTTP/1.1\n");
    client.print("Host: api.thingspeak.com\n");
    client.print("Connection: close\n");
    client.print("X-THINGSPEAKAPIKEY: " + writeAPIKey + "\n");
    client.print("Content-Type: application/x-www-form-urlencoded\n");
    client.print("Content-Length: ");
    client.print(data.length());
    client.print("\n\n");
    client.print(data);
    lastConnectionTime = millis();
    if (client.connected())
    {
      Serial.println("Connecting to ThingSpeak...");
      Serial.println();
      failedCounter = 0;
    }
    else
    {
      failedCounter++;
      Serial.println("Connection to ThingSpeak failed (" + String(failedCounter, DEC) + ")");
      Serial.println();
    }
  }
  else
  {
    failedCounter++;
    Serial.println("Connection to ThingSpeak Failed (" + String(failedCounter, DEC) + ")");
    Serial.println();
    lastConnectionTime = millis();
  }
}


void startEthernet()
{
  client.stop();
  Serial.println("Connecting Arduino to network...");
  Serial.println();
  delay(1000);
  // Connect to network amd obtain an IP address using DHCP
  if (Ethernet.begin(mac) == 0)
  {
    Serial.println("DHCP Failed, reset Arduino to try again");
    Serial.println();
  }
  else
  {
    Serial.println("Arduino connected to network using DHCP");
    Serial.println();
  }
  delay(1000);
}

Fitness04 - Newby!

hbachetti

Quote
A ton avis, quelle est la meilleure solution ?
C'est plus la question de l'alimentation qui guidera le choix.

Une MEGA consommera plus qu'une PRO MINI et aura donc une alimentation secteur.
Je n'ai jamais essayé de faire dormir une MEGA mais certains parlent de 17mA.
D'autre part elle s'alimente en 5V.
OK si y a une prise secteur à proximité.

Avec une PRO MINI 3.3V on obtiendra plutôt une vingtaine de µA avec un bon régulateur et une batterie LITHIUM-ION 3.7V.
Par contre cela impose d'échanger la batterie régulièrement, peut-être une fois par an, en fonction de la qualité de celle-ci, en particulier de son courant d'auto-décharge. Un petit panneau solaire de quelques watts peut permettre d'éviter cette opération.
Cela impose également de remonter à la MEGA une information supplémentaire : la tension batterie.


@+
Linux is like a wigwam: no Windows, no Gates, and an Apache inside ...

68tjs

#8
May 26, 2018, 07:15 pm Last Edit: May 26, 2018, 07:21 pm by 68tjs
LE BME 280 possède les deux interfaces I2C et SPI.
As tu essayé en SPI, le SPI est moins chatouilleux que l'I2C.

S'il le faut en SPI on peut adapter les lignes de transmission qui, dans la mesure où il n'y a qu'un maître, sont unidirectionnelles et non pas bidirectionnelles comme l'I2C.

Voir aussi ici pour "splitter" une liaison I2C en deux pour le transport ce qui permet l'adaptation du câble ethernet Zc = 100 ohms..
https://www.edn.com/5G/4441669/Splitting-and-arbiting-a-bidirectional-serial-bus

fitness04

Merci à tous les deux pour votre aide.

Pour 68tjs,
 j'aurais bien essayé de brancher le BME280 en SPI mais il me manque un conducteur dans ma liaison Capteurs - Méga avec mon câble 8 conducteurs. Ou alors, il faut que je supprime le Capteur DS18b20 et que j'utilise le thermomètre du BME280. Ce qui me gène, c'est que le BME280 est dans une boite de dérivation à l'intérieur de l'abri aéré alors que le DS18b20 étanche est dans les courants d'air à l'intérieur de l'abri. La mesure de température est donc plus précise.

Ou alors:
- il faut que je trouve un câble 10 conducteurs
- je fais un montage diviseur de tension pour passer du 5v à 3.3v et je récupère un fil

Pour ce qui est du Splitting, ça dépasse mes compétences...

Je pense que je vais suivre l'idée de Hbachetti et commander une arduino pro mini et 2 modules radio qui vont mettre un mois pour arriver et, en attendant, je vais creuser l'idée du branchement SPI.

Affaire à suivre donc...
Fitness04 - Newby!

hbachetti

Je commande souvent chez ModuleFans

NRF24L01
PRO MINI

Ma dernière commande : 50€
Envoyée le 25 avril
Reçue le 4 mai

Ne commande pas seulement les exemplaires dont tu as besoin. Un accident est vite arrivé.
Personnellement je commande par 10.
Et puis une fois qu'on a goûté au couple PRO MINI et NRF24L01 on en met partout.
Chez ModuleFans ils ont une quantité de capteurs impressionnante.

Pense aussi à la programmation de la PRO MINI. Il te faut un FTDI acceptant le 3.3V.
Voir ICI. Chapitre 5.

Un module comme celui-ci. Ils ont plusieurs modèles compatibles 3.3V et 5V.

@+
Linux is like a wigwam: no Windows, no Gates, and an Apache inside ...

fitness04

Bonjour Hbachetti,

Je vais commander à cette boutique. Merci pour les liens.

Au rythme ou je programme, j'ai qu'un seul projet en cours même si parfois je pars dans des digressions au hasard d'un tutorial...

Et toi, tu te sers de ces composants pour quelles applications ?

A bientôt.

Firtness04

PS: c'est vrai que je commence à avoir beaucoup de pièces arduino et qu'il va falloir que je trouve un système de rangement... pour l'instant c'est tout dans un tiroir !
Fitness04 - Newby!

hbachetti

Quote
Et toi, tu te sers de ces composants pour quelles applications ?
Applications domotique, mesure et audio.

Quote
PS: c'est vrai que je commence à avoir beaucoup de pièces arduino et qu'il va falloir que je trouve un système de rangement... pour l'instant c'est tout dans un tiroir !
C'est clair. Dans mon atelier cela occupe plusieurs mètre carrés sur un mur.
Deux types :
Casier
Bloc tiroirs
Linux is like a wigwam: no Windows, no Gates, and an Apache inside ...

MicroQuettas

Bonsoir,

Avant de refaire tout votre montage, il y a une chose simple que vous pourriez essayer : ralentir la communication en I2C avec le BME280. Les lignes un peu longues déforment plus qu'elles n'atténuent le signal et baisser la vitesse est une solution à explorer.

Le capteur, qui fonctionne en esclave, n'a aucun problème. Ce qui est limité, c'est la vitesse max du bus, pas sa vitesse minimum. La vitesse nominale est 100000bps.

En plus, sur un Arduino AVR, c'est très simple à faire.
Je suppose que votre bibliothèque "cactus_io_BME280_I2C" utilise l'objet "Wire" (à vous de vérifier).

L'AVR règle sa vitesse en I2C avec un registre (TWBR) et un prédiviseur (bits TWPS0 et TWPS1 dans TWSR). Tout est accessible sur AVR et en plus, l'objet Wire a une méthode de calcul de la valeur du registre TWBR en fonction de la vitesse du bus.
Le grand confort.

Dans tous les cas, en fin de setup(), rajouter :
Code: [Select]
Wire.setClock(vitesse);

et

Pour une 10000 <= vitesse < 50000, rajouter :
Code: [Select]
TWSR |= TWPS0;

ou

Pour une 2000 <= vitesse < 20000, rajouter :
Code: [Select]
TWSR |= TWPS1;

ou

Pour une vitesse < 1000, rajouter en :
Code: [Select]
TWSR |= (TWPS1 | TWPS0);

Exemple, pour ramener la vitesse à 5000bps, rajouter
Code: [Select]
Wire.setClock(5000);
TWSR |= TWPS1;


Diminuez progressivement la vitesse et regardez à quelle vitesse cela commence à marcher.

Bonne bidouille

MicroQuettas

PS : ne publiez pas vos identifiants, si vous ne voulez pas que des petits malins en profitent.

fitness04

Bonjour MicroQuettas,

Merci pour ces infos, je vais essayer et vous tiendrai au courant...

Merci aussi pour vos conseil concernant mes identifiants. Je vois que j'ai mon adresse IP affichée mais je ne vois pas comment l'enlever dans mon profil.
Pouvez vous m'aiguiller ?

Fitness04
Fitness04 - Newby!

Go Up