BH1750 mit Kabel und GY-302

Lichtsensor BH1750

Zum Messen der Stärke des Umgebungslichts gibt es viele verschiedene Sensoren. Dieser Beitrag stellt den BH1750 vor, der die Beleuchtungsstärke in Lux misst und seine Messungen digital über den I2C-Bus an einen Mikrocontroller ausgibt. Er ist für die Nutzung mit Arduino & Co. meist in zwei Varianten zu finden: als Modulplatine GY-302 (oder GY-30) mit fünf Anschlüssen oder als Modul in einer transparenten, halbkugelförmigen Kunststoff-Kappe, das mit einem 5-poligen JST-Stecker (XH 2.54) angeschlossen wird.

Ein wenig Physik

Der Sensor enthält eine Fotodiode, die Licht in einem Frequenzbereich von ca. 400 – 700 Nanometern (nm) registriert; die höchste Empfindlichkeit liegt bei 560 nm. Das entspricht im wesentlichen dem Spektrum, das für das menschliche Auge sichtbar ist, nämlich Licht im Bereich von ca. 380 nm (Violett) bis 780 nm (Rot). [1]siehe Wikipedia: Elektromagnetisches Spektrum

Der BH1750 misst die Beleuchtungsstärke (Maßeinheit: Lux bzw. lx) – das ist der Lichtstrom pro Flächeneinheit, d.h. laienhaft formuliert, wie viel für das menschliche Auge sichtbares Licht auf eine Fläche fällt. Da die Beleuchtungsstärke quadratisch mit der Entfernung abnimmt, erscheint dem Auge eine Kerze in der Nähe meist heller als z.B. die viele Meter entfernte Straßenbeleuchtung. Die Beleuchtungsstärke ist also kein Maß für das von einer Lichtquelle abgestrahlte Licht (das ist die Lichtstärke), sondern für das, was beim Auge ankommt.

Ein paar Beispielangaben zu Beleuchtungsstärken und Links zu Wikipedia-Artikeln enthält der Beitrag zum analogen Lichtsensor TEMT6000 – ich spare mir hier die Wiederholung.

Datenblatt und technische Daten

Die vollständige Bezeichnung des Sensors lautet BH1750FVI; der Hersteller ist ROHM Semiconductor.

Datenblatt bei Mouser Electronics: www.mouser.de/datasheet/2/348/Rohm_11162017_ROHMS34826-1-1279292.pdf [2]Auf der Website des Herstellers ist kein Datenblatt zum BH1750 verlinkt.

  • Versorgungsspannung VCC: 3,3 – 5 V [3]Das rote Modul mit der Kunststoffkappe wird bei den allermeisten Anbietern nur als 5-Volt-tauglich beschrieben. Bei mir hat es auch problemlos am gleichen I2C-Bus wie das „blaue” Modul … Continue reading
    Auf den Platinen befindet sich ein Spannungsregler – Beschriftung 662K –, der bei Sensoren für Mikrocontroller häufig zum Einsatz kommt.
  • I2C-Adresse: 0x23 (alternativ 0x5C)
  • geringe Messabweichung: ±20%
  • Obergrenze des Messbereichs: je nach eingestelllter Auflösung von rund 7.400 bis ca. 120.000 lx (siehe Beschreibung der Bibliothek)
  • Auflösung: 0,11 – 7,4 lx (je nach Messqualität; siehe Beschreibung der Bibliothek)
  • 3 Qualitätsstufen:
    • LOW: Messbereich 0 – 121.557 lx; Auflösung 0,9 – 7,4 lx (Aufl. 0,9 bis max. 14.836 lx)
    • HIGH: Messbereich 0 – 121.557 lx; Auflösung 0,23 – 1,85 lx (Aufl. 0,23 bis max. 14.836 lx)
    • HIGH2: Messbereich 0 – 60.778 lx; Auflösung 0,11 – 0,9 lx (Aufl. 0,11 bis max. 7.418 lx)

Der BH1750 ist für die Nutzung mit Mikrocontrollern in mehreren Varianten erhältlich: ich besitze eine (blaue) Modulplatine GY-302 mit fünf Anschlusspins und ein (rotes) Modul in einer transparenten Kunststoff-Kappe mit einer 5-poligen JST-Buchse (XH 2.54). Es gibt auch ein Modul GY-30, das etwa doppelt so groß wie das GY-302 ist, und andere Module wie das von Adafruit angebotene.

Beide Varianten sind bei Elektronik-Versendern in D ab ca. 3 € zu bekommen (mit viel Spielraum nach oben); in China zahlt man meist zwischen 1 und 3 €.

  • Maße der GY-302-Platine: ca. 13 mm * 18 mm
  • Maße des Moduls mit Kunstoffkappe: Außendurchmesser der Kappe ca. 28 mm (inkl. Rand, ohne Rand ca. 26 mm); Höhe bis Buchsenkante: ca. 21 mm; Platinendurchmesser ca. 21,5 mm

Die Kappe des „roten” Moduls schluckt viel Licht (in etwa die Hälfte; siehe unten), schützt die Platine aber vor Feuchtigkeit.

Anschlüsse des BH1750 (I2C-Schnittstelle)

Der Sensor kommuniziert per I2C-Protokoll; neben den üblichen Anschlüssen kann über einen Adress-Pin die I2C-Adresse eingestellt werden. Je nachdem, ob man ADDR mit Masse oder Spannung verbindet, nutzt der Sensor folgende Adresse:

  • LOW (max. 0,3 * VCC) → 0x23
  • HIGH (min. 0,7 * VCC) → 0x5C

Die GY-302-Platine wird mit loser Pinleiste geliefert, d.h. man muss die Anschlusspins selbst anlöten. Eine Beschriftung ist nur auf der Unterseite der Platine vorhanden.
Zum „roten” Modul mit Kappe wird ein passendes Adapterkabel (JST-Stecker an Jumperkabeln mit Female-Anschlüssen) mitgeliefert – Löten ist nicht erforderlich. Die Platine ist nur in die Kappe gepresst (nicht geklebt) – man kann sie vorsichtig herausdrücken.

