IT博客汇
  • 首页
  • 精华
  • 技术
  • 设计
  • 资讯
  • 扯淡
  • 权利声明
  • 登录 注册

    Windows 10 IoT开发:读取GY-30(BH1750FVI)光线传感器

    汪宇杰发表于 2016-03-26 10:31:27
    love 0

    最近买了个GAY-30光线传感器,这个型号也叫BH1750FVI。结果网上搜了一圈,没人写过Windows 10 IoT驱动这个传感器的例子,只能自己爆一个出来了。

    光线传感器外观是这样的:

    我用的板子是树莓派3,GPIO布局如下:

    因为GAY-30是个I2C设备,所以我们不能用GPIO端口操作,必须用I2C方式去爆。并且因为这个特性,不支持热插拔。必须把树莓派关机,连接好传感器,再开机才能找到设备。这是坑了我很久的一个地方。

    连接如下:

    GAY-30针脚 树莓派端口 备注
    VCC PIN 01 3.3V电源正极
    ADO 不接 没有什么卵用
    SDA PIN 03 SDA1 I2C
    SCL PIN 05 SLC1 I2C
    GND PIN 06 接地线,电源负极

     

    然后就可以爆代码了:

    先来看看Windows 10 IoT官网操作I2C的代码是这样的

    I2C
            Pin 3 - I2C1 SDA
            Pin 5 - I2C1 SCL
    
    using Windows.Devices.Enumeration;
    using Windows.Devices.I2c;
     
    public async void I2C()
    {
        // Get a selector string for bus "I2C1"
        string aqs = I2cDevice.GetDeviceSelector("I2C1");
         
        // Find the I2C bus controller with our selector string
        var dis = await DeviceInformation.FindAllAsync(aqs);
        if (dis.Count == 0)
            return; // bus not found
         
        // 0x40 is the I2C device address
        var settings = new I2cConnectionSettings(0x40);
         
        // Create an I2cDevice with our selected bus controller and I2C settings
        using (I2cDevice device = await I2cDevice.FromIdAsync(dis[0].Id, settings))
        {
            byte[] writeBuf = { 0x01, 0x02, 0x03, 0x04 };
            device.Write(writeBuf);
        }
    }

    这里面有个神器的东西,就是

        // 0x40 is the I2C device address
        var settings = new I2cConnectionSettings(0x40);

    这个0x40的地址是怎么得到的呢。。。

    经过一番爆破,发现每个I2C硬件用的地址都不一样,一般要到对应硬件的说明文档里找。如果找不到,可以在Raspbian系统里按照这个方法去找:

    http://www.raspberrypi-spy.co.uk/2014/11/enabling-the-i2c-interface-on-the-raspberry-pi/

    我的这个GAY-30传感器的I2C地址是0x23,如果不出意外,所有这个型号的传感器在连接3.3V电源的时候都应该用0x23.

    不多废话,经过一番爆破,贴出完整的GY30LightSensor驱动代码:

    代码是参考Ardunio的版本写的。原帖在:http://blog.simtronyx.de/en/measurement-of-illuminance-with-a-bh1750fvi-breakout-board-gy-30-and-an-arduino-uno/ 

    using System;
    using System.Diagnostics;
    using System.IO;
    using System.Threading;
    using System.Threading.Tasks;
    using Windows.Devices.Enumeration;
    using Windows.Devices.I2c;
    
    namespace GY30LightSensor
    {
        public class GY30LightSensorEventArgs : EventArgs
        {
            public int? Lux { get; set; }
    
            public GY30LightSensorEventArgs(int? lux)
            {
                Lux = lux;
            }
        }
    
        public class GY30LightSensor
        {
            public int Bh1750Address => 0x23;
    
            public I2cDevice I2CLightSensor { get; private set; }
    
            private Timer PeriodicTimer { get; set; }
    
            public int TimerIntervalMs { get; set; }
    
            public event ReadingEventHandler Reading;
    
            public delegate void ReadingEventHandler(object sender, GY30LightSensorEventArgs e);
    
            private void OnReading(int lux)
            {
                Reading?.Invoke(lux, new GY30LightSensorEventArgs(lux));
            }
    
            public GY30LightSensor(int timerIntervalMs = 100)
            {
                TimerIntervalMs = timerIntervalMs;
            }
    
            public async Task InitLightSensorAsync()
            {
                string aqs = I2cDevice.GetDeviceSelector();
                /* Get a selector string that will return all I2C controllers on the system */
                var dis = await DeviceInformation.FindAllAsync(aqs);
                /* Find the I2C bus controller device with our selector string           */
                if (dis.Count == 0)
                {
                    throw new FileNotFoundException("No I2C controllers were found on the system");
                }
    
                var settings = new I2cConnectionSettings(Bh1750Address)
                {
                    BusSpeed = I2cBusSpeed.FastMode
                };
    
                I2CLightSensor = await I2cDevice.FromIdAsync(dis[0].Id, settings);
                /* Create an I2cDevice with our selected bus controller and I2C settings */
                if (I2CLightSensor == null)
                {
                    throw new UnauthorizedAccessException(string.Format("Slave address {0} on I2C Controller {1} is currently in use by " +
                                     "another application. Please ensure that no other applications are using I2C.", settings.SlaveAddress, dis[0].Id));
                }
    
                /* Write the register settings */
                try
                {
                    I2CLightSensor.Write(new byte[] { 0x10 }); // 1 [lux] aufloesung
                }
                /* If the write fails display the error and stop running */
                catch (Exception ex)
                {
                    Debug.WriteLine("Failed to communicate with device: " + ex.Message);
                    throw;
                }
    
                PeriodicTimer = new Timer(this.TimerCallback, null, 0, TimerIntervalMs);
            }
    
            private void TimerCallback(object state)
            {
                var lux = ReadI2CLux();
                OnReading(lux);
            }
    
            private int ReadI2CLux()
            {
                byte[] regAddrBuf = new byte[] { 0x23 };
                byte[] readBuf = new byte[2];
                I2CLightSensor.WriteRead(regAddrBuf, readBuf);
    
                // is this calculation correct?
                var valf = ((readBuf[0] << 8) | readBuf[1]) / 1.2; 
    
                return (int)valf;
            }
        }
    }
    

    使用方法:

    public GY30LightSensor Gy30LightSensor { get; set; }
    
    public MainPage()
    {
        this.InitializeComponent();
        Gy30LightSensor = new GY30LightSensor();
    
        Loaded += OnLoaded;
    }
    
    private async void OnLoaded(object sender, RoutedEventArgs routedEventArgs)
    {
        await Gy30LightSensor.InitLightSensorAsync();
        Gy30LightSensor.Reading += (o, args) =>
        {
            var task = this.Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () =>
            {
                TxtLux.Text = args.Lux + " lx";
            });
        };
    }
    

    现在当有光线照射到传感器上的时候就可以得到流明(Lx)值了。

    我也是刚刚才弄完,还没完整的验证过。我的代码里可能有个坑爹的地方就是Lx的计算。我不确定这个计算方式对不对:

    var valf = ((readBuf[0] << 8) | readBuf[1]) / 1.2; 

    如果有错还请读者指出~



沪ICP备19023445号-2号
友情链接