bmp180.c 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237
  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. #include <unistd.h>
  31. #include <stdint.h>
  32. #include <stdio.h>
  33. #include <math.h>
  34. #include "wiringPi.h"
  35. #include "wiringPiI2C.h"
  36. #include "bmp180.h"
  37. #undef DEBUG
  38. #define I2C_ADDRESS 0x77
  39. #define BMP180_OSS 0
  40. // Static calibration data
  41. // The down-side of this is that there can only be one BMP180 in
  42. // a system - which is practice isn't an issue as it's I2C
  43. // address is fixed.
  44. static int16_t AC1, AC2, AC3 ;
  45. static uint16_t AC4, AC5, AC6 ;
  46. static int16_t VB1, VB2 ;
  47. static int16_t MB, MC, MD ;
  48. static double c5, c6, mc, md, x0, x1, x2, yy0, yy1, yy2, p0, p1, p2 ;
  49. // Pressure & Temp variables
  50. uint32_t cPress, cTemp ;
  51. static int altitude ;
  52. /*
  53. * read16:
  54. * Quick hack to read the 16-bit data with the correct endian
  55. *********************************************************************************
  56. */
  57. uint16_t read16 (int fd, int reg)
  58. {
  59. return (wiringPiI2CReadReg8 (fd, reg) << 8) | wiringPiI2CReadReg8 (fd, reg + 1) ;
  60. }
  61. /*
  62. * bmp180ReadTempPress:
  63. * Does the hard work of reading the sensor
  64. *********************************************************************************
  65. */
  66. static void bmp180ReadTempPress (int fd)
  67. {
  68. double fTemp, fPress ;
  69. double tu, a ;
  70. double pu, s, x, y, z ;
  71. uint8_t data [4] ;
  72. // Start a temperature sensor reading
  73. wiringPiI2CWriteReg8 (fd, 0xF4, 0x2E) ;
  74. delay (5) ;
  75. // Read the raw data
  76. data [0] = wiringPiI2CReadReg8 (fd, 0xF6) ;
  77. data [1] = wiringPiI2CReadReg8 (fd, 0xF7) ;
  78. // And calculate...
  79. tu = (data [0] * 256.0) + data [1] ;
  80. a = c5 * (tu - c6) ;
  81. fTemp = a + (mc / (a + md)) ;
  82. cTemp = (int)rint (((100.0 * fTemp) + 0.5) / 10.0) ;
  83. #ifdef DEBUG
  84. printf ("fTemp: %f, cTemp: %6d\n", fTemp, cTemp) ;
  85. #endif
  86. // Start a pressure snsor reading
  87. wiringPiI2CWriteReg8 (fd, 0xF4, 0x34 | (BMP180_OSS << 6)) ;
  88. delay (5) ;
  89. // Read the raw data
  90. data [0] = wiringPiI2CReadReg8 (fd, 0xF6) ;
  91. data [1] = wiringPiI2CReadReg8 (fd, 0xF7) ;
  92. data [2] = wiringPiI2CReadReg8 (fd, 0xF8) ;
  93. // And calculate...
  94. pu = ((double)data [0] * 256.0) + (double)data [1] + ((double)data [2] / 256.0) ;
  95. s = fTemp - 25.0 ;
  96. x = (x2 * pow (s, 2.0)) + (x1 * s) + x0 ;
  97. y = (yy2 * pow (s, 2.0)) + (yy1 * s) + yy0 ;
  98. z = (pu - x) / y ;
  99. fPress = (p2 * pow (z, 2.0)) + (p1 * z) + p0 ;
  100. cPress = (int)rint (((100.0 * fPress) + 0.5) / 10.0) ;
  101. #ifdef DEBUG
  102. printf ("fPress: %f, cPress: %6d\n", fPress, cPress) ;
  103. #endif
  104. }
  105. /*
  106. * myAnalogWrite:
  107. * Write to a fake register to represent the height above sea level
  108. * so that the peudo millibar register can read the pressure in mB
  109. *********************************************************************************
  110. */
  111. static void myAnalogWrite (struct wiringPiNodeStruct *node, int pin, int value)
  112. {
  113. int chan = pin - node->pinBase ;
  114. if (chan == 0)
  115. altitude = value ;
  116. }
  117. /*
  118. * myAnalogRead:
  119. *********************************************************************************
  120. */
  121. static int myAnalogRead (struct wiringPiNodeStruct *node, int pin)
  122. {
  123. int chan = pin - node->pinBase ;
  124. bmp180ReadTempPress (node->fd) ;
  125. /**/ if (chan == 0) // Read Temperature
  126. return cTemp ;
  127. else if (chan == 1) // Pressure
  128. return cPress ;
  129. else if (chan == 2) // Pressure in mB
  130. return cPress / pow (1 - ((double)altitude / 44330.0), 5.255) ;
  131. else
  132. return -9999 ;
  133. }
  134. /*
  135. * bmp180Setup:
  136. * Create a new instance of a PCF8591 I2C GPIO interface. We know it
  137. * has 4 pins, (4 analog inputs and 1 analog output which we'll shadow
  138. * input 0) so all we need to know here is the I2C address and the
  139. * user-defined pin base.
  140. *********************************************************************************
  141. */
  142. int bmp180Setup (const int pinBase)
  143. {
  144. double c3, c4, b1 ;
  145. int fd ;
  146. struct wiringPiNodeStruct *node ;
  147. if ((fd = wiringPiI2CSetup (I2C_ADDRESS)) < 0)
  148. return FALSE ;
  149. node = wiringPiNewNode (pinBase, 4) ;
  150. node->fd = fd ;
  151. node->analogRead = myAnalogRead ;
  152. node->analogWrite = myAnalogWrite ;
  153. // Read calibration data
  154. AC1 = read16 (fd, 0xAA) ;
  155. AC2 = read16 (fd, 0xAC) ;
  156. AC3 = read16 (fd, 0xAE) ;
  157. AC4 = read16 (fd, 0xB0) ;
  158. AC5 = read16 (fd, 0xB2) ;
  159. AC6 = read16 (fd, 0xB4) ;
  160. VB1 = read16 (fd, 0xB6) ;
  161. VB2 = read16 (fd, 0xB8) ;
  162. MB = read16 (fd, 0xBA) ;
  163. MC = read16 (fd, 0xBC) ;
  164. MD = read16 (fd, 0xBE) ;
  165. // Calculate coefficients
  166. c3 = 160.0 * pow (2.0, -15.0) * AC3 ;
  167. c4 = pow (10.0, -3.0) * pow(2.0,-15.0) * AC4 ;
  168. b1 = pow (160.0, 2.0) * pow(2.0,-30.0) * VB1 ;
  169. c5 = (pow (2.0, -15.0) / 160.0) * AC5 ;
  170. c6 = AC6 ;
  171. mc = (pow (2.0, 11.0) / pow(160.0,2.0)) * MC ;
  172. md = MD / 160.0 ;
  173. x0 = AC1 ;
  174. x1 = 160.0 * pow (2.0, -13.0) * AC2 ;
  175. x2 = pow (160.0, 2.0) * pow(2.0,-25.0) * VB2 ;
  176. yy0 = c4 * pow (2.0, 15.0) ;
  177. yy1 = c4 * c3 ;
  178. yy2 = c4 * b1 ;
  179. p0 = (3791.0 - 8.0) / 1600.0 ;
  180. p1 = 1.0 - 7357.0 * pow (2.0, -20.0) ;
  181. p2 = 3038.0 * 100.0 * pow (2.0, -36.0) ;
  182. return TRUE ;
  183. }