Beide Module haben folgende Anschlüsse, die auf den Bildern gleich nummeriert sind – wichtig ist, auf die unterschiedliche Reihenfolge zu achten.
Die Tabelle zeigt die Reihenfolge jeweils von links nach rechts (die Beschriftung auf dem roten Modul läuft aber von rechts – Pin 1 – nach links – Pin 5):

BH1750 Modul (Pin-Beschriftung)
BH1750 Modul
BH1750 mit JST-Stecker
BH1750 mit JST-Stecker
GY-302 (blau) Modul mit Kappe (rot)
Funktion Funktion Farbe
1 VCC (Spannung) 5 ADDR (I2C-Adresse) gelb
2 GND (Masse) 2 GND (Masse) schwarz
3 SCL (Takt) 4 SDA bzw. DAT (Daten) weiß
4 SDA (Daten) 3 SCL (Takt) braun
5 ADDR (I2C-Adresse) 1 VCC (Spannung) rot

Bibliothek hp_BH1750

Die Bibliothek hp_BH1750 ist eine weit verbreitete Bibliothek zur Programmierung des BH1750.[4]Sogar die Entwickler von Adafruit haben für ihr BH1750-Modul keine eigene Bibliothek programmiert, sondern empfiehlt ausdrücklich die hp_BH1750-Library. Man kann sie über die Arduino-Bibliotheksverwaltung installieren (Suchbegriff z.B. »bh1750« – dann wird auch eine Anzahl weiterer Bibliotheken aufgelistet) oder direkt von Github herunterladen: github.com/Starmbi/hp_BH1750.

Die Bibliothekt ist sehr umfangreich und enthält auch Funktionen, um tief in die Funktion des Sensors einzugreifen, weshalb sich auf jeden Fall ein Blick in die ausführliche Dokumentation im Wiki lohnt. Dort findet man die Beschreibung aller Funktionen und Einstellungen sowie Beispielcode. Außerdem werden bei der Installation der Bibliothek mehrere Beispielprogramme mitinstalliert (in der Arduino-IDE im Menü Datei → Beispiele - Beispiele aus eigenen Bibliotheken → hp_BH1750).

Nutzt man die von der Bibliothek bereitgestellte sog. „Autoranging”-Funktionalität, verwendet man immer die bestmögliche Messqualität, womit sich die Auflösung des Sensors von 16 auf 20 Bit steigern lässt. Das ist sicher für viele Einsatzzwecke nicht nötig, aber vielleicht manchmal hilfreich.

Wie die Bespielprogramme zeigen, muss man sich nicht mit der Einstellung der Qualität und vor allem mit den Timings der Messungen befassen – man kann es zwar tun, aber meist wird man das wohl die Bibliothek automatisch im Hintergrund erledigen lassen.

Grundlegende Funktionen

Für einfache Messungen genügen wenige Basisfunktionen, die unten im ersten Beispielprogramm verwendet werden. Es sind:

  • begin() – initialisiert den Sensor; als Parameter wird die Verbindung des Adress-Pins übergeben, um darüber die I2C-Adresse zu bestimmen
    • BH1750_TO_GROUND: LOW, Verbindung mit Masse → Adresse 0x23
    • BH1750_TO_VCC: HIGH, Verbindung mit der Versorgungsspannung → Adresse 0x5C;

    optional kann als zweiter Parameter ein TwoWire-Objekt übergeben werden, wenn man nicht die Standard-GPIOs für die I2C-Schnittstelle des Mikrocontrollers verwendet.

  • start(): startet eine Messung; am einfachsten ist es, mit den Standardwerten zu arbeiten und/oder das Autoranging zu nutzen (in beiden Fällen ruft man die Funktion ohne Parameter auf).
  • getLux(): liest den Messwert in Lux als Fließkommazahl (float) aus.

Die Funktion getLux() ist blockierend, d.h. sie wartet so lange, bis die mit start() angestoßene Messung einen Wert liefert – das kann je nach gewählter Genauigkeit zwischen weniger als 1/100 bis rund ½ Sekunde dauern, und in dieser Zeit kann der Prozessor keine weiteren Aktionen durchführen. Bei einfachen Programmen, die alle paar Sekunden eine Messung machen und dann in Abhängigkeit vom Helligkeitswert eine Aktion durchführen (z.B. eine Lampe an- oder ausschalten), ist das nicht von Bedeutung.

Weitergehende Funktionen

Beim Starten einer Messung kann man die gewünschte Qualität einstellen.

  • start(): startet eine Messung
    • Mit zwei optionalen Parametern kann man die Qualität einstellen, die so lange beibehalten wird, bis etwas anderes eingestellt wird; man muss beide Parameter setzen oder keinen.
    • Der erste Parameter steuert die Qualität: BH1750_QUALITY_LOW, BH1750_QUALITY_HIGH oder BH1750_QUALITY_HIGH2;
    • der zweite beeinflusst das Timing der Messungen; möglich sind Werte zwischen 31 und 254 (BH1750_MTREG_LOW und BH1750_MTREG_HIGH); gibt man einen zu kleinen oder zu großen Wert an, verwendet die Bibliothek den kleinsten oder größten gültigen Wert.
    • Will man ausdrücklich in niedriger Qualität messen, kann man start(BH1750_QUALITY_LOW, BH1750_MTREG_LOW) verwenden.
    • Verwendet man das Autoranging, d.h. die Funktion adjustSettings(), ruft man start() ohne Parameter auf.
    • Zu den Details siehe die Dokumentation.

