첨부 실행 코드는 나눔고딕코딩 폰트를 사용합니다.
본 블로그는 광고를 포함하고 있습니다.
광고 클릭에서 발생하는 수익금은 모두 블로그 콘텐츠 향상을 위해 쓰여집니다.

728x90
반응형
728x170

TestApplication.zip
다운로드

▶ 부품 내역

구분 모델 수량 비고
SENSOR/TEMPERATURE BME280 1  

 

728x90

 

▶ 회로 구성도

 

300x250

 

▶ MainPage.xaml

<Page x:Class="TestApplication.MainPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:TestApplication"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d">
    <Page.Resources>
        <Style TargetType="TextBlock">
            <Setter Property="Margin" Value="5" />
        </Style>
    </Page.Resources>
    <Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
        <Grid
            HorizontalAlignment="Center"
            VerticalAlignment="Center">
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="Auto" />
                <ColumnDefinition Width="Auto" />
            </Grid.ColumnDefinitions>
            <Grid.RowDefinitions>
                <RowDefinition Height="Auto" />
                <RowDefinition Height="Auto" />
                <RowDefinition Height="Auto" />
            </Grid.RowDefinitions>
            <TextBlock Grid.Column="0" Grid.Row="0" Text="온도 :" />
            <TextBlock Name="temperatureTextBlock" Grid.Column="1" Grid.Row="0" />
            <TextBlock Grid.Column="0" Grid.Row="1" Text="기압 :" />
            <TextBlock Name="pressureTextBlock" Grid.Column="1" Grid.Row="1" />
            <TextBlock Grid.Column="0" Grid.Row="2" Text="습도 :" />
            <TextBlock Name="humidityTextBlock" Grid.Column="1" Grid.Row="2" />
        </Grid>
    </Grid>
</Page>

 

▶ MainPage.xaml.cs

using System;
using System.Threading.Tasks;
using Windows.Devices.Enumeration;
using Windows.Devices.I2c;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;

namespace TestApplication
{
    /// <summary>
    /// 메인 페이지
    /// </summary>
    public sealed partial class MainPage : Page
    {
        //////////////////////////////////////////////////////////////////////////////////////////////////// Enumeration
        ////////////////////////////////////////////////////////////////////////////////////////// Private

        #region 보정 레지스터 주소 - CalibrationRegisterAddress

        /// <summary>
        /// 보정 레지스터 주소
        /// </summary>
        private enum CalibrationRegisterAddress : byte
        {
            DIGITAL_T1 = 0x88,
            DIGITAL_T2 = 0x8a,
            DIGITAL_T3 = 0x8c,

            DIGITAL_P1 = 0x8e,
            DIGITAL_P2 = 0x90,
            DIGITAL_P3 = 0x92,
            DIGITAL_P4 = 0x94,
            DIGITAL_P5 = 0x96,
            DIGITAL_P6 = 0x98,
            DIGITAL_P7 = 0x9a,
            DIGITAL_P8 = 0x9c,
            DIGITAL_P9 = 0x9e,

            DIGITAL_H1 = 0xa1,
            DIGITAL_H2 = 0xe1,
            DIGITAL_H3 = 0xe3,
            DIGITAL_H4 = 0xe4,
            DIGITAL_H5 = 0xe5,
            DIGITAL_H6 = 0xe7,
        }

        #endregion

        //////////////////////////////////////////////////////////////////////////////////////////////////// Field
        ////////////////////////////////////////////////////////////////////////////////////////// Private

        #region Field

        /// <summary>
        /// I2C 장치
        /// </summary>
        private I2cDevice i2cDevice;

        /// <summary>
        /// BME280 주소
        /// </summary>
        private byte ADDRESS_BME280 = 0x76;

        #region BME280 보정 데이터 값

        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;

        #endregion
        #region BME280 레지스터 주소

