samedi 22 décembre 2018

Les capteurs de température, humidité, pression & luminosité

Les capteurs de température

humidité, pression & luminosité


S'il est facile de mesurer une tension avec une grande précision, il n'en va pas de même avec la température. Rares sont les capteurs dont la précision est inférieure à 0.5°.
Les meilleurs capteurs ont une précision de +/- 0.1°.
Voir ici : Farnell

Dans cet article nous allons essayer plusieurs capteurs de température, humidité et pression atmosphérique :
  • MAX6675 + thermocouple de type K : température
  • MAX31865 + sonde PT100 3 fils
  • LM35DZ : température
  • LM335 : température
  • MCP9808 : température
  • TMP102 : température
  • DS18B20 : température
  • DHT11 : température & humidité
  • AM2301 : température & humidité
  • DHT22 : température & humidité
  • SHT31D : température & humidité
  • HTU21D : température & humidité
  • HDC2080 : température & humidité
  • SI7021 : température & humidité
  • BMP180 : température, pression
  • BME280 : température, humidité, pression
Une sonde de type PT1000 et un MAX31865 ont été commandés pour compléter ces tests.

L'AM2301 est un DHT21 câblé et mis en boîtier.

Nous allons également évoquer l'utilisation de capteurs de luminosité :
  • BH1750
  • OPT3001
  • TEMT6000
  • TSL2561
  • une LDR GL5528
L'intérêt de cet article est aussi de fournir une base de câblage et de code, avec les librairies à utiliser pour la mise en œuvre de ces capteurs.

Il ne s'agit pas ici de nous substituer à un laboratoire de métrologie. Les mesures sont effectuées sur table, à l'air libre, sans enceinte de confinement, ce qui est plus que suffisant dans le cadre d'applications domestiques.

J'ajouterai simplement une remarque qu sujet des mesurer en extérieur. Il est totalement illusoire de vouloir mesurer une température extérieure sans abri adéquat. Il existe des abris normalisés pour cet usage :
Sans une enceinte de ce type, permettant de réfléchir la lumière du soleil et pourvue d'une ventilation, un thermomètre placé à l'extérieur sans précautions, même s'il est à l'ombre, donnera un résultat plus qu’approximatif.

1. Les caractéristiques

Les caractéristiques de ces capteurs sont les suivantes :
 
Module Plage
Température
Précision 
Température
Précision
Humidité
Précision
Pression
Prix
MAX6675 0°C à +800°C ±0.25°

2.00
MAX31865 0°C à +800°C ±0.5°

4.00
LM35DZ -55°C à +150°C ±2°

0.40
LM335 -40°C à +100°C ±2°

1.00
MCP9808 -40°C à +125°C ±0.25° ±0.5° maxi

1.00
TMP102 -40°C à +125°C ±2°

1.60
DS18B20 -55°C à +125°C ±0.5°

0.50
DHT11 0°C à +50°C ±2°

0.50
AM2301 -40°C à +80°C ±0.3° ±3%
1.80
DHT22 -40°C à +80°C ±0.5° ±2-5%
2.10
SHT31D -40°C à +125°C ±0.3° ±2%
4.00
HTU21D -40°C à +125°C ±0.3° ±2%
1.50
HDC2080 -40°C à +125°C ±0.2° ±0.4° maxi ±2%
4.00
SI7021 -40°C à +125°C ±0.4° ±3%
1.80
BMP180 -40°C à +85°C ±1°
0.12 Pa 1.00
BME280 -40°C à +85°C ±1° ±3% 0.2 Pa 2.00

Le tableau suivant regroupe les caractéristiques d'alimentation :
Module Tension Courant Courant de veille Interruption
MAX6675 3.0V - 3.6V 1.5mA
NON
MAX31865 3.0V - 5.5V 2mA
NON
LM35DZ 4.0V - 30V 60µA
NON
LM335
400µA
NON
MCP9808 2.7V - 5.5V 200 μA 0.1 μA OUI
TMP102 1.4V - 3.6V 10 µA 1µA OUI
DS18B20 3.0V - 5.5V 1.5 mA 1µA NON
DHT11 3.0V - 5.5V 2.5 mA 50µA NON
AM2301 3.3V - 6V 2.5 mA 50µA NON
DHT22 3.3V - 6V 2.5 mA 50µA NON
SHT31D 2.4V - 5.5V 350µA 0.2µA NON
HTU21D 1.5V - 3.6V 500µA 0.14µA NON
HDC2080 1.62V - 3.6V 550µA 0.05µA OUI
SI7021 1.9V - 3.6 V 150µA 0.06µA NON
BMP180 1.8V - 3.6V 1mA 3µA NON
BME280 1.71V - 3.6V 700µA 0.1µA NON

La plupart de ces capteurs sont adaptés à la basse consommation, sauf le MAX6675 et le MAX31865 bien sûr.
Certains capteurs (MCP9808, TMP102 et HDC2080) peuvent activer une interruption du processeur via une broche spéciale.

2. Le câblage

Le câblage est réalisé comme ceci :