Wenn das Programm bzw. der Mikrocontroller außer der Durchführung der Messungen des BH1750 noch andere Arbeiten erledigen soll, kann (bei höchster Messgenauigkeit) eine Wartezeit von ½ Sekunde auf den Abschluss der Messung zu lang sein. Dann hilft folgende Funktion weiter, um das nicht-blockierende Lesen des Messwerts zu steuern:

  • hasValue(): liefert TRUE, wenn eine mit start() angestoßene Messung durchgeführt wurde und ein neuer Messwert zur Verfügung steht – in diesem Fall kann er sofort mit getLux() ausgelesen und mit start() die nächste Messung angestoßen werden; ist die Messung noch nicht komplett, wird FALSE zurückgegeben – dann kann das Programm (ohne zu blockieren) erst einmal andere Aufgaben erledigen und im nächsten Durchlauf erneut prüfen, ob die Messung erledigt ist
  • calibrateTiming(): ermittelt die für jeden Sensor individuellen Antwortzeiten für verschiedene Messgenauigkeiten.
    • So können bei „guten” Sensorchips deutlich schnellere Messungen durchgeführt werden als mit den Standardwerten („langsame” Sensoren benötigen bis zu bis zu 50 % mehr Zeit als schnellere; Ursache sind Toleranzen bei der Fertigung).
    • Am einfachsten ist es, die Kalibrierung einmal zu Programmbeginn in der setup()-Routine durchzuführen. [5]Die Timings sind zwar für jeden Sensorchip individuell, ändern sich aber nicht. Zu den Details siehe die Bibliotheks-Dokumentation im Abschnitt Working Principle. Wenn gewünscht, kann man sie … Continue reading
    • Zum Kalibrieren muss etwas Licht vorhanden sein (mind. 0,9 Lux; für optimale Ergebnisse max. 14.800 Lux – also kein allzu helles direktes Tages-/Sonnenlicht). Schlägt das Kalibrieren fehl, arbeitet der Sensor mit den Standardwerten.
    • Eine Kalibrierung wird nicht benötigt, wenn Messwerte nur blockierend gelesen werden, d.h. hasValue() nicht benutzt wird.
  • saturated(): überprüft, ob die letzte Messung einen für die eingestellte Genauigkeit zu hohen Messwert ergeben hat („Sättigung”).
  • adjustSettings(): implementiert die automatische Anpassung der Messgenauigkeit, sodass immer mit der bestmöglichen Genauigkeit gemessen wird – das oben erwähnte Autoranging.
    • Ausgehend vom letzten Messwert wird ein Intervall für die nächste Messung festgelegt; das ist insbes. wichtig, wenn man mit saturated() ein Überschreiten der maximal messbaren Helligkeit festgestellt hat.
    • Man übergibt (optional; als ersten Parameter) eine Prozentangabe, die das neue Messintervall an das Ergebnis der letzten Messung anpasst. Der Standardwert 50 legt das Intervall so fest, dass sich der letzte Messwert genau in der Mitte befindet. Gibt man einen höheren Wert an (bspw. 80 oder 90), schiebt das die Obergrenze des Messintervalls nur wenig über den letzten Messwert hinaus. Das erhöht die Messgenauigkeit (weil erst später auf eine niedrigere Auflösung umgeschaltet wird), kann aber dazu führen, dass bei ansteigenden Messwerten nicht ausreichend Spielraum nach oben ist und die nächste Messung zu einem gesättigten Messwert führt.
    • Um das zu vermeiden, kann man mit dem zweiten Parameter steuern, ob vor der eigentlichen Messung eine schnelle Testmessung in niedrigster Qualität erfolgen soll. Das ist vor allem dann sinnvoll, wenn die Messwerte stärker schwanken, z.B. weil zwischen einzelnen Messungen längere Zeit (mehrere Sekunden) vergeht.
    • adjustSettings() schaltet bei Bedarf zwischen den Auflösungen HIGH und HIGH2 um. Hat man im Programm die Qualität LOW eingestellt, wird diese von adjustSettings() nicht verändert.
    • Zu den Details siehe die Dokumentation.

Weiter unten folgt ein ausführlicheres Beispiel, das mit zwei Sensoren arbeitet und das Kalibrieren und das nicht-blockierende Lesen zeigt.
Will man ein paar Einstellungen ausprobieren, bietet sich das mitinstallierte Beispielprogramm Testsuite.ino an – damit kann man interaktiv über Eingaben im seriellen Monitor an einigen Parametern des Sensors „drehen”.

In allerhöchster Qualität (HIGH2; Auflösung 0,11 lx) misst der BH1750 Werte bis 7.418 lx, mit etwas niedrigerer Auflösung (zwischen 0,11 und 0,93 lx) bis zu 60.788 lx. Werte darüber bis max. 121.557 lx muss man in hoher Qualität (HIGH; halb so gut wie HIGH2, aber mit doppelt so hohem Wertebereich) oder niedriger Qualität (LOW; Auflösung 0,9 – 7,4 lx) messen. Messungen in Qualität LOW lösen nur ein Viertel so gut auf wie in Stufe HIGH, werden aber dafür fast 8 mal schneller ausgeführt. (Zu den Details siehe Autoranging in der Dokumentation.)
Will man nur grob abgestufte Helligkeitsstufen messen (wie es z.B. bei der Einstellung der Display-Helligkeit eines Smartphones erfolgt), reichen Messungen der Qualitätsstufe LOW völlig aus (und sind mit weniger als einer Hundertstel Sekunde Dauer sehr schnell).
Für genauere Messungen (Qualität HIGH oder HIGH2) muss man sich um die Feinheiten (Anpassen der Auflösung) nicht selbst kümmern – wenn man will, erledigt das die oben erwähnte Bibliotheksfunktion adjustSettings().

Programm 1: Einfaches Auslesen der Sensorwerte