        private const byte TEMP_MSB_REGISTER_ADDRESS   = 0xfa;
        private const byte TEMP_LSB_REGISTER_ADDRESS   = 0xfb;
        private const byte TEMP_XLSB_REGISTER_ADDRESS  = 0xfc;

        private const byte PRESS_MSB_REGISTER_ADDRESS  = 0xf7;
        private const byte PRESS_LSB_REGISTER_ADDRESS  = 0xf8;
        private const byte PRESS_XLSB_REGISTER_ADDRESS = 0xf9;

        private const byte HUM_MSB_REGISTER_ADDRESS    = 0xfd;
        private const byte HUM_LSB_REGISTER_ADDRESS    = 0xfe;

        #endregion

        /// <summary>
        /// BME280 데이터 교정용
        /// </summary>
        private Int32 fineTunning = Int32.MinValue;

        /// <summary>
        /// 타이머
        /// </summary>
        private DispatcherTimer timer;

        /// <summary>
        /// 온도
        /// </summary>
        private double temperature;

        /// <summary>
        /// 기압
        /// </summary>
        private double pressure;

        /// <summary>
        /// 습도
        /// </summary>
        private double humidity;

        #endregion

        //////////////////////////////////////////////////////////////////////////////////////////////////// Constructor
        ////////////////////////////////////////////////////////////////////////////////////////// Public

        #region 생성자 - MainPage()

        /// <summary>
        /// 생성자
        /// </summary>
        public MainPage()
        {
            this.InitializeComponent();


            InitializeDevice();


            this.timer = new DispatcherTimer();

            this.timer.Interval = TimeSpan.FromSeconds(10);

            this.timer.Tick += timer_Tick;

            this.timer.Start();
        }

        #endregion

        //////////////////////////////////////////////////////////////////////////////////////////////////// Method
        ////////////////////////////////////////////////////////////////////////////////////////// Private
        //////////////////////////////////////////////////////////////////////////////// Event

        #region 타이머 틱 처리하기 - timer_Tick(sender, e)

        /// <summary>
        /// 타이머 틱 처리하기
        /// </summary>
        /// <param name="sender">이벤트 발생자</param>
        /// <param name="e">이벤트 인자</param>
        private async void timer_Tick(object sender, object e)
        {
            this.temperature = await ReadTemperatureData();
            this.pressure    = await ReadPressureData();
            this.humidity    = await ReadHumidityData();

            this.temperatureTextBlock.Text = this.temperature.ToString("F1");
            this.humidityTextBlock.Text    = this.humidity.ToString("F1");
            this.pressureTextBlock.Text    = this.pressure.ToString("F1");
        }

        #endregion

        //////////////////////////////////////////////////////////////////////////////// Function

        #region 센서 구성하기 - ConfigureSensor()

        /// <summary>
        /// 센서 구성하기
        /// </summary>
        private async Task ConfigureSensor()
        {
            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 ctrl_hum  = osrs_h;
            uint ctrl_meas = (osrs_t << 5) | (osrs_p << 2) | mode;
            uint config    = (t_sb << 5) | (filter << 2) | spi3w_en;

            this.i2cDevice.Write(new byte[] { 0xf2, (byte)ctrl_hum  });
            this.i2cDevice.Write(new byte[] { 0xf4, (byte)ctrl_meas });
            this.i2cDevice.Write(new byte[] { 0xf5, (byte)config    });

            await Task.Delay(10);
        }

        #endregion
        #region 바이트 데이터 읽기 - ReadByteData(register)

        /// <summary>
        /// 바이트 데이터 읽기
        /// </summary>
        /// <param name="register">레지스터</param>
        /// <returns>바이트 데이터</returns>
        private byte ReadByteData(byte register)
        {
            byte[] writeByteArray = new byte[] { 0x00 };
            byte[] readByteArray  = new byte[] { 0x00 };

            writeByteArray[0] = register;

            this.i2cDevice.WriteRead(writeByteArray, readByteArray);

            return readByteArray[0];
        }

