adding the BH1750 from their downloads

This commit is contained in:
Roald Batts 2023-01-15 18:37:43 -05:00
parent f92231dbff
commit 064a8ffd26
16 changed files with 1023 additions and 0 deletions

21
BH1750/LICENSE Normal file
View file

@ -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.

165
BH1750/README.md Normal file
View file

@ -0,0 +1,165 @@
# BH1750
[![Build Status](https://travis-ci.org/claws/BH1750.svg?branch=master)](https://travis-ci.org/claws/BH1750)<br>
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
``<Your User Directory>/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 <Wire.h>
#include <BH1750.h>
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.

View file

@ -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

1
BH1750/component.mk Normal file
View file

@ -0,0 +1 @@
COMPONENT_ADD_INCLUDEDIRS := .

View file

@ -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 <Wire.h>
#include <BH1750.h>
/*
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");
}
}

View file

@ -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 <Wire.h>
#include <BH1750.h>
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);
}

View file

@ -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 <Wire.h>
#include <BH1750.h>
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);
}

View file

@ -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 <Wire.h>
#include <BH1750.h>
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);
}

View file

@ -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);
}

34
BH1750/keywords.txt Normal file
View file

@ -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

12
BH1750/library.json Normal file
View file

@ -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"
}

10
BH1750/library.properties Normal file
View file

@ -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

Binary file not shown.

After

Width:  |  Height:  |  Size: 206 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 62 KiB

297
BH1750/src/BH1750.cpp Normal file
View file

@ -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 <pgmspace.h>
#define _delay_ms(ms) delayMicroseconds((ms) * 1000)
// Use _delay_ms from utils for AVR-based platforms
#elif defined(__avr__)
#include <util/delay.h>
// 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;
}

83
BH1750/src/BH1750.h Normal file
View file

@ -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 <Arduino.h>
#else
#include <WProgram.h>
#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