Hardware components | ||||||
![]() |
| × | 1 | |||
| × | 1 | ||||
![]() |
| × | 1 | |||
![]() |
| × | 1 | |||
Software apps and online services | ||||||
![]() |
| |||||
![]() |
|
Get connected
Read moreConnect the BMP280 to the Raspberry Pi like this:
- BMP280 = Jumper Wire Color = Raspberry Pi
- VIN = Orange = Pin 2 (5V)
- Ground = Black = Pin 6 (Ground)
- SCK = White = Pin 5 (I2C Clock)
- SDI = Green = Pin 3 (I2C Data)
Connection
public class BMP280_CalibrationData
{
//BMP280 Registers
public UInt16 dig_T1 { get; set; }
public Int16 dig_T2 { get; set; }
public Int16 dig_T3 { get; set; }
public UInt16 dig_P1 { get; set; }
public Int16 dig_P2 { get; set; }
public Int16 dig_P3 { get; set; }
public Int16 dig_P4 { get; set; }
public Int16 dig_P5 { get; set; }
public Int16 dig_P6 { get; set; }
public Int16 dig_P7 { get; set; }
public Int16 dig_P8 { get; set; }
public Int16 dig_P9 { get; set; }
}
public class BMP280
{
//The BMP280 register addresses according the the datasheet: http://www.adafruit.com/datasheets/BST-BMP280-DS001-11.pdf
const byte BMP280_Address = 0x77;
const byte BMP280_Signature = 0x58;
enum eRegisters : byte
{
BMP280_REGISTER_DIG_T1 = 0x88,
BMP280_REGISTER_DIG_T2 = 0x8A,
BMP280_REGISTER_DIG_T3 = 0x8C,
BMP280_REGISTER_DIG_P1 = 0x8E,
BMP280_REGISTER_DIG_P2 = 0x90,
BMP280_REGISTER_DIG_P3 = 0x92,
BMP280_REGISTER_DIG_P4 = 0x94,
BMP280_REGISTER_DIG_P5 = 0x96,
BMP280_REGISTER_DIG_P6 = 0x98,
BMP280_REGISTER_DIG_P7 = 0x9A,
BMP280_REGISTER_DIG_P8 = 0x9C,
BMP280_REGISTER_DIG_P9 = 0x9E,
BMP280_REGISTER_CHIPID = 0xD0,
BMP280_REGISTER_VERSION = 0xD1,
BMP280_REGISTER_SOFTRESET = 0xE0,
BMP280_REGISTER_CAL26 = 0xE1, // R calibration stored in 0xE1-0xF0
BMP280_REGISTER_CONTROLHUMID = 0xF2,
BMP280_REGISTER_CONTROL = 0xF4,
BMP280_REGISTER_CONFIG = 0xF5,
BMP280_REGISTER_PRESSUREDATA_MSB = 0xF7,
BMP280_REGISTER_PRESSUREDATA_LSB = 0xF8,
BMP280_REGISTER_PRESSUREDATA_XLSB = 0xF9, // bits <7:4>
BMP280_REGISTER_TEMPDATA_MSB = 0xFA,
BMP280_REGISTER_TEMPDATA_LSB = 0xFB,
BMP280_REGISTER_TEMPDATA_XLSB = 0xFC, // bits <7:4>
BMP280_REGISTER_HUMIDDATA_MSB = 0xFD,
BMP280_REGISTER_HUMIDDATA_LSB = 0xFE,
};
//String for the friendly name of the I2C bus
const string I2CControllerName = "I2C1";
//Create an I2C device
private I2cDevice bmp280 = null;
//Create new calibration data for the sensor
BMP280_CalibrationData CalibrationData;
//Variable to check if device is initialized
bool init = false;
//Method to initialize the BMP280 sensor
public async Task Initialize()
{
Debug.WriteLine("BMP280::Initialize");
try
{
//Instantiate the I2CConnectionSettings using the device address of the BMP280
I2cConnectionSettings settings = new I2cConnectionSettings(BMP280_Address);
//Set the I2C bus speed of connection to fast mode
settings.BusSpeed = I2cBusSpeed.FastMode;
//Use the I2CBus device selector to create an advanced query syntax string
string aqs = I2cDevice.GetDeviceSelector(I2CControllerName);
//Use the Windows.Devices.Enumeration.DeviceInformation class to create a collection using the advanced query syntax string
DeviceInformationCollection dis = await DeviceInformation.FindAllAsync(aqs);
//Instantiate the the BMP280 I2C device using the device id of the I2CBus and the I2CConnectionSettings
bmp280 = await I2cDevice.FromIdAsync(dis[0].Id, settings);
//Check if device was found
if (bmp280 == null)
{
Debug.WriteLine("Device not found");
}
}
catch (Exception e)
{
Debug.WriteLine("Exception: " + e.Message + "\n" + e.StackTrace);
throw;
}
}
private async Task Begin()
{
Debug.WriteLine("BMP280::Begin");
byte[] WriteBuffer = new byte[] { (byte)eRegisters.BMP280_REGISTER_CHIPID };
byte[] ReadBuffer = new byte[] { 0xFF };
//Read the device signature
bmp280.WriteRead(WriteBuffer, ReadBuffer);
Debug.WriteLine("BMP280 Signature: " + ReadBuffer[0].ToString());
//Verify the device signature
if (ReadBuffer[0] != BMP280_Signature)
{
Debug.WriteLine("BMP280::Begin Signature Mismatch.");
return;
}
//Set the initalize variable to true
init = true;
//Read the coefficients table
CalibrationData = await ReadCoefficeints();
//Write control register
await WriteControlRegister();
//Write humidity control register
await WriteControlRegisterHumidity();
}
//Method to write 0x03 to the humidity control register
private async Task WriteControlRegisterHumidity()
{
byte[] WriteBuffer = new byte[] { (byte)eRegisters.BMP280_REGISTER_CONTROLHUMID, 0x03 };
bmp280.Write(WriteBuffer);
await Task.Delay(1);
return;
}
//Method to write 0x3F to the control register
private async Task WriteControlRegister()
{
byte[] WriteBuffer = new byte[] { (byte)eRegisters.BMP280_REGISTER_CONTROL, 0x3F };
bmp280.Write(WriteBuffer);
await Task.Delay(1);
return;
}
//Method to read a 16-bit value from a register and return it in little endian format
private UInt16 ReadUInt16_LittleEndian(byte register)
{
UInt16 value = 0;
byte[] writeBuffer = new byte[] { 0x00 };
byte[] readBuffer = new byte[] { 0x00, 0x00 };
writeBuffer[0] = register;
bmp280.WriteRead(writeBuffer, readBuffer);
int h = readBuffer[1] << 8;
int l = readBuffer[0];
value = (UInt16)(h + l);
return value;
}
//Method to read an 8-bit value from a register
private byte ReadByte(byte register)
{
byte value = 0;
byte[] writeBuffer = new byte[] { 0x00 };
byte[] readBuffer = new byte[] { 0x00 };
writeBuffer[0] = register;
bmp280.WriteRead(writeBuffer, readBuffer);
value = readBuffer[0];
return value;
}
//Method to read the caliberation data from the registers
private async Task<BMP280_CalibrationData> ReadCoefficeints()
{
// 16 bit calibration data is stored as Little Endian, the helper method will do the byte swap.
CalibrationData = new BMP280_CalibrationData();
// Read temperature calibration data
CalibrationData.dig_T1 = ReadUInt16_LittleEndian((byte)eRegisters.BMP280_REGISTER_DIG_T1);
CalibrationData.dig_T2 = (Int16)ReadUInt16_LittleEndian((byte)eRegisters.BMP280_REGISTER_DIG_T2);
CalibrationData.dig_T3 = (Int16)ReadUInt16_LittleEndian((byte)eRegisters.BMP280_REGISTER_DIG_T3);
// Read presure calibration data
CalibrationData.dig_P1 = ReadUInt16_LittleEndian((byte)eRegisters.BMP280_REGISTER_DIG_P1);
CalibrationData.dig_P2 = (Int16)ReadUInt16_LittleEndian((byte)eRegisters.BMP280_REGISTER_DIG_P2);
CalibrationData.dig_P3 = (Int16)ReadUInt16_LittleEndian((byte)eRegisters.BMP280_REGISTER_DIG_P3);
CalibrationData.dig_P4 = (Int16)ReadUInt16_LittleEndian((byte)eRegisters.BMP280_REGISTER_DIG_P4);
CalibrationData.dig_P5 = (Int16)ReadUInt16_LittleEndian((byte)eRegisters.BMP280_REGISTER_DIG_P5);
CalibrationData.dig_P6 = (Int16)ReadUInt16_LittleEndian((byte)eRegisters.BMP280_REGISTER_DIG_P6);
CalibrationData.dig_P7 = (Int16)ReadUInt16_LittleEndian((byte)eRegisters.BMP280_REGISTER_DIG_P7);
CalibrationData.dig_P8 = (Int16)ReadUInt16_LittleEndian((byte)eRegisters.BMP280_REGISTER_DIG_P8);
CalibrationData.dig_P9 = (Int16)ReadUInt16_LittleEndian((byte)eRegisters.BMP280_REGISTER_DIG_P9);
await Task.Delay(1);
return CalibrationData;
}
//t_fine carries fine temperature as global value
Int32 t_fine = Int32.MinValue;
//Method to return the temperature in DegC. Resolution is 0.01 DegC. Output value of 5123 equals 51.23 DegC.
private double BMP280_compensate_T_double(Int32 adc_T)
{
double var1, var2, T;
//The temperature is calculated using the compensation formula in the BMP280 datasheet
var1 = ((adc_T / 16384.0) - (CalibrationData.dig_T1 / 1024.0)) * CalibrationData.dig_T2;
var2 = ((adc_T / 131072.0) - (CalibrationData.dig_T1 / 8192.0)) * CalibrationData.dig_T3;
t_fine = (Int32)(var1 + var2);
T = (var1 + var2) / 5120.0;
return T;
}
//Method to returns the pressure in Pa, in Q24.8 format (24 integer bits and 8 fractional bits).
//Output value of 24674867 represents 24674867/256 = 96386.2 Pa = 963.862 hPa
private Int64 BMP280_compensate_P_Int64(Int32 adc_P)
{
Int64 var1, var2, p;
//The pressure is calculated using the compensation formula in the BMP280 datasheet
var1 = t_fine - 128000;
var2 = var1 * var1 * (Int64)CalibrationData.dig_P6;
var2 = var2 + ((var1 * (Int64)CalibrationData.dig_P5) << 17);
var2 = var2 + ((Int64)CalibrationData.dig_P4 << 35);
var1 = ((var1 * var1 * (Int64)CalibrationData.dig_P3) >> 8) + ((var1 * (Int64)CalibrationData.dig_P2) << 12);
var1 = (((((Int64)1 << 47) + var1)) * (Int64)CalibrationData.dig_P1) >> 33;
if (var1 == 0)
{
Debug.WriteLine("BMP280_compensate_P_Int64 Jump out to avoid / 0");
return 0; //Avoid exception caused by division by zero
}
//Perform calibration operations as per datasheet: http://www.adafruit.com/datasheets/BST-BMP280-DS001-11.pdf
p = 1048576 - adc_P;
p = (((p << 31) - var2) * 3125) / var1;
var1 = ((Int64)CalibrationData.dig_P9 * (p >> 13) * (p >> 13)) >> 25;
var2 = ((Int64)CalibrationData.dig_P8 * p) >> 19;
p = ((p + var1 + var2) >> 8) + ((Int64)CalibrationData.dig_P7 << 4);
return p;
}
public async Task<float> ReadTemperature()
{
//Make sure the I2C device is initialized
if (!init) await Begin();
//Read the MSB, LSB and bits 7:4 (XLSB) of the temperature from the BMP280 registers
byte tmsb = ReadByte((byte)eRegisters.BMP280_REGISTER_TEMPDATA_MSB);
byte tlsb = ReadByte((byte)eRegisters.BMP280_REGISTER_TEMPDATA_LSB);
byte txlsb = ReadByte((byte)eRegisters.BMP280_REGISTER_TEMPDATA_XLSB); // bits 7:4
//Combine the values into a 32-bit integer
Int32 t = (tmsb << 12) + (tlsb << 4) + (txlsb >> 4);
//Convert the raw value to the temperature in degC
double temp = BMP280_compensate_T_double(t);
//Return the temperature as a float value
return (float)temp;
}
public async Task<float> ReadPreasure()
{
//Make sure the I2C device is initialized
if (!init) await Begin();
//Read the temperature first to load the t_fine value for compensation
if (t_fine == Int32.MinValue)
{
await ReadTemperature();
}
//Read the MSB, LSB and bits 7:4 (XLSB) of the pressure from the BMP280 registers
byte tmsb = ReadByte((byte)eRegisters.BMP280_REGISTER_PRESSUREDATA_MSB);
byte tlsb = ReadByte((byte)eRegisters.BMP280_REGISTER_PRESSUREDATA_LSB);
byte txlsb = ReadByte((byte)eRegisters.BMP280_REGISTER_PRESSUREDATA_XLSB); // bits 7:4
//Combine the values into a 32-bit integer
Int32 t = (tmsb << 12) + (tlsb << 4) + (txlsb >> 4);
//Convert the raw value to the pressure in Pa
Int64 pres = BMP280_compensate_P_Int64(t);
//Return the temperature as a float value
return ((float)pres) / 256;
}
//Method to take the sea level pressure in Hectopascals(hPa) as a parameter and calculate the altitude using current pressure.
public async Task<float> ReadAltitude(float seaLevel)
{
//Make sure the I2C device is initialized
if (!init) await Begin();
//Read the pressure first
float pressure = await ReadPreasure();
//Convert the pressure to Hectopascals(hPa)
pressure /= 100;
//Calculate and return the altitude using the international barometric formula
return 44330.0f * (1.0f - (float)Math.Pow((pressure / seaLevel), 0.1903f));
}
}
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<Grid x:Name="TemperatureSensorGrid" Background="White" Margin="1110,330,10,250">
<Ellipse x:Name="TemperatureOutsideEllipse" Fill="White" HorizontalAlignment="Center" Height="400" Stroke="Black" VerticalAlignment="Center" Width="400"/>
<Ellipse Fill="White" HorizontalAlignment="Center" Height="300" Stroke="Black" VerticalAlignment="Center" Width="300"/>
<Grid x:Name= "internalTemperatureGrid">
<Grid.RowDefinitions>
<RowDefinition Height="0.5*"/>
<RowDefinition Height="*"/>
<RowDefinition Height="0.5*"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Grid x:Name="CenterOfTemperatureGrid" Grid.Row="1" Grid.Column="1">
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="4*"/>
<RowDefinition Height="*"/>
<RowDefinition Height="*"/>
<RowDefinition Height="*"/>
<RowDefinition Height="*"/>
<RowDefinition Height="*"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<TextBlock x:Name="TemperatureUnitsMain" Grid.Row="5" Text="Celsius" TextAlignment="Center" HorizontalAlignment="Center" TextWrapping="Wrap" VerticalAlignment="Bottom" Width="155" RenderTransformOrigin="0.46,4.286" Foreground="#323232" Margin="56,0,56,15" Grid.RowSpan="2"/>
<TextBlock x:Name="CurrentTemperatureNumber" Grid.Row="1" Text="0" HorizontalAlignment="Center" TextWrapping="Wrap" VerticalAlignment="Top" FontSize="70" TextAlignment="Center" Foreground="#323232" Margin="115,38,114,0" Grid.RowSpan="3"/>
<TextBlock x:Name="CurrentTemperatureText" Grid.Row="1" Text="Current Temperature" TextAlignment="Center" HorizontalAlignment="Center" VerticalAlignment="Top" TextWrapping="Wrap" Width="155" RenderTransformOrigin="0.207,0.569" Foreground="#323232" Margin="56,13,56,0"/>
<TextBlock x:Name="CurrentTime" Text="0:00" HorizontalAlignment="Center" TextWrapping="Wrap" VerticalAlignment="Top" FontSize="70" TextAlignment="Center" Foreground="#323232" Margin="-1042,-351,1136,0" Width="173"/>
</Grid>
</Grid>
</Grid>
<Rectangle Fill="#C44D58" HorizontalAlignment="Left" Height="24" VerticalAlignment="Center" Width="24" Margin="585,392,0,664"/>
<TextBlock x:Name="TooHigh" Text=" = Too Hot" VerticalAlignment="Center" HorizontalAlignment="Left" Foreground="Black" Margin="609,392,0,664" Height="24"/>
<Rectangle Fill="#FFEC6B6B" HorizontalAlignment="Left" Height="24" VerticalAlignment="Center" Width="24" Margin="486,392,0,664"/>
<TextBlock x:Name="TooHigh_Copy" Text=" = Hot" VerticalAlignment="Center" HorizontalAlignment="Left" Foreground="Black" Margin="515,392,0,664" Height="24"/>
<Rectangle Fill="#FFC7F464" HorizontalAlignment="Left" Height="24" VerticalAlignment="Center" Width="24" Margin="388,392,0,664"/>
<TextBlock x:Name="TooHigh_Copy1" Text=" = OK" VerticalAlignment="Center" HorizontalAlignment="Left" Foreground="Black" Margin="417,392,0,664" Height="24"/>
<Rectangle Fill="#FF4ECDC4" HorizontalAlignment="Left" Height="24" VerticalAlignment="Center" Width="24" Margin="296,392,0,664"/>
<TextBlock x:Name="TooHigh_Copy2" Text=" = Cold" VerticalAlignment="Center" HorizontalAlignment="Left" Foreground="Black" Margin="325,392,0,664" Height="24"/>
<TextBlock x:Name="TooHigh_Copy3" Text=" = Too Cold" VerticalAlignment="Center" HorizontalAlignment="Left" Foreground="Black" Margin="206,392,0,664" Height="24"/>
<Rectangle Fill="#FF556270" HorizontalAlignment="Left" Height="24" VerticalAlignment="Center" Width="24" Margin="177,392,0,664"/>
<TextBlock x:Name="CurrentDate" Text="0/0/0000" HorizontalAlignment="Center" TextWrapping="Wrap" VerticalAlignment="Top" FontSize="48" TextAlignment="Center" Foreground="#323232" Margin="296,226,1362,0" Width="262"/>
</Grid>
public delegate void DataReceivedEventHandler(object sender, SensorDataEventArgs e);
public class SensorDataProvider
{
public event DataReceivedEventHandler DataReceived;
//Barometric Sensor
public BMP280 BMP280;
private Timer timer;
private Timer writeToFile;
Random rand = new Random();
public SensorDataProvider()
{
BMP280 = new BMP280();
}
public void StartTimer()
{
timer = new Timer(timerCallback, this, 0, 3000);
writeToFile = new Timer(writeToFileTimerCallback, this, 20000, 9000);
}
private async void writeToFileTimerCallback(object state)
{
for (int ii = 0; ii < App.TemperatureList.Count; ii++)
{
App.Temperatureresult.Add(App.TemperatureList[ii]);
await Windows.Storage.FileIO.AppendTextAsync(App.TemperatureFile, App.TemperatureList[ii]);
}
}
/**
* This method records on a timer the data measured by the temperature, brightness, and soil moisture sensor,
* then organizes all of the information collected.
* */
private async void timerCallback(object state)
{
//ensures that the temperature sensor is initialized before it is measured from
if (BMP280 == null)
{
Debug.WriteLine("BMP280 is null");
}
else
{
//receives the value from the temperature sensor and saves
//the data in the SensorDataEventArgs class, which holds
//the sensor name, the data point, and the time the value was measured.
//this data is then sent back to the main page and the UI is adjusted based
//off of the measurement.
//float currentTemperature = (float) rand.NextDouble() * 10;
float currentTemperature = await BMP280.ReadTemperature();
var tempArgs = new SensorDataEventArgs()
{
SensorName = "Temperature",
SensorValue = currentTemperature,
Timestamp = DateTime.Now
};
OnDataReceived(tempArgs);
}
protected virtual void OnDataReceived(SensorDataEventArgs e)
{
if (DataReceived != null)
{
DataReceived(this, e);
}
}
}
public class SensorDataEventArgs : EventArgs
{
public string SensorName;
public float SensorValue;
public DateTime Timestamp;
}
public sealed partial class MainPage : Page
{
public Timer controlPanelTimer;
//This is the timer for the altitude and pressure
public Timer altPressTimer;
//This will be able to be set by the user in the next sprint
//These colors dictate what the tabs that determine time span look like
Color colorBlue;
Color colorlightBlue;
Color colorWhite;
Color colorlightRed;
Color colorRed;
SolidColorBrush SolidColorBrushBlue;
SolidColorBrush SolidColorBrushLightBlue;
SolidColorBrush SolidColorBrushWhite;
SolidColorBrush SolidColorBrushLightRed;
SolidColorBrush SolidColorBrushRed;
public static float currentTemperature
public MainPage()
{
this.InitializeComponent();
controlPanelTimer = new Timer(timerControlPanel, this, 0, 1000);
colorBlue = Color.FromArgb(255, 85, 98, 112);
colorlightBlue = Color.FromArgb(255, 78, 205, 196);
colorWhite = Color.FromArgb(255, 199, 244, 100);
colorlightRed = Color.FromArgb(255, 236, 107, 107);
colorRed = Color.FromArgb(255, 196, 77, 88);
SolidColorBrushBlue = new SolidColorBrush(colorBlue);
SolidColorBrushLightBlue = new SolidColorBrush(colorlightBlue);
SolidColorBrushWhite = new SolidColorBrush(colorWhite);
SolidColorBrushLightRed = new SolidColorBrush(colorlightRed);
SolidColorBrushRed = new SolidColorBrush(colorRed);
DateTime Now = DateTime.Now;
Random rand = new Random();
TimeSpan oneDay = new TimeSpan(1, 0, 0, 0);
TimeSpan oneHour = new TimeSpan(1, 0, 0);
DateTime LowerBound = Now - oneDay;
while (LowerBound < Now)
{
float randomValue = (float)rand.NextDouble() * 10;
String nextValue = randomValue + "," + LowerBound + Environment.NewLine;
App.TemperatureList.Add(nextValue);
randomValue = (float)rand.NextDouble() * 10;
nextValue = randomValue + "," + LowerBound + Environment.NewLine;
App.BrightnessList.Add(nextValue);
randomValue = (float)rand.NextDouble() * 10;
nextValue = randomValue + "," + LowerBound + Environment.NewLine;
App.SoilMoistureList.Add(nextValue);
LowerBound += oneHour;
}
}
private async void SensorProvider_DataReceived(object sender, SensorDataEventArgs e)
{
String format = formatOfSensorValue(e.SensorValue);
String nextValue = e.SensorValue + "," + DateTime.Now + Environment.NewLine;
SolidColorBrush ellipseFill;
switch (e.SensorName)
{
case "Temperature":
await Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
{
currentTemperature = e.SensorValue;
float suggestionTemperature = idealTemperature - e.SensorValue;
CurrentTemperatureNumber.Text = e.SensorValue.ToString(format);
OurSuggestionNumberTemperature.Text = suggestionTemperature.ToString(format);
ellipseFill = FigureOutFill(suggestionTemperature);
TemperatureOutsideEllipse.Fill = ellipseFill;
TemperatureUnitsMain.Foreground = ellipseFill;
IdealTemperatureText.Foreground = ellipseFill;
IdealTemperatureNumber.Foreground = ellipseFill;
CurrentTemperatureNumber.Foreground = ellipseFill;
CurrentTemperatureText.Foreground = ellipseFill;
OurSuggestionTextTemperature.Foreground = ellipseFill;
OurSuggestionNumberTemperature.Foreground = ellipseFill;
App.TemperatureList.Add(nextValue);
});
break;
}
}
public SolidColorBrush FigureOutFill(float suggestion)
{
if (suggestion > 9)
{
return SolidColorBrushBlue;
}
else if (suggestion > 3)
{
return SolidColorBrushLightBlue;
}
else if (suggestion > -3)
{
return SolidColorBrushWhite;
}
else if (suggestion > -9)
{
return SolidColorBrushLightRed;
}
else
{
return SolidColorBrushRed;
}
}
}
Comments
Please log in or sign up to comment.