        #endregion
        #region UINT16 데이터 읽기 - ReadUInt16Data(register)

        /// <summary>
        /// UINT16 데이터 읽기
        /// </summary>
        /// <param name="register">레지스터</param>
        /// <returns>UINT16 데이터</returns>
        private UInt16 ReadUInt16Data(byte register)
        {
            byte[] writeByteArray = new byte[] { 0x00 };
            byte[] readByteArray  = new byte[] { 0x00, 0x00 };

            writeByteArray[0] = register;

            this.i2cDevice.WriteRead(writeByteArray, readByteArray);

            int highValue = readByteArray[1] << 8;
            int lowValue  = readByteArray[0];

            return (UInt16)(highValue + lowValue);
        }

        #endregion
        #region 보정 데이터 설정하기 - SetCalibrationData()

        /// <summary>
        /// 보정 데이터 설정하기
        /// </summary>
        private void SetCalibrationData()
        {
            // 온도
            this.T1 = ReadUInt16Data((byte)CalibrationRegisterAddress.DIGITAL_T1);
            this.T2 = (Int16)ReadUInt16Data((byte)CalibrationRegisterAddress.DIGITAL_T2);
            this.T3 = (Int16)ReadUInt16Data((byte)CalibrationRegisterAddress.DIGITAL_T3);

            // 기압
            this.P1 = ReadUInt16Data((byte)CalibrationRegisterAddress.DIGITAL_P1);
            this.P2 = (Int16)ReadUInt16Data((byte)CalibrationRegisterAddress.DIGITAL_P2);
            this.P3 = (Int16)ReadUInt16Data((byte)CalibrationRegisterAddress.DIGITAL_P3);
            this.P4 = (Int16)ReadUInt16Data((byte)CalibrationRegisterAddress.DIGITAL_P4);
            this.P5 = (Int16)ReadUInt16Data((byte)CalibrationRegisterAddress.DIGITAL_P5);
            this.P6 = (Int16)ReadUInt16Data((byte)CalibrationRegisterAddress.DIGITAL_P6);
            this.P7 = (Int16)ReadUInt16Data((byte)CalibrationRegisterAddress.DIGITAL_P7);
            this.P8 = (Int16)ReadUInt16Data((byte)CalibrationRegisterAddress.DIGITAL_P8);
            this.P9 = (Int16)ReadUInt16Data((byte)CalibrationRegisterAddress.DIGITAL_P9);

            //습도
            this.H1 = ReadByteData((byte)CalibrationRegisterAddress.DIGITAL_H1);
            this.H2 = (Int16)ReadUInt16Data((byte)CalibrationRegisterAddress.DIGITAL_H2);
            this.H3 = ReadByteData((byte)CalibrationRegisterAddress.DIGITAL_H3);
            this.H4 = (Int16)(ReadByteData((byte)CalibrationRegisterAddress.DIGITAL_H4) << 4 | ReadByteData((byte)CalibrationRegisterAddress.DIGITAL_H4 + 1) & 0xf);
            this.H5 = (Int16)(ReadByteData((byte)CalibrationRegisterAddress.DIGITAL_H5 + 1) << 4 | ReadByteData((byte)CalibrationRegisterAddress.DIGITAL_H5) >> 4);
            this.H6 = (Int16)ReadByteData((byte)CalibrationRegisterAddress.DIGITAL_H6);
        }

        #endregion
        #region 장치 초기화 하기 - InitializeDevice()

        /// <summary>
        /// 장치 초기화 하기
        /// </summary>
        private async void InitializeDevice()
        {
            string advancedQuerySyntax = I2cDevice.GetDeviceSelector("I2C1");

            DeviceInformationCollection deviceInformationCollection = await DeviceInformation.FindAllAsync(advancedQuerySyntax);

            I2cConnectionSettings i2cConnectionSettings = new I2cConnectionSettings(ADDRESS_BME280);

            i2cConnectionSettings.BusSpeed = I2cBusSpeed.FastMode;

            this.i2cDevice = await I2cDevice.FromIdAsync(deviceInformationCollection[0].Id, i2cConnectionSettings);

            await ConfigureSensor();

            SetCalibrationData();
        }

