1////////////////////////////////////////////////////////////////////////////////
2// //
3// This software is supplied under the terms of a license agreement or //
4// nondisclosure agreement with Mitov Software and may not be copied //
5// or disclosed except in accordance with the terms of that agreement. //
6// Copyright(c) 2002-2016 Mitov Software. All Rights Reserved. //
7// //
8////////////////////////////////////////////////////////////////////////////////
9
10#ifndef _MITOV_BMP180_h
11#define _MITOV_BMP180_h
12
13#include <Mitov.h>
14#include <Wire.h> //I2C Arduino Library
15
16namespace Mitov
17{
18
19 const byte BMP180_Address = 0x77; // 7-bit address
20 const byte BMP180_REG_CONTROL = 0xF4;
21 const byte BMP180_REG_RESULT = 0xF6;
22
23 const byte BMP180_COMMAND_TEMPERATURE = 0x2E;
24 const byte BMP180_COMMAND_PRESSURE0 = 0x34;
25 const byte BMP180_COMMAND_PRESSURE1 = 0x74;
26 const byte BMP180_COMMAND_PRESSURE2 = 0xB4;
27 const byte BMP180_COMMAND_PRESSURE3 = 0xF4;
28//---------------------------------------------------------------------------
29 enum BMP180_PressureResolution { prLow, prStandard, prHigh, prHighest };
30//---------------------------------------------------------------------------
31 class BMP180_Pressure : public EnabledComponent, public Mitov::ClockingSupport
32 {
33 typedef Mitov::EnabledComponent inherited;
34
35 public:
36 OpenWire::SourcePin PressureOutputPin;
37 OpenWire::SourcePin TemperatureOutputPin;
38 OpenWire::TypedSourcePin<bool> ErrorOutputPin;
39
40 protected:
41 enum TState { stCoeff, stIdle, stTemperature, stPressure };
42
43 public:
44 BMP180_PressureResolution Resolution : 2;
45 bool InFahrenheit : 1;
46
47 protected:
48 bool FClocked : 1;
49 TState FState : 2;
50
51 uint32_t FStartTime;
52 uint32_t FInterval;
53
54 int16_t AC1,AC2,AC3,VB1,VB2,MB,MC,MD;
55 uint16_t AC4,AC5,AC6;
56 double c5,c6,mc,md,x0,x1,x2,y0,y1,y2,p0,p1,p2;
57 float T;
58
59 protected:
60 bool WriteBytes( byte *values, char length )
61 {
62 Wire.beginTransmission( BMP180_Address );
63 Wire.write(values,length);
64 bool AError = ( Wire.endTransmission() != 0 );
65 ErrorOutputPin.SetValue( AError, true );
66
67 return ( ! AError );
68 }
69
70 bool ReadBytes( byte *values, byte length )
71 {
72 Wire.beginTransmission( BMP180_Address );
73 Wire.write(values[0]);
74 bool AError = ( Wire.endTransmission() != 0 );
75// Serial.println( AError );
76 ErrorOutputPin.SetValue( AError, true );
77 if ( ! AError )
78 {
79// Serial.println( "READ" );
80 Wire.requestFrom( BMP180_Address, length );
81 while(Wire.available() != length) ; // wait until bytes are ready
82
83 while( length-- )
84 *values++ = Wire.read();
85
86/*
87 values += length;
88 while( length-- )
89 *--values = Wire.read();
90*/
91 }
92
93 return ( ! AError );
94 }
95
96 uint32_t ReadBytes( byte length )
97 {
98/*
99 union T24BitData
100 {
101 uint8_t Bytes[ 4 ];
102 uint32_t Value;
103 };
104
105 T24BitData AData;
106 AData.Value = 0;
107
108 ReadBytes( AData.Bytes + 3 - length, length );
109
110 return AData.Value;
111*/
112 uint8_t ABytes[ 4 ];
113 ABytes[0] = BMP180_REG_RESULT;
114
115 ReadBytes( ABytes, length );
116
117 uint32_t AValue = 0;
118 for( int i = 0; i < length; ++i )
119 {
120 AValue <<= 8;
121 AValue |= ABytes[ i ];
122 }
123
124 return AValue;
125 }
126
127 void StartReading( byte AType, TState AState, uint32_t AInterval )
128 {
129 byte data[ 2 ] =
130 {
131 BMP180_REG_CONTROL
132 };
133
134 data[ 1 ] = AType;
135
136// Serial.println( "StartReading" );
137 if( WriteBytes(data, 2))
138 {
139// Serial.println( "STATE" );
140
141 FState = AState;
142 FInterval = AInterval;
143 FStartTime = millis();
144 }
145 }
146
147 bool ReadUnsignedInt(char address, uint16_t &value)
148 {
149 unsigned char data[2];
150
151 data[0] = address;
152 if (ReadBytes(data,2))
153 {
154 value = (((uint16_t)data[0]<<8)|(uint16_t)data[1]);
155 return( true );
156 }
157
158 value = 0;
159 return( false );
160 }
161
162 bool ReadInt(char address, int16_t &value)
163 {
164 return ReadUnsignedInt( address, *(uint16_t *)&value );
165 }
166
167 void StartReadingTemp()
168 {
169 if( FState == stCoeff )
170 {
171// Serial.println( "TEST0" );
172 if( !
173 (
174 ReadInt(0xAA,AC1) &&
175 ReadInt(0xAC,AC2) &&
176 ReadInt(0xAE,AC3) &&
177 ReadUnsignedInt(0xB0,AC4) &&
178 ReadUnsignedInt(0xB2,AC5) &&
179 ReadUnsignedInt(0xB4,AC6) &&
180 ReadInt(0xB6,VB1) &&
181 ReadInt(0xB8,VB2) &&
182 ReadInt(0xBA,MB) &&
183 ReadInt(0xBC,MC) &&
184 ReadInt(0xBE,MD)
185 )
186 )
187 return;
188
189 // All reads completed successfully!
190
191 // If you need to check your math using known numbers,
192 // you can uncomment one of these examples.
193 // (The correct results are commented in the below functions.)
194
195 // Example from Bosch datasheet
196 // AC1 = 408; AC2 = -72; AC3 = -14383; AC4 = 32741; AC5 = 32757; AC6 = 23153;
197 // B1 = 6190; B2 = 4; MB = -32768; MC = -8711; MD = 2868;
198
199 // Example from http://wmrx00.sourceforge.net/Arduino/BMP180-Calcs.pdf
200 // AC1 = 7911; AC2 = -934; AC3 = -14306; AC4 = 31567; AC5 = 25671; AC6 = 18974;
201 // VB1 = 5498; VB2 = 46; MB = -32768; MC = -11075; MD = 2432;
202
203 // Compute floating-point polynominals:
204
205 double c3 = 160.0 * pow(2,-15) * AC3;
206 double c4 = pow(10,-3) * pow(2,-15) * AC4;
207 double b1 = pow(160,2) * pow(2,-30) * VB1;
208 c5 = (pow(2,-15) / 160) * AC5;
209 c6 = AC6;
210 mc = (pow(2,11) / pow(160,2)) * MC;
211 md = MD / 160.0;
212 x0 = AC1;
213 x1 = 160.0 * pow(2,-13) * AC2;
214 x2 = pow(160,2) * pow(2,-25) * VB2;
215 y0 = c4 * pow(2,15);
216 y1 = c4 * c3;
217 y2 = c4 * b1;
218 p0 = (3791.0 - 8.0) / 1600.0;
219 p1 = 1.0 - 7357.0 * pow(2,-20);
220 p2 = 3038.0 * 100.0 * pow(2,-36);
221
222// Serial.println( "TEST1" );
223 FState = stIdle;
224 }
225
226 StartReading( BMP180_COMMAND_TEMPERATURE, stTemperature, 5 );
227 }
228
229 void StartReadingPressure()
230 {
231 switch( Resolution )
232 {
233 case prLow: StartReading( BMP180_COMMAND_PRESSURE0, stPressure, 5 ); break;
234 case prStandard: StartReading( BMP180_COMMAND_PRESSURE1, stPressure, 8 ); break;
235 case prHigh: StartReading( BMP180_COMMAND_PRESSURE2, stPressure, 14 ); break;
236 case prHighest: StartReading( BMP180_COMMAND_PRESSURE3, stPressure, 26 ); break;
237 }
238 }
239
240 bool IsIdle() { return (( FState == stCoeff ) || ( FState == stIdle )); }
241
242 protected:
243 virtual void DoClockReceive( void *_Data ) override
244 {
245 if( IsIdle() )
246 StartReadingTemp();
247
248 else
249 FClocked = true;
250 }
251
252 protected:
253 virtual void SystemStart()
254 {
255 if( Enabled )
256 if( ! ClockInputPin.IsConnected() )
257 StartReadingTemp();
258
259 inherited::SystemStart();
260 }
261
262 virtual void SystemLoopBegin( unsigned long currentMicros )
263 {
264 if( ! Enabled )
265 {
266 if( ! IsIdle() )
267 if( FState == stTemperature )
268 ReadBytes( 2 );
269
270 else
271 ReadBytes( 3 );
272
273 FState = stIdle;
274 }
275
276 else
277 {
278 if( IsIdle() )
279 {
280 if( FClocked || ( ! ClockInputPin.IsConnected() ))
281 StartReadingTemp();
282 }
283
284 else
285 {
286 unsigned long ACurrentMillis = millis();
287// Serial.println( "TEST2" );
288 if( ACurrentMillis - FStartTime >= FInterval )
289 if( FState == stTemperature )
290 {
291 float tu = ReadBytes( 2 );
292// Serial.print( "T1: " ); Serial.println( tu );
293 //example from Bosch datasheet
294 //tu = 27898;
295
296 //example from http://wmrx00.sourceforge.net/Arduino/BMP085-Calcs.pdf
297 //tu = 0x69EC;
298
299 float a = c5 * (tu - c6);
300 T = a + (mc / (a + md));
301
302 if( InFahrenheit )
303 T = T * ( 9.0/5.0 ) + 32.0;
304
305 TemperatureOutputPin.Notify( &T );
306 StartReadingPressure();
307 }
308
309 else
310 {
311 float pu = ReadBytes( 3 );
312// Serial.print( "P1: " ); Serial.println( pu );
313 pu /= 256.0;
314// pu = (data[0] * 256.0) + data[1] + (data[2]/256.0);
315
316 //example from Bosch datasheet
317 //pu = 23843;
318
319 //example from http://wmrx00.sourceforge.net/Arduino/BMP085-Calcs.pdf, pu = 0x982FC0;
320 //pu = (0x98 * 256.0) + 0x2F + (0xC0/256.0);
321
322 float s = T - 25.0;
323 float x = (x2 * pow(s,2)) + (x1 * s) + x0;
324 float y = (y2 * pow(s,2)) + (y1 * s) + y0;
325 float z = (pu - x) / y;
326 float P = (p2 * pow(z,2)) + (p1 * z) + p0;
327
328 PressureOutputPin.Notify( &P );
329
330// Serial.println( "VVVVVV" );
331 if( ClockInputPin.IsConnected() )
332 {
333// Serial.println( "PPPPP" );
334 FState = stIdle;
335 if( FClocked )
336 {
337// Serial.println( "TTTTTTT" );
338 FClocked = false;
339 StartReadingTemp();
340 }
341 }
342
343 else
344 StartReadingTemp();
345 }
346
347 }
348 }
349
350/*
351 if( ! Enabled )
352 if( FClocked || ( ! ClockInputPin.IsConnected() ))
353 ReadCompass();
354*/
355 inherited::SystemLoopBegin( currentMicros );
356 }
357
358 public:
359 BMP180_Pressure() :
360 FClocked( false ),
361 Resolution( prStandard ),
362 FState( stCoeff ),
363 InFahrenheit( false )
364 {
365 }
366 };
367}
368
369#endif