Das folgende Programm zeigt die Basisfunktionen, die zum einfachen Auslesen der Messwerte des BH1750 benötigt werden. Es liest einen Messwert, gibt ihn in den seriellen Monitor aus, wartet ein paar Sekunden usw. usf.

  1. /* Lichtsensor BH1750
  2.  * (Basisfunktionen zum Auslesen der Messwerte)
  3.  *
  4.  * 2021-08-22 Heiko (unsinnsbasis.de)
  5.  */
  6. #include <Arduino.h>
  7.  
  8. // Bibliothek und Sensor-Objekt für den BH1750
  9. #include <hp_BH1750.h>
  10. hp_BH1750 BH1750;
  11.  
  12. void setup() {
  13.   Serial.begin(115200);
  14.   delay(500);
  15.   Serial.println("Lichtsensor BH1750 - Messwerte ausgeben");
  16.  
  17.   // Init des BH1750 (Standard-I2C-Adresse; ADDR ist mit Masse verbunden)
  18.   if (! BH1750.begin(BH1750_TO_GROUND)) {
  19.     Serial.println("Fehler beim Initialisieren des BH1750");
  20.     while(1);  // unendliche Schleife -> Programm nicht forsetzen
  21.   }
  22. }
  23.  
  24. void loop() {
  25.   float lux;
  26.  
  27.   BH1750.start();   // Start einer Messung
  28.     // Messwert lesen (wartet, bis die Messung erledigt ist)
  29.   lux = BH1750.getLux();
  30.  
  31.   Serial.print("BH1750: ");
  32.   Serial.print(lux,2);
  33.   Serial.println(" lx");
  34.  
  35.   delay(5000);
  36. }

Quellcode auf Github

Programm 2: Weitere Funktionen, nicht-blockierendes Lesen

Das zweite Programm nutzt die anderen oben erwähnten Funktionen und zeigt, wie das nicht-blockierende Lesen funktioniert.
Hierzu habe ich beide Sensoren an die Standard-I2C-GPIOs des ESP32 (SDA = GPIO21, SCL = GPIO 22) angeschlossen. (Die Masse- und Spannungsversorgung des GY-302-Moduls erfolgt mit Steckbrücken unterhalb des Moduls und ist deshalb auf dem Bild nicht zu erkennen.)

Beide Sensoren messen in jeweils höchstmöglicher Frequenz; in höchster Qualität bedeutet das 2, in niedrigster Qualität rund 100 Messungen pro Sekunde. Um nicht zuviele Daten in den seriellen Monitor auszugeben, macht das Programm nur bei einer Änderung der Messwerte eine Ausgabe.

Zwei BH1750-Sensoren am ESP32
Zwei BH1750-Sensoren am ESP32

Das blaue GY-302-Modul nutzt das Autoranging und misst mit höchster Qualität. Das andere (rote) Modul misst schnellstmöglich in niedrigster Qualität und Auflösung; in diesem Fall ist kein Autoranging zur Anpassung der Auflösung nötig; eine Sättigung kann nur in extremem Sonnenschein (> 121.000 lx) auftreten, was im norddeutschen Spätsommer eher nicht zu erwarten ist.

  1. /* Lichtsensoren am ESP32
  2.  * Vergleich der beiden BH1750-Varianten
  3.  * - nicht-blockierendes Lesen
  4.  * - verschiedene Qualitätsstufen, "Autoranging"
  5.  * - blaues Modul GY-302 an I2C-Adr. 0x23
  6.  * - rotes Modul mit Kappe an I2C-Adr. 0x5C
  7.  *
  8.  * 2021-08-25 Heiko (unsinnsbasis.de)
  9.  */
  10. #include <Arduino.h>
  11.  
  12. // Bibliothek und Sensor-Objekte für den BH1750
  13. #include <hp_BH1750.h>
  14. hp_BH1750 BH1750_blue, BH1750_red;
  15.  
  16.     // Dauer der Messungen in Millisekunden
  17. long ms_blue, ms_red;
  18.    // letzter Messwert des jew. Sensors für Vergleich
  19. float lux_blue, lux_red;
  20.  
  21.  
  22. void setup() {
  23.   int rc;  // Returncode
  24.   long m;  // Millisekunden zum Kalibrieren der Sensoren
  25.  
  26.   Serial.begin(115200);
  27.   delay(500);
  28.   Serial.println("Lichtsensoren BH1750 - Vergleich (mit Kappe)");
  29.  
  30.   // Init des BH1750 (mit der Standard-I2C-Adresse)
  31.   if (! BH1750_blue.begin(BH1750_TO_GROUND)) {
  32.     Serial.println("Fehler beim Initialisieren des BH1750 GY-302");
  33.   } else {
  34.     m = millis();
  35.     rc = BH1750_blue.calibrateTiming();
  36.     m = millis() - m;
  37.     Serial.print("Blauer BH1750 GY-302 wurde kalibriert (Dauer: ");
  38.     Serial.print(m);
  39.     Serial.print(" ms)");
  40.     if (rc != 0) {
  41.       Serial.print(" - Fehlercode ");
  42.       Serial.print(rc);
  43.     }
  44.     Serial.println();
  45.   }
  46.  
  47.   // Init des zweiten BH1750 (I2C-Adresse 0x5C)
  48.   if (! BH1750_red.begin(BH1750_TO_VCC)) {
  49.     Serial.println("Fehler beim Initialisieren des roten BH1750");
  50.   } else {
  51.     m = millis();
  52.     rc = BH1750_red.calibrateTiming();
  53.     m = millis() - m;
  54.     Serial.print("Roter BH1750 wurde kalibriert (Dauer: ");
  55.     Serial.print(m);
  56.     Serial.print(" ms)");
  57.     if (rc != 0) {
  58.       Serial.print(" - Fehlercode ");
  59.       Serial.print(rc);
  60.     }
  61.     Serial.println();
  62.   }
  63.   // jeweils erste Messung (und Zeitmessung) starten
  64.   lux_blue = -1;  // kein Vergleichswert vorhanden
  65.   BH1750_blue.start();
  66.   ms_blue = millis();
  67.     // der rote misst in niedriger Qualität; der zweite Parameter wird 
  68.     // ggf. auf den kleinsten gültigen Wert gesetzt (BH1750_MTREG_LOW = 31)
  69.   lux_red = -1;  // kein Vergleichswert vorhanden
  70.   BH1750_red.start(BH1750_QUALITY_LOW, 1);
  71.   ms_red = millis();
  72. }
  73.  
  74. // ------------------------------------------------------------
  75.  
  76. void loop() {
  77.   float lux;
  78.  
  79.   // wenn der "blaue" Sensor eine Messung durchgeführt hat,
  80.   // wird das Ergebnis ausgegeben
  81.   // da die Messungen recht schnell erfolgen (insbes. in niedriger
  82.   // Qualität), wird der Wert nur bei einer Änderung ausgegeben
  83.   if (BH1750_blue.hasValue()) {
  84.     ms_blue = millis() - ms_blue;  // Zeit stoppen
  85.     // falls der Sättigungswert erreicht ist, wird die Messung
  86.     // verworfen / nicht angezeigt)
  87.     if (!BH1750_blue.saturated()) {
  88.       lux = BH1750_blue.getLux();
  89.         // gestoppte Zeit und Messwert ausgeben, wenn sich der Wert geändert hat
  90.       if (lux != lux_blue) {
  91.         lux_blue = lux;
  92.         Serial.print("blau (");
  93.         Serial.print(ms_blue);
  94.         Serial.print(" ms): ");
  95.         Serial.print(lux);
  96.         Serial.println(" lx");
  97.       }
  98.     }
  99.       // Intervall für die nächste Messung anpassen
  100.     BH1750_blue.adjustSettings(90);
  101.       // nächste Messung starten
  102.     BH1750_blue.start();
  103.     ms_blue = millis();
  104.   }
  105.  
  106.   // analoges Vorgehen für den "roten" Sensor
  107.   // - eine Anpassung des Messintervalls ist in niedrigster
  108.   //   Qualität und Auflösung nicht nötig
  109.   if (BH1750_red.hasValue()) {
  110.     ms_red = millis() - ms_red;  // Zeit stoppen
  111.     // falls der Sättigungswert erreicht ist, wird die Messung
  112.     // verworfen / nicht angezeigt)
  113.     if (!BH1750_red.saturated()) {
  114.       lux = BH1750_red.getLux();
  115.         // gestoppte Zeit und Messwert ausgeben, wenn sich der Wert geändert hat
  116.       if (lux != lux_red) {
  117.         lux_red = lux;
  118.         Serial.print("rot  (");
  119.         Serial.print(ms_red);
  120.         Serial.print(" ms):\t\t");
  121.         Serial.print(lux);
  122.         Serial.println(" lx");
  123.       }
  124.     }
  125.       // nächste Messung starten
  126.     BH1750_red.start();
  127.     ms_red = millis();
  128.   }
  129. }