        #endregion

        #region 온도 데이터 읽기 - ReadTemperatureData()

        /// <summary>
        /// 온도 데이터 읽기
        /// </summary>
        /// <returns>온도 데이터</returns>
        private async Task<double> ReadTemperatureData()
        {
            byte temp_msb  = ReadByteData(TEMP_MSB_REGISTER_ADDRESS );
            byte temp_lsb  = ReadByteData(TEMP_LSB_REGISTER_ADDRESS );
            byte temp_xlsb = ReadByteData(TEMP_XLSB_REGISTER_ADDRESS);

            Int32 rawValue = (temp_msb << 12) | (temp_lsb << 4) | (temp_xlsb >> 4);

            double value1;
            double value2;
            double temperature;

            value1 = ((rawValue / 16384.0 ) - (T1 / 1024.0)) * T2;
            value2 = ((rawValue / 131072.0) - (T1 / 8192.0)) * T3;

            this.fineTunning = (Int32)(value1 + value2);

            temperature = (value1 + value2) / 5120.0;

            await Task.Delay(1);

            return temperature;     
        }

        #endregion
        #region 기압 데이터 읽기 - ReadAtmosphericPressureData()

        /// <summary>
        /// 기압 데이터 읽기
        /// </summary>
        /// <returns>기압 데이터</returns>
        private async Task<double> ReadPressureData()
        {
            /*
            if(this.fineTunning == Int32.MinValue)
            {
                this.temperature = await ReadTemperatureData();
            }
            */

            byte press_msb  = ReadByteData(PRESS_MSB_REGISTER_ADDRESS );
            byte press_lsb  = ReadByteData(PRESS_LSB_REGISTER_ADDRESS );
            byte press_xlsb = ReadByteData(PRESS_XLSB_REGISTER_ADDRESS);

            Int32 rawPressure = (press_msb << 12) | (press_lsb << 4) | (press_xlsb >> 4);

            Int64 value1;
            Int64 value2;
            Int64 pressure;

            value1 = fineTunning - 128000;
            value2 = value1 * value1 * (Int64)P6;
            value2 = value2 + ((value1 * (Int64)P5) << 17);
            value2 = value2 + ((Int64)P4 << 35);
            value1 = ((value1 * value1 * (Int64)P3) >> 8) + ((value1 * (Int64)P2) << 12);
            value1 = (((((Int64)1 << 47) + value1)) * (Int64)P1) >> 33;

            if(value1 == 0)
            {
                return 0;
            }

            pressure = 1048576 - rawPressure;
            pressure = (((pressure << 31) - value2) * 3125) / value1;

            value1 = ((Int64)P9 * (pressure >> 13)) >> 25;
            value2 = ((Int64)P8 * pressure) >> 19;

            pressure = ((pressure + value1 + value2) >> 8) + ((Int64)P7 << 4);

            await Task.Delay(1);

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

        #endregion
        #region 습도 데이터 읽기 - ReadHumidityData()

        /// <summary>
        /// 습도 데이터 읽기
        /// </summary>
        /// <returns>습도 데이터</returns>
        private async Task<double> ReadHumidityData()
        {
            byte hum_msb = ReadByteData(HUM_MSB_REGISTER_ADDRESS);
            byte hum_lsb = ReadByteData(HUM_LSB_REGISTER_ADDRESS);

            int rawHumidity = (hum_msb << 8) | hum_lsb;

            Int32 humidity;

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

            await Task.Delay(1);

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

        #endregion
    }
}
728x90
반응형
그리드형
Posted by 사용자 icodebroker

댓글을 달아 주세요