Attention, certains modules sont alimentés en 3.3V.
Le HDC2080 a sa broche ADD reliée au 3.3V pour changer son adresse I2C de (0x41 au lieu de 0x40 par défaut) sinon il entre en conflit I2C avec le HTU21D.
Le SI7021 a été testé à part à l'aide du sketch exemple de la librairie car son adresse 0x40 n'est pas modifiable.

Le câblage de la sonde PT100 dépend du nombre de fils de celle-ci :
https://learn.adafruit.com/adafruit-max31865-rtd-pt100-amplifier/rtd-wiring-config

A l'origine le module est préparé pour une sonde 4 fils. A droite et en bas, les plots 2&4 sont reliés par une piste de cuivre :

Comme j'ai utilisé une sonde PT100 3 fils Bleu Jaune Rouge, j'ai coupé la piste entre 2&4, et effectué les soudures sur le shield comme recommandé par le tuto AdaFruit :


Le Chip Select du MAX31865 est câblé sur D7, D10 étant déjà occupé par le MAX6675.
Comme j'ai testé le MAX31865 et le SI7021 longtemps après la première rédaction de cet article, j'ai fait un montage à part et j'ai comparé les résultats au HDC2080.

3. L'IDE ARDUINO

Les librairies ARDUINO suivantes ont été installées :
MAX6675 : https://github.com/adafruit/MAX6675-library.git
MAX31865 : https://github.com/adafruit/Adafruit_MAX31865.git
MCP9808 : https://github.com/adafruit/Adafruit_MCP9808_Library.git
HDC2080 : https://github.com/tinkeringtech/HDC2080_breakout.git
HTU21D : https://github.com/adafruit/Adafruit_HTU21DF_Library.git
TMP102 : https://github.com/sparkfun/SparkFun_TMP102_Arduino_Library.git
DHT : https://github.com/adafruit/DHT-sensor-library.git
SHT31D : https://github.com/adafruit/Adafruit_SHT31.git
SI7021 : https://github.com/adafruit/Adafruit_Si7021.git

Dans l'IDE (arduino-cc 1.8.5 par exemple), dans le menu "Outils/Type de Carte" choisir "Arduino NANO".
Dans le menu "Outils/Processeur", en fonction de l'âge de votre carte, il se peut que vous ayez à choisir "ATmega328P" ou "ATmega328P (Old Bootloader)".

4. Le sketch

Le sketch utilise les adresses I2C suivantes :
  • MCP9808 : 0x18
  • SHT31D : 0x44
  • HTU21D : 0x40
  • BMP180 : 0x77
  • BME280 : 0x76
  • TMP102 : 0x48 
  • HDC2080 : 0x41 (adresse alternative)
  • SI7021 : 0x40 (en conflit avec HTU21D, testé séparément)
#include <Arduino.h>
#include <Wire.h>
#include <max6675.h>
#include <Adafruit_MAX31865.h>
#include <Adafruit_SHT31.h>
#include <Adafruit_HTU21DF.h>
#include <SparkFunTMP102.h>
#include <Adafruit_BMP085_U.h>
#include <Adafruit_BME280.h>
#include <Adafruit_MCP9808.h>
#include <HDC2080.h>
#include <OneWire.h>
#include <DallasTemperature.h>
#include "DHT.h"

#define RREF      430.0
#define RNOMINAL  100.0
#define ONE_WIRE_BUS  2
#define DHT11PIN      4
#define DHT21PIN      3
#define DHT22PIN      5
#define LM335_PIN     A1
#define VCC           4.90

MAX6675 ktc(10, 9, 8);
Adafruit_MAX31865 max = Adafruit_MAX31865(7, 11, 12, 13);
Adafruit_SHT31 sht31 = Adafruit_SHT31();
Adafruit_HTU21DF htu21 = Adafruit_HTU21DF();
TMP102 tmp102(0x48);
Adafruit_BMP085_Unified bmp180 = Adafruit_BMP085_Unified(10085);
Adafruit_BME280 bme280; // I2C
Adafruit_MCP9808 mcp9808 = Adafruit_MCP9808();
HDC2080 hdc2080(0x41);
OneWire oneWire(ONE_WIRE_BUS);
DallasTemperature ds18b20(&oneWire);
DHT dht11(DHT11PIN, DHT11);
DHT dht21(DHT21PIN, DHT21);
DHT dht22(DHT22PIN, DHT22);

void setup() {
  Serial.begin(115200);

  Serial.println("Meteo sensors test");
  max.begin(MAX31865_3WIRE);
  if (! sht31.begin(0x44)) {
    Serial.println("Couldn't find SHT31");
    while (1) delay(1);
  }
  Serial.println("SHT31 OK");
  if (!htu21.begin()) {
    Serial.println("Couldn't find sensor!");
    while (1);
  }
  tmp102.begin();
  Serial.println("TMP102 OK");
  if (!mcp9808.begin()) {
    Serial.println("Couldn't find MCP9808!");
    while (1);
  }
  Serial.println("MCP9808 OK");
  hdc2080.begin();
  hdc2080.setMeasurementMode(TEMP_AND_HUMID);
  hdc2080.setRate(ONE_HZ);
  hdc2080.setTempRes(FOURTEEN_BIT);
  hdc2080.setHumidRes(FOURTEEN_BIT);  Serial.println("HDC2080 OK");
  hdc2080.triggerMeasurement();
  if (!bmp180.begin()) {
    Serial.print("Could not find a valid BME180 sensor, check wiring!");
    while (1);
  }
  Serial.println("BMP180 OK");
  if (!bme280.begin(0x76)) {
    Serial.println("Could not find a valid BME280 sensor, check wiring!");
    while (1) delay(1);
  }
  Serial.println("BME280 OK");
  delay(2000); // for DHT21
}


