-
Notifications
You must be signed in to change notification settings - Fork 0
/
bmp085.cpp
361 lines (321 loc) · 10.3 KB
/
bmp085.cpp
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
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
/*
* File: bmp085.cpp
* Author: Craig Hollinger
*
* Description:
*
* Firmware to read data from the Bosch BMP085 pressure sensor. The formulas
* used below for calculating the temperature and pressure from the raw data
* are taken directly from the BMP085 data sheet.
*
* This file is free software; you can redistribute it and/or modify
* it under the terms of either the GNU General Public License version 3
* or the GNU Lesser General Public License version 3, both as
* published by the Free Software Foundation.
*/
#include <BMP085.h>
#include <WIRE.H>
// This union is used to manipulate a two byte unsigned int
typedef union _WORD_TYPE
{
unsigned int val;
struct
{
unsigned char LSB;
unsigned char MSB;
};
unsigned char v[2];
} WORD_TYPE;
// This union is used to manipulate a two byte signed int
typedef union _SIGNED_WORD_TYPE
{
int val;
struct
{
unsigned char LSB;
unsigned char MSB;
};
unsigned char v[2];
} SIGNED_WORD_TYPE;
// This union is used to manipulate a four byte signed long
typedef union _LONG_TYPE
{
long val;
struct
{
unsigned char LSB;
unsigned char MSB;
unsigned char b0;
unsigned char b1;
};
unsigned char v[4];
} LONG_TYPE;
/*
* Bosch BMP085 pressure and temperature module device slave address
* - 0xee shifted 1-bit to right
*
* 0xee is the correct slave address for the Bosch device, Arduino's weird
* implementation of the Wire library requires the shift.
*/
#define BMP085SlaveAdrs 0x77
/*
* EEPROM registers containing the calibration data
*/
#define BMP085_EEPROM 0xaa
#define BMP085_AC1 0xaa
#define BMP085_AC2 0xac
#define BMP085_AC3 0xae
#define BMP085_AC4 0xb0
#define BMP085_AC5 0xb2
#define BMP085_AC6 0xb4
#define BMP085_B1 0xb6
#define BMP085_B2 0xb8
#define BMP085_MB 0xba
#define BMP085_MC 0xbc
#define BMP085_MD 0xbe
#define BMP085_MAX_CAL_FACTORS 22
/*
* Register and the codes written to the register to start temperature and
* pressure conversions.
*/
#define BMP085_START_REG 0xf4
#define BMP085_START_UT 0x2e // temperature
#define BMP085_START_UP 0x34 // pressure
#define BMP085_CONVERSION_TIME 4 // conversion time in ms
/*
* Registers containing the 16-bit temperature and pressure data after a
* conversion. The same register is used, what is read is determined by what
* was previously written into the Start register.
*/
#define BMP085_UT 0xf6
#define BMP085_UP 0xf6
/*
* Local registers for storing the calibration data read from the EEPROM.
* These are setup as unions defined above so that they can be accessed one byte
* at a time when read from the device EEPROM.
*/
SIGNED_WORD_TYPE Bosch_ac1,
Bosch_ac2,
Bosch_ac3;
WORD_TYPE Bosch_ac4,
Bosch_ac5,
Bosch_ac6;
SIGNED_WORD_TYPE Bosch_b1,
Bosch_b2,
Bosch_mb,
Bosch_mc,
Bosch_md;
/*
* Raw temperature read from module
*/
LONG_TYPE Bosch_ut;
/*
* Raw pressure read from module
*/
LONG_TYPE Bosch_up;
/*
* Intermediate registers for calculations
*/
long Bosch_x1,
Bosch_x2,
Bosch_x3,
Bosch_b3,
Bosch_b5,
Bosch_b6,
Bosch_p,
Bosch_t;
unsigned long Bosch_b4,
Bosch_b7;
/*
* constructor()
*
* Read all 22 bytes of calibration data from the BMP085 EEPROM. The factors
* are 16 bits each but are in big endian format (MSB first). The byte order
* must be switched to make the factors into standard 16-bit integer format.
*/
BMP085::BMP085(void){
/*
* Arduino Wire automatically enables the internal pull-up resistors for SCL
* and SDA. When connected to a 3.3V slave device, the pull-ups have enough
* strength to pull the slave device pins to 5V. Not good for the device.
* Write a zero to the PORT register for each of the pins to disable the
* pull-ups.
*/
PORTC &= 0b11001111;
/*
* Start the transfer by sending the Slave Address to the device. Next, write
* the starting address of the calibration EEPROM to set the read address in
* the device. Stop the transmission, but issue a repeated start on the I2C
* bus, (endTransmission() with false parameter does this. Finally, issue a
* requestFrom() for the data. Wait until all bytes have been read into the
* buffer, then copy them to the local registers, swapping the MSB and LSB.
*/
Wire.beginTransmission(BMP085SlaveAdrs);
Wire.write(BMP085_EEPROM);
Wire.endTransmission(false);
Wire.requestFrom(BMP085SlaveAdrs, BMP085_MAX_CAL_FACTORS, true);
/*
* wait here until all data bytes have been read
*/
while(Wire.available() < BMP085_MAX_CAL_FACTORS);
Bosch_ac1.MSB = Wire.read();
Bosch_ac1.LSB = Wire.read();
Bosch_ac2.MSB = Wire.read();
Bosch_ac2.LSB = Wire.read();
Bosch_ac3.MSB = Wire.read();
Bosch_ac3.LSB = Wire.read();
Bosch_ac4.MSB = Wire.read();
Bosch_ac4.LSB = Wire.read();
Bosch_ac5.MSB = Wire.read();
Bosch_ac5.LSB = Wire.read();
Bosch_ac6.MSB = Wire.read();
Bosch_ac6.LSB = Wire.read();
Bosch_b1.MSB = Wire.read();
Bosch_b1.LSB = Wire.read();
Bosch_b2.MSB = Wire.read();
Bosch_b2.LSB = Wire.read();
Bosch_mb.MSB = Wire.read();
Bosch_mb.LSB = Wire.read();
Bosch_mc.MSB = Wire.read();
Bosch_mc.LSB = Wire.read();
Bosch_md.MSB = Wire.read();
Bosch_md.LSB = Wire.read();
}/* end constructor() */
/*
*
* getBoschRawTemperature()
*
* This routine starts the temperature conversion, then reads the raw
* (uncalibrated) into storage. The BMP085 sensor will take up to 4.5ms to do
* a conversion. This routine is written to not block during the conversion
* time or need an interrupt (although one is available from the sensor).
* Simply call this routine repeatedly and when the conversion is done the data
* is read. During the conversion time, the routine will return false. After
* the conversion time has elapsed and the data has been read, the routine will
* return true.
*/
boolean BMP085::getBoschRawTemperature(void){
static boolean state = false;
static unsigned long time = 0;
if(state == false){
Wire.beginTransmission(BMP085SlaveAdrs);
Wire.write(BMP085_START_REG);
Wire.write(BMP085_START_UT);
Wire.endTransmission();
time = millis();
state = true;
return(false);
}
else {
if(millis() - time > BMP085_CONVERSION_TIME){
Wire.beginTransmission(BMP085SlaveAdrs);
Wire.write(BMP085_UT);
Wire.endTransmission(false);
Wire.requestFrom(BMP085SlaveAdrs, 2, true);
while(Wire.available() < 2);
Bosch_ut.MSB = Wire.read();
Bosch_ut.LSB = Wire.read();
Bosch_ut.b0 = 0;
Bosch_ut.b1 = 0;
state = false;
return(true);
}
else{
return(false);
}
}
}/* end getBoschRawTemperature() */
/*
*
* getBoschRawPressure()
*
* This routine starts the pressure conversion, then reads the raw
* (uncalibrated) into storage. The BMP085 sensor will take up to 4.5ms to do
* a conversion. This routine is written to not block during the conversion
* time or need an interrupt (although one is available from the sensor).
* Simply call this routine repeatedly and when the conversion is done the data
* is read. During the conversion time, the routine will return false. After
* the conversion time has elapsed and the data has been read, the routine will
* return true.
*/
boolean BMP085::getBoschRawPressure(void){
static boolean state = false;
static unsigned long time = 0;
if(state == false){
Wire.beginTransmission(BMP085SlaveAdrs);
Wire.write(BMP085_START_REG);
Wire.write(BMP085_START_UP);
Wire.endTransmission();
time = millis();
state = true;
return(false);
}
else {
if(millis() - time > BMP085_CONVERSION_TIME){
Wire.beginTransmission(BMP085SlaveAdrs);
Wire.write(BMP085_UP);
Wire.endTransmission(false);
Wire.requestFrom(BMP085SlaveAdrs, 2, true);
while(Wire.available() < 2);
Bosch_up.MSB = Wire.read();
Bosch_up.LSB = Wire.read();
Bosch_up.b0 = 0;
Bosch_up.b1 = 0;
state = false;
return(true);
}
else{
return(false);
}
}
}/* end getBoschRawPressure() */
/*
*
* calculateBoschTemperature()
*
* Calculate the actual temperature from the Bosch BMP085 sensor. The raw
* temperature is in Bosch_ut. All other parameters have been previously read
* from the sensor's calibration EEPROM.
*
* The formula is a direct copy from the sensor's data sheet.
*/
int BMP085::calculateBoschTemperature(void){
Bosch_x1 = (Bosch_ut.val - Bosch_ac6.val) * Bosch_ac5.val / 32768L;
Bosch_x2 = Bosch_mc.val * 2048L / (Bosch_x1 + Bosch_md.val);
Bosch_b5 = Bosch_x1 + Bosch_x2;
Bosch_t = (Bosch_b5 + 8) / 16L;
return((int)Bosch_t);
}/* end calculateBoschTemperature() */
/*
*
* calculateBoschPressure()
*
* Calculate the actual pressure from the Bosch BMP085 sensor. The raw pressure
* is in Bosch_up. All other parameters have been previously read from the
* sensor's calibration EEPROM.
*
* The formula is a direct copy from the sensor's data sheet.
*/
long BMP085::calculateBoschPressure(void){
Bosch_b6 = Bosch_b5 - 4000L;
Bosch_x1 = (Bosch_b2.val * (Bosch_b6 * Bosch_b6 / 4096L)) / 2048L;
Bosch_x2 = Bosch_ac2.val * Bosch_b6 / 2048L;
Bosch_x3 = Bosch_x1 + Bosch_x2;
Bosch_b3 = ((Bosch_ac1.val * 4L + Bosch_x3) + 2L) / 4L;
Bosch_x1 = Bosch_ac3.val * Bosch_b6 / 8192L;
Bosch_x2 = (Bosch_b1.val * (Bosch_b6 * Bosch_b6 / 4096L)) / 65536;
Bosch_x3 = ((Bosch_x1 + Bosch_x2) + 2L) / 4L;
Bosch_b4 = Bosch_ac4.val * (unsigned long)(Bosch_x3 + 32768L) / 32768UL;
Bosch_b7 = ((unsigned long)Bosch_up.val - Bosch_b3) * 50000UL;
if(Bosch_b7 < 0x80000000){
Bosch_p = (Bosch_b7 * 2L) / Bosch_b4;
}
else{
Bosch_p = (Bosch_b7 / Bosch_b4) * 2L;
}
Bosch_x1 = (Bosch_p / 256L) * (Bosch_p / 256L);
Bosch_x1 = (Bosch_x1 * 3038L) / 65536L;
Bosch_x2 = (-7357L * Bosch_p) / 65536L;
Bosch_p = Bosch_p + (Bosch_x1 + Bosch_x2 + 3791L) / 16;
return(Bosch_p);
}/* end calculateBoschPressure() */