This repository has been archived by the owner on Jan 3, 2020. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 75
/
BMP280.cs
326 lines (270 loc) · 13.2 KB
/
BMP280.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Windows.Devices.Enumeration;
using Windows.Devices.Gpio;
using Windows.Devices.I2c;
namespace Lesson_203
{
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));
}
}
}