Quellcode auf Github

Die folgenden Ausgaben aus dem seriellen Monitor (während der Abenddämmerung) zeigen leichte Änderungen der Messwerte des „blauen” Sensors, der in hoher Qualität misst, während die Messungen in niedriger Qualität immer wieder etwas springen, wenn ein bestimmter Helligkeitswert sich noch nicht stabilisiert hat. Danach sind dessen Werte dann eine gewisse Zeit stabil, d.h. es erfolgt keine Ausgabe in den seriellen Monitor.

Man sieht deutlich den Unterschied in der Dauer der Messungen bei höchster und niedrigster Qualität: 448 vs. 8 ms; während der Sensor in hoher Qualität eine Messung „schafft”, führt der andere in niedriger Qualität eine Vielzahl an Messungen durch.

19:40:30.363 -> Lichtsensoren BH1750 - Vergleich (mit Kappe)
19:40:30.917 -> Blauer BH1750 GY-302 wurde kalibriert (Dauer: 574 ms)
19:40:31.521 -> Roter BH1750 wurde kalibriert (Dauer: 608 ms)
19:40:31.568 -> rot  (8 ms):		74.19 lx
19:40:31.661 -> blau (122 ms): 187.08 lx
19:40:32.121 -> blau (448 ms): 187.44 lx
19:40:32.540 -> blau (448 ms): 187.33 lx
19:40:33.003 -> blau (448 ms): 187.21 lx
19:40:33.464 -> blau (448 ms): 186.99 lx
19:40:34.338 -> blau (448 ms): 186.76 lx
19:40:34.801 -> blau (448 ms): 186.65 lx
19:40:35.261 -> blau (448 ms): 186.54 lx
19:40:35.721 -> blau (448 ms): 186.31 lx
19:40:36.596 -> blau (448 ms): 186.20 lx
19:40:37.056 -> blau (448 ms): 186.08 lx
19:40:37.517 -> blau (448 ms): 185.97 lx
19:40:37.978 -> blau (448 ms): 185.86 lx
19:40:38.394 -> blau (448 ms): 185.63 lx
19:40:38.856 -> blau (448 ms): 185.52 lx
19:40:39.317 -> blau (448 ms): 185.40 lx
19:40:39.777 -> blau (448 ms): 185.18 lx
19:40:40.193 -> blau (448 ms): 185.06 lx
19:40:40.654 -> blau (448 ms): 184.95 lx
19:40:41.573 -> blau (448 ms): 184.72 lx
19:40:41.989 -> blau (448 ms): 184.61 lx
19:40:42.449 -> blau (448 ms): 184.50 lx
19:40:42.910 -> blau (448 ms): 184.27 lx
19:40:43.367 -> blau (448 ms): 184.16 lx
19:40:43.828 -> blau (448 ms): 183.93 lx
19:40:44.707 -> blau (448 ms): 183.71 lx
19:40:44.753 -> rot  (8 ms):		66.77 lx
19:40:44.753 -> rot  (8 ms):		74.19 lx
19:40:44.800 -> rot  (8 ms):		66.77 lx
19:40:44.800 -> rot  (8 ms):		74.19 lx
19:40:45.398 -> rot  (8 ms):		66.77 lx
19:40:45.398 -> rot  (8 ms):		74.19 lx
19:40:45.444 -> rot  (8 ms):		66.77 lx
19:40:45.444 -> rot  (8 ms):		74.19 lx
19:40:45.628 -> blau (448 ms): 183.48 lx
19:40:45.720 -> rot  (8 ms):		66.77 lx
19:40:45.720 -> rot  (8 ms):		74.19 lx
19:40:46.043 -> blau (448 ms): 183.37 lx
19:40:46.275 -> rot  (8 ms):		66.77 lx
19:40:46.275 -> rot  (8 ms):		74.19 lx
19:40:46.505 -> blau (448 ms): 183.14 lx
19:40:46.690 -> rot  (8 ms):		66.77 lx
19:40:46.690 -> rot  (8 ms):		74.19 lx
19:40:46.965 -> blau (448 ms): 183.03 lx
19:40:46.965 -> rot  (8 ms):		66.77 lx
19:40:46.965 -> rot  (8 ms):		74.19 lx
19:40:47.242 -> rot  (8 ms):		66.77 lx
19:40:47.242 -> rot  (8 ms):		74.19 lx
19:40:47.426 -> blau (448 ms): 182.91 lx
19:40:47.519 -> rot  (8 ms):		66.77 lx
19:40:47.519 -> rot  (8 ms):		74.19 lx
19:40:47.704 -> rot  (8 ms):		66.77 lx
19:40:47.750 -> rot  (8 ms):		74.19 lx
19:40:47.842 -> rot  (8 ms):		66.77 lx
19:40:47.842 -> rot  (8 ms):		74.19 lx
19:40:48.163 -> rot  (8 ms):		66.77 lx
19:40:48.163 -> rot  (8 ms):		74.19 lx
19:40:48.301 -> blau (448 ms): 182.80 lx
19:40:48.348 -> rot  (8 ms):		66.77 lx
19:40:48.348 -> rot  (8 ms):		74.19 lx
19:40:48.499 -> rot  (8 ms):		66.77 lx
19:40:48.499 -> rot  (8 ms):		74.19 lx
19:40:48.762 -> blau (448 ms): 183.03 lx
19:40:49.176 -> rot  (8 ms):		66.77 lx
19:40:49.176 -> rot  (8 ms):		74.19 lx
19:40:49.223 -> blau (448 ms): 183.37 lx
19:40:49.591 -> rot  (8 ms):		66.77 lx
19:40:49.591 -> rot  (8 ms):		74.19 lx
19:40:49.636 -> blau (448 ms): 182.91 lx
19:40:49.867 -> rot  (8 ms):		66.77 lx
19:40:49.867 -> rot  (8 ms):		74.19 lx
19:40:50.097 -> blau (448 ms): 182.69 lx
19:40:50.557 -> blau (448 ms): 182.80 lx
19:40:50.742 -> rot  (8 ms):		66.77 lx
19:40:50.742 -> rot  (8 ms):		74.19 lx
19:40:50.879 -> rot  (8 ms):		66.77 lx
19:40:50.879 -> rot  (8 ms):		74.19 lx
19:40:50.971 -> rot  (8 ms):		66.77 lx
19:40:50.971 -> rot  (8 ms):		74.19 lx
19:40:51.017 -> blau (448 ms): 182.23 lx
19:40:51.063 -> rot  (8 ms):		66.77 lx
19:40:51.063 -> rot  (8 ms):		74.19 lx
19:40:51.109 -> rot  (8 ms):		66.77 lx
19:40:51.155 -> rot  (8 ms):		74.19 lx
19:40:51.155 -> rot  (8 ms):		66.77 lx
19:40:51.155 -> rot  (8 ms):		74.19 lx
19:40:51.201 -> rot  (8 ms):		66.77 lx
19:40:51.201 -> rot  (8 ms):		74.19 lx
19:40:51.385 -> rot  (8 ms):		66.77 lx
19:40:51.431 -> rot  (8 ms):		74.19 lx
19:40:51.431 -> rot  (8 ms):		66.77 lx
19:40:51.431 -> rot  (8 ms):		74.19 lx
19:40:51.477 -> blau (448 ms): 182.01 lx
 
