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

J'ai utilisé une sonde PT100 3 fils Bleu Jaune Rouge, coupé le pont 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

dimanche 25 novembre 2018

Afficheur MAX7219 et RTC DS3231 sur STM32








Afficheur MAX7219 et RTC DS3231

sur STM32


J'aborde une phase cruciale de mon existence : le dernier trimestre de ma vie professionnelle.

Il m'est venu à l'idée d'afficher sur mon bureau le décompte de secondes qui va s'écouler jusqu'à ce moment tant attendu.

Une espèce de QUILLE électronique.

1. Le matériel

Qu'allons-nous utiliser comme matériel ?
Un ARDUINO avec un MAX7219 + afficheur 8x7 segments ?
Oui mais c'est trop facile. Il fallait que je fasse un petit effort supplémentaire.

J'ai donc choisi cette carte : la "petite" BLUE PILL que l'on peut trouver ICI à un prix plus qu'intéressant.

Pour le même prix qu'une NANO :
  • cœur 32bits 72MHz
  • large gamme de tension d'utilisation de 2V à 3.6V
  • 128Ko de mémoire flash
  • 20Ko de SRAM
  • RTC interne
  • unité de calcul CRC, ID unique 96 bits
  • deux convertisseurs A/N 1µs 12 bits (jusqu'à 10 voies)
  • dontrôleur DMA 7 voies, 3 timers à usage général et 1 timer de contrôle avancé
  • 37 ports E/S rapides
  • interfaces de débogage fil série (SWD) et JTAG
  • interfaces : deux SPI, deux I2C, trois USART, une USB et une CAN
  • 50% des entrées sont tolérantes au 5V

Le module MAX7219 se présente sous cette forme :
Il est câblé comme suit :
  • GND : GND
  • VCC : 3.3V
  • DIN : PA1
  • CLK : PA2
  • CS : PA3
Afin de conserver l'heure et la date en cas de coupure, un module RTC DS3231 est utilisé :
 
Il est câblé ainsi :
  • GND : GND
  • VCC : 3.3V
  • SDA : PB7
  • SCL : PB6
Le STM32 a deux I2C et l'I2C1 peut utiliser soit PB9+PB8 ou PB7+PB6 en fonction de la configuration des GPIOs.
Le problème est qu'il faudrait lire le code de la librairie core pour savoir comment tout cela est configuré.

Remarque : le STM32F103C8 possède un RTC interne et un oscillateur 32.768KHz est implanté sur la carte BLUE PILL.
Mais j'avais envie de jouer avec l'I2C. :)

2. Le logiciel

Mon intention est de faire tourner ce petit sketch :

#include <TimeLib.h>
#include <LedControl.h>
#include <Wire.h>

#define TIME_HEADER  "T"   // Header tag for serial time sync message
#define TIME_REQUEST  7    // ASCII bell character requests a time sync message 

#define LED     PC13
#define DS3231_I2C_ADDRESS  0x68

LedControl lc = LedControl(PA1, PA2, PA3, 1);

const unsigned long DEFAULT_TIME = 1543138573; // Nov 25 2018

byte decToBcd(byte val)
{
  return ((val / 10 * 16) + (val % 10));
}
// Convert binary coded decimal to normal decimal numbers
byte bcdToDec(byte val)
{
  return ((val / 16 * 10) + (val % 16));
}

void setDS3231time(int second, int minute, int hour, int wday, int day, int month, int year)
{
  Serial.println("Writing DS3231: ");
  Serial.print(day);
  Serial.print("/");
  Serial.print(month);
  Serial.print("/");
  Serial.print(year);
  Serial.print(" ");
  Serial.print(hour);
  Serial.print(":");
  Serial.print(minute);
  Serial.print(":");
  Serial.println(second);
  // sets time and date data to DS3231
  Wire.beginTransmission(DS3231_I2C_ADDRESS);
  Wire.write(0); // set next input to start at the seconds register
  Wire.write(decToBcd(second)); // set seconds
  Wire.write(decToBcd(minute)); // set minutes
  Wire.write(decToBcd(hour)); // set hours
  Wire.write(decToBcd(wday)); // set day of week (1=Sunday, 7=Saturday)
  Wire.write(decToBcd(day)); // set date (1 to 31)
  Wire.write(decToBcd(month)); // set month
  Wire.write(decToBcd(year-2000)); // set year (0 to 99)
  Wire.endTransmission();
}

