I’ve got a few more I2C devices to go in this series – this time I’m writing the code for a digital light sensor, the BH1750FVI.

As usual, I’ve uploaded all the code to GitHub.

Useful information about the sensor

It’s possible to have a couple of slave addresses for this device:

  • If the ADD pin is low, the address is 0x23
  • If the ADD pin is high, the address is 0x5C

I’ve stored these in an enumeration, which can be used in the constructor.

public enum AddPinConnection
{
    PIN_HIGH = 0x5C,
    PIN_LOW = 0x23
}

The device requires that we set a measurement mode – the manufacturer’s recommended setting is High Resolution mode, which rejects noise and is suitable for detecting darkness.

After writing the slave address to the device, we can read the two bytes returned for the light level. The first byte can be right-shifted by 8 (i.e. multiplied by 256) and added to the second byte to get the device’s raw output reading.

To convert this to lux, we divide this by 1.2.

public int GetLightLevel()
{
    var readBuffer = new byte[2];
 
    this.Slave.WriteRead(new byte[] { I2C_ADDRESS }, readBuffer);
 
    var lightLevel = readBuffer[0<< 8 | readBuffer[1];
 
    return (int)(lightLevel / 1.2f);
}

Calling this is pretty simple, using the same pattern as calling the other I2C devices I’ve written about:

public MainPage()
{
    this.InitializeComponent();
 
    Loaded += MainPage_Loaded;
}
 
private async void MainPage_Loaded(object sender, Windows.UI.Xaml.RoutedEventArgs e)
{
    try
    {
        var lightSensitivityMeter = new BH1750FVI(AddPinConnection.PIN_LOW);
 
        await lightSensitivityMeter.Initialize();
 
        lightSensitivityMeter.SetMode(MeasurementMode.ContinuouslyHighResolutionMode);
 
        while (true)
        {
            var lux = lightSensitivityMeter.GetLightLevel();
 
            Debug.WriteLine("Lux = " + lux);
 
            Task.Delay(1000).Wait();
        }
    }
    catch (Exception ex)
    {
        Debug.WriteLine(ex.Message);
    }
}