[...]
 
19:45:56.543 -> blau (448 ms): 215.17 lx
19:45:56.589 -> rot  (8 ms):		81.61 lx
19:45:56.635 -> rot  (8 ms):		89.03 lx
19:45:56.681 -> rot  (8 ms):		81.61 lx
19:45:56.681 -> rot  (8 ms):		89.03 lx
19:45:56.820 -> rot  (8 ms):		81.61 lx
19:45:56.866 -> rot  (8 ms):		89.03 lx
19:45:56.912 -> rot  (8 ms):		81.61 lx
19:45:56.912 -> rot  (8 ms):		89.03 lx
19:45:56.912 -> rot  (8 ms):		81.61 lx
19:45:56.959 -> rot  (8 ms):		89.03 lx
19:45:57.005 -> rot  (8 ms):		81.61 lx
19:45:57.005 -> rot  (8 ms):		89.03 lx
19:45:57.097 -> rot  (8 ms):		81.61 lx
19:45:57.097 -> rot  (8 ms):		89.03 lx
19:45:57.143 -> rot  (8 ms):		81.61 lx
19:45:57.143 -> rot  (8 ms):		89.03 lx
19:45:57.282 -> rot  (8 ms):		81.61 lx
19:45:57.282 -> rot  (8 ms):		89.03 lx
19:45:57.374 -> rot  (8 ms):		81.61 lx
19:45:57.420 -> rot  (8 ms):		89.03 lx
19:45:57.559 -> rot  (8 ms):		81.61 lx
19:45:57.559 -> rot  (8 ms):		89.03 lx
19:45:57.606 -> rot  (8 ms):		81.61 lx
19:45:57.606 -> rot  (8 ms):		89.03 lx
19:45:57.837 -> rot  (8 ms):		81.61 lx
19:45:57.883 -> rot  (8 ms):		89.03 lx
19:45:57.883 -> blau (448 ms): 215.40 lx
19:45:58.206 -> rot  (8 ms):		81.61 lx
19:45:58.206 -> rot  (8 ms):		89.03 lx
19:45:58.251 -> rot  (8 ms):		81.61 lx
19:45:58.251 -> rot  (8 ms):		89.03 lx
19:45:58.343 -> blau (448 ms): 215.51 lx
19:45:58.389 -> rot  (8 ms):		81.61 lx
19:45:58.389 -> rot  (8 ms):		89.03 lx
19:45:58.757 -> rot  (8 ms):		81.61 lx
19:45:58.757 -> rot  (8 ms):		89.03 lx
19:45:58.803 -> blau (448 ms): 215.62 lx
19:45:59.220 -> blau (448 ms): 215.74 lx
19:45:59.451 -> rot  (8 ms):		81.61 lx
19:45:59.451 -> rot  (8 ms):		89.03 lx
19:45:59.591 -> rot  (8 ms):		81.61 lx
19:45:59.591 -> rot  (8 ms):		89.03 lx
19:45:59.683 -> rot  (8 ms):		81.61 lx
19:45:59.683 -> rot  (8 ms):		89.03 lx
19:46:00.468 -> rot  (8 ms):		81.61 lx
19:46:00.468 -> rot  (8 ms):		89.03 lx
19:46:00.607 -> blau (448 ms): 215.96 lx
19:46:01.438 -> rot  (8 ms):		81.61 lx
19:46:01.438 -> rot  (8 ms):		89.03 lx
19:46:01.484 -> blau (448 ms): 216.19 lx
19:46:02.409 -> blau (448 ms): 216.30 lx
19:46:03.008 -> rot  (8 ms):		81.61 lx
19:46:03.008 -> rot  (8 ms):		89.03 lx
19:46:03.744 -> blau (448 ms): 216.42 lx
19:46:04.206 -> blau (448 ms): 216.30 lx
19:46:04.621 -> blau (448 ms): 216.42 lx
19:46:05.081 -> blau (448 ms): 216.53 lx
19:46:05.542 -> blau (448 ms): 216.64 lx
19:46:06.463 -> blau (448 ms): 216.42 lx
19:46:06.879 -> blau (448 ms): 216.53 lx
19:46:07.341 -> blau (448 ms): 216.64 lx
19:46:07.802 -> blau (448 ms): 216.87 lx
19:46:08.264 -> blau (448 ms): 217.32 lx
19:46:09.139 -> blau (448 ms): 217.44 lx
19:46:09.599 -> blau (448 ms): 217.55 lx
19:46:10.477 -> blau (448 ms): 217.44 lx
19:46:10.940 -> blau (448 ms): 217.32 lx
 
[...]
 
19:53:37.751 -> blau (448 ms): 74.59 lx
19:53:37.935 -> rot  (8 ms):		14.84 lx
19:53:37.935 -> rot  (8 ms):		22.26 lx
19:53:37.981 -> rot  (8 ms):		14.84 lx
19:53:37.981 -> rot  (8 ms):		22.26 lx
19:53:38.534 -> rot  (8 ms):		14.84 lx
19:53:38.534 -> rot  (8 ms):		22.26 lx
19:53:38.672 -> blau (448 ms): 74.70 lx
19:53:39.133 -> blau (448 ms): 74.82 lx
19:53:40.008 -> blau (448 ms): 74.93 lx
19:53:40.239 -> rot  (8 ms):		14.84 lx
19:53:40.239 -> rot  (8 ms):		22.26 lx
19:53:40.469 -> blau (448 ms): 75.04 lx
19:53:40.930 -> blau (448 ms): 75.16 lx
19:53:41.113 -> rot  (8 ms):		14.84 lx
19:53:41.113 -> rot  (8 ms):		22.26 lx
19:53:41.389 -> blau (448 ms): 75.27 lx
19:53:41.805 -> blau (448 ms): 75.38 lx
19:53:42.727 -> blau (448 ms): 75.50 lx
19:53:43.005 -> rot  (8 ms):		14.84 lx
19:53:43.050 -> rot  (8 ms):		22.26 lx
19:53:43.189 -> blau (448 ms): 75.61 lx
19:53:43.602 -> blau (448 ms): 75.72 lx
19:53:44.064 -> blau (448 ms): 75.84 lx
19:53:44.987 -> blau (448 ms): 76.06 lx
19:53:45.403 -> blau (448 ms): 76.18 lx
19:53:46.326 -> blau (448 ms): 76.29 lx
19:53:46.788 -> blau (448 ms): 76.40 lx
19:53:47.203 -> blau (448 ms): 76.52 lx

Vergleich der Messwerte

Einfluss der Kunststoffkappe

Bei der Ausgabe der Messwerte sieht man, dass die Kunststoffkappe in diesem Fall mehr als die Hälfte des einfallenden Lichts schluckt. Das ist auch ungefähr das, was ich als Faustregel bei Vergleichsmessungen festgestellt habe, bei denen beide Sensoren mit höchster Qualität zu verschiedenen Tageszeiten mit und ohne direkten Sonnenschein gemessen haben: Egal bei welcher Beleuchtungsstärke schluckt die Kappe mindestens die Hälfte des Lichts, d.h. der „blaue” Sensor misst immer mindestens doppelt so hohe Beleuchtungsstärken wie der „rote” unter der Kunststoffkappe.

  • Bei Beleuchtungsstärken zwischen etwa 200 und 2000 Lux sind die Werte rund 2 – 2,15 mal höher;
  • in direktem Sonnenschein misst er etwa 2,3 – 2,5 mal so hohe Werte;
  • bei niedrigeren Helligkeiten als 100 lx sind die Werte etwa 2,2 mal höher; Werte unter 1 lx registriert der „rote” Sensor durch die Kappe nicht mehr.

Das sagt aber nur etwas über meinen Sensor aus dem Jahr 2019 aus. Wenn der Hersteller seitdem z.B. die Wandstärke der Kunststoffkappe oder die Zusammensetzung, Farbe oder Transparenz des Kunststoffs geändert hat, kann sich das Verhältnis in die eine oder andere Richtung verschieben.

