BH1750FVI (GY-30, 302) Lichtsensormodul

Über den Beitrag

In diesem Beitrag meiner Reihe1 über Licht-, Gestik-, Bewegungs- und Abstandssensoren möchte ich den Lichtsensor BH1750FVI vorstellen. Genauer gesagt geht es um das BH1750FVI Modul – der BH1750FVI selbst ist der kleine sechsbeinige IC auf dem Modul. Oftmals findet man dazu auch die Kurzbezeichnung BH1750 oder auch nur GY-302 oder GY-30, dabei handelt es sich aber immer um das gleiche Modul, bzw. dieselbe Basis. 

Ein paar Beiträge zuvor habe ich den Lichtsensor TSL2561 vorgestellt, der auf den ersten Blick ähnlich wie der BH1750FVI arbeitet, aber im Detail doch deutliche Unterschied aufweist. Eine Gegenüberstellung dieser und aller anderen Sensoren dieser Reihe gibt es, wenn ich die Reihe abgeschlossen habe.  

In diesem Beitrag werde ich zunächst auf die technischen Eigenschaften eingehen, die Einstellmöglichkeiten vorstellen, die Ansteuerung per Arduino erklären und meine Bibliothek dazu vorstellen. Es gibt zwar schon eine ganze Reihe von Bibliotheken für den BH1750FVI, ich habe aber keine gefunden, bei der die Einstellung der Messzeit implementiert war und auch vollständig funktionierte. 

1 Eine Zusammenfassung der Reihe gibt es hier.

Eigenschaften

Verschiedene BH1750FVI Module
Zwei BH1750FVI Module

Funktionsprinzip

Der BH1750FVI besitzt eine Fotodiode mit einem Ansprechbereich von ca. 400 – 700 nm, also im Wesentlichen dem Bereich des sichtbaren Lichts. Die Fotospannung wird verstärkt und mit einem A/D-Wandler in einem 16-Bit Messwert gespeichert. Der Messwert wird dazu über einen einstellbaren Messzeitraum integriert. 

Technische Daten des BH1750FVI Moduls

Die wichtigsten technischen Daten sind:

  • Stromversorgung: 3 – 5 VDC
  • Stromaufnahme:  ~ 0.14 mA 
    • Power Off Modus: 0 mA  
  • Kommunikation: I2C (SDA/SCL)
  • I2C Adressen: 0x23 oder 0x5C einstellbar
  • Messbereich: 0 – 65535 lx, erweiterbar bis 100000 (lt. Datenblatt)
    • aus meiner Sicht stimmen die Werte nicht ganz – dazu später mehr 
  •  maximale Auflösung: einstellungsabhängig 0.11 – 7.4 lx

Die Standard I2C Adresse des Moduls ist 0x23. Ihr könnt sie durch Anschluss des Adresspins (ADDR oder ADD) an HIGH auf 0x5C ändern. Der Pin ist anscheinend „pulled down“. Deshalb ist für die Verwendung der Standardadresse kein Anschluss an GND notwendig. Ihr könnt die Adresse mit einem I2C Scanner überprüfen, zum Beispiel dem hier

Das Modul bekommt für ca. 2 Euro das Stück z.B. auf Amazon bei zahlreichen Anbietern. 

Ein ausführliches Datenblatt bekommt ihr hier.

Einstellmöglichkeiten / Betriebsmodi

Resolution Modes

Der BH1750HVI verfügt über drei kontinuierliche („Continuously“) und drei diskontinuierliche („One Time“) Modi:

  • Continuously H-Resolution Mode
  • Continuously H-Resolution Mode2
  • Continuously L-Resolution Mode
  • One Time H-Resolution Mode
  • One Time H-Resolution Mode2
  • One Time L-Resolution Mode

Der Vorteil der „One Time“ Modi ist, dass das Modul nach der Messung automatisch in den Power Off Modus geht und so Strom spart. 

Ansonsten unterscheiden sich die Modi hinsichtlich ihrer Auflösung und der Messzeit: 

Betriebsmodi des BH1750HVI versus Messzeit und Auflösung

Der Continuously H-Resolution Mode ist die Voreinstellung. In den L-Resolution Mode geht ihr, wenn ihr schnell bzw. in hoher Frequenz messen wollt. Der H-Resolution Mode2 bietet sich an, um eine höhere Auflösung im Dunkeln zu erreichen. 

Auflösung vs maximale Lichtstärke

Der Messwert wird als 16 Bit Wert gespeichert, entsprechend ist 65535 der Maximalwert. Zur Umrechnung in Lux müssen laut Datenblatt die Rohdaten im H-Resolution und L-Resolution Mode durch 1.2 geteilt werden. Daraus ergibt sich dann ein Maximalwert von 54612 lx. Im H-Resolution Mode2 muss das Ergebnis noch einmal durch zwei geteilt werden. Daraus ergibt sich ein Maximalwert von 27306 lx. 

Wie stellt man die Modi ein?

Wenn ihr keine Bibliothek verwendet, dann müsst ihr zur Einstellung des gewünschten Modus lediglich ein einzelnes Steuerbyte (im Datenblatt OpeCode genannt) über I2C an den BH1750HVI senden. Später seht ihr in den Beispielsketchen wie das im Detail funktioniert.    

OpeCodes des BH1750FVI zur Einstellung der Auflösung
Einstellung der Auflösung mittels Steuercodes