void loop() {
  uint16_t rtd = max.readRTD();

  Serial.print("\nMAX31865 temperature");
  Serial.print("RTD value: "); Serial.println(rtd);
  float ratio = rtd;
  ratio /= 32768;
  Serial.print("Ratio = "); Serial.println(ratio, 8);
  Serial.print("Resistance = "); Serial.println(RREF * ratio, 8);
  Serial.print("Temperature = "); Serial.println(max.temperature(RNOMINAL, RREF));

  // Check and print any faults
  uint8_t fault = max.readFault();
  if (fault) {
    Serial.print("Fault 0x"); Serial.println(fault, HEX);
    if (fault & MAX31865_FAULT_HIGHTHRESH) {
      Serial.println("RTD High Threshold");
    }
    if (fault & MAX31865_FAULT_LOWTHRESH) {
      Serial.println("RTD Low Threshold");
    }
    if (fault & MAX31865_FAULT_REFINLOW) {
      Serial.println("REFIN- > 0.85 x Bias");
    }
    if (fault & MAX31865_FAULT_REFINHIGH) {
      Serial.println("REFIN- < 0.85 x Bias - FORCE- open");
    }
    if (fault & MAX31865_FAULT_RTDINLOW) {
      Serial.println("RTDIN- < 0.85 x Bias - FORCE- open");
    }
    if (fault & MAX31865_FAULT_OVUV) {
      Serial.println("Under/Over voltage");
    }
    max.clearFault();
  }
  Serial.print("\nMAX6675 temperature = ");
  float ktct = ktc.readCelsius();
  Serial.print(ktct);
  Serial.println(" *C\n");

  float sht31t = sht31.readTemperature();
  float sht31h = sht31.readHumidity();

  if (! isnan(sht31t)) {
    Serial.print("SHT31 temperature = ");
    Serial.print(sht31t);
  } else {
    Serial.println("Failed to read temperature");
  }
  Serial.println(" *C");
  if (!isnan(sht31h)) {
    Serial.print("SHT31 humidity = ");
    Serial.print(sht31h);
  } else {
    Serial.println("Failed to read humidity");
  }
  Serial.println(" %");
  Serial.println();

  float ht21t = htu21.readTemperature();
  float ht21h = htu21.readHumidity();
  Serial.print("HTU21 temperature = ");
  Serial.print(ht21t);
  Serial.println(" *C");
  Serial.print("HTU21 humidity = ");
  Serial.print(ht21h);
  Serial.println(" %\n");

  float tmp102t = tmp102.readTempC();
  Serial.print("TMP102 temperature = ");
  Serial.print(tmp102t);
  Serial.println(" *C\n");

  float bmp180t;
  bmp180.getTemperature(&bmp180t);
  Serial.print("BMP180 temperature = ");
  Serial.print(bmp180t);
  Serial.println(" *C");
  float bmp180p ;
  bmp180.getPressure(&bmp180p);
  Serial.print("BMP180 pressure = ");
  Serial.print(bmp180p / 100.0F);
  Serial.println(" hPa\n");

  Serial.print("BME280 temperature = ");
  Serial.print(bme280.readTemperature());
  Serial.println(" *C");
  Serial.print("BME280 pressure = ");
  Serial.print(bme280.readPressure() / 100.0F);
  Serial.println(" hPa");
  Serial.print("BME280 humidity = ");
  Serial.print(bme280.readHumidity());
  Serial.println(" %\n");

  float mcp9808t = mcp9808.readTempC();
  Serial.print("MCP9808 Temperature: ");
  Serial.print(mcp9808t);
  Serial.print(" *C\n");
  Serial.println();

  float hdc2080t = hdc2080.readTemp();
  float hdc2080h = hdc2080.readHumidity();
  Serial.print("HDC2080 temperature = ");
  Serial.print(hdc2080t);
  Serial.println(" *C");
  Serial.print("HDC2080 humidity = ");
  Serial.print(hdc2080h);
  Serial.println(" %\n");

  ds18b20.requestTemperatures();
  Serial.print("DS18B20 Temperature: ");
  Serial.print(ds18b20.getTempCByIndex(0));
  Serial.println(" *C\n");

  float dht11h = dht11.readHumidity();
  float dht11t = dht11.readTemperature();
  if (isnan(dht11h) || isnan(dht11t)) {
    Serial.println("Failed to read from DHT sensor!");
    return;
  }
  Serial.print("DH11 Temperature: ");
  Serial.print(dht11t);
  Serial.println(" *C");
  Serial.print("DH11 Humidity: ");
  Serial.print(dht11h);
  Serial.println(" %\n");

  float dht21h = dht21.readHumidity();
  float dht21t = dht21.readTemperature();
  if (isnan(dht21h) || isnan(dht21t)) {
    Serial.println("Failed to read from DHT sensor!");
    return;
  }
  Serial.print("DH21 Temperature: ");
  Serial.print(dht21t);
  Serial.println(" *C");
  Serial.print("DH21 Humidity: ");
  Serial.print(dht21h);
  Serial.println(" %\n");

  float dht22h = dht22.readHumidity();
  float dht22t = dht22.readTemperature();
  if (isnan(dht22h) || isnan(dht22t)) {
    Serial.println("Failed to read from DHT sensor!");
    return;
  }
  Serial.print("DH22 Temperature: ");
  Serial.print(dht22t);
  Serial.println(" *C");
  Serial.print("DH22 Humidity: ");
  Serial.print(dht22h);
  Serial.println(" %\n");
  float lm335v = (analogRead(LM335_PIN) * VCC) / 1023.0;
  float lm335k = lm335v * 100;
  float lm335c = lm335k - 273.15;
  Serial.print("LM335 voltage: ");
  Serial.println(lm335v, 3);
  Serial.print("LM335 Temperature: ");
  Serial.print(lm335c);
  Serial.println(" *C\n");

  Serial.println("#################################");

  delay(10000);
}