Direkter Vergleich

Zwei BH1750-Modulplatinen am ESP32
Zwei BH1750-Modulplatinen am ESP32

Vorab: Ein Teil der festgestellten Abweichungen ist sicherlich auf meinen „Versuchsaufbau” zurückzuführen. Die Messwerte sind stark vom Einfallswinkel des Lichts abhängig – trotz Fixierung des roten Sensors mit Klebeband habe ich es sicher nicht geschafft, beide Sensoren genau gleich auszurichten.
Im Programm habe ich zwar beide Messungen gleichzeitig gestartet. Die Messungen dauern aber mehrere Zehntelsekunden[6]Ein Auslesen der Timings zeigt für meine Sensoren, dass das „blaue” GY-302-Modul für eine Messung in höchster Qualität 446 ms benötigt und damit etwas schneller ist als das … Continue reading, dabei ist unklar, wie sich die unterschiedlich langen Messzeiten bemerkbar machen (wie/wann reagieren die Sensoren auf sich während der Messung ändernde Lichtverhältnisse?).
Außerdem habe ich nicht unter reproduzierbaren Bedingungen gemessen – das Tageslicht schwankt stark, je nach Sonnenstand, Bewölkung etc. – und ein zuverlässiges Messgerät (Luxmeter) zum Vergleich habe ich auch nicht. Möglicherweise spielt auch eine unterschiedlich starke Erwärmung der Sensoren eine Rolle.

Im direkten Vergleich zeigen sich jedenfalls sowohl schwankende Messwerte als auch Abweichungen der Messwerte beider Sensoren untereinander. Egal ob bei normalem Tageslicht oder in direktem Sonnenschein – mal hatte der eine Sensor höhere Messwerte, mal der andere (nicht von Messung zu Messung, aber über mehrere Minuten betrachtet). Hat ein Sensor in mehreren Zeiträumen ungefähr einen Wert x gemessen, hat der andere Sensor nie jeweils auch nur annähernd den gleichen Wert y gemessen – mal lag der GY-302 um 6 % vorne, mal weniger als 2 %, in anderen Fällen lieferte der „rote” Sensor höhere Werte. Die Abweichungen haben selten den Bereich von ±8 % verlassen.

Dabei dürfte auch die im Datenblatt genannte Messabweichung von bis zu ±20 % (»Small measurement variation (+/- 20%)«[7]Seite 1 des Datenblatts; Punkt 12 der Eigenschaften des Sensors) eine Rolle spielen.

Fazit

Man muss akzeptieren, dass die Messwerte der BH1750-Sensoren im Tageslicht etwas schwanken – sonst würde eine Abweichung der Messwerte von bis zu 20 % im Datenblatt kaum als »gering« bezeichnet werden. Die absoluten Messwerte sind deshalb mit ein wenig Vorsicht zu genießen.

Zum Erkennen von Helligkeitsänderungen ist der BH1750 – anders als der TEMT6000 – sowohl bei schwachem als auch bei sehr hellem Licht (direkter Sonnenschein) nach meiner Meinung sehr gut geeignet.

Die Bibliothek hp_BH1750 von Stefan Armborst ist sehr mächtig. Davon sollte man sich nicht abschrecken lassen, da man für einfache Messungen nur wenige Funktionen bernötigt. Mit dem Autoranging gibt es eine einfache Möglichkeit, die Messungen immer in bester Qualität durchzuführen, ohne sich selbst um die internen Funktionen des Sensors kümmern zu müssen.

Fußnoten

Fußnoten
1 siehe Wikipedia: Elektromagnetisches Spektrum
2 Auf der Website des Herstellers ist kein Datenblatt zum BH1750 verlinkt.
3 Das rote Modul mit der Kunststoffkappe wird bei den allermeisten Anbietern nur als 5-Volt-tauglich beschrieben. Bei mir hat es auch problemlos am gleichen I2C-Bus wie das „blaue” Modul mit den 3,3 V funktioniert, die der ESP32 liefert – siehe die Schaltung zum zweiten Beispielprogramm.
4 Sogar die Entwickler von Adafruit haben für ihr BH1750-Modul keine eigene Bibliothek programmiert, sondern empfiehlt ausdrücklich die hp_BH1750-Library.
5 Die Timings sind zwar für jeden Sensorchip individuell, ändern sich aber nicht. Zu den Details siehe die Bibliotheks-Dokumentation im Abschnitt Working Principle. Wenn gewünscht, kann man sie auslesen (Funktion getTiming()) und im Programm hart codieren oder z.B. auf einem Arduino im EEPROM bzw. auf einem ESP32 mit den Funktionen der Preferences-Bibliothek speichern und im setup() zurückschreiben (Funktion setTiming()). Da das Kalibrieren aber nur ein paar 100 Millisekunden dauert und nur einmal nötig ist, kann man sich den Programmieraufwand zum dauerhaften Speichern meiner Meinung nach sparen.
6 Ein Auslesen der Timings zeigt für meine Sensoren, dass das „blaue” GY-302-Modul für eine Messung in höchster Qualität 446 ms benötigt und damit etwas schneller ist als das „rote” (474 ms).
BH1750 wurde kalibriert (Dauer: 573 ms)
Timings:
 - MTregLow_QualityHigh: 56 - MTregHigh_QualityHigh: 446
 - MTregLow_QualityLow: 9 - MTregHigh_QualityLow: 57
 
BH1750_rot wurde kalibriert (Dauer: 608 ms)
Timings:
 - MTregLow_QualityHigh: 60 - MTregHigh_QualityHigh: 474
 - MTregLow_QualityLow: 9 - MTregHigh_QLow: 61

7 Seite 1 des Datenblatts; Punkt 12 der Eigenschaften des Sensors

Kommentar hinterlassen

Deine E-Mail-Adresse wird nicht veröffentlicht.