Einstellung der Messzeit

Offen gestanden musste ich den Abschnitt zur Einstellungsprozedur der Messzeit mehrfach lesen, denn sie ist, sagen wir einmal ungewöhnlich. Zunächst einmal sollte man wissen, dass die Einstellung der Messzeit relativ zu der durch den Modus eingestellten Grundmesszeit, also 16 bzw. 120 ms, erfolgt. Das heißt, man gibt keinen Wert in Millisekunden an, sondern arbeitet mit Faktoren. 

Die Messzeit bzw. der Faktor wird im Measurement Time Register (MTReg) eingestellt.  Als Grundeinstellung steht dort der Wert 69 (0b01000101). Diesen Wert kann man von 31 bis 254 variieren. Eine Veränderung auf 31 bedeutet:

Neue Messzeit = Grundwert x 31/69 ≈ Grundwert x 0,45

Eine Veränderung auf den Maximalwert 254 bedeutet:

Neue Messzeit = Grundwert x 254/69 ≈ Grundwert x 3,68

Die Messzeit kann um den Faktor 0,45 bis 3,68 verändert werden. 

Die Messzeitveränderung schlägt sich direkt proportional auf die Rohdaten nieder. Entsprechend ändern sich auch die maximal messbaren Lichtstärken. Ein Beispiel: im Continuous H-Mode beträgt der maximal messbare Lux-Wert 65535 / 1.2 ≈ 54612. Senkt man die Messzeit auf das 0.45 fache, dann kann das Licht entsprechend intensiver sein, ohne dass das 16 Bit Datenregister überläuft. Der maximal messbare Lux-Wert liegt damit bei 65535 ⋅ (69/31) / 1.2 ≈ 121557 lx. Warum das Datenblatt 100000 lx als Maximalwert angibt, weiß ich nicht.

Wichtig ist, dass man die Faktoren bei der Umrechnung der Rohdaten in Lux Werte berücksichtigt, denn sonst sind sie natürlich falsch. Es kann aber auch einen Grund geben, genau das nicht zu tun, nämlich bei einer Kalibrierung. Dazu gleich mehr.     

Warum die Messzeit verändern?

Es gibt drei Gründe die Messzeit zu verändern:

  1. Den Messbereich nach oben erweitern
  2. Im unteren Messbereich für eine höhere Auflösung sorgen 
  3. Kalibrierung, z.B. wegen Verwendung eines Fensters, das einen Teil des Lichtes absorbiert

Sagen wir einmal, der BH1750FVI würde hinter einem Fenster verbaut, welches nur 50 % des Lichts durchlässt. In diesem Fall würde man die Messzeit verdoppeln, um den Effekt auszugleichen (Kalibration). Und in diesem Fall würde man den Faktor natürlich nicht wie bei 1 und 2 am Ende wieder herausrechnen. 

Auflösung versus Messzeit

Aus den oben angegebenen Berechnungsvorschriften lässt sich die Auflösung in Abhängigkeit des MTReg Wertes ermitteln:

Auflösung in H-Resolution Mode = 1/1.2 x 69/MTReg

Auflösung in H-Resolution Mode2 = (1/1.2 x 69/MTReg)/2 

Auflösung in L-Resolution Mode = (1/1.2 x 69/MTReg) x 4

Daraus ergibt sich:

Auflösung versus Messzeit und Betriebsmodus
Auflösung versus Messzeit und Betriebsmodus

Wie verändert man die Messzeit?

Im Prinzip habe ich die Antwort auf diese Frage ja schon gegeben. Ihr müsst den Defaultwert im MTReg von 69 auf den gewünschten Wert ändern. Habt ihr eine Bibliothek, die diese Funktion implementiert hat, dann müsst ihr euch um die Details nicht kümmern und könnt den Rest des Abschnitts überspringen. 

Für diejenigen, die ohne Bibliothek arbeiten oder etwas in ihrer Bibliothek ändern wollen oder einfach nur wissen wollen, was hinter den Kulissen passiert, führe ich das weiter aus. 

Normalerweise ist man es gewohnt einen Registerwert zu verändern, indem man ein Kontrollregister anspricht, diesem das Zielregister mitteilt und dann byteweise die Werte übergibt. Hier läuft es ein bisschen anders. Die drei oberen Bits und die fünf unteren Bits des MTReg Wertes (kurz: MTReg) werden in zwei Schritten, verpackt in zwei Steuerbytes an den BH1750FVI übergeben. Das passiert nach folgendem Schema:

  • Byte1 = 01000 [MTReg Bit7] [MTReg Bit6] [MTReg Bit5]
  • Byte2 = 011 [MTReg Bit4] [MTReg Bit3] [MTReg Bit2] [MTReg Bit1] [MTReg Bit0]

Die Bytes berechnet man am besten über Binäroperationen:

Byte1 = (MTReg >> 5) | 0b01000000

Die Verschiebung um 5 Stellen positioniert die Bits 7,6 und 5 an die richtige Stelle. Die anschließende logische ODER Operation sorgt dafür, dass die unteren Bits unverändert bleiben und oben die 01000 steht.

Byte2 = (MTReg & 0b01111111) | 0b01100000

Hier sorgt das erste logische UND für eine 0 an Bit 7 des Byte2 ohne die anderen Stellen zu ändern. Die anschließende ODER Operation setzt Bit 6 und 7 ohne die anderen Bits zu verändern. 

