Library for BH1750 I2C light sensor. Supports autoranging! True to datasheet. (beware: calls are blocking at the moment)
So there is this light sensor (like the one present in any phone), BH1750
.
I got mine soldered to some nice breakout board.
Few facts about this library: it is very true to the datasheet. it takes advantage of MTreg (time of measurement), which lets you to increase resolution up to 3.86 times at the cost of time it takes to perform a measurement. Measurement is blocking ! I've also implemented an autoranging feature. Just like in those fancy multimeters! It works as follows, thresholds are hard-coded:
- <5 lx switches to Hi-res2 and to max MTreg (so measurement time is like 500ms)
- <1000 lx Hi-res, MTreg default.
- above there is no real need for Hi-res, so Low-res mode is used.
Last note: I greatly recommend you to use log10 value of the luminosity data. it makes much more sense, because it becomes linear.
Revision 0:a7280a6c3c9b, committed 2017-08-22
- Comitter:
- amateusz
- Date:
- Tue Aug 22 00:29:50 2017 +0000
- Commit message:
- initial commit. supports autoranging, addresss selection, all continous modes
Changed in this revision
BH1750.cpp | Show annotated file Show diff for this revision Revisions of this file |
BH1750.h | Show annotated file Show diff for this revision Revisions of this file |
diff -r 000000000000 -r a7280a6c3c9b BH1750.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/BH1750.cpp Tue Aug 22 00:29:50 2017 +0000 @@ -0,0 +1,144 @@ +#include "BH1750.h" + + +BH1750::BH1750(I2C & i2c_inst, bool autoRange, bool addressPinState): _i2c_inst(i2c_inst) { + if (addressPinState == true) _address = ADDRESS_HIGH; + else _address = ADDRESS_LOW; + + _autoModeAdjustSwitch = autoRange; +} + + +void BH1750::_sendCommand(char toSend) { + char toSendPseudoArray[] = {toSend}; + _i2c_inst.write(_address << 1, toSendPseudoArray, 1); +} + +unsigned int BH1750::_readRaw() { + unsigned int measurement; + char measurement_intermediate [2]; + _i2c_inst.read(_address << 1, measurement_intermediate, 2); + measurement = (measurement_intermediate[0] << 8) + measurement_intermediate[1]; + return measurement; +} +bool BH1750::_autoModeAdjust(float measurement) { // returns if adjusted or left alone +// printf("\tcurrentMode: %d\r\n", _currentMode); + char previousMode = _currentMode; + char previousMtreg = _currentMtreg; + bool changed = false; + + if (measurement < 5.0 ) { + if (_currentMode != CONTINOUS_H2_RES_CMD ) { + setMode(CONTINOUS_H2_RES_CMD); + setMtreg(254); //maximum + changed = true; + } + } else if (measurement < 1000.0) { + if (_currentMode != CONTINOUS_H_RES_CMD ) { + + setMtreg(DEFAULTMTREG); + setMode(CONTINOUS_H_RES_CMD); + changed = true; + } + } else if (_currentMode != CONTINOUS_L_RES_CMD) { + setMtreg(DEFAULTMTREG); + setMode(CONTINOUS_L_RES_CMD); + changed = true; + } + + if (changed) { + wait_ms(_waitForMeasurement); // one more wait in PREVIOUS state. guarantees valid values on state transitions + return true; + } else + return false; +} + +float BH1750::_readSingle() { + float measurement; + // measurement switch + switch(_currentMode) { + case ONETIME_L_RES_CMD: + _sendCommand(_currentMode); + _waitForMeasurement = L_RES_MEASUREMENT_TIME; + break; + case ONETIME_H_RES_CMD: + _sendCommand(_currentMode); + _waitForMeasurement = H_RES_MEASUREMENT_TIME; + break; + case ONETIME_H2_RES_CMD: + _sendCommand(_currentMode); + _waitForMeasurement = H_RES_MEASUREMENT_TIME; + break; + case CONTINOUS_L_RES_CMD: + _waitForMeasurement = L_RES_MEASUREMENT_TIME; + break; + case CONTINOUS_H_RES_CMD: + _waitForMeasurement = H_RES_MEASUREMENT_TIME; + break; + case CONTINOUS_H2_RES_CMD: + _waitForMeasurement = H_RES_MEASUREMENT_TIME; + break; + } + + _waitForMeasurement *= (unsigned int) ((float) _currentMtreg / (float) DEFAULTMTREG); // a bit too late, but nevermind + wait_ms(_waitForMeasurement); + measurement = (float)_readRaw(); + + // post-measurement switch + switch(_currentMode) { + case ONETIME_L_RES_CMD: + case ONETIME_H_RES_CMD: + case ONETIME_H2_RES_CMD: + break; + + case CONTINOUS_L_RES_CMD: + break; + case CONTINOUS_H_RES_CMD: + break; + case CONTINOUS_H2_RES_CMD: + measurement /= 2.0; + break; + } + +// printf("wait for meas value: %d\r\n", _waitForMeasurement); + + measurement = measurement / 1.2 * (float) DEFAULTMTREG / (float) _currentMtreg; + return measurement; +} + +void BH1750::power(bool state) { + if (state == true) {// power on + _sendCommand(powerOn_cmd); + } else { // power off} + _sendCommand(powerDown_cmd); + } +} + +float BH1750::read() { + float measurement; + do { + measurement = _readSingle(); +// printf("measurement do while: %.1f\r\n", measurement); + if (!_autoModeAdjustSwitch) break; + // else continue +// wait_ms(1.3*_waitForMeasurement); + } while(_autoModeAdjust(measurement)); + return measurement; +} + +void BH1750::setMode(const char mode) { + _sendCommand(mode); + _currentMode = mode; + wait(.01); +} + +void BH1750::setMtreg(char newMtreg) { + // min. 31 + // default 69 + // max. 254 + if (newMtreg >= 31 && newMtreg <= 254) { + _sendCommand((0b01000 << 3) | (newMtreg >> 5)); + _sendCommand((0b011 << 5 ) | (newMtreg & 0b111)); + _currentMtreg = newMtreg; + } +} \ No newline at end of file
diff -r 000000000000 -r a7280a6c3c9b BH1750.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/BH1750.h Tue Aug 22 00:29:50 2017 +0000 @@ -0,0 +1,46 @@ +#include "mbed.h" + +#ifndef BH1750_h +#define BH1750_h + +class BH1750 +{ +private: + static const char ADDRESS_LOW = 0x23; + static const char ADDRESS_HIGH = 0x5C; + static const char powerOn_cmd = 0b00000001; + static const char powerDown_cmd = 0b00000000; + static const char reset_cmd = 0b00000111; + + static const char L_RES_MEASUREMENT_TIME = 12; // ms + static const char H_RES_MEASUREMENT_TIME = 120; // ms + + char _address; + char _currentMode; + char _currentMtreg; + unsigned int _waitForMeasurement; + bool _autoModeAdjustSwitch; + I2C &_i2c_inst; + + void _sendCommand(char); + + unsigned int _readRaw(); + bool _autoModeAdjust(float measurement); // returns if adjusted or left alone + float _readSingle(); +public: + static const char CONTINOUS_L_RES_CMD = 0b00010011; + static const char CONTINOUS_H_RES_CMD = 0b00010000; + static const char CONTINOUS_H2_RES_CMD = 0b00010001; + static const char ONETIME_L_RES_CMD = 0b01000011; + static const char ONETIME_H_RES_CMD = 0b01000000; + static const char ONETIME_H2_RES_CMD = 0b01000001; + static const char DEFAULTMTREG = 69; + + BH1750(I2C & , bool autoRange = false, bool addressPinState = false); + void power(bool); // power on or off. + float read(); // main function to read a value (or rather perform a read when in one_time mode) + void setMode(const char); // set mode. datasheet lists L, H, H2 resolution modes in continous and one_time versions + void setMtreg(char); // correcting measurement time. can be used to increase precision by a factor of 3.86 at the cost of time +}; + +#endif \ No newline at end of file