4. Les résultats

La première constatation est que les modules I2C cohabitent sans problème sur le bus. En tout 7 capteurs I2C sont utilisés.

Les résultats de mesure sont les suivants :

Module Température Humidité Pression
MAX6675 20.50°C

MAX31865 20.40°C

LM35DZ


LM335 20.47 °C

MCP9808 20.36 °C

TMP102 19.12 °C

DS18B20 20.50 °C

DHT11 20.00°C 36.00 %
AM2301 20.60 °C 32.80 %
DHT22 20.20°C 35.20 %
SHT31D 20.63 °C 32.94 %
HTU21D 20.29 °C 37.28 %
HDC2080 20.56°C 32.13%
SI7021 20.00°C 29.70%
BMP180 19.40 °C
974.60 hPa
BME280 20.62 °C 34.44 % 976.35 hPa

Si l'on considère la sonde de type K comme étant la référence en matière de mesure de température, le capteur dont la mesure s'en éloigne le plus est le TMP102, ainsi que le BMP180.

4.1. Précautions

Lorsque l'on fait un comparatif de mesure de température il faut prendre la précaution d'éloigner les capteur de toute source de chaleur - écran par exemple - et de soi-même, car le corps humain émet de la chaleur qui peut fausser les mesures, même à 30cm de distance.
Et c'est flagrant ! Le HDC2080 était au départ le capteur le plus proche de moi et donnait 1°C de trop. Après éloignement, tout est rentré dans l'ordre.

Il faut également prendre garde de placer les capteurs le plus près possible les uns des autres et ne pas avoir par exemple les capteurs enfichés sur une breadboard et une sonde PT100, K ou DS18B20 qui pend dans le vide au bord de la table, car cette sonde subira un courant d'air que les autres capteurs ne subiront pas. Cela peut produire des différences de plus d'un degré !


4.2. Le LM35DZ

Je n'ai pu tester le LM35DZ. Les exemplaires fournis ne fonctionnent pas. Ils sont sérigraphiés LM35 mais je doute qu'ils correspondent à la description. Ils fument lorsqu'on les alimente au delà de 6V, ce qui est étonnant lorsque l'on sait qu'ils supportent jusqu'à 30V.
Le LM35 est de plus inadapté à la mesure de températures inférieures à 2°, à moins de l'alimenter avec deux tensions, une positive et une négative.

4.3. Le LM335

La mesure effectuée sur le LM335 semble excellente par rapport à sa précision nominale de ±2°. Mais comme celle-ci est de ±0.5° aux alentours de 25°, il n'y a rien d'anormal.
Ce capteur devra de préférence être réservé à des mesures de températures intérieures.

La mesure est fortement dépendante de la tension de référence de l'ADC, ici le +5V (définie par VCC dans le sketch).

A température ambiante de 20° une tension de référence variant de 10mV produira une différence de mesure de 0.4° !

Autant dire qu'alimenter l'ARDUINO avec le 5V de l'USB conduira forcément à un résultat de mesure fortement erroné, la tension USB de certains hubs pouvant varier de 4.7V à 5V du jour au lendemain.

Il est possible de rendre la mesure plus fiable en utilisant deux moyens :
  • alimenter l'ARDUINO avec une tension 5V très stable et précise. La mesurer et se servir de la valeur comme référence.
  • utiliser la référence de tension interne 1.1V, après l'avoir mesurée sur la broche VREF, ou une source de tension externe.
La référence 1.1V varie en fonction de la température, ce qui complique encore les choses. Les mêmes remarques s'appliquent à tous les capteurs analogiques, le LM35DZ par exemple.

La difficulté de mise en œuvre me font largement préférer les capteurs numériques.

4.4. Le DS18B20

Le DS18B20 est un composant bon marché qui donne d'excellents résultats. De plus il existe sous la forme de sonde étanche, ce qui permet de le placer dans un environnement particulier : liquide, réfrigérateur, congélateur, etc :

