GrovePi icon indicating copy to clipboard operation
GrovePi copied to clipboard

Add support for: Grove - Temp&Humi&Barometer Sensor (BME280)

Open Se3ker opened this issue 8 years ago • 0 comments

Here's the code for the sensor, if you want to integrate into your library. For the C# Win 10 IoT

All features of the sensor work as expected.

class SensorBME280
    {
        private I2cDevice SensorBme280;
        private byte SensorAddress = 0x76;

        // BME280 Calibration variables
        private UInt16 T1;
        private Int16 T2;
        private Int16 T3;
        private UInt16 P1;
        private Int16 P2;
        private Int16 P3;
        private Int16 P4;
        private Int16 P5;
        private Int16 P6;
        private Int16 P7;
        private Int16 P8;
        private Int16 P9;
        private byte H1;
        private Int16 H2;
        private byte H3;
        private Int16 H4;
        private Int16 H5;
        private Int16 H6;

        // BME280 Data register addresses
        private byte HumLsbAddr = 0xfe;
        private byte HumMsbAddr = 0xfd;
        private byte TmpXlsbAddr = 0xfc;
        private byte TmpLsbAddr = 0xfb;
        private byte TmpMsbAddr = 0xfa;
        private byte PreXlsbAddr = 0xf9;
        private byte PreLsbAddr = 0xf8;
        private byte PreMsbAddr = 0xf7;

        // BME280 Variable data calibration
        private Int32 t_fine = Int32.MinValue;

        // BME280 Calibration data address
        enum Register : byte
        {
            Dig_T1 = 0x88,
            Dig_T2 = 0x8a,
            Dig_T3 = 0x8c,

            Dig_P1 = 0x8e,
            Dig_P2 = 0x90,
            Dig_P3 = 0x92,
            Dig_P4 = 0x94,
            Dig_P5 = 0x96,
            Dig_P6 = 0x98,
            Dig_P7 = 0x9a,
            Dig_P8 = 0x9c,
            Dig_P9 = 0x9e,

            Dig_H1 = 0xa1,
            Dig_H2 = 0xe1,
            Dig_H3 = 0xe3,
            Dig_H4 = 0xe4,
            Dig_H5 = 0xe5,
            Dig_H6 = 0xe7,
        }

        // BME280 measurement data acquisition register address
        enum Command : byte
        {
            ReadTemperature = 0xfa,
            ReadPressure = 0xf7,
            ReadHumidity = 0xfd,
        }

        public async void InitializeSensor()
        {
            I2cController I2c = await I2cController.GetDefaultAsync();
            SensorBme280 = I2c.GetDevice(new I2cConnectionSettings(SensorAddress));

            // Sensor initialization
            uint osrs_t = 3;
            uint osrs_p = 3;
            uint osrs_h = 3;
            uint mode = 3;
            uint t_sb = 5;
            uint filter = 0;
            uint spi3w_en = 0;

            uint ctrlMeasReg = (osrs_t << 5) | (osrs_p << 2) | mode;
            uint configReg = (t_sb << 5) | (filter << 2) | spi3w_en;
            uint ctrlHumReg = osrs_h;

            SensorBme280.Write(new byte[] { 0xf2, (byte)ctrlHumReg });
            SensorBme280.Write(new byte[] { 0xf4, (byte)ctrlMeasReg });
            SensorBme280.Write(new byte[] { 0xf5, (byte)configReg });

            await Task.Delay(10);

            // Load calibration data
            // Temperature
            T1 = ReadUInt16((byte)Register.Dig_T1);
            T2 = (Int16)ReadUInt16((byte)Register.Dig_T2);
            T3 = (Int16)ReadUInt16((byte)Register.Dig_T3);

            // Barometric pressure
            P1 = ReadUInt16((byte)Register.Dig_P1);
            P2 = (Int16)ReadUInt16((byte)Register.Dig_P2);
            P3 = (Int16)ReadUInt16((byte)Register.Dig_P3);
            P4 = (Int16)ReadUInt16((byte)Register.Dig_P4);
            P5 = (Int16)ReadUInt16((byte)Register.Dig_P5);
            P6 = (Int16)ReadUInt16((byte)Register.Dig_P6);
            P7 = (Int16)ReadUInt16((byte)Register.Dig_P7);
            P8 = (Int16)ReadUInt16((byte)Register.Dig_P8);
            P9 = (Int16)ReadUInt16((byte)Register.Dig_P9);

            // Humidity
            H1 = ReadByte((byte)Register.Dig_H1);
            H2 = (Int16)ReadUInt16((byte)Register.Dig_H2);
            H3 = ReadByte((byte)Register.Dig_H3);
            H4 = (short)(ReadByte((byte)Register.Dig_H4) << 4 | ReadByte((byte)Register.Dig_H4 + 1) & 0xf);
            H5 = (short)(ReadByte((byte)Register.Dig_H5 + 1) << 4 | ReadByte((byte)Register.Dig_H5) >> 4);
            H6 = (sbyte)ReadByte((byte)Register.Dig_H6);

        }

        /// <summary>
        /// Temperature data acquisition (Celsius)
        /// </summary>
        /// <returns></returns>
        public async Task<double> ReadTemperature()
        {
            byte tmsb = ReadByte(TmpMsbAddr);
            byte tlsb = ReadByte(TmpLsbAddr);
            byte txlsb = ReadByte(TmpXlsbAddr);

            Int32 tmpRaw = (tmsb << 12) | (tlsb << 4) | (txlsb >> 4);

            double var1, var2, T;

            var1 = ((tmpRaw / 16384.0) - (T1 / 1024.0)) * T2;
            var2 = ((tmpRaw / 131072.0) - (T1 / 8192.0)) * T3;
            t_fine = (Int32)(var1 + var2);

            T = (var1 + var2) / 5120.0;

            await Task.Delay(1);

            return T;
        }

        /// <summary>
        /// Pressure data acquisition (Hectopascal)
        /// </summary>
        /// <returns></returns>
        public async Task<double> ReadPressure()
        {
            byte pmsb = ReadByte(PreMsbAddr);
            byte plsb = ReadByte(PreLsbAddr);
            byte pxlsb = ReadByte(PreXlsbAddr);

            Int32 preRaw = (pmsb << 12) | (plsb << 4) | (pxlsb >> 4);

            Int64 var1, var2, P;

            var1 = t_fine - 128000;
            var2 = var1 * var1 * (Int64)P6;
            var2 = var2 + ((var1 * (Int64)P5) << 17);
            var2 = var2 + ((Int64)P4 << 35);
            var1 = ((var1 * var1 * (Int64)P3) >> 8) + ((var1 * (Int64)P2) << 12);
            var1 = (((((Int64)1 << 47) + var1)) * (Int64)P1) >> 33;
            if (var1 == 0)
            {
                return 0;
            }

            P = 1048576 - preRaw;
            P = (((P << 31) - var2) * 3125) / var1;
            var1 = ((Int64)P9 * (P >> 13)) >> 25;
            var2 = ((Int64)P8 * P) >> 19;
            P = ((P + var1 + var2) >> 8) + ((Int64)P7 << 4);

            await Task.Delay(1);

            return (double)(P / 256 / 100);
        }

        /// <summary>
        /// Humidity data acquisition (Relative Humidity)
        /// </summary>
        /// <returns></returns>
        public async Task<double> ReadHumidity()
        {
            byte hmsb = ReadByte(HumMsbAddr);
            byte hlsb = ReadByte(HumLsbAddr);
            int humRaw = (hmsb << 8) | hlsb;

            Int32 H;
            H = t_fine - 76800;
            H = (((((humRaw << 14) - (((Int32)H4) << 20) - ((Int32)H5 * H)) + ((Int32)16384)) >> 15) * (((((((H * ((Int32)H6)) >> 10) * (((H * ((Int32)H3)) >> 11) + ((Int32)32768))) >> 10) + ((Int32)2097152)) * ((Int32)H2) + 8192) >> 14));
            H = (H - (((((H >> 15) * (H >> 15)) >> 7) * ((Int32)H1)) >> 4));
            H = (H < 0 ? 0 : H);
            H = (H > 419430400 ? 419430400 : H);

            await Task.Delay(1);

            return (UInt32)((H >> 12) / 1000);
        }

        public double ReadAltitude(double pressure, bool useInternationalFormula = true)
        {
            if (useInternationalFormula)
            {
                // International Barometric Formula
                return 44330.0f * (1.0f - (float)Math.Pow((pressure / 1013), 0.1903f));
            }
            else
            {
                // Seeedstudio Grove BME280 formula
                double a = pressure / 101325;
                double b = 1 / 5.25588;
                double c = Math.Pow(a, b);
                c = 1.0 - c;
                c = c / 0.0000225577;
                c = c / 100;
                return c;
            }
        }

        /// <summary>
        /// Double-byte data readout
        /// </summary>
        /// <param name="register"></param>
        /// <returns></returns>
        private UInt16 ReadUInt16(byte register)
        {
            byte[] writeBuf = new byte[] { 0x00 };
            byte[] readBuf = new byte[] { 0x00, 0x00 };

            writeBuf[0] = register;
            SensorBme280.WriteRead(writeBuf, readBuf);

            int h = readBuf[1] << 8;
            int l = readBuf[0];

            return (UInt16)(h + l);
        }

        /// <summary>
        /// Read byte
        /// </summary>
        /// <param name="register"></param>
        /// <returns></returns>
        private byte ReadByte(byte register)
        {
            byte[] writeBuf = new byte[] { 0x00 };
            byte[] readBuf = new byte[] { 0x00 };

            writeBuf[0] = register;
            SensorBme280.WriteRead(writeBuf, readBuf);

            return readBuf[0];
        }

        /// <summary>
        /// Display temperature (°C)
        /// </summary>
        /// <returns></returns>
        public string DisplayTemperature(double temperature)
        {
            return $"{Math.Round(temperature, 0)} °C";
        }

        /// <summary>
        /// Display pressure (hPa)
        /// </summary>
        /// <returns></returns>
        public string DisplayPressure(double pressure)
        {
            return $"{Math.Round(pressure, 1)} hPa";
        }

        /// <summary>
        /// Display humidity (%rh)
        /// </summary>
        /// <returns></returns>
        public string DisplayHumidity(double humidity)
        {
            return $"{Math.Round(humidity, 0)}% rh";
        }

        /// <summary>
        /// Display altitude (m)
        /// </summary>
        /// <returns></returns>
        public string DisplayAltitude(double altitude)
        {
            return $"{Math.Round(altitude, 0)} m";
        } 

Se3ker avatar May 22 '17 17:05 Se3ker