Andere Einstellungen

Hier noch ein paar weitere Einstellungen mit den entsprechenden Steuercodes:

Weitere Einstellungen am BH1750FVI

Ansteuerung des BH1750FVI ohne Bibliothek

Der Sketch

Hier nun der Arduino Sketch für die Ansteuerung des BH1750FVI ohne Bibliothek.

Der MTReg Wert (measuringTimeFactor) wird als Faktor eingegeben und daraus der Byte Wert für das MT Register berechnet. Ich finde das praxisnäher, als den MTReg Wert direkt festzulegen. In Zeile 38 bzw. 41 wird der Faktor wieder herausgerechnet um die „echten“ Lux Werte zu erhalten. Wird der Faktor zur Kalibrierung benutzt, dann ist dieser Rechenteilschritt zu unterlassen. 

Aufgrund der vorhergehenden Erklärungen sollte der Sketch ansonsten selbsterklärend sein. 

#include <Wire.h>
#define BH_1750 0x23
#define DATA_REG_RESET 0b00000111
#define POWER_DOWN 0b00000000
#define POWER_ON 0b00000001

enum BH1750Mode {
  CHM = 0b00010000,     //CHM: Continuously H-Resolution Mode
  CHM_2 = 0b00010001,   //CHM_2: Continuously H-Resolution Mode2
  CLM = 0b00010011,     //CLM: Continuously L-Resolution Mode
  OTH = 0b00100000,     //OTH: One Time H-Resolution Mode
  OTH_2 = 0b00100001,   //OTH_2: One Time H-Resolution Mode2
  OTL = 0b00100011      //OTL: One Time L-Resolution Mode
} mode;

float measuringTimeFactor;

void setup(){
  Serial.begin(9600);
  Wire.begin();
  mode = CHM;
  measuringTimeFactor = 1;
  setMode();
  setMeasuringTime(); 
  delay(200);
}

void loop(){ 
  getLux();
  delay(1000);
}

void getLux(){
  uint16_t rawLux;
  float lux;
  rawLux = readBH1750();
  if((mode==CHM_2)||(mode==OTH_2)){
    lux = (rawLux/2.4)/measuringTimeFactor;     
  }
  else{
    lux = (rawLux/1.2)/measuringTimeFactor;
  }
  Serial.print(F("Lichtstärke: "));
  Serial.print(lux);
  Serial.println(F(" Lux"));
}

void powerDown(){
  writeBH1750(POWER_DOWN);
}

void powerOn(){
  writeBH1750(POWER_ON);
  setMode();
}

void dataRegReset(){
  writeBH1750(DATA_REG_RESET);
}

void setMode(){
  writeBH1750(mode);
}

void setMeasuringTime(){
  byte mt = round(measuringTimeFactor*69);
  byte highByteMT = ((mt>>5) | 0b01000000);
  byte lowByteMT = (mt & 0b01111111);
  lowByteMT |= 0b01100000;
  writeBH1750(highByteMT);
  writeBH1750(lowByteMT);
}

uint16_t readBH1750(){
  uint8_t MSbyte, LSbyte;
  Wire.requestFrom(BH_1750, 2);
  if(Wire.available()){
    MSbyte=Wire.read();
    LSbyte=Wire.read(); 
  }
  return ((MSbyte<<8) + LSbyte);
}

void writeBH1750(byte val){
  Wire.beginTransmission(BH_1750);
  Wire.write(val);
  Wire.endTransmission();
}

 

Die Schaltung

Der Vollständigkeit halber hier noch die Schaltung, auch wenn sie alles andere als komplex ist. Es sei einzig noch angemerkt, dass ich auf Pull-Up Widerstände für die SDA / SCL Leitungen verzichtet habe. Es funktioniert auch ohne. Falls Ihr Probleme bekommt, fügt sie hinzu. 

Schaltung: der BH1750FVI am Arduino
Der BH1750FVI am Arduino

BH1750FVI Bibliothek

Da ich wie schon erwähnt keine Bibliothek gefunden habe, bei der die Einstellung der Messzeit zu meiner Zufriedenheit implementiert war, habe ich eine eigene geschrieben. Sie heißt BH1750_WE und ihr findet sie hier auf Github. Wenn ihr damit arbeiten wollt, dann ladet sie als zip-Datei herunter und entpackt sie im Arduino/libraries Ordner. Den folgenden Beispielsketch findet ihr im examples Ordner. (Neu: ihr könnt die Bibliothek jetzt auch direkt über die Bibliotheksverwaltung in der Arduino IDE installieren). 

/***************************************************************************
* Example sketch for the BH1750_WE library
* 
* Mode selection / abbreviations:
* CHM:    Continuously H-Resolution Mode
* CHM_2:  Continuously H-Resolution Mode2
* CLM:    Continuously L-Resolution Mode
* OTH:    One Time H-Resolution Mode
* OTH_2:  One Time H-Resolution Mode2
* OTL:    One Time L-Resolution Mode
* 
* Measuring time factor:
* 1.0 ==> Mresuring Time Register = 69
* 0.45 ==> Measuring Time Register = 31
* 3.68 ==> Mesuring Time Register = 254
* 
* Other implemented functions, not used in the example:
* resetDataReg() --> rests Data Register
* powerOn() --> Wake Up!
* powerDown() --> Sleep well, my BH1750
* 
* If you change the measuring time factor for calibration purpose, 
* then you need to devide the light intensity by the measuring time factor 
* 
* Further information can be found on:
* https://wolles-elektronikkiste.de/en/bh1750fvi-gy-30-302-ambient-light-sensor
* or in German:
* https://wolles-elektronikkiste.de/bh1750fvi-lichtsensormodul
***************************************************************************/

