1/*
2 SFE_BMP180.cpp
3 Bosch BMP180 pressure sensor library for the Arduino microcontroller
4 Mike Grusin, SparkFun Electronics
5
6 Uses floating-point equations from the Weather Station Data Logger project
7 http://wmrx00.sourceforge.net/
8 http://wmrx00.sourceforge.net/Arduino/BMP085-Calcs.pdf
9
10 Forked from BMP085 library by M.Grusin
11
12 version 1.0 2013/09/20 initial version
13 Verison 1.1.2 - Updated for Arduino 1.6.4 5/2015
14
15 Our example code uses the "beerware" license. You can do anything
16 you like with this code. No really, anything. If you find it useful,
17 buy me a (root) beer someday.
18*/
19
20#include <SFE_BMP180.h>
21#include <Wire.h>
22#include <stdio.h>
23#include <math.h>
24
25
26SFE_BMP180::SFE_BMP180()
27// Base library type
28{
29}
30
31
32char SFE_BMP180::begin()
33// Initialize library for subsequent pressure measurements
34{
35 double c3,c4,b1;
36
37 // Start up the Arduino's "wire" (I2C) library:
38
39 Wire.begin();
40
41 // The BMP180 includes factory calibration data stored on the device.
42 // Each device has different numbers, these must be retrieved and
43 // used in the calculations when taking pressure measurements.
44
45 // Retrieve calibration data from device:
46
47 if (readInt(0xAA,AC1) &&
48 readInt(0xAC,AC2) &&
49 readInt(0xAE,AC3) &&
50 readUInt(0xB0,AC4) &&
51 readUInt(0xB2,AC5) &&
52 readUInt(0xB4,AC6) &&
53 readInt(0xB6,VB1) &&
54 readInt(0xB8,VB2) &&
55 readInt(0xBA,MB) &&
56 readInt(0xBC,MC) &&
57 readInt(0xBE,MD))
58 {
59
60 // All reads completed successfully!
61
62 // If you need to check your math using known numbers,
63 // you can uncomment one of these examples.
64 // (The correct results are commented in the below functions.)
65
66 // Example from Bosch datasheet
67 // AC1 = 408; AC2 = -72; AC3 = -14383; AC4 = 32741; AC5 = 32757; AC6 = 23153;
68 // B1 = 6190; B2 = 4; MB = -32768; MC = -8711; MD = 2868;
69
70 // Example from http://wmrx00.sourceforge.net/Arduino/BMP180-Calcs.pdf
71 // AC1 = 7911; AC2 = -934; AC3 = -14306; AC4 = 31567; AC5 = 25671; AC6 = 18974;
72 // VB1 = 5498; VB2 = 46; MB = -32768; MC = -11075; MD = 2432;
73
74 /*
75 Serial.print("AC1: "); Serial.println(AC1);
76 Serial.print("AC2: "); Serial.println(AC2);
77 Serial.print("AC3: "); Serial.println(AC3);
78 Serial.print("AC4: "); Serial.println(AC4);
79 Serial.print("AC5: "); Serial.println(AC5);
80 Serial.print("AC6: "); Serial.println(AC6);
81 Serial.print("VB1: "); Serial.println(VB1);
82 Serial.print("VB2: "); Serial.println(VB2);
83 Serial.print("MB: "); Serial.println(MB);
84 Serial.print("MC: "); Serial.println(MC);
85 Serial.print("MD: "); Serial.println(MD);
86 */
87
88 // Compute floating-point polynominals:
89
90 c3 = 160.0 * pow(2,-15) * AC3;
91 c4 = pow(10,-3) * pow(2,-15) * AC4;
92 b1 = pow(160,2) * pow(2,-30) * VB1;
93 c5 = (pow(2,-15) / 160) * AC5;
94 c6 = AC6;
95 mc = (pow(2,11) / pow(160,2)) * MC;
96 md = MD / 160.0;
97 x0 = AC1;
98 x1 = 160.0 * pow(2,-13) * AC2;
99 x2 = pow(160,2) * pow(2,-25) * VB2;
100 y0 = c4 * pow(2,15);
101 y1 = c4 * c3;
102 y2 = c4 * b1;
103 p0 = (3791.0 - 8.0) / 1600.0;
104 p1 = 1.0 - 7357.0 * pow(2,-20);
105 p2 = 3038.0 * 100.0 * pow(2,-36);
106
107 /*
108 Serial.println();
109 Serial.print("c3: "); Serial.println(c3);
110 Serial.print("c4: "); Serial.println(c4);
111 Serial.print("c5: "); Serial.println(c5);
112 Serial.print("c6: "); Serial.println(c6);
113 Serial.print("b1: "); Serial.println(b1);
114 Serial.print("mc: "); Serial.println(mc);
115 Serial.print("md: "); Serial.println(md);
116 Serial.print("x0: "); Serial.println(x0);
117 Serial.print("x1: "); Serial.println(x1);
118 Serial.print("x2: "); Serial.println(x2);
119 Serial.print("y0: "); Serial.println(y0);
120 Serial.print("y1: "); Serial.println(y1);
121 Serial.print("y2: "); Serial.println(y2);
122 Serial.print("p0: "); Serial.println(p0);
123 Serial.print("p1: "); Serial.println(p1);
124 Serial.print("p2: "); Serial.println(p2);
125 */
126
127 // Success!
128 return(1);
129 }
130 else
131 {
132 // Error reading calibration data; bad component or connection?
133 return(1);
134 }
135}
136
137
138char SFE_BMP180::readInt(char address, int16_t &value)
139// Read a signed integer (two bytes) from device
140// address: register to start reading (plus subsequent register)
141// value: external variable to store data (function modifies value)
142{
143 unsigned char data[2];
144
145 data[0] = address;
146 if (readBytes(data,2))
147 {
148 value = (int16_t)((data[0]<<8)|data[1]);
149 //if (*value & 0x8000) *value |= 0xFFFF0000; // sign extend if negative
150 return(1);
151 }
152 value = 0;
153 return(0);
154}
155
156
157char SFE_BMP180::readUInt(char address, uint16_t &value)
158// Read an unsigned integer (two bytes) from device
159// address: register to start reading (plus subsequent register)
160// value: external variable to store data (function modifies value)
161{
162 unsigned char data[2];
163
164 data[0] = address;
165 if (readBytes(data,2))
166 {
167 value = (((uint16_t)data[0]<<8)|(uint16_t)data[1]);
168 return(1);
169 }
170 value = 0;
171 return(0);
172}
173
174
175char SFE_BMP180::readBytes(unsigned char *values, char length)
176// Read an array of bytes from device
177// values: external array to hold data. Put starting register in values[0].
178// length: number of bytes to read
179{
180 char x;
181
182 Wire.beginTransmission(BMP180_ADDR);
183 Wire.write(values[0]);
184 _error = Wire.endTransmission();
185 if (_error == 0)
186 {
187 Wire.requestFrom(BMP180_ADDR,length);
188 while(Wire.available() != length) ; // wait until bytes are ready
189 for(x=0;x<length;x++)
190 {
191 values[x] = Wire.read();
192 }
193 return(1);
194 }
195 return(0);
196}
197
198
199char SFE_BMP180::writeBytes(unsigned char *values, char length)
200// Write an array of bytes to device
201// values: external array of data to write. Put starting register in values[0].
202// length: number of bytes to write
203{
204 char x;
205
206 Wire.beginTransmission(BMP180_ADDR);
207 Wire.write(values,length);
208 _error = Wire.endTransmission();
209 if (_error == 0)
210 return(1);
211 else
212 return(0);
213}
214
215
216char SFE_BMP180::startTemperature(void)
217// Begin a temperature reading.
218// Will return delay in ms to wait, or 0 if I2C error
219{
220 unsigned char data[2], result;
221
222 data[0] = BMP180_REG_CONTROL;
223 data[1] = BMP180_COMMAND_TEMPERATURE;
224 result = writeBytes(data, 2);
225 if (result) // good write?
226 return(5); // return the delay in ms (rounded up) to wait before retrieving data
227 else
228 return(0); // or return 0 if there was a problem communicating with the BMP
229}
230
231
232char SFE_BMP180::getTemperature(double &T)
233// Retrieve a previously-started temperature reading.
234// Requires begin() to be called once prior to retrieve calibration parameters.
235// Requires startTemperature() to have been called prior and sufficient time elapsed.
236// T: external variable to hold result.
237// Returns 1 if successful, 0 if I2C error.
238{
239 unsigned char data[2];
240 char result;
241 double tu, a;
242
243 data[0] = BMP180_REG_RESULT;
244
245 result = readBytes(data, 2);
246 if (result) // good read, calculate temperature
247 {
248 tu = (data[0] * 256.0) + data[1];
249
250 //example from Bosch datasheet
251 //tu = 27898;
252
253 //example from http://wmrx00.sourceforge.net/Arduino/BMP085-Calcs.pdf
254 //tu = 0x69EC;
255
256 a = c5 * (tu - c6);
257 T = a + (mc / (a + md));
258
259 /*
260 Serial.println();
261 Serial.print("tu: "); Serial.println(tu);
262 Serial.print("a: "); Serial.println(a);
263 Serial.print("T: "); Serial.println(*T);
264 */
265 }
266 return(result);
267}
268
269
270char SFE_BMP180::startPressure(char oversampling)
271// Begin a pressure reading.
272// Oversampling: 0 to 3, higher numbers are slower, higher-res outputs.
273// Will return delay in ms to wait, or 0 if I2C error.
274{
275 unsigned char data[2], result, delay;
276
277 data[0] = BMP180_REG_CONTROL;
278
279 switch (oversampling)
280 {
281 case 0:
282 data[1] = BMP180_COMMAND_PRESSURE0;
283 delay = 5;
284 break;
285 case 1:
286 data[1] = BMP180_COMMAND_PRESSURE1;
287 delay = 8;
288 break;
289 case 2:
290 data[1] = BMP180_COMMAND_PRESSURE2;
291 delay = 14;
292 break;
293 case 3:
294 data[1] = BMP180_COMMAND_PRESSURE3;
295 delay = 26;
296 break;
297 default:
298 data[1] = BMP180_COMMAND_PRESSURE0;
299 delay = 5;
300 break;
301 }
302 result = writeBytes(data, 2);
303 if (result) // good write?
304 return(delay); // return the delay in ms (rounded up) to wait before retrieving data
305 else
306 return(0); // or return 0 if there was a problem communicating with the BMP
307}
308
309
310char SFE_BMP180::getPressure(double &P, double &T)
311// Retrieve a previously started pressure reading, calculate abolute pressure in mbars.
312// Requires begin() to be called once prior to retrieve calibration parameters.
313// Requires startPressure() to have been called prior and sufficient time elapsed.
314// Requires recent temperature reading to accurately calculate pressure.
315
316// P: external variable to hold pressure.
317// T: previously-calculated temperature.
318// Returns 1 for success, 0 for I2C error.
319
320// Note that calculated pressure value is absolute mbars, to compensate for altitude call sealevel().
321{
322 unsigned char data[3];
323 char result;
324 double pu,s,x,y,z;
325
326 data[0] = BMP180_REG_RESULT;
327
328 result = readBytes(data, 3);
329 if (result) // good read, calculate pressure
330 {
331 pu = (data[0] * 256.0) + data[1] + (data[2]/256.0);
332
333 //example from Bosch datasheet
334 //pu = 23843;
335
336 //example from http://wmrx00.sourceforge.net/Arduino/BMP085-Calcs.pdf, pu = 0x982FC0;
337 //pu = (0x98 * 256.0) + 0x2F + (0xC0/256.0);
338
339 s = T - 25.0;
340 x = (x2 * pow(s,2)) + (x1 * s) + x0;
341 y = (y2 * pow(s,2)) + (y1 * s) + y0;
342 z = (pu - x) / y;
343 P = (p2 * pow(z,2)) + (p1 * z) + p0;
344
345 /*
346 Serial.println();
347 Serial.print("pu: "); Serial.println(pu);
348 Serial.print("T: "); Serial.println(*T);
349 Serial.print("s: "); Serial.println(s);
350 Serial.print("x: "); Serial.println(x);
351 Serial.print("y: "); Serial.println(y);
352 Serial.print("z: "); Serial.println(z);
353 Serial.print("P: "); Serial.println(*P);
354 */
355 }
356 return(result);
357}
358
359
360double SFE_BMP180::sealevel(double P, double A)
361// Given a pressure P (mb) taken at a specific altitude (meters),
362// return the equivalent pressure (mb) at sea level.
363// This produces pressure readings that can be used for weather measurements.
364{
365 return(P/pow(1-(A/44330.0),5.255));
366}
367
368
369double SFE_BMP180::altitude(double P, double P0)
370// Given a pressure measurement P (mb) and the pressure at a baseline P0 (mb),
371// return altitude (meters) above baseline.
372{
373 return(44330.0*(1-pow(P/P0,1/5.255)));
374}
375
376
377char SFE_BMP180::getError(void)
378 // If any library command fails, you can retrieve an extended
379 // error code using this command. Errors are from the wire library:
380 // 0 = Success
381 // 1 = Data too long to fit in transmit buffer
382 // 2 = Received NACK on transmit of address
383 // 3 = Received NACK on transmit of data
384 // 4 = Other error
385{
386 return(_error);
387}
388