5. Les capteurs de luminosité

Utiliser un module du type BH1750 permet une mesure directe de la luminosité en lux.
Le BH1750 est un composant I2C que l'on peut trouver sous forme de modules à 5 broches :
Le problème d'un tel module réside dans son intégration dans un boîtier, car le capteur doit être positionné à la surface de celui-ci. Il est possible de ménager une fenêtre transparente dans le boîtier, mais c'est tout de même une opération peu aisée.

Le format d'une LDR se prête plus facilement à une intégration mécanique :
Avec le schéma suivant, il vous sera possible d'effectuer une mesure avec un ARDUINO :

J'ai utilisé une LDR GL5528, une résistance R1 de 10KΩ et l'entrée A0 de l'ARDUINO.

A l'utilisation, une LDR permet facilement d'effectuer une mesure dans le but de comparer le résultat à un seuil de luminosité, et agir en fonction du résultat. Dans ce genre d'application, mesurer la luminosité en lux n'est pas utile. Le réglage du seuil se fait à l’œil.

Mais si vous voulez effectuer une mesure en lux, il va falloir caractériser la LDR, c'est à dire déterminer la courbe donnant la résistance de la LDR en fonction de la luminosité.
Cet article vous explique comment faire :
https://www.allaboutcircuits.com/projects/design-a-luxmeter-using-a-light-dependent-resistor/

L'auteur relève une courbe résistance LDR / luminosité.
La mesure de luminosité doit être faite avec un luxmètre, ou un BH1750 monté sur un ARDUINO, et la source de lumière doit être alimentée en tension variable (une ampoule de voiture et une alimentation de labo par exemple).

Ensuite il entre les résultats dans une feuille de calcul EXCEL (la feuille est téléchargeable).
Il en déduit une formule de calcul du type :


Votre code devrait ressembler à ceci :

#define VREF 5.0
#define RREF 10000.0
#define LUX_CALC_SCALAR 14500000
#define LUX_CALC_EXPONENT -1.405
#define NSAMPLE 10

float readLdr(void)
{
  uint32_t adc = 0;

  for (int i = 0 ; i < NSAMPLE ; i++) {
    adc += analogRead(A0);
    delay(10);
  }
  adc /= NSAMPLE;
  float voltage = VREF - (adc * VREF / 1023);
  float current = (float)adc * VREF / 1023 / RREF;
  float resistance = voltage / current;
  Serial.print("ADC: ");
  Serial.println(adc);
  Serial.print("V: ");
  Serial.println(voltage);
  Serial.print("I: ");
  Serial.println(current * 1000);
  Serial.print("R: ");
  Serial.println(resistance);
  return (LUX_CALC_SCALAR * pow(resistance, LUX_CALC_EXPONENT));
}


Une LDR donne un résultat de mesure très acceptable.

Mais il existe divers capteurs dans le commerce, allant de la LDR au capteur numérique an passant par le phototransistor.
Nous allons essayer les modules suivants :
  • BH1750
  • OPT3001
  • TSL2561
  • un phototransistor TEMT6000
  • une LDR GL5528

5.1. Les caractéristiques

Les caractéristiques de ces capteurs sont les suivantes :
 
Module Alimentation Consommation Longueur d'onde Résolution Prix
BH1750 2.4V - 3.6V 190 µA 560 nm 1 lux 1.00
OPT3001 1.6V - 3.6V 3.7µA 550 nm 0.01 lux 3.20
TEMT6000 6V maxi 50 µA 560 nm Analogique 1.00
TSL2561 2.7V - 3.6V 600µA 650 nm 1 lux 1.00
GL5528
250µA 540 nm Analogique

Ces capteurs sont parfaitement adaptés à des montages basse consommation.
Le TSL2561 et le OPT3001 possèdent une broche pouvant activer une interruption sur une broche du processeur.

5.2. Le câblage

Le câblage est réalisé comme ceci :
Le module TEMT6000 est représenté sous la forme d'un phototransistor avec sa résistance d'émetteur :
Mais on trouve facilement dans le commerce des modules tout prêts intégrant les deux composants :

5.3. L'IDE ARDUINO

Les librairies ARDUINO suivantes ont été installées :
BH1750 : https://github.com/claws/BH1750
OPT3001 : https://github.com/node-it/OPT3001.git
ADAFRUIT : https://github.com/adafruit/Adafruit_Sensor.git 
TSL2561 : https://github.com/adafruit/TSL2561-Arduino-Library.git
TSL2561 : https://github.com/adafruit/Adafruit_TSL2561.git

Avec cette dernière librairie il est possible de récupérer la luminosité par bande de spectre :
  • infra-rouge
  • visible
  • totale

5.4. Le sketch

Le sketch utilise les adresses I2C suivantes :
  • BH1750 : 0x23
  • OPT3001 : 0x44
  • TSL2561 : 0x39
#include <BH1750.h>
#include <Adafruit_Sensor.h>
#include <Adafruit_TSL2561_U.h>
#include <Opt3001.h>

#define VREF 5.0
#define RREF 10000.0
#define LUX_CALC_SCALAR 14500000
#define LUX_CALC_EXPONENT -1.405
#define NSAMPLE 10