#include <Wire.h>
#include <BH1750_WE.h>
#define BH1750_ADDRESS 0x23

BH1750_WE myBH1750(BH1750_ADDRESS); 
// You may also pass a TwoWire object like wire2 
// BH1750_WE myBH1750(&wire2, BH1750_ADDRESS);

void setup(){
  Serial.begin(9600);
  Wire.begin();
  myBH1750.init(); // sets default values: mode = CHM, measuring time factor = 1.0
  // myBH1750.setMode(CLM);  // uncomment if you want to change default values
  // myBH1750.setMeasuringTimeFactor(0.45); // uncomment for selection of value between 0.45 and 3.68
}

void loop(){ 
  float lightIntensity = myBH1750.getLux();
  Serial.print(F("Lichtstärke: "));
  Serial.print(lightIntensity);
  Serial.println(F(" Lux"));
  delay(1000);
}

 

Messungen in den One Time Modi

Bei Messungen in den One Time Modi ist zu beachten, dass setMode() die Messung startet. Dann müsst ihr warten, bis die Messung vollendet ist und ihr den neuen Messwert auslesen könnt. Eine Messung in den OTH Modi benötigt laut Datenblatt ca. 120 Millisekunden, im OTL Modus sind es 16 Millisekunden.

#include <Wire.h>
#include <BH1750_WE.h>
#define BH1750_ADDRESS 0x23

BH1750_WE myBH1750 = BH1750_WE(BH1750_ADDRESS); 
// You may also pass a TwoWire object: 
//BH1750_WE myBH1750 = BH1750_WE(&Wire, BH1750_ADDRESS);
// If you don't pass any parameter, Wire and 0x23 will be applied

void setup(){
  Serial.begin(9600);
  Wire.begin();
  if(!myBH1750.init()){ // sets default values: mode = CHM, measuring time factor = 1.0
    Serial.println("Connection to the BH1750 failed");
    Serial.println("Check wiring and I2C address");
    while(1){}
  }
  else{
    Serial.println("BH1750 is connected");
  }
  // myBH1750.setMeasuringTimeFactor(0.45); // uncomment for selection of value between 0.45 and 3.68
}

void loop(){ 
  myBH1750.setMode(OTH); // sets mode and starts measurement
  /* An OTH and OTH_2 measurement takes ~120 ms. I suggest to wait 
     140 ms to be on the safe side. 
     An OTL measurement takes about 16 ms. I suggest to wait 20 ms
     to be on the safe side. */
  delay(140); // wait for measurement to be completed.
  float lightIntensity = myBH1750.getLux();
  Serial.print(F("Light intensity: "));
  Serial.print(lightIntensity);
  Serial.println(F(" Lux"));
  delay(1000);
}

 

Danksagungen

Den Hintergrund für das Beitragsbild stammt von Hanna Kovalchuk auf Pixabay.

Den BH1750FVI als Fritzing Bauteil habe ich von vdemay auf Github.

