diff --git a/BH1750/LICENSE b/BH1750/LICENSE new file mode 100644 index 0000000..604d838 --- /dev/null +++ b/BH1750/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2018 claws + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/BH1750/README.md b/BH1750/README.md new file mode 100644 index 0000000..8d6e0b6 --- /dev/null +++ b/BH1750/README.md @@ -0,0 +1,165 @@ +# BH1750 + +[![Build Status](https://travis-ci.org/claws/BH1750.svg?branch=master)](https://travis-ci.org/claws/BH1750)
+ +This package contains an Arduino library for digital light sensor breakout boards containing the +BH1750FVI IC. + +The BH1750 board uses I2C for communication which requires two pins to +communicate with the device. Configuring the I2C bus must be done in user code +(not library code). This approach has been adopted so it can be done once and +will better support the various options for different platforms. + +A common module containing the BH1750 component is the GY-30 shown below. + +![GY-30 Module image](resources/gy30-module.jpg) + + +## Overview + +The BH1750 has six different measurement modes which are divided in two groups; +continuous and one-time measurements. In continuous mode the sensor +continuously measures lightness value. In one-time mode, the sensor makes only +one measurement and then goes into Power Down mode. + +Each mode has three different precisions: + + - Low Resolution Mode - (4 lx precision, 16ms measurement time) + - High Resolution Mode - (1 lx precision, 120ms measurement time) + - High Resolution Mode 2 - (0.5 lx precision, 120ms measurement time) + +By default, this library uses Continuous High Resolution Mode, but you can +change this to a different mode by passing the mode argument to +BH1750.begin(). + +When the One-Time mode is used your sensor will go into Power Down mode when +it completes the measurement and you've read it. When the sensor is powered up +again it returns to the default mode which means it needs to be reconfigured +back into One-Time mode. This library has been implemented to automatically +reconfigure the sensor when you next attempt a measurement so you should not +have to worry about such low level details. + +Usually you will get an integer value which represent the lux equivalent. + - Low Resolution Mode - (generic range: 0.0 up to 54612.5 lux) + - High Resolution Mode - (generic range: 0.0 up to 54612.5 lux) + - High Resolution Mode 2 - (generic range: 0.0 up to 27306.25 lux) + +The sensor itself returns a 16 bit unsigned integer. Therefore the maximum value is limited in general. +The standard conversion between the so called 'counts' to lux is 1/1.2, that means you get a smaller value. +As we use float, if an error occurs you will get a negative value. + - -1 no valid data was transmitted from the sensor + - -2 device is not configured +Otherwise the measured counts are converted to lux and returned. If no advanced parameters are changed the maximum lux value is 54612.5 lx. + +As the sensor counts impact of light in a specific time frame you could change this time frame. +This is needed if you use an overlay window or compensate for environmental influence like darkness. +This time frame is defined by a register which is called MTreg. Therefore you could choose a value between 32 and 254. +The default value is 69; keep in mind that the measurement time is changed accordingly. + +The datasheet for the BH1750 chip can be obtained +[here](https://www.mouser.de/datasheet/2/348/Rohm_11162017_ROHMS34826-1-1279292.pdf)[2011.11 Rev.D] + + +## Installation [![arduino-library-badge](https://www.ardu-badge.com/badge/BH1750.svg?)](https://www.ardu-badge.com/BH1750) + +- **(For Arduino >= 1.5.x)** Install this package by searching for it in the + Arduino Library Manager and then clicking ``install``. Alternatively, this + library can be installed manually by clicking "Clone or download" -> "Download ZIP" + button. Then open Arduino IDE, click `Sketch -> Include library -> Add .ZIP library` + and select the downloaded archive. + +- **(For Arduino < 1.5.x)** Download this package as an archive by clicking + "Clone or download" -> "Download ZIP" button. Then extract the archive to + ``/My Documents/Arduino/libraries/`` folder and rename + it to `BH1750`. Restart IDE. + +The following YouTube [video](https://youtu.be/ACTMQvPVMLs) (specifically from +7:20 onwards) provides a good overview of manually installing this library and +loading an example using the Arduino IDE. + +[![BH1750 Video Tutorial](https://img.youtube.com/vi/ACTMQvPVMLs/0.jpg)](https://youtu.be/ACTMQvPVMLs?t=437) + +Information about the library installation process - https://www.arduino.cc/en/Guide/Libraries + + +## Example + +An example using the BH1750 library in conjunction with the GY-30 board +(which contains the BH1750 component) is presented below. The example +code uses the BH1750 library in the default continuous high precision +mode when making light measurements. + +### Wiring + +Connections: + + - VCC -> 3V3 or 5V + - GND -> GND + - SCL -> SCL (A5 on Arduino Nano, Uno, Leonardo, etc or 21 on Mega and Due, on esp8266 free selectable) + - SDA -> SDA (A4 on Arduino Nano, Uno, Leonardo, etc or 20 on Mega and Due, on esp8266 free selectable) + - ADD -> NC/GND or VCC (see below) + +The ADD pin is used to set the sensor I2C address. By default (if ADD voltage +less than 0.7 * VCC) the sensor address will be 0x23. If it has voltage +greater or equal to 0.7VCC voltage (e.g. you've connected it to VCC) the +sensor address will be 0x5C. + +Wiring up the GY-30 sensor board to an Arduino is shown in the diagram below. + +![Example wiring diagram image](resources/wiring-diagram-gy30-module.png) + +*The image above was created using [Fritzing](http://fritzing.org/home/) and +the GY-30 module was obtained from [here](http://omnigatherum.ca/wp/?p=6)*. + +### Code + +Upload the BH1750 test code to your Arduino. + +``` c++ +#include +#include + +BH1750 lightMeter; + +void setup(){ + + Serial.begin(9600); + + // Initialize the I2C bus (BH1750 library doesn't do this automatically) + // On esp8266 devices you can select SCL and SDA pins using Wire.begin(D4, D3); + Wire.begin(); + + lightMeter.begin(); + Serial.println(F("BH1750 Test")); + +} + +void loop() { + + float lux = lightMeter.readLightLevel(); + Serial.print("Light: "); + Serial.print(lux); + Serial.println(" lx"); + delay(1000); + +} +``` + +### Output + +Moving the sensor to face more light results in the lux measurements increasing. +``` +BH1750 Test +Light: 70.0 lx +Light: 70.0 lx +Light: 59.0 lx +Light: 328.0 lx +Light: 333.0 lx +Light: 335.0 lx +Light: 332.0 lx +``` + +## More Examples + +The ``examples`` directory contains more advanced use cases such as using different modes, I2C addresses and multiple Wire instances. + diff --git a/BH1750/build-examples.bash b/BH1750/build-examples.bash new file mode 100644 index 0000000..c2916bc --- /dev/null +++ b/BH1750/build-examples.bash @@ -0,0 +1,36 @@ +#!/usr/bin/env bash +# +# A simple script to automate building BH1750 examples. +# +# Example (MacOSX): +# $ ARDUINO_IDE_PATH=/Applications/Arduino.app/Contents/Java ./build-examples.bash +# + +# Path to script directory. +SCRIPTPATH="$( cd "$(dirname "$0")" ; pwd -P )" +LIBNAME="$(basename "$SCRIPTPATH")" + +if [[ -z "${ARDUINO_IDE_PATH}" ]]; then + echo "ARDUINO_IDE_PATH env var is not set" + exit 1 +fi + +# Link BH1750 library into Arduino libraries directory +ln -s $SCRIPTPATH $ARDUINO_IDE_PATH/libraries/ + +cd $ARDUINO_IDE_PATH + +for sketch in `find $SCRIPTPATH/examples -name '*.ino'` +do + echo "Compiling $sketch" + ./arduino-builder -hardware ./hardware -tools ./hardware/tools/avr -tools ./tools-builder -libraries ./libraries -fqbn arduino:avr:uno --prefs "compiler.warning_level=all" $sketch + # ./arduino-builder -hardware ./hardware -tools ./hardware/tools/avr -tools ./tools-builder -libraries ./libraries -fqbn esp8266:esp8266:generic --prefs "compiler.warning_level=all" $sketch + if [ $? -ne 0 ]; then + echo -e "\xe2\x9c\x96" # check icon + else + echo -e "\xe2\x9c\x93" # tick icon + fi +done + +# Unlink BH1750 library from Arduino libraries directory +unlink $ARDUINO_IDE_PATH/libraries/$LIBNAME diff --git a/BH1750/component.mk b/BH1750/component.mk new file mode 100644 index 0000000..27ad11a --- /dev/null +++ b/BH1750/component.mk @@ -0,0 +1 @@ +COMPONENT_ADD_INCLUDEDIRS := . diff --git a/BH1750/examples/BH1750advanced/BH1750advanced.ino b/BH1750/examples/BH1750advanced/BH1750advanced.ino new file mode 100644 index 0000000..d03f051 --- /dev/null +++ b/BH1750/examples/BH1750advanced/BH1750advanced.ino @@ -0,0 +1,95 @@ +/* + + Advanced BH1750 library usage example + + This example has some comments about advanced usage features. + + Connection: + + VCC -> 3V3 or 5V + GND -> GND + SCL -> SCL (A5 on Arduino Uno, Leonardo, etc or 21 on Mega and Due, on esp8266 free selectable) + SDA -> SDA (A4 on Arduino Uno, Leonardo, etc or 20 on Mega and Due, on esp8266 free selectable) + ADD -> (not connected) or GND + + ADD pin is used to set sensor I2C address. If it has voltage greater or equal to + 0.7VCC voltage (e.g. you've connected it to VCC) the sensor address will be + 0x5C. In other case (if ADD voltage less than 0.7 * VCC) the sensor address will + be 0x23 (by default). + +*/ + +#include +#include + +/* + BH1750 can be physically configured to use two I2C addresses: + - 0x23 (most common) (if ADD pin had < 0.7VCC voltage) + - 0x5C (if ADD pin had > 0.7VCC voltage) + + Library uses 0x23 address as default, but you can define any other address. + If you had troubles with default value - try to change it to 0x5C. + +*/ +BH1750 lightMeter(0x23); + +void setup(){ + + Serial.begin(9600); + + // Initialize the I2C bus (BH1750 library doesn't do this automatically) + Wire.begin(); + // On esp8266 you can select SCL and SDA pins using Wire.begin(D4, D3); + + /* + + BH1750 has six different measurement modes. They are divided in two groups; + continuous and one-time measurements. In continuous mode, sensor continuously + measures lightness value. In one-time mode the sensor makes only one + measurement and then goes into Power Down mode. + + Each mode, has three different precisions: + + - Low Resolution Mode - (4 lx precision, 16ms measurement time) + - High Resolution Mode - (1 lx precision, 120ms measurement time) + - High Resolution Mode 2 - (0.5 lx precision, 120ms measurement time) + + By default, the library uses Continuous High Resolution Mode, but you can + set any other mode, by passing it to BH1750.begin() or BH1750.configure() + functions. + + [!] Remember, if you use One-Time mode, your sensor will go to Power Down + mode each time, when it completes a measurement and you've read it. + + Full mode list: + + BH1750_CONTINUOUS_LOW_RES_MODE + BH1750_CONTINUOUS_HIGH_RES_MODE (default) + BH1750_CONTINUOUS_HIGH_RES_MODE_2 + + BH1750_ONE_TIME_LOW_RES_MODE + BH1750_ONE_TIME_HIGH_RES_MODE + BH1750_ONE_TIME_HIGH_RES_MODE_2 + + */ + + // begin returns a boolean that can be used to detect setup problems. + if (lightMeter.begin(BH1750::CONTINUOUS_HIGH_RES_MODE)) { + Serial.println(F("BH1750 Advanced begin")); + } + else { + Serial.println(F("Error initialising BH1750")); + } + +} + + +void loop() { + if (lightMeter.measurementReady()) { + float lux = lightMeter.readLightLevel(); + Serial.print("Light: "); + Serial.print(lux); + Serial.println(" lx"); + } + +} diff --git a/BH1750/examples/BH1750autoadjust/BH1750autoadjust.ino b/BH1750/examples/BH1750autoadjust/BH1750autoadjust.ino new file mode 100644 index 0000000..8ac7e71 --- /dev/null +++ b/BH1750/examples/BH1750autoadjust/BH1750autoadjust.ino @@ -0,0 +1,98 @@ +/* + + Example of BH1750 library usage. + + This example initialises the BH1750 object using the default high resolution + one shot mode and then makes a light level reading every five seconds. + + After the measurement the MTreg value is changed according to the result: + lux > 40000 ==> MTreg = 32 + lux < 40000 ==> MTreg = 69 (default) + lux < 10 ==> MTreg = 138 + Remember to test your specific sensor! Maybe the MTreg value range from 32 + up to 254 is not applicable to your unit. + + Connection: + + VCC -> 3V3 or 5V + GND -> GND + SCL -> SCL (A5 on Arduino Uno, Leonardo, etc or 21 on Mega and Due, on esp8266 free selectable) + SDA -> SDA (A4 on Arduino Uno, Leonardo, etc or 20 on Mega and Due, on esp8266 free selectable) + ADD -> (not connected) or GND + + ADD pin is used to set sensor I2C address. If it has voltage greater or equal to + 0.7VCC voltage (e.g. you've connected it to VCC) the sensor address will be + 0x5C. In other case (if ADD voltage less than 0.7 * VCC) the sensor address will + be 0x23 (by default). + +*/ + +#include +#include + +BH1750 lightMeter; + +void setup(){ + + Serial.begin(9600); + + // Initialize the I2C bus (BH1750 library doesn't do this automatically) + Wire.begin(); + // On esp8266 you can select SCL and SDA pins using Wire.begin(D4, D3); + + lightMeter.begin(BH1750::ONE_TIME_HIGH_RES_MODE); + //lightMeter.setMTreg(69); // not needed, only mentioning it + + Serial.println(F("BH1750 Test begin")); + +} + +void loop() { + //we use here the maxWait option due fail save + if (lightMeter.measurementReady(true)) { + float lux = lightMeter.readLightLevel(); + Serial.print(F("Light: ")); + Serial.print(lux); + Serial.println(F(" lx")); + + if (lux < 0) { + Serial.println(F("Error condition detected")); + } + else { + if (lux > 40000.0) { + // reduce measurement time - needed in direct sun light + if (lightMeter.setMTreg(32)) { + Serial.println(F("Setting MTReg to low value for high light environment")); + } + else { + Serial.println(F("Error setting MTReg to low value for high light environment")); + } + } + else { + if (lux > 10.0) { + // typical light environment + if (lightMeter.setMTreg(69)) { + Serial.println(F("Setting MTReg to default value for normal light environment")); + } + else { + Serial.println(F("Error setting MTReg to default value for normal light environment")); + } + } + else { + if (lux <= 10.0) { + //very low light environment + if (lightMeter.setMTreg(138)) { + Serial.println(F("Setting MTReg to high value for low light environment")); + } + else { + Serial.println(F("Error setting MTReg to high value for low light environment")); + } + } + } + } + + } + Serial.println(F("--------------------------------------")); + } + delay(5000); +} diff --git a/BH1750/examples/BH1750onetime/BH1750onetime.ino b/BH1750/examples/BH1750onetime/BH1750onetime.ino new file mode 100644 index 0000000..c22ff9a --- /dev/null +++ b/BH1750/examples/BH1750onetime/BH1750onetime.ino @@ -0,0 +1,44 @@ +/* + + Example of BH1750 library usage. + + This example initialises the BH1750 object using the high resolution + one-time mode and then makes a light level reading every second. + + The BH1750 component starts up in default mode when it next powers up. + The BH1750 library automatically reconfigures the one-time mode in + preparation for the next measurement. + +*/ + +#include +#include + +BH1750 lightMeter; + +void setup(){ + + Serial.begin(9600); + + // Initialize the I2C bus (BH1750 library doesn't do this automatically) + Wire.begin(); + // On esp8266 you can select SCL and SDA pins using Wire.begin(D4, D3); + + lightMeter.begin(BH1750::ONE_TIME_HIGH_RES_MODE); + + Serial.println(F("BH1750 One-Time Test")); + +} + + +void loop() { + + while (!lightMeter.measurementReady(true)) { + yield(); + } + float lux = lightMeter.readLightLevel(); + Serial.print("Light: "); + Serial.print(lux); + Serial.println(" lx"); + lightMeter.configure(BH1750::ONE_TIME_HIGH_RES_MODE); +} diff --git a/BH1750/examples/BH1750test/BH1750test.ino b/BH1750/examples/BH1750test/BH1750test.ino new file mode 100644 index 0000000..4ca5c10 --- /dev/null +++ b/BH1750/examples/BH1750test/BH1750test.ino @@ -0,0 +1,54 @@ +/* + + Example of BH1750 library usage. + + This example initialises the BH1750 object using the default high resolution + continuous mode and then makes a light level reading every second. + + Connection: + + VCC -> 3V3 or 5V + GND -> GND + SCL -> SCL (A5 on Arduino Uno, Leonardo, etc or 21 on Mega and Due, on esp8266 free selectable) + SDA -> SDA (A4 on Arduino Uno, Leonardo, etc or 20 on Mega and Due, on esp8266 free selectable) + ADD -> (not connected) or GND + + ADD pin is used to set sensor I2C address. If it has voltage greater or equal to + 0.7VCC voltage (e.g. you've connected it to VCC) the sensor address will be + 0x5C. In other case (if ADD voltage less than 0.7 * VCC) the sensor address will + be 0x23 (by default). + +*/ + + +#include +#include + +BH1750 lightMeter; + + +void setup(){ + + Serial.begin(9600); + + // Initialize the I2C bus (BH1750 library doesn't do this automatically) + Wire.begin(); + // On esp8266 you can select SCL and SDA pins using Wire.begin(D4, D3); + // For Wemos / Lolin D1 Mini Pro and the Ambient Light shield use Wire.begin(D2, D1); + + lightMeter.begin(); + + Serial.println(F("BH1750 Test begin")); + +} + + +void loop() { + + float lux = lightMeter.readLightLevel(); + Serial.print("Light: "); + Serial.print(lux); + Serial.println(" lx"); + delay(1000); + +} diff --git a/BH1750/examples/BH1750two_i2c/BH1750two_i2c.ino b/BH1750/examples/BH1750two_i2c/BH1750two_i2c.ino new file mode 100644 index 0000000..49bcd8e --- /dev/null +++ b/BH1750/examples/BH1750two_i2c/BH1750two_i2c.ino @@ -0,0 +1,73 @@ +/* + + Example of BH1750 library usage. + + This example initialises two BH1750 objects using different TwoWire + instances (Wire and Wire1) and then makes a light level reading every second. + This is the case for boards such as the ESP8266 and ESP32 + + Connection: + + BH1750 A: + VCC -> 3V3 or 5V + GND -> GND + SCL -> SCL (19 in this example) + SDA -> SDA (18 in this example) + ADD -> (not connected) or GND + + BH1750 B: + VCC -> 3V3 or 5V + GND -> GND + SCL -> SCL (22 in this example) + SDA -> SDA (21 in this example) + ADD -> (not connected) or GND + + ADD pin is used to set sensor I2C address. If it has voltage greater or equal to + 0.7VCC voltage (e.g. you've connected it to VCC) the sensor address will be + 0x5C. In other case (if ADD voltage less than 0.7 * VCC) the sensor address will + be 0x23 (by default). + +*/ + +#include "BH1750.h" +#include "Wire.h" + +BH1750 bh1750_a; +BH1750 bh1750_b; + +void setup() { + Serial.begin(115200); + Wire.begin(18, 19); + Wire1.begin(21, 22); + bh1750_a.begin(BH1750::CONTINUOUS_HIGH_RES_MODE, 0x23, &Wire); + bh1750_b.begin(BH1750::CONTINUOUS_HIGH_RES_MODE, 0x23, &Wire1); +} + +int error_counter_1_a = 0; +int error_counter_2_a = 0; +int error_counter_1_b = 0; +int error_counter_2_b = 0; + +void loop() { + float light_level_a; + if (bh1750_a.measurementReady()) { light_level_a = bh1750_a.readLightLevel(); } + float light_level_b; + if (bh1750_b.measurementReady()) { light_level_b = bh1750_b.readLightLevel(); } + + if (lround(light_level_a) == -1) { + error_counter_1_a++; + } + if (lround(light_level_a) == -2) { + error_counter_2_a++; + } + if (lround(light_level_b) == -1) { + error_counter_1_b++; + } + if (lround(light_level_b) == -2) { + error_counter_2_b++; + } + Serial.printf("A: %.0f lux %d:%d :: B: %.0f lux %d:%d\n", light_level_a, + error_counter_1_a, error_counter_2_a, light_level_b, + error_counter_1_b, error_counter_2_b); + delay(1000); +} diff --git a/BH1750/keywords.txt b/BH1750/keywords.txt new file mode 100644 index 0000000..b7c12da --- /dev/null +++ b/BH1750/keywords.txt @@ -0,0 +1,34 @@ +####################################### +# Syntax Coloring Map For BH1750 +####################################### + +####################################### +# Datatypes (KEYWORD1) +####################################### + +BH1750 KEYWORD1 + +####################################### +# Methods and Functions (KEYWORD2) +####################################### + +begin KEYWORD2 +configure KEYWORD2 +setMTreg KEYWORD2 +readLightLevel KEYWORD2 +measurementReady KEYWORD2 +####################################### +# Instances (KEYWORD2) +####################################### + + +####################################### +# Constants (LITERAL1) +####################################### +BH1750_CONTINUOUS_HIGH_RES_MODE LITERAL1 +BH1750_CONTINUOUS_HIGH_RES_MODE_2 LITERAL1 +BH1750_CONTINUOUS_LOW_RES_MODE LITERAL1 +BH1750_ONE_TIME_HIGH_RES_MODE LITERAL1 +BH1750_ONE_TIME_HIGH_RES_MODE_2 LITERAL1 +BH1750_ONE_TIME_LOW_RES_MODE LITERAL1 +BH1750_DEFAULT_MTREG LITERAL1 diff --git a/BH1750/library.json b/BH1750/library.json new file mode 100644 index 0000000..d575750 --- /dev/null +++ b/BH1750/library.json @@ -0,0 +1,12 @@ +{ + "name": "BH1750", + "keywords": "BH1750FVI, light, lux, sensor, Arduino, ESP8266, ESP32", + "description": "Arduino library for the digital light sensor breakout boards containing the BH1750FVI IC. Arduino, ESP8266 & ESP32 compatible.", + "repository": { + "type": "git", + "url": "https://github.com/claws/BH1750.git" + }, + "frameworks": "arduino", + "platforms": ["atmelavr", "atmelsam", "espressif8266", "espressif32", "stm32"], + "version": "1.2.0" +} diff --git a/BH1750/library.properties b/BH1750/library.properties new file mode 100644 index 0000000..142a0d4 --- /dev/null +++ b/BH1750/library.properties @@ -0,0 +1,10 @@ +name=BH1750 +version=1.2.0 +author=Christopher Laws +maintainer=Christopher Laws +sentence=Arduino library for the digital light sensor breakout boards containing the BH1750FVI IC +paragraph=Pretty simple and robust BH1750 library. Arduino, ESP8266 & ESP32 compatible. +category=Sensors +url=https://github.com/claws/BH1750 +architectures=avr,sam,esp8266,esp32,stm32 +includes=BH1750.h diff --git a/BH1750/resources/gy30-module.jpg b/BH1750/resources/gy30-module.jpg new file mode 100644 index 0000000..15cf099 Binary files /dev/null and b/BH1750/resources/gy30-module.jpg differ diff --git a/BH1750/resources/wiring-diagram-gy30-module.png b/BH1750/resources/wiring-diagram-gy30-module.png new file mode 100644 index 0000000..f8efe5c Binary files /dev/null and b/BH1750/resources/wiring-diagram-gy30-module.png differ diff --git a/BH1750/src/BH1750.cpp b/BH1750/src/BH1750.cpp new file mode 100644 index 0000000..f7916e6 --- /dev/null +++ b/BH1750/src/BH1750.cpp @@ -0,0 +1,297 @@ +/* + + This is a library for the BH1750FVI Digital Light Sensor breakout board. + + The BH1750 board uses I2C for communication. Two pins are required to + interface to the device. Configuring the I2C bus is expected to be done + in user code. The BH1750 library doesn't do this automatically. + + Written by Christopher Laws, March, 2013. + +*/ + +#include "BH1750.h" + +// Define milliseconds delay for ESP8266 platform +#if defined(ESP8266) + + #include + #define _delay_ms(ms) delayMicroseconds((ms) * 1000) + +// Use _delay_ms from utils for AVR-based platforms +#elif defined(__avr__) + #include + +// Use Wiring's delay for compability with another platforms +#else + #define _delay_ms(ms) delay(ms) +#endif + + +// Legacy Wire.write() function fix +#if (ARDUINO >= 100) + #define __wire_write(d) I2C->write(d) +#else + #define __wire_write(d) I2C->send(d) +#endif + + +// Legacy Wire.read() function fix +#if (ARDUINO >= 100) + #define __wire_read() I2C->read() +#else + #define __wire_read() I2C->receive() +#endif + + +/** + * Constructor + * @params addr Sensor address (0x76 or 0x72, see datasheet) + * + * On most sensor boards, it was 0x76 + */ +BH1750::BH1750(byte addr) { + + BH1750_I2CADDR = addr; + // Allows user to change TwoWire instance + I2C = &Wire; +} + + +/** + * Configure sensor + * @param mode Measurement mode + * @param addr Address of the sensor + * @param i2c TwoWire instance connected to I2C bus + */ +bool BH1750::begin(Mode mode, byte addr, TwoWire *i2c) { + + // I2C is expected to be initialized outside this library + // But, allows a different address and TwoWire instance to be used + if(i2c) { + I2C = i2c; + } + if(addr) { + BH1750_I2CADDR = addr; + } + + // Configure sensor in specified mode and set default MTreg + return (configure(mode) && setMTreg(BH1750_DEFAULT_MTREG)); +} + + +/** + * Configure BH1750 with specified mode + * @param mode Measurement mode + */ +bool BH1750::configure(Mode mode) { + + // default transmission result to a value out of normal range + byte ack = 5; + + // Check measurement mode is valid + switch (mode) { + + case BH1750::CONTINUOUS_HIGH_RES_MODE: + case BH1750::CONTINUOUS_HIGH_RES_MODE_2: + case BH1750::CONTINUOUS_LOW_RES_MODE: + case BH1750::ONE_TIME_HIGH_RES_MODE: + case BH1750::ONE_TIME_HIGH_RES_MODE_2: + case BH1750::ONE_TIME_LOW_RES_MODE: + + // Send mode to sensor + I2C->beginTransmission(BH1750_I2CADDR); + __wire_write((uint8_t)mode); + ack = I2C->endTransmission(); + + // Wait a few moments to wake up + _delay_ms(10); + break; + + default: + // Invalid measurement mode + Serial.println(F("[BH1750] ERROR: Invalid mode")); + break; + + } + + // Check result code + switch (ack) { + case 0: + BH1750_MODE = mode; + lastReadTimestamp = millis(); + return true; + case 1: // too long for transmit buffer + Serial.println(F("[BH1750] ERROR: too long for transmit buffer")); + break; + case 2: // received NACK on transmit of address + Serial.println(F("[BH1750] ERROR: received NACK on transmit of address")); + break; + case 3: // received NACK on transmit of data + Serial.println(F("[BH1750] ERROR: received NACK on transmit of data")); + break; + case 4: // other error + Serial.println(F("[BH1750] ERROR: other error")); + break; + default: + Serial.println(F("[BH1750] ERROR: undefined error")); + break; + } + + return false; + +} + +/** + * Configure BH1750 MTreg value + * MT reg = Measurement Time register + * @param MTreg a value between 32 and 254. Default: 69 + * @return bool true if MTReg successful set + * false if MTreg not changed or parameter out of range + */ +bool BH1750::setMTreg(byte MTreg) { + //Bug: lowest value seems to be 32! + if (MTreg <= 31 || MTreg > 254) { + Serial.println(F("[BH1750] ERROR: MTreg out of range")); + return false; + } + byte ack = 5; + // Send MTreg and the current mode to the sensor + // High bit: 01000_MT[7,6,5] + // Low bit: 011_MT[4,3,2,1,0] + I2C->beginTransmission(BH1750_I2CADDR); + __wire_write((0b01000 << 3) | (MTreg >> 5)); + ack = I2C->endTransmission(); + I2C->beginTransmission(BH1750_I2CADDR); + __wire_write((0b011 << 5 ) | (MTreg & 0b11111)); + ack = ack | I2C->endTransmission(); + I2C->beginTransmission(BH1750_I2CADDR); + __wire_write(BH1750_MODE); + ack = ack | I2C->endTransmission(); + + // Wait a few moments to wake up + _delay_ms(10); + + // Check result code + switch (ack) { + case 0: + BH1750_MTreg = MTreg; + return true; + case 1: // too long for transmit buffer + Serial.println(F("[BH1750] ERROR: too long for transmit buffer")); + break; + case 2: // received NACK on transmit of address + Serial.println(F("[BH1750] ERROR: received NACK on transmit of address")); + break; + case 3: // received NACK on transmit of data + Serial.println(F("[BH1750] ERROR: received NACK on transmit of data")); + break; + case 4: // other error + Serial.println(F("[BH1750] ERROR: other error")); + break; + default: + Serial.println(F("[BH1750] ERROR: undefined error")); + break; + } + + return false; +} + +/** + * Checks whether enough time has gone to read a new value + * @param maxWait a boolean if to wait for typical or maximum delay + * @return a boolean if a new measurement is possible + * + */ +bool BH1750::measurementReady(bool maxWait) { + unsigned long delaytime = 0; + switch (BH1750_MODE) { + case BH1750::CONTINUOUS_HIGH_RES_MODE: + case BH1750::CONTINUOUS_HIGH_RES_MODE_2: + case BH1750::ONE_TIME_HIGH_RES_MODE: + case BH1750::ONE_TIME_HIGH_RES_MODE_2: + maxWait ? delaytime = (180 * BH1750_MTreg/(byte)BH1750_DEFAULT_MTREG) : delaytime = (120 * BH1750_MTreg/(byte)BH1750_DEFAULT_MTREG); + break; + case BH1750::CONTINUOUS_LOW_RES_MODE: + case BH1750::ONE_TIME_LOW_RES_MODE: + // Send mode to sensor + maxWait ? delaytime = (24 * BH1750_MTreg/(byte)BH1750_DEFAULT_MTREG) : delaytime = (16 * BH1750_MTreg/(byte)BH1750_DEFAULT_MTREG); + break; + default: + break; + } + // Wait for new measurement to be possible. + // Measurements have a maximum measurement time and a typical measurement + // time. The maxWait argument determines which measurement wait time is + // used when a one-time mode is being used. The typical (shorter) + // measurement time is used by default and if maxWait is set to True then + // the maximum measurement time will be used. See data sheet pages 2, 5 + // and 7 for more details. + unsigned long currentTimestamp = millis(); + if (currentTimestamp - lastReadTimestamp >= delaytime) { + return true; + } + else + return false; +} + +/** + * Read light level from sensor + * The return value range differs if the MTreg value is changed. The global + * maximum value is noted in the square brackets. + * @return Light level in lux (0.0 ~ 54612,5 [117758,203]) + * -1 : no valid return value + * -2 : sensor not configured + */ +float BH1750::readLightLevel() { + + if (BH1750_MODE == UNCONFIGURED) { + Serial.println(F("[BH1750] Device is not configured!")); + return -2.0; + } + + // Measurement result will be stored here + float level = -1.0; + + // Read two bytes from the sensor, which are low and high parts of the sensor + // value + if (2 == I2C->requestFrom((int)BH1750_I2CADDR, (int)2)) { + unsigned int tmp = 0; + tmp = __wire_read(); + tmp <<= 8; + tmp |= __wire_read(); + level = tmp; + } + lastReadTimestamp = millis(); + + if (level != -1.0) { + // Print raw value if debug enabled + #ifdef BH1750_DEBUG + Serial.print(F("[BH1750] Raw value: ")); + Serial.println(level); + #endif + + if (BH1750_MTreg != BH1750_DEFAULT_MTREG) { + level *= (float)((byte)BH1750_DEFAULT_MTREG/(float)BH1750_MTreg); + // Print MTreg factor if debug enabled + #ifdef BH1750_DEBUG + Serial.print(F("[BH1750] MTreg factor: ")); + Serial.println( String((float)((byte)BH1750_DEFAULT_MTREG/(float)BH1750_MTreg)) ); + #endif + } + if (BH1750_MODE == BH1750::ONE_TIME_HIGH_RES_MODE_2 || BH1750_MODE == BH1750::CONTINUOUS_HIGH_RES_MODE_2) { + level /= 2; + } + // Convert raw value to lux + level /= BH1750_CONV_FACTOR; + + // Print converted value if debug enabled + #ifdef BH1750_DEBUG + Serial.print(F("[BH1750] Converted float value: ")); + Serial.println(level); + #endif + } + + return level; + +} diff --git a/BH1750/src/BH1750.h b/BH1750/src/BH1750.h new file mode 100644 index 0000000..dd4575c --- /dev/null +++ b/BH1750/src/BH1750.h @@ -0,0 +1,83 @@ +/* + + This is a library for the BH1750FVI Digital Light Sensor breakout board. + + The BH1750 board uses I2C for communication. Two pins are required to + interface to the device. Configuring the I2C bus is expected to be done + in user code. The BH1750 library doesn't do this automatically. + + Datasheet: http://www.elechouse.com/elechouse/images/product/Digital%20light%20Sensor/bh1750fvi-e.pdf + + Written by Christopher Laws, March, 2013. + +*/ + +#ifndef BH1750_h +#define BH1750_h + +#if (ARDUINO >= 100) + #include +#else + #include +#endif + +#include "Wire.h" + +// Uncomment, to enable debug messages +// #define BH1750_DEBUG + +// No active state +#define BH1750_POWER_DOWN 0x00 + +// Waiting for measurement command +#define BH1750_POWER_ON 0x01 + +// Reset data register value - not accepted in POWER_DOWN mode +#define BH1750_RESET 0x07 + +// Default MTreg value +#define BH1750_DEFAULT_MTREG 69 + +class BH1750 { + + public: + + enum Mode + { + // same as Power Down + UNCONFIGURED = 0, + // Measurement at 1 lux resolution. Measurement time is approx 120ms. + CONTINUOUS_HIGH_RES_MODE = 0x10, + // Measurement at 0.5 lux resolution. Measurement time is approx 120ms. + CONTINUOUS_HIGH_RES_MODE_2 = 0x11, + // Measurement at 4 lux resolution. Measurement time is approx 16ms. + CONTINUOUS_LOW_RES_MODE = 0x13, + // Measurement at 1 lux resolution. Measurement time is approx 120ms. + ONE_TIME_HIGH_RES_MODE = 0x20, + // Measurement at 0.5 lux resolution. Measurement time is approx 120ms. + ONE_TIME_HIGH_RES_MODE_2 = 0x21, + // Measurement at 4 lux resolution. Measurement time is approx 16ms. + ONE_TIME_LOW_RES_MODE = 0x23 + }; + + BH1750(byte addr = 0x23); + bool begin(Mode mode = CONTINUOUS_HIGH_RES_MODE, byte addr = 0x23, + TwoWire* i2c = nullptr); + bool configure(Mode mode); + bool setMTreg(byte MTreg); + bool measurementReady(bool maxWait = false); + float readLightLevel(); + + private: + byte BH1750_I2CADDR; + byte BH1750_MTreg = (byte)BH1750_DEFAULT_MTREG; + // Correction factor used to calculate lux. Typical value is 1.2 but can + // range from 0.96 to 1.44. See the data sheet (p.2, Measurement Accuracy) + // for more information. + const float BH1750_CONV_FACTOR = 1.2; + Mode BH1750_MODE = UNCONFIGURED; + TwoWire* I2C; + unsigned long lastReadTimestamp; +}; + +#endif