void readDS3231time(int *second, int *minute, int *hour, int *wday, int *day, int *month, int *year)
{
  Serial.print("Reading DS3231: ");
  Wire.beginTransmission(DS3231_I2C_ADDRESS);
  Wire.write(0); // set DS3231 register pointer to 00h
  Wire.endTransmission();
  Wire.requestFrom(DS3231_I2C_ADDRESS, 7);
  // request seven bytes of data from DS3231 starting from register 00h
  *second = bcdToDec(Wire.read() & 0x7f);
  *minute = bcdToDec(Wire.read());
  *hour = bcdToDec(Wire.read() & 0x3f);
  *wday = bcdToDec(Wire.read());
  *day = bcdToDec(Wire.read());
  *month = bcdToDec(Wire.read());
  *year = bcdToDec(Wire.read()) + 2000;
  Serial.print(*day);
  Serial.print("/");
  Serial.print(*month);
  Serial.print("/");
  Serial.print(*year);
  Serial.print(" ");
  Serial.print(*hour);
  Serial.print(":");
  Serial.print(*minute);
  Serial.print(":");
  Serial.println(*second);
}

void processSyncMessage() {
  time_t pctime;

  if (Serial.find(TIME_HEADER)) {
    pctime = Serial.parseInt();
    Serial.print("PC TIME: ");
    Serial.println(pctime);
    if ( pctime >= DEFAULT_TIME) { // check the integer is a valid time
      setTime(pctime); // Sync Arduino clock to the time received on the serial port
      setDS3231time(second(), minute(), hour(), weekday(), day(), month(), year());
    }
  }
}

time_t requestSync()
{
  Serial.write(TIME_REQUEST);
  return 0; // the time will be sent later in response to serial mesg
}

void setup()
{
  Serial.begin(115200);
  Wire.begin();
  pinMode(LED, OUTPUT);
  lc.shutdown(0, false);
  lc.setIntensity(0, 4);
  lc.clearDisplay(0);
  setTime(DEFAULT_TIME);
  setSyncProvider(requestSync);
}

tmElements_t t = {0, 0, 0, 6, 1, 2, 2019 - 1970};

void loop()
{
  int second = 0, minute = 0, hour = 0, wday = 0, day = 0, month = 0, year = 0;

  readDS3231time(&second, &minute, &hour, &wday, &day, &month, &year);
  if (second > 59 || minute > 59 || hour > 23 | day > 31 || year > 2030) {
    Serial.println("Invalid Time");
    setDS3231time(0, 0, 0, 1, 25, 11, 2018);
  }
  setTime(hour, minute, second, day, month, year);

  time_t retirement = makeTime(t);  // convert time elements into time_t
  if (Serial.available()) {
    processSyncMessage();
  }
  lc.clearDisplay(0);
  printNumber(0, retirement - now());
  if (timeStatus() == timeSet) {
    digitalWrite(LED, LOW); // LED on if synced
  } else {
    digitalWrite(LED, HIGH);  // LED off if needs refresh
  }
  delay(1000);
}

void printNumber(int addr, long num) {
  byte c;
  int j;
  int d;
  num = abs(num);
  Serial.print(":");
  Serial.println(num);
  d = countDigits(num);
  for (j = 0; j < d; j++) {
    c = num % 10;                      // Modulo division = remainder
    num /= 10;                         // Divide by 10 = next digit
    boolean dp = (j == 3);              // Add decimal point at 3rd digit.
    lc.setDigit(addr, j, c, dp);
  }
}

int countDigits(long num) {
  int c = 0;
  if (num == 0) {
    return 1;
  }
  while (num) {
    c++;
    num /= 10;
  }
  return c;
}

Comme vous pouvez le remarquer, la différence par rapport à un sketch ARDUINO ne saute pas aux yeux.
Ceci est normal, car je l'ai développé d'abord sur une NANO.

Seules ces deux lignes diffèrent :

// version NANO
#define LED     13
LedControl lc = LedControl(12, 11, 10, 1);

// version STM32
#define LED     PC13
LedControl lc = LedControl(PA1, PA2, PA3, 1);

3. Le chargement

Comment faire pour exécuter du code ARDUINO sur un STM32 ?
Toutes les explications sont ICI.
Un petit tuto personnel pour aider pas à pas les néophytes ICI.

Le sketch utilise Wire, TimeLib et LedControl, des librairies classiques qui ne devraient à priori pas poser de problème particulier.
De plus, le Board Package "Arduino SAM Boards" utilisé pour l'installation dans l'IDE ARDUINO - qui inclut l'ARDUINO DUE - nous laisse penser que nous avons toutes les chances que cela fonctionne.

Et cela fonctionne !


1er février 00H00 :

Maintenant :

4. Mise en route

La date par défaut dans le code est la date d'aujourd'hui.
Pour mettre à l'heure le montage, il faut utiliser le moniteur série de l'IDE ARDUINO ou n'importe quel autre terminal série.
Il faut envoyer la commande suivante :

TXXXXXXXXXX 

La commande se compose de la lettre T suivie du timestamp (nombre de secondes écoulées depuis le 1/1/1970) correspondant à l'heure courante.
Si vous possédez une machine sous LINUX entrez la commande shell suivante :

expr `date +%s` + 3600

La commande affiche un nombre correspondant à l'heure GMT + 1H:

1543157582

Vous pouvez utiliser aussi ce site :

http://www.timestamp.fr/

Il vous faudra également ajouter 3600.

Copiez / collez le timestamp dans votre moniteur série :

T1543157582

Le sketch mettra alors votre RTC à l'heure ainsi que votre horloge système.

5. Conclusion

Ce petit exemple démontre que l'utilisation de librairies prévues pour les cartes ARDUINO est possible sur d'autres cartes.
L'apport des librairies ARDUINO en matière de simplification est indéniable  et permet de gagner un temps fou sur le développement logiciel.
Les développeurs ayant déjà travaillé avec les librairies STM32 de chez ST MicroElectronics savent de quoi je parle.

Cordialement
Henri

mercredi 21 novembre 2018

Les régulateurs LDO




Les régulateurs LDO


Si certains montages classiques se contentent d'un régulateur courant LM7805 ou LF33CV, la majeure partie des circuits alimentés par batterie réclament un peu plus, et même beaucoup plus.

Dans cette petite page nous allons étudier les caractéristiques essentielles des régulateurs de tension destinés à alimenter des montages peu gourmands en énergie, ceci afin de faire un choix correspondant à nos attentes. Il comporte une liste de modèles susceptibles d'être utilisés dans cette optique.

1. Présentation

Tous les montages basse-consommation à l'heure actuelle sont axés autour d'un processeur Low Power fonctionnant de manière générale en 3.3V ou moins. Nous allons nous intéresser à la catégorie des microcontrôleurs accessibles au grand public :
  • ATMEGA328P
  • STM32
  • ESP8266
  • etc.
Il arrive souvent que l'on réussisse au prix de peu d'efforts à obtenir d'un montage utilisant ces processeurs une consommation qui s'exprime en µA ou en dizaines de µA. Malheureusement, ces processeurs ou leurs périphériques ne supportent en général pas que l'on se permette de les alimenter avec une tension supérieure à 3.6V ou 4V.

Que faire lorsque l'on ne dispose pour ce faire que d'une batterie LITHIUM-ION, LIFEPRO ou NI-MH ?
La courbe de décharge d'une batterie LITHIUM-ION part de 4.2V à pleine charge et se termine aux environs de 3V, tension en dessous de laquelle il est déconseillé de descendre, sous peine de réduire la durée de vie de celle-ci.

Un ATMEGA328P cadencé à 8MHz supportera jusqu'à 6V et pourra espérer fonctionner jusqu'aux environs de 2.7V. On pourra donc l'alimenter directement avec une batterie LITHIUM-ION, sans régulateur.
Mais ce n'est pas le cas d'autres processeurs, ou de certains modules ou circuits périphériques destinés à les servir.

Un exemple typique est le NRF24L01, un module radio qui doit être alimenté au maximum sous 3.6V.

C'est aussi le cas des STM32 et ESP8266, limités eux aussi à 3.6V.

Il faut impérativement limiter la tension d'alimentation fournie par la batterie. Et pour ce faire, nous aurons besoin d'un régulateur.

Quelles qualités doit-on attendre d'un régulateur destiné à alimenter un montage basse consommation ?
 

2. Courant de sortie

Bien entendu notre régulateur devra fournir le courant de sortie nécessaire à notre montage.

Un ATMEGA328P et un NRF24L01 pourront se contenter de 50mA.
Un ESP8266 devra être alimenté avec un régulateur capable de fournir les 430mA nécessaires au démarrage de sa connexion WIFI.

3. Quiescent current

Bien entendu la deuxième caractéristique essentielle semble être le courant consommé par le régulateur lui-même, sans qu'il soit chargé, dit "quiescent current". A quoi servirait-il d'alimenter un montage consommant 5µA avec un régulateur LM7833 consommant 4.5mA au repos ?

Il ne faut pas focaliser son choix sur les modèles ayant un quiescent current extrêmement bas, car souvent la batterie que vous allez choisir aura un courant de fuite supérieur à celui-ci. Un jeu de piles aura plus de chances d'avoir un courant de fuite suffisamment bas pour justifier l'emploi d'un tel régulateur.

4. Drop Out Voltage

La dernière caractéristique essentielle est la valeur de la chute de tension provoquée par le régulateur.
Pour en revenir au LM7833, celui-ci a une tension de drop-out de 2V. Alimenter notre montage à partir d'une batterie 3.7V à travers un tel régulateur réduirait à néant nos efforts, car il nous resterait une petite tension de 1.7V à sa sortie.

Un régulateur ayant une tension de drop-out de 200mV sera capable  d'alimenter votre montage jusqu'à ce que la tension de la batterie descende au plus bas. Une batterie LITHIUM-ION dont la tension la plus basse est de 3V pourra dans de bonnes conditions alimenter un ATMEGA328P car il restera dans le pire des cas 2.8V.

Comment va se comporter un régulateur lorsque sa tension d'entrée chute en dessous de sa tension de sortie nominale ?
Sa tension de sortie va chuter elle aussi. Sa valeur sera égale à celle de la tension d'entrée diminuée de la tension de drop-out. Mais il y a une limite basse. La datasheet vous renseignera de toutes façons sur la tension minimale en dessous de laquelle il ne faut pas descendre.

Remarque concernant le 7133-1: lorsque sa tension d'entrée descend en dessous de sa tension nominale, la chute de tension provoquée par le régulateur est ridicule : 1mV pour 60µA !
Ce régulateur est particulièrement intéressant lorsque l'on travaille avec une batterie LITHIUM-ION 3.7V ou NI-MH 3.6V avec de faibles courants.
Il équipe les fameux détecteurs de passage HC-SR501.

Attention : la tension de drop-out est toujours indiquée pour un courant donné.
Par exemple un ME6211 3.3V :
  • 120mV pour 100mA
  • 260mV pour 200mA
La datasheet vous fournira généralement une courbe :



Autre exemple, le RT9013 3.3V :
  • 160mV pour 400mA
  • 250mV pour 500mA
On voit donc que la tension de drop-out augmente avec le courant. Certains modules, même s'ils sont capables de fonctionner en mode veille avec quelques µA ou dizaines de µA, nécessitent un courant élevé pour pouvoir démarrer.
C'est le cas de l'ESP8266, qui a besoin de 300mA avec des pics à 430mA pour démarrer sa connexion WIFI :
https://www.ondrovo.com/a/20170207-esp-consumption/
Avec une batterie chargée à 3.7V, la tension de sortie d'un régulateur ME6211 chutera à 3.7V - 550mV = 3.15V.
Avec un RT9013 elle sera de 3.7V - 250mV = 3.55V. Le régulateur limitera à 3.3V

Autre remarque : il semblerait que l'ESP8266 soit capable de démarrer à partir de 2.5V.
Avec un régulateur RT9013, la tension de la batterie pourra chuter au maximum à 2.75V (ce n'est cependant pas recommandé).
Avec un régulateur ME6211, celle-ci pourra chuter au maximum à 3.05V.

Il est possible d'associer un gros condensateur de 1000µF ou plus, en parallèle sur la sortie du régulateur, pour fournir les pics de courant nécessaires, si le régulateur n'est pas capable de les fournir. Mais il semble illusoire qu'un régulateur fournissant 250mA puisse être utilisé.

5. La liste 

La liste qui suit n'est pas exhaustive, loin de là, mais elle est régulièrement enrichie.
 

Les régulateurs sont classés par tension de drop-out croissante.
La tension mini en entrée est celle qu'il vous faudra appliquer pour obtenir 3.3V en sortie.
 

Nous nous intéresserons ici uniquement aux modèles exploitables par les amateurs que nous sommes, en excluant ceux dont les boîtiers sont trop exotiques, tels les DFN par exemple.
 

Comme vous pouvez le remarquer, rares sont les modèles qui pourront vous offrir une tension de drop-out très basse et également un courant de repos très bas. Il faut souvent choisir un compromis.



A titre indicatif, le deuxième onglet donne une courte liste de régulateurs 5V.

Les fameux AMS1117 et LM7833 ne sont présents qu'à titre d'exemple de ce qu'il ne faut pas employer bien entendu. Avec de tels régulateurs votre batterie de 1000mAH serait vide au bout de 200 heures.

Les régulateurs ayant une tension de dropout de 600mV vous obligeront à adopter une tension d'alimentation supérieure, au delà de 3.9V, 4 batteries AA par exemple.
Pour un régulateur ayant une tension de dropout de 2V, une alimentation d'au moins 5.3V sera nécessaire. 5 batteries AA ou 2 batteries 18650 par exemple.

5. Mesurer la tension batterie

Ceci est un peu hors sujet mais il vous faudra prévoir une mesure périodique de la tension batterie en amont du régulateur afin d'éviter que celle-ci ne chute en dessous de 3V (pour une LITHIUM-ION).
Tous les processeurs cités ici possèdent un ADC. Il est intéressant de l'utiliser afin de réaliser cette opération.
Cet article montre comment mesurer une tension batterie à l'aide d'un pont diviseur :
Le sketch du projet permet de calculer la capacité restante et de la remonter par liaison radio à un serveur domotique (DOMOTICZ dans mon cas).

On peut facilement développer la même solution sur un ESP8266 ou un ESP32.

L'essentiel est de pouvoir visualiser à distance le résultat pour pouvoir le consulter.

Il est possible également de faire clignoter une LED rouge avec des flashs de très courte durée espacés de quelques dizaines de secondes. La tension de seuil sera par exemple de 3.35V, ce qui correspond à environ 20% de capacité restante.
Le courant dans la LED devra être suffisamment faible pour ne pas décharger la batterie à l'excès et suffisamment fort pour que les flashs se remarquent

6. Trier ses régulateurs

Dans un lot de régulateurs les dispersions de caractéristiques peuvent être importantes. Il peut même arriver que le composant acheté ne soit pas du tout le modèle annoncé, malgré une sérigraphie correcte.

Sur un lot de 20 régulateurs HT7533-1 achetés sur AliExpress j'ai pu remarquer que le courant sans charge (quiescent current) était dans la fourchette de la datasheet pour la majorité d'entre eux : 2.5µA - 5µA.
Un seul régulateur était très au dessus : 30µA
Quelques-uns étaient en dessous : 1.2µA.

Lorsque l'on recherche un régulateur très performant, un petit tri s'impose.

7. Conclusion

J'espère que ce document vous aura aidé à éclairer votre choix en matière de régulateur pour votre future réalisation basse consommation.


Cordialement
Henri

8. Mises à jour

25/06/2019 : 6. Trier ses régulateurs
12/07/2019 : liste de régulateurs 5V