BH1750 bh1750;
Adafruit_TSL2561_Unified tsl2561 = Adafruit_TSL2561_Unified(0x39);
Opt3001 opt3001;

float readLdr(void)
{
  uint32_t adc = 0;

  for (int i = 0 ; i < NSAMPLE ; i++) {
    adc += analogRead(A0);
    delay(40);
  }
  adc /= NSAMPLE;
  float voltage = VREF - (adc * VREF / 1023);
  float current = adc * VREF / 1023 / RREF;
  float resistance = voltage / current;
  Serial.print("ADC: ");
  Serial.println(adc);
  Serial.print("V: ");
  Serial.println(voltage);
  Serial.print("I: ");
  Serial.println(current * 1000);
  Serial.print("R: ");
  Serial.println(resistance);
  return (LUX_CALC_SCALAR * pow(resistance, LUX_CALC_EXPONENT));
}

float readTemt6000(void)
{
  uint32_t adc = 0;

  for (int i = 0 ; i < NSAMPLE ; i++) {
    adc += analogRead(A1);
    delay(40);
  }
  adc /= NSAMPLE;
  float volts = adc * VREF / 1023.0;
  float microamps = volts / RREF * 1000000;
  float lux = microamps * 1.6;
  return lux;
}

void setup()
{
  Serial.begin(115200);
  bh1750.begin(BH1750_CONTINUOUS_HIGH_RES_MODE_2);
  if (tsl2561.begin()) {
    Serial.println("Found sensor");
  } else {
    Serial.println("No sensor?");
    while (1);
  }
  tsl2561.enableAutoRange(true);
  tsl2561.setIntegrationTime(TSL2561_INTEGRATIONTIME_13MS);
  opt3001.begin();
  unsigned int readings = opt3001.readManufacturerId(); 
  Serial.print("Manufacturer ID: ");
  Serial.println(readings, BIN);

  // get device ID from OPT3001. Default = 0011000000000001
  readings = opt3001.readDeviceId(); 
  Serial.print("Device ID: ");
  Serial.println(readings, BIN);
 
  // read config register from OPT3001. Default = 1100110000010000
  readings = opt3001.readConfigReg(); 
  Serial.print("Configuration Register: ");
  Serial.println(readings, BIN);

  // read Low Limit register from OPT3001. Default = 0000000000000000
  readings = opt3001.readLowLimitReg(); 
  Serial.print("Low Limit Register: ");
  Serial.println(readings, BIN);
 
  // read High Limit register from OPT3001. Default = 1011111111111111
  readings = opt3001.readHighLimitReg(); 
  Serial.print("High Limit Register: ");
  Serial.println(readings, BIN);   
}

void loop()
{
  float ldrl = readLdr();
  Serial.print("GL5528 : ");
  Serial.print(ldrl);
  Serial.println(" lux\n");
  float temt600l = readTemt6000();
  Serial.print("TEMT6000 : ");
  Serial.print(temt600l);
  Serial.println(" lux\n");
  Serial.print("BH1750 : ");
  float bh150l = bh1750.readLightLevel();
  Serial.print(bh150l);
  Serial.println(" lux\n");
  Serial.print("TSL2561 : ");
  sensors_event_t event;
  tsl2561.getEvent(&event);
  if (event.light) {
    Serial.print(event.light);
    Serial.println(" lux\n");
  } else {
    Serial.println("Sensor overload\n");
  } 
  Serial.print("OPT3001 : ");
  uint32_t opt3001l = opt3001.readResult(); 
  Serial.print(opt3001l, DEC);
  Serial.println(" lux\n");

  Serial.println("#################################");

  delay(10000);
}

 

5.5. Les résultats


Les résultats de mesure sont les suivants :

Module Luminosité
GL5528177.70 lux
TEMT6000 187.68 lux
BH1750 183.33 lux
TSL2561 113.00 lux
OPT3001 189.00 lux

La GL5528 donne un résultat très proche du BH1750. Ceci est normal étant donné que le BH1750 a été utilisé pour caractériser cette LDR.

Le TEMT6000 utilise un code approximatif. le BH1750 a été utilisé pour caractériser ce phototransistor. Une méthode analogue à celle utilisée pour la LDR pourraît parfaitement être utilisée.

L'OPT3001 et le BH1750 donnent des résultats très comparables.

Le TSL2561 semble donner une mesure assez éloignée des autres modules. Ceci est peut-être du à sa longueur d'onde différente et à la source de lumière que j'ai utilisé : une lampe halogène, à lumière plutôt chaude.

Capteurs analogiques GL5528 et TEMT6000
La mesure à l'aide de capteurs de ce type souffre des mêmes problème que ceux évoqués plus haut, c'est à dire que la mesure est fortement tributaire de la tension de référence. Voir 4.2. Le LM335
Mais en matière de mesure de lumière nous serons certainement moins exigeants que pour une mesure de température.


6. Liens utiles

Voici quelques pages qui publient de informations et des comparatifs :

http://www.kandrsmith.org/RJS/Misc/Hygrometers/calib_many.html
https://www.geekstips.com/temperature-sensor-dht22-ds18b20-arduino-tutorial/
https://www.intorobotics.com/pick-best-temperature-sensor-arduino-project/