38 thoughts on “BH1750FVI (GY-30, 302) Lichtsensormodul

  1. Hi Wolfgang,
    in deiner ‚Betriebsmodi des BH1750HVI versus Messzeit und Auflösung‘- Tabelle hast du H-Mode und H-Mode2 vertauscht. Laut Datenblatt hat der Mode2 die höhere Auflösung von 0.5lx.

    Vielen Dank für den tollen Artikel! Der hat sehr geholfen, auch mich hat der Abschnitt mit der Messzeit ziemlich verwirrt und so konnte ich mir eine zweite Einschätzung einholen! Danke

  2. Hallo Wolfgang, ich hab folgendes Problem, vermutlich um den BH1750:
    Ich verwende deine Library und der BH1750 ist eines von ein paar (wenigen) I2C Devices. Alle funktioniert wie’s soll aber wenn es finster wird (0 Lux … vermutlich) wird der Bus blockiert.
    Hab jetzt im Datenblatt gelesen, dass im H-Resolution-Mode das Teil bei 0 Lux abschaltet …. könnte das die Ursache sein?
    Wie kann man in der Library eigentlich den Messmodus einstellen?
    Wäre sehr dankbar, wenn du mir da einen Tip geben könntest!

    1. Hallo Alois,
      zuerst zum Einfachen: den Modus stellst du mit myBH1750.setMode(modus); ein. Als modus kannst du wählen:
      CHM: Continuously H-Resolution Mode
      CHM_2: Continuously H-Resolution Mode2
      CLM: Continuously L-Resolution Mode
      OTH: One Time H-Resolution Mode
      OTH_2: One Time H-Resolution Mode2
      OTL: One Time L-Resolution Mode
      Meine Voereinstellung ist CHM.

      Den Hinweis auf die Abschaltung habe ich nicht gelesen. Aufwecken kann man den BH1750 mit myBH1750.powerOn(). Das nützt aber wahrscheinlich nichts, wenn dein Mikrocontroller auf Antwort warte und keine bekommt. Du könntest mal einen der One Time Modi probieren. Die Bibliothek hat einen Besipielsketch dafür. In dem Modus geht der BH1750 sowieso schlafen zwischen den Messungen.
      Dann könntest du noch probieren, ein Wire.setWireTimeout(timeout, reset_on_timeout); in das setup zu schreiben. timeout ist die maximale Wartezeit in Mikrosekunden, reset_on_timeout gibt an, ob Wire neu gestartet werden soll. Das ist also true oder false.
      Mehr fällt mir im Moment nicht ein.
      VG, Wolfgang

      1. Hallo Wolfgang, erst mal vielen Dank für die Info!
        Kann es sein das mittlerweile Wire.setWireTimeout(timeout, reset_on_timeout); aus der Library genommen wurde. Meine IDE behaubtet class ‚TowWire‘ hätte keinen member ’setWireTimeout‘.
        Hab‘ auch das mit dem sleep-Modus probiert und das ist wohl nicht die Ursache.
        So wie’s aussieht verursacht mein selbstgebauter I2C-Slave (ATtiny85, BASCOM) irgendwas. Leider nicht systematisch, sondern irgendwann.

        1. Hallo Alois,
          da die I2C Übertragung hardwarespezifisch ist, gibt es nicht die eine Wire Bibliothek. Ich habe Wire.setTimeout() mal mit dem ATtiny85 und dem AttinyCore Paket ausprobiert und die Funktion ist tatsächlich nicht implementiert. Mit einem Arduino UNO R3 oder Nano hingegen geht es, allerdings nur mit dem ersten Parameter (timeout). Vielleicht ist der Zweite irgendwann mal „wegaktualisiert“ worden.
          Ich glaube, aus der Ferne werde ich dir wenig helfen können. Wenn du ein Oszilloskop hast, könntest du mal schauen, ob die Signalübertragung sauber ist. Fehler, die sporadisch auftreten, sind die blödesten. Hoffe, du findest das Problem.
          VG, Wolfgang

          1. Hallo Wolfgang, das hier nur zur Info:
            Auf meiner Suche nach der Ursache habe ich nach dem I2C-senden/lesen jeweils ein delay(20) eingebaut und siehe da …. Problem ist verschwunden!
            Zur Absicherung habe ich auch noch den Watchdog in meinem I2C-Slave so konfiguriert, dass wenn das Problem trotzdem nochmal auftreten sollte, ein echter Reset des ATtiny85 erfolgt.

            Wie auch immer …. danke für das konstruktive Gespräch!

            1. Hallo Alois, das ist aber schön, dass du das so lösen könntest. Danke, dass du dich damit noch einmal meldest!

  3. Hallo Wolle

    leider hast Du für das onetime measurement kein Beispiel mitgegeben. Ich habe folgendes Problem:
    1. Wenn ich im Beispiel nach
    myBH1750.init();
    die Zeile
    myBH1750.setMode(OTH);
    einfüge, erhalte ich bei weiteren Messungen immer den Wert der ersten Messung.
    2. Dann habe ich die Zeile
    myBH1750.setMode(OTH);
    vor die Zeile
    float f_lux = myBH1750.getLux();
    gesetzt.
    Als Ergebnis erhalte ich bei der nächsten Messung wieder den alten Wert
    bei der übernächsten Messung dann den aktuellen.
    Natürlich möchte ich bei jeder Messung den aktuellen Wert erhalten. Kannst Du mir weiterhelfen?
    viele Grüße
    Jörg

    die erste Messung ist korrekt, danach erhalte ich immer wieder dengleichen Wert.

    1. Hallo Jörg,

      „myBH1750.setMode(OTH);“ wechselt nicht nur den Modus, sondern startet auch die Messung. Dass du direkt nach dem Start der Messung noch den alten Wert liest, liegt daran, dass eine Messung im OTH-Modus laut Datenblatt ca. 120 ms benötigt. Du müsstest also ein Delay einfügen. Da es ungefähr 120 ms sind, würde ich vielleicht 140 ms nehmen, um auf der sicheren Seite zu sein. Leider hat das Modul kein „Data Ready“ oder „Conversion Completed bit“.

      Aber guter Punkt. Ich werde mal einen Sketch dazu schreiben oder zumindest Kommentare im Beispielsketch ergänzen.

      VG, Wolle

      1. vielen Dank
        Ich habe es ausprobiert, jetzt bekomme ich den richtigen Wert.
        Ich dachte, dass .getlux() die Messung startet.
        Danke Jörg

        1. Das kannst du ja auch nicht wissen, wenn ich nichts dazu schreibe. Ich habe jetzt in der Bibliothek und im Beitrag einen Beispielsketch hinzugefügt. Vielen Dank, dass du dich zu dem Problem gemeldet hast!

  4. Hi Wolfgang,
    und Danke für deine Lib.

    Wie kann ich mit deiner Lib einen Verbindungsfehler feststellen ?

    Wenn man z.b. eine Leitung ( SCL, SDA) zieht, bekommt man immer 0 Lux zurück.
    Das ist aber ein gültiger Wert. Finger auf den Sensor und man bekommt auch ‚0‘ zurück.

    Gruß und Dank
    Gerd

    1. Hi Gerd,

      bis vor 20 min: gar nicht. Jetzt aber schon. Ich habe der init-Funktion einen Rückgabewert spendiert und den Beispielsketch entsprechend geändert. Falls die I2C Verbindung gestört ist, gibt es eine Fehlermeldung. Das ist jetzt die Version 1.1.9. Auf GitHub ist sie schon, bis die Arduino IDE merkt, dass es eine neue Version gibt, dauert es ein paar Stunden.

      Du kannst in der Zwischenzeit mal mit einem I2C Scanner probieren, ob du eine I2C Adresse erhältst und ob du sie ggf. ändern musst (im Sketch oder über den Adresspin):

      https://wolles-elektronikkiste.de/i2c-scanner

      VG, Wolfgang

      1. Danke für die schnelle Reaktion.
        Die init- Funktion dafür ist sicher eine gute Sache.

        Nur wenn im laufenden Betrieb was hängt, was dann ?

        Wie wärs bei getLux() mit dem Rückgabewert (-1) ? (-1) Lux gibts nicht.
        Dann kann man danach z.B. die init Funktion so lange aufrufen, bis alle Kabel wieder dran sind …

        GRuß und DAnk
        Gerd

        1. Hatte die Frage missverstanden. Ich dachte, es ginge um Probleme zu Beginn. Danke für die Anregung. Das werde ich vielleicht auch noch einmal einbauen, aber das nicht kurzfristig.

  5. Hallo Wolfgang,
    vielen Dank für die ausführliche Beschreibung des BH1750. Ich verwende den
    Sensor in einer kleinen Wetterstation mit einem ESP32 und Deiner Bibliothek
    im CLM –Mode und mit mtf=0.45. 65535 Lux sind für die maximal auftretende
    Messung der Globalstrahlung (ca. 600 W/m²) zu gering. Es läuft alles bestens.
    Ich habe trotzdem eine Frage. Den über“ get“ erhaltenen Lux-Wert muss ich
    nicht noch einmal korrigieren? In der cpp-Datei sind die Umrechnungen ja
    schon enthalten. Oder..

    Viele Grüße
    Dietrich

    1. Hallo Dietrich,
      ja, die die Messwerte sind in Lux, d.h. die Rohdaten sind nach den Angaben des Datenblattes umgerechnet. Der maximal messbare Wert nach meinen Berechnungen theoretisch 121557 Lux ((65536/1.2)/0.45). Nach Datenblatt sind es 100000 lux. Mehr gibt der Sensor nicht her. Inwieweit man Lichtmessungen überhaupt trauen kann, steht auf einem anderen Blatt Papier. Vergleichsmessungen zwischen verschiedenen Sensoren waren etwas ernüchternd:
      https://wolles-elektronikkiste.de/sensorvergleich
      VG, Wolfgang

  6. Hallo Wolfgang
    Komme mit den Anschlüssen des BH1750 nicht klar. Laut Datenblatt des Moduls verträgt das Modul eine Spannung von 3,3V bis 5V. Wenn ich mir das Schema zum Modul ansehe, so ist dort ein Regler drauf der vermutlich die Spannung auf 3,3V legt. Wie kann er dann funktionieren mit 3,3V und 5V? Sind den die Ausgänge SCL und SDA für 3,3V oder 5V geeignet oder muss ein Pegelwandler rein um den Bus an 5V anzuschliessen? Auf dem Modul sind ja auch 2 Widerstände mit 4,7kR drauf.
    achim

    1. Hallo Achim,

      ich habe gerade nochmal beide oben abgebildete Module nachgemessen. Sie scheinen unterschiedliche Schaltungen zu haben, aber bei beiden konnte ich nur die erlaubten 3,3 V an den SDA und SCL Beinchen direkt am BH1750 (also am IC) feststellen. Das kleine Modul scheint die gesamte I2C Leitung abzusenken. D.h. auch direkt am SDA und SCL Anschluss des Arduino habe ich diese Spannung festgestellt, sofern der BH1750 angeschlossen war. Wie das schaltungstechnisch realisiert wird ist mir nicht klar. Klingt irgendwie richtig, weil dann ja Strom über die I2C Leitung abfließen muss.

      Bei dem großen Modul ist die I2C Leitung über ein BSS138 (der als J1 gekennzeichnete „Dreibeiner“) Mosfet getrennt in einen 5 und einen 3.3 Volt Teil. Da messe ich unterschiedliche Spannungen am Arduino SDA/SCL und direkt am BH1750. Da verstehe ich allerdings nicht wie das mit nur einem BSS138 realisiert wird.

      Wie das mit zwei BSS138 gemacht wird sieht man beim Adafruit BH1750, denn die haben ihre Schaltung veröffentlicht:
      https://learn.adafruit.com/adafruit-bh1750-ambient-light-sensor/downloads

      Lange Rede, kurzer Sinn: es scheint, dass man grundsätzlich keinen Levelshifter braucht. Wenn du sicher gehen willst, dann miss einfach die Spannung am BH1750 IC nach.

      1. Hallo Wolfgang
        Habe die Schaltungen von beiden Modulen im Internet gesucht. Das Modul GY302 hat eine Vcc von 3,3V und keinen Pegelwandler drin. Die Ausgänge des BH1750 scheinen nur 3,3V zu vertragen. In dem anderen Modul (GY30) ist ein Mosfet als Pegelwandler drin und der andere hat einen Widerstand und eine Diode. Wie das gehen soll ist mir unklar. Werde wohl für das GY302 2x Pegalanpassung einbauen. Sonst habe ich auch keine Lösung dazu.
        achim

        1. Hallo Wolfgang
          Habe weiter nach einer Lösung gesucht. Es wird mir leider immer unklarer. Nach DB hat der BH1750 ja die 2 Ausgänge SCL und SDA. Beide gehen von 1,8V bis Vcc. Bei einer Spannung von 3,3V kommen dort auch nur max. 3,3V bei 7mA. Pegelwandler sind eigentlich kein Problem dabei. Dazu werden aber die 3,3V gebraucht und diese sind nicht rausgeführt. Leider bin jetzt so ziemlich am Ende mit meinem Wissen. Hast du eine Idee dazu?
          achim

          1. Das ist merkwürdig, dazu sind doch die Pull-Ups drauf?!

            Also wenn ich das Modul, das nur den Spannungsregler und die Pull-Ups besitzt, an 5 V anschließe, messe ich 3.3 V an SDA und SCL.

            1. Hallo Wolfgang
              Da der IC über Spannungswandler von 5V auf 3,3V gesetzt wir, wird er auch mit 3,3V betriben. Da haben SCL und SDA nur 3,3V. Die Pull-Ups dienen doch nur dazu SCL und SDA auf High zu ziehen. Wenn ich den Bus an 5V anschliesse kann alles möglich passieren. Sehr merkwürdig.
              achim

              1. In deinem vorherigen Kommentar hattest du geschrieben:

                „Pegelwandler sind eigentlich kein Problem dabei. Dazu werden aber die 3,3V gebraucht und diese sind nicht rausgeführt.“

                Aber wenn SDA und SCL auf der Seite des BH1750 auf 3.3 V hochgezogen werden, dann brauchst du doch keinen extra 3.3 V Ausgang. Setz einfach den Pegelwandler dazwischen und es sollte funktionieren. Ggf. musst du noch auf der MCU Seite den Pegelwandler mit 5 V versorgen.

                Und – auch wenn ich mich wiederhole – zu meinem Erstaunen hat auch das einfache BH1750 Modul die gesamte I2C Leitung auf 3.3 V heruntergezogen. Mein Fazit ist deshalb, dass man selbst für die einfachen Teile keinen Pegelwandler braucht. Aber das lässt sich ja auch nachmessen. Und wenn man dann eine zu hohe Spannung misst, nimmt man halt doch einen Pegelwandler. In der Regel gehen die Module nicht gleich bei kurzfristiger Überlatung kaputt.

  7. Vielen Dank für deine Bemühungen. Das muss ich mal testen. Stehen tuen die Libs bei mir in dem Verzeichnispfad des Projektordners. Es kommt wohl auf die Schreibweise drauf an. bei manchen gehts, bei anderen nicht. Ich habe bisher immer den physikalischen Dateipfad eingetragen angegeben anstatt $(ARDUINO_DIR).
    Auf jeden Fall funktioniert das Auslesen der Sensoren. Inzwischen habe ich auch eine Sensorvariante gefunden und bestellt, die ideal für außen geeignet ist. z.B. hier: https://www.amazon.de/gp/product/B083TDQPTG/ref=ppx_yo_dt_b_asin_title_o00_s00?ie=UTF8&psc=1.
    Kosten auch nur ein paar Cent mehr. Gibt es auch von einem deutschen Anbieter, kosten dann aber das doppelte. Aber dafür Lieferzeit nur ein paar Tage. Wenn ich die Sensoren habe, werde ich berichten, ob sie was taugen.

    1. Diese Variante kannte ich noch nicht. Sehr sinnvoll. Bist du sonst noch weitergekommen? Vielleicht erwartet CB auch eine andere und es hängt es mit der Schreibweise des Konstruktors in meiner Bibliothek zusammen!? Ich könnte noch einmal etwas probieren, wenn es noch nicht klappt und du noch nicht die Lust verloren hast.

  8. Hallo Wolfgang,
    ich bin gerade dabei, meine Rolladensteuerung mit 2 analogen Sonnensensoren auf digital umzustellen. Ich habe zunächst deinen Code für einen Sensor ohne Bib benutzt. Hat auch einwandfrei funktioniert.
    Mit der Bib bekomme ich mit einem Sensor beim Compilieren allerdings eine Fehlermeldung.
    Ich bin aber auch kein Spezialist was Klassen und Bibs betrifft.
    Zur Softwareentwicklung benutze ich seit 2013 Codeblocks f. Arduino. Ist zwar gewöhnungsbedürftig und eigentlich überqualifiziert, hat bisher aber immer funktioniert.
    Dazu folgende Fragen:
    1. Hat jemand eine Idee, wodurch die Fehlermeldung entstanden sein könnte?
    2. Habe mit den Deklarationen schon mal einen Ansatz gemacht, um 2 Sensoren anzusprechen.
    Würde das so funktionieren, da ja in den Lese-/Schreibroutinen die I2C-Adresse übergeben wird.
    Codeschnipsel und Fehlermeldungen:
    // —- Bibliotheken
    #include
    #include
    #include
    #include
    #include
    #include
    #include
    //——– 1750 I2C Adressen ——
    #define BH1750_1Adr 0x23
    #define BH1750_2Adr 0x5c
    //—– 1750-Zuweisungen ——
    BH1750_WE my1750_1 (BH1750_1Adr);
    //BH1750_WE my1750_2(BH1750_2Adr);

    void setup()
    {
    Serial.begin(9600);
    lcd.begin(20,4);
    Wire.begin();
    my1750_1.init(); // sets default values: mode = CHM, measuring time factor = 1.0
    // my1750_1.setMode(CHM2); // uncomment if you want to change default values
    // my1750_1.setMeasuringTimeFactor(0.45); // uncomment for selection of value between 0.45 and 3.68
    //my1750_2.init(); // sets default values: mode = CHM, measuring time factor = 1.0
    // my1750_2.setMode(CHM2); // uncomment if you want to change default values
    // my1750_2.setMeasuringTimeFactor(0.45); // uncomment for selection of value between 0.45 and 3.68
    }
    void loop()
    {
    float lightInt_1 = my1750_1.getLux();
    // float lightInt_2 = my1750_2.getLux();
    .
    .
    .
    delay(1000);
    }

    ————– Build: Arduino Uno in 1750 (compiler: GNU AVR GCC Compiler)—————

    Compiling: 1750.ino
    Linking console executable: build\1750_uno.elf
    build\1750.o: In function `global constructors keyed to my1750_1′:
    1750.ino:(.text._GLOBAL__I_my1750_1+0x12): undefined reference to `BH1750_WE::BH1750_WE(int)‘
    build\1750.o: In function `setup‘:
    1750.ino:(.text.setup+0x34): undefined reference to `BH1750_WE::init()‘
    Process terminated with status 1 (0 minute(s), 5 second(s))
    2 error(s), 0 warning(s) (0 minute(s), 5 second(s))

    1. Hallo Jürgen, zumindest die zweite Frage kann ich beantworten: ja, so solltest du zwei BH1750 betrieben können. Nützt natürlich nichts wenn schon einer nicht geht, was zur schwierigeren Frage 1 führt. Ich habe Codeblocks zwar schon mal ausprobiert, aber nicht zum Arduino Programmieren. Ich weiß als nicht, ob es an Codeblocks und dessen Compiler liegen kann. Kannst du mir mal dass ganze Programm an wewald@gmx.de schicken? Vielleicht werde ich daraus schlauer. Und kannst du mal „BH1750_WE my1750_1 (BH1750_1Adr);“ ersetzen durch „BH1750_WE my1750_1 = BH1750_WE(BH1750_1Adr);“. Sollte eigentlich dasselbe bewirken, aber probiere es mal.

      1. Und ich habe nochmal ein bisschen gegoogelt und bin auf Folgendes im Codeblocks Forum gestoßen:

        http://forums.codeblocks.org/index.php?topic=20651.0

        Dasselbe Problem mit denselben Fehlermeldungen. Am Ende wurde es gelöst, indem die .cpp und .h Dateien (also für dich BH1750_WE.h bzw. BH1750_WE.cpp) in den Projektordner kopiert wurden und die Dateien dem Projekt in Codeblocks zugefügt wurden. Hilft das weiter?

        Hier das Original:
        I had to add .cpp and .h library files into my project folder AND – add these files into project in CodeBlocks.
        After that everything goes ok.

  9. Hallo Wolfgang,

    vielen Dank.

    Da ist ein kleiner Fehler
    in der Funktion uint16_t getLux() ohne Bibliothek.
    Der Rückgabewert fehlt.

    return lux;

    Ansonsten klappt das auf meinem Nano einwandfrei.

    Gruß

  10. Hallo,
    Vielen Dank(!!) für die schnelle Hilfe.Jetzt klappt Alles, aber den Fehler habe ich bisher nicht gefunden(??!) Aber….
    Viele Grüße

    1. Der Fehler war, dass die Funktion readBH1750 einen Wert zurückliefern soll, ich aber „void“ davor geschrieben habe. Ich habe „void“ gegen „uint16_t“ , das entspricht „unsigned int“ getauscht.

      1. Hallo,
        ich hatte inzwischen den Unterschied gefunden aber nicht verstanden. Ihr letzter Satz war für mich die Lösung. Wieder etwas gelernt!! Danke!
        B. Kniebusch

  11. Hallo, ich bin Anfänger(!) und besonders erfreut, auf Ihrer Website diese ausführliche Beschreibung des „BH1750“ gefunden zu haben. Ich habe mir den Code (ohne Bibliothek) kopiert, in die Arduino IDE eingefügt
    und erst einmal die Fehlersuche der IDE laufen lassen. Diese gab mir folgenden Fehler aus:
    „void value not ignored as it ought to be“ in Zeile 31 (rawLux = readBH1750();“)
    Leider kann ich damit nichts anfangen(??) Was mache ich falsch???

    Ich würde mich über eine Hilfe Ihrerseits sehr freuen Vielen Dank im voraus! B. Kniebusch

    1. Hallo, Sie haben nichts falsch gemacht, ich habe es gerade geprüft und da ist noch ein Fehler in meinem Sketch. Ich werde ihn umgehend beseitigen und melde mich dann.

      1. Jetzt sollte es gehen. Beim Kompilieren gibt es keine Beschwerde mehr. Wenn es nicht funktioniert, dann bitte noch mal melden. Eigentlich sind alle Sketche getestet. Es ist aber nie ganz ausgeschlossen, dass ich doch mal beim Kopieren nicht die Endversion erwische…. Tut mir leid, wenn Sie schon viel Zeit damit verbracht haben!

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert