Statistics
| Branch: | Revision:

ddr4s / fw / wiringPi / wiringPi / bmp180.c @ 32:cadb9025f1e0

History | View | Annotate | Download (6 KB)

1
/*
2
 * bmp180.c:
3
 *        Extend wiringPi with the BMP180 I2C Pressure and Temperature
4
 *        sensor. This is used in the Pi Weather Station
5
 *        Copyright (c) 2016 Gordon Henderson
6
 *
7
 *        Information from the document held at:
8
 *                http://wmrx00.sourceforge.net/Arduino/BMP085-Calcs.pdf
9
 *        was very useful when building this code.
10
 *
11
 ***********************************************************************
12
 * This file is part of wiringPi:
13
 *        https://projects.drogon.net/raspberry-pi/wiringpi/
14
 *
15
 *    wiringPi is free software: you can redistribute it and/or modify
16
 *    it under the terms of the GNU Lesser General Public License as
17
 *    published by the Free Software Foundation, either version 3 of the
18
 *    License, or (at your option) any later version.
19
 *
20
 *    wiringPi is distributed in the hope that it will be useful,
21
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
22
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
23
 *    GNU Lesser General Public License for more details.
24
 *
25
 *    You should have received a copy of the GNU Lesser General Public
26
 *    License along with wiringPi.
27
 *    If not, see <http://www.gnu.org/licenses/>.
28
 ***********************************************************************
29
 */
30

    
31
#include <unistd.h>
32
#include <stdint.h>
33
#include <stdio.h>
34
#include <math.h>
35

    
36
#include "wiringPi.h"
37
#include "wiringPiI2C.h"
38

    
39
#include "bmp180.h"
40

    
41
#undef        DEBUG
42

    
43
#define        I2C_ADDRESS        0x77
44
#define        BMP180_OSS           0
45

    
46

    
47
// Static calibration data
48
//        The down-side of this is that there can only be one BMP180 in
49
//        a system - which is practice isn't an issue as it's I2C
50
//        address is fixed.
51

    
52
static  int16_t AC1, AC2, AC3 ;
53
static uint16_t AC4, AC5, AC6 ;
54
static  int16_t VB1, VB2 ;
55
static  int16_t  MB,  MC, MD ;
56

    
57
static double c5, c6, mc, md, x0, x1, x2, yy0, yy1, yy2, p0, p1, p2 ;
58

    
59
// Pressure & Temp variables
60

    
61
uint32_t cPress, cTemp ;
62

    
63
static int altitude ;
64

    
65
/*
66
 * read16:
67
 *        Quick hack to read the 16-bit data with the correct endian
68
 *********************************************************************************
69
 */
70

    
71
uint16_t read16 (int fd, int reg)
72
{
73
  return (wiringPiI2CReadReg8 (fd, reg) <<  8) | wiringPiI2CReadReg8 (fd, reg + 1) ;
74

    
75
}
76

    
77

    
78
/*
79
 * bmp180ReadTempPress:
80
 *        Does the hard work of reading the sensor
81
 *********************************************************************************
82
 */
83

    
84
static void bmp180ReadTempPress (int fd)
85
{
86
  double fTemp, fPress ;
87
  double tu, a ;
88
  double pu, s, x, y, z ;
89

    
90
  uint8_t data [4] ;
91

    
92
// Start a temperature sensor reading
93

    
94
  wiringPiI2CWriteReg8 (fd, 0xF4, 0x2E) ;
95
  delay (5) ;
96

    
97
// Read the raw data
98

    
99
  data [0] = wiringPiI2CReadReg8 (fd, 0xF6) ;
100
  data [1] = wiringPiI2CReadReg8 (fd, 0xF7) ;
101

    
102
// And calculate...
103

    
104
  tu = (data [0] * 256.0) + data [1] ;
105

    
106
  a = c5 * (tu - c6) ;
107
  fTemp = a + (mc / (a + md)) ;
108
  cTemp = (int)rint (((100.0 * fTemp) + 0.5) / 10.0) ;
109

    
110
#ifdef        DEBUG
111
  printf ("fTemp: %f, cTemp: %6d\n", fTemp, cTemp) ;
112
#endif
113

    
114
// Start a pressure snsor reading
115

    
116
  wiringPiI2CWriteReg8 (fd, 0xF4, 0x34 | (BMP180_OSS << 6)) ;
117
  delay (5) ;
118

    
119
// Read the raw data
120

    
121
  data [0] = wiringPiI2CReadReg8 (fd, 0xF6) ;
122
  data [1] = wiringPiI2CReadReg8 (fd, 0xF7) ;
123
  data [2] = wiringPiI2CReadReg8 (fd, 0xF8) ;
124

    
125
// And calculate...
126

    
127
  pu = ((double)data [0] * 256.0) + (double)data [1] + ((double)data [2] / 256.0) ;
128
  s = fTemp - 25.0 ;
129
  x = (x2 * pow (s, 2.0)) + (x1 * s) + x0 ;
130
  y = (yy2 * pow (s, 2.0)) + (yy1 * s) + yy0 ;
131
  z = (pu - x) / y ;
132
  fPress = (p2 * pow (z, 2.0)) + (p1 * z) + p0 ;
133
  cPress = (int)rint (((100.0 * fPress) + 0.5) / 10.0) ;
134

    
135
#ifdef        DEBUG
136
  printf ("fPress: %f, cPress: %6d\n", fPress, cPress) ;
137
#endif
138
}
139

    
140

    
141
/*
142
 * myAnalogWrite:
143
 *        Write to a fake register to represent the height above sea level
144
 *        so that the peudo millibar register can read the pressure in mB
145
 *********************************************************************************
146
 */
147

    
148
static void myAnalogWrite (struct wiringPiNodeStruct *node, int pin, int value)
149
{
150
  int chan = pin - node->pinBase ;
151

    
152
  if (chan == 0)
153
    altitude = value ;
154
}
155

    
156
/*
157
 * myAnalogRead:
158
 *********************************************************************************
159
 */
160

    
161
static int myAnalogRead (struct wiringPiNodeStruct *node, int pin)
162
{
163
  int chan = pin - node->pinBase ;
164

    
165
  bmp180ReadTempPress (node->fd) ;
166

    
167
  /**/ if (chan == 0)        // Read Temperature
168
    return cTemp ;
169
  else if (chan == 1)        // Pressure
170
    return cPress ;
171
  else if (chan == 2)        // Pressure in mB
172
    return cPress / pow (1 - ((double)altitude / 44330.0), 5.255) ;
173
  else
174
    return -9999 ;
175

    
176
}
177

    
178

    
179
/*
180
 * bmp180Setup:
181
 *        Create a new instance of a PCF8591 I2C GPIO interface. We know it
182
 *        has 4 pins, (4 analog inputs and 1 analog output which we'll shadow
183
 *        input 0) so all we need to know here is the I2C address and the
184
 *        user-defined pin base.
185
 *********************************************************************************
186
 */
187

    
188
int bmp180Setup (const int pinBase)
189
{
190
  double c3, c4, b1 ;
191
  int fd ;
192
  struct wiringPiNodeStruct *node ;
193

    
194
  if ((fd = wiringPiI2CSetup (I2C_ADDRESS)) < 0)
195
    return FALSE ;
196

    
197
  node = wiringPiNewNode (pinBase, 4) ;
198

    
199
  node->fd          = fd ;
200
  node->analogRead  = myAnalogRead ;
201
  node->analogWrite = myAnalogWrite ;
202

    
203
// Read calibration data
204

    
205
  AC1 = read16 (fd, 0xAA) ;
206
  AC2 = read16 (fd, 0xAC) ;
207
  AC3 = read16 (fd, 0xAE) ;
208
  AC4 = read16 (fd, 0xB0) ;
209
  AC5 = read16 (fd, 0xB2) ;
210
  AC6 = read16 (fd, 0xB4) ;
211
  VB1 = read16 (fd, 0xB6) ;
212
  VB2 = read16 (fd, 0xB8) ;
213
   MB = read16 (fd, 0xBA) ;
214
   MC = read16 (fd, 0xBC) ;
215
   MD = read16 (fd, 0xBE) ;
216

    
217
// Calculate coefficients
218

    
219
  c3 = 160.0 * pow (2.0, -15.0) * AC3 ;
220
  c4 = pow (10.0, -3.0) * pow(2.0,-15.0) * AC4 ;
221
  b1 = pow (160.0, 2.0) * pow(2.0,-30.0) * VB1 ;
222
  c5 = (pow (2.0, -15.0) / 160.0) * AC5 ;
223
  c6 = AC6 ;
224
  mc = (pow (2.0, 11.0) / pow(160.0,2.0)) * MC ;
225
  md = MD / 160.0 ;
226
  x0 = AC1 ;
227
  x1 = 160.0 * pow (2.0, -13.0) * AC2 ;
228
  x2 = pow (160.0, 2.0) * pow(2.0,-25.0) * VB2 ;
229
  yy0 = c4 * pow (2.0, 15.0) ;
230
  yy1 = c4 * c3 ;
231
  yy2 = c4 * b1 ;
232
  p0 = (3791.0 - 8.0) / 1600.0 ;
233
  p1 = 1.0 - 7357.0 * pow (2.0, -20.0) ;
234
  p2 = 3038.0 * 100.0 * pow (2.0,  -36.0) ;
235

    
236
  return TRUE ;
237
}