7. Photo

La photo des breadboards utilisées pour les tests :



8. Tests en situation réelle

J'ai actuellement en test un SHD31 à l'extérieur, et un AM2301.

Mesures actuelles :

Chez moi, officiellement (weather.com)  : 7° et 66% (à l'extérieur bien sûr)
Le AM2301 : 9.3° et 40%
Le SHT31 : 8.5 et 65%

Le SHT31 est placé sur le rebord de la fenêtre de la cuisine, ce qui explique qu'il soit un peu optimiste. Un double vitrage rayonne un peu quand même.

L'AM2301 est placé sous le linteau de la buanderie, non chauffée. La mesure de température est franchement trop optimiste. Sa mesure d'humidité est bien trop basse.
Et il a plafonné à 99% pendant les mois de décembre et janvier.

Le SHT31 me semble largement préférable aux AM2301 DHT11 DHT21.

9. Mises à jour

30/01/2019 : ajout des capteurs MAX6675 + thermocouple de type K, TMP102,
                     DHT22, HTU21D, HDC2080, OPT3001, TSL2561, TEMT6000
16/02/2019 : 8. Tests en situation réelle
06/10/2019 : ajout PT100 avec MAX31865
07/10/2019 : ajout SI7021
                     4.1. Précautions


Cordialement
Henri

mercredi 19 décembre 2018

Consommation d'une carte ARDUINO, ESP8266 ou ESP32

Consommation d'une carte ARDUINO,

ESP8266ou ESP32

Nous allons répondre à une question souvent posée sur les forums : Quelle est la consommation d'une carte ARDUINO ou d'un ESP8266 ?

1. Les conditions de mesure

J'ai utilisé le voltmètre / ampèremètre décrit ICI.

Le sketch utilisé pour la mesure en mode éveillé est celui-ci :

#define LED 13

void setup() {
  pinMode(LED, OUTPUT);
  Serial.begin(115200);
}

void loop() {
  digitalWrite(LED, HIGH);
  delay(1000);
  digitalWrite(LED, LOW);
  delay(3000);
  Serial.println("OK");
}


Le sketch utilisé pour la mesure en mode veille est celui-ci :

#include <LowPower.h>

#define LED 13

 void setup() {
  pinMode(
LED, OUTPUT);
  Serial.begin(115200);
}

void lowPowerSleep(int minutes)
{
  int seconds = minutes * 60;
  int sleeps = seconds / 8;
  for (int i = 0 ; i < sleeps ; i++) {
    LowPower.powerDown(SLEEP_8S, ADC_OFF, BOD_OFF);
  }
}

void loop() {
  lowPowerSleep(15);
  Serial.println("HELLO");
  digitalWrite(
LED, HIGH);
  delay(1000);
  digitalWrite(
LED, LOW);
}


2. La UNO

Les mesures suivantes ont été réalisées avec une carte UNO clone équipée d'un convertisseur USB / série CH340 et un régulateur 5V AMS1117.

Alimentation Mode éveillé Mode veille
USB 38mA 20mA
Broche 5V 25mA 6mA
JACK ou broche VIN (7V) 30mA 11mA

Remarque: quand la carte est alimentée autrement que par l'USB le régulateur CH340 n'est pas actif.
L'alimentation par le JACK ou la broche VIN provoque une consommation supplémentaire de 5mA due au régulateur 5V.

3. La NANO

Les mesures suivantes ont été réalisées avec une carte NANO clone équipée d'un convertisseur USB / série CH340 et un régulateur 5V AMS1117.

Alimentation Mode éveillé Mode veille
USB 29mA 13mA
Broche 5V 27mA 7.5mA
Broche VIN (7V) 32mA 12.5mA

Remarque: quand la carte est alimentée autrement que par l'USB le régulateur CH340 n'est pas actif.
Comme pour la UNO l'alimentation par le JACK ou la broche VIN provoque une consommation supplémentaire de 5mA due au régulateur 5V.

La consommation de la NANO est légèrement supérieure à celle de la UNO, mais peut s'expliquer par la dispersion de caractéristiques de composants, en particulier le régulateur AMS1117.

4. La PRO MINI

4.1. La PRO MINI 16MHz 5V

Les mesures suivantes ont été réalisées avec une carte PRO MINI 16MHz 5V clone équipée d'un régulateur marqué S8PL (non identifié).

Alimentation Mode éveillé Mode veille
Broche VCC en 5V 24mA 3.2mA
Broche RAW en 7.5V 28mA 3.22mA


4.2. La PRO MINI 8MHz 3.3V

Les mesures suivantes ont été réalisées avec une carte PRO MINI 8MHz 3.3V clone équipée d'un régulateur XC6204 (marquage 4A2D).

Alimentation Mode éveillé Mode veille
Broche VCC en 3.3V 5.6mA 1.4mA
Broche RAW en 5V 5.7mA 1.5mA


Il existe différents modèles de PRO MINI avec des régulateurs différents, et je pense que la consommation due au régulateur doit varier fortement en fonction du type de régulateur. Ici 1.4mA est une valeur assez élevée.
D'autre part la diode LED1 est alimentée également et consomme 180µA si elle est polarisée par une résistance de 10KΩ ou 380µA si elle est polarisée par une résistance de 4.7KΩ.
Avec certaines cartes, supprimer le régulateur fait économiser 70µA.

4.3. La PRO MINI bricolée

Est-il possible de consommer encore moins ?
Bien sûr : avec une PRO MINI 8MHz légèrement modifiée la consommation peut descendre à 1.5µA en mode veille.
La PRO MINI 16MHz modifiée de la même façon aura une consommation de 3µA en mode veille.

La solution est ICI.

5. La MEGA

Les mesures suivantes ont été réalisées avec une carte MEGA clone équipée d'un convertisseur USB / série CH340 et un régulateur 5V AMS1117.

Alimentation Mode éveillé Mode veille
USB 75mA 20mA
Broche 5V 61mA 7mA
Broche VIN (7V) 59mA 7.2mA

6. La DUE

Les mesures suivantes ont été réalisées avec une carte DUE CORE clone équipée d'un convertisseur USB / série natif et un régulateur 5V AMS1117.

Alimentation Mode éveillé Mode veille
USB 138mA 97mA
Broche VCC (5V) 96mA 96mA
Broche 3.3V


Le port USB natif semble consommer énormément.
Je n'ai pas trouvé le moyen de faire tourner le SAM3X8E en mode veille. Si vous envisagez une application basse consommation ne vous tournez pas vers cette plateforme.

7. L'ESP8266 et l'ESP32

Le sketch utilisé pour l'ESP8266 est celui de l'article suivant :
https://riton-duino.blogspot.com/2019/02/esp8266-sur-batterie.html

L'ESP8266 a besoin de 300mA avec des pics à 430mA pour démarrer sa connexion WIFI.

Pendant les transmissions de données, la consommation dépend de la puissance d'émission :
https://bbs.espressif.com/viewtopic.php?t=133

Dans les tableaux suivants, la consommation en mode éveillé est donnée pour une période d'inactivité (réception), le modem étant actif. Un serveur HTTP convient très bien.

7.1. L'ESP8266-12E

Les mesures suivantes ont été réalisées avec un module ESP8266-12E seul, câblé comme ceci :

Alimentation Mode éveillé Mode veille
Broche VCC en 3.3V 72mA 20µA

La consommation en mode veille autorise largement un fonctionnement sur batterie.

7.2. L'ESP01

Les mesures suivantes ont été réalisées avec une carte ESP01 dont la LED power a été retirée.

Alimentation Mode éveillé Mode veille
Broche VCC en 3.3V 72mA 18µA

Avec la LED rouge, la consommation est de 340µA en mode veille.

7.3. Les cartes NodeMCU, D1 MINI, etc.

Les mesures suivantes ont été réalisées avec une carte NodeMCU.

Alimentation Mode éveillé Mode veille
USB 80mA 11mA
Broche 5V 72mA 1mA
Broche VCC en 3.3V 72mA 92µA


L'exemplaire que j'ai testé ne possède pas de LED de mise sous tension.

Avec une WEMOS D1 MINI j'obtiens 108µA.

7.4. L'ESP-WROOM-32

Les mesures suivantes ont été réalisées avec une carte ESP-WROOM-32 dont la LED power a été retirée.

Alimentation Mode éveillé Mode veille
USB 80mA 10.75mA
Broche 5V 72mA 9.4mA
Broche VCC en 3.3V 63mA 3mA

Les cartes ESP-WROOM-32 sont implémentées de diverses manières. Celle-ci n'est visiblement pas adaptée à de la basse consommation. C'est probablement dû à la présence d'un régulateur AMS1117 sur la carte.

Un ESP32 devrait consommer 5µA en veille profonde. Certains fabricants prennent des libertés, mais cela n'empêche pas les vendeurs d'annoncer "Faible Consommation D'énergie".


La carte LOLIN32 par exemple alimentée par sa broche 3.3V consomme 1.7mA en veille.

8. Conclusion

Si les cartes ARDUINO UNO ou NANO sont intéressantes d'un point de vue pratique car disposant d'un connecteur USB permettant le téléversement et l'utilisation du moniteur série, elles restent avant tout des cartes qu'il est préférable d'alimenter par une alimentation secteur.
La PRO MINI reste imbattable en matière de consommation et pourra être alimentée par une petite batterie pour peu qu'on l'alimente en 3.3V et que l'on prenne soin de supprimer sa LED power et éventuellement son régulateur.

Les plateformes à base d'ESP8266 constituent également un bon choix pour des solutions WIFI basse consommation.

J'espère que ce petit document vous aidera dans vos choix.

Cordialement
Henri

9. Liens utiles

https://www.carnetdumaker.net/articles/test-comparatif-de-la-consommation-electrique-vide-de-diverses-cartes-arduino-et-compatible/#les-cartes-arduino-officielles

11. Mises à jour

24/02/2019 : 5. La MEGA
                     6. La DUE
                     7. L'ESP8266
25/02/2019 : 7.4. L'ESP-WROOM-32
                     ajout photos
21/04/2020 : 4. La PRO MINI 16MHz