Adafruit_BMP183.cpp 9.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401
  1. /*!
  2. * @file Adafruit_BMP183.cpp
  3. *
  4. * @mainpage Adafruit BMP183 Library
  5. *
  6. * @section intro_sec Introduction
  7. *
  8. * This is a library for the Adafruit BMP183 Barometric Pressure + Temp sensor
  9. *
  10. * Designed specifically to work with the Adafruit BMP183 Breakout
  11. * ----> http://www.adafruit.com/products/1900
  12. *
  13. * These sensors use SPI to communicate, 4 pins are required to
  14. * interface
  15. * Adafruit invests time and resources providing this open source code,
  16. * please support Adafruit and open-source hardware by purchasing
  17. * products from Adafruit!
  18. *
  19. * @section author Author
  20. *
  21. * Written by Limor Fried/Ladyada for Adafruit Industries.
  22. *
  23. * @section license License
  24. *
  25. * BSD license, all text above must be included in any redistribution
  26. */
  27. #include "Adafruit_BMP183.h"
  28. #ifdef __AVR__
  29. #include <util/delay.h>
  30. #endif
  31. #define _delay_ms(t) \
  32. delay(t) //!< Delay for use in-between different lines/parts of code
  33. #include <SPI.h>
  34. /*!
  35. * @brief Instantiates a new Adafruit_BMP183 class using hardware SPI
  36. * @param SPICS
  37. * cs pin
  38. * @param *theSPI
  39. * optional SPI object, defaults to SPI
  40. */
  41. Adafruit_BMP183::Adafruit_BMP183(int8_t SPICS, SPIClass *theSPI) {
  42. _cs = SPICS;
  43. _clk = _miso = _mosi = -1;
  44. _spi = theSPI;
  45. }
  46. /*!
  47. * @brief Instantiates a new Adafruit_BMP183 class using software SPI
  48. * @param SPICLK
  49. * SPI chip clock
  50. * @param SPIMISO
  51. * SPI MISO (Data to microcontroller from sensor)
  52. * @param SPIMOSI
  53. * SPI MOSI (Data from microcontroller to sensor)
  54. * @param SPICS
  55. * SPI CS PIN
  56. */
  57. Adafruit_BMP183::Adafruit_BMP183(int8_t SPICLK, int8_t SPIMISO, int8_t SPIMOSI,
  58. int8_t SPICS) {
  59. _cs = SPICS;
  60. _clk = SPICLK;
  61. _miso = SPIMISO;
  62. _mosi = SPIMOSI;
  63. }
  64. /*!
  65. * @brief Setups the HW
  66. * @param mode
  67. * selected BMP183 mode
  68. * @return true if successful
  69. */
  70. boolean Adafruit_BMP183::begin(bmp183_mode_t mode) {
  71. if (_clk == -1) {
  72. _spi->begin();
  73. _spi->setDataMode(SPI_MODE0);
  74. #ifdef __AVR__
  75. _spi->setClockDivider(SPI_CLOCK_DIV16);
  76. #endif
  77. #ifdef __SAM3X8E__
  78. _spi->setClockDivider(11); // 8-ish MHz (full! speed!)
  79. #endif
  80. } else {
  81. pinMode(_clk, OUTPUT);
  82. digitalWrite(_clk, HIGH);
  83. pinMode(_mosi, OUTPUT);
  84. digitalWrite(_mosi, HIGH);
  85. pinMode(_miso, INPUT);
  86. }
  87. pinMode(_cs, OUTPUT);
  88. digitalWrite(_cs, HIGH);
  89. /* Mode boundary check */
  90. if ((mode > BMP183_MODE_ULTRAHIGHRES) || (mode < 0)) {
  91. mode = BMP183_MODE_ULTRAHIGHRES;
  92. }
  93. /* Set the mode indicator */
  94. oversampling = mode;
  95. if (read8(0xD0) != 0x55)
  96. return false;
  97. /* Read calibration data */
  98. ac1 = read16(BMP183_REGISTER_CAL_AC1);
  99. ac2 = read16(BMP183_REGISTER_CAL_AC2);
  100. ac3 = read16(BMP183_REGISTER_CAL_AC3);
  101. ac4 = read16(BMP183_REGISTER_CAL_AC4);
  102. ac5 = read16(BMP183_REGISTER_CAL_AC5);
  103. ac6 = read16(BMP183_REGISTER_CAL_AC6);
  104. b1 = read16(BMP183_REGISTER_CAL_B1);
  105. b2 = read16(BMP183_REGISTER_CAL_B2);
  106. mb = read16(BMP183_REGISTER_CAL_MB);
  107. mc = read16(BMP183_REGISTER_CAL_MC);
  108. md = read16(BMP183_REGISTER_CAL_MD);
  109. #if (BMP183_DEBUG == 1)
  110. Serial.print("ac1 = ");
  111. Serial.println(ac1, DEC);
  112. Serial.print("ac2 = ");
  113. Serial.println(ac2, DEC);
  114. Serial.print("ac3 = ");
  115. Serial.println(ac3, DEC);
  116. Serial.print("ac4 = ");
  117. Serial.println(ac4, DEC);
  118. Serial.print("ac5 = ");
  119. Serial.println(ac5, DEC);
  120. Serial.print("ac6 = ");
  121. Serial.println(ac6, DEC);
  122. Serial.print("b1 = ");
  123. Serial.println(b1, DEC);
  124. Serial.print("b2 = ");
  125. Serial.println(b2, DEC);
  126. Serial.print("mb = ");
  127. Serial.println(mb, DEC);
  128. Serial.print("mc = ");
  129. Serial.println(mc, DEC);
  130. Serial.print("md = ");
  131. Serial.println(md, DEC);
  132. #endif
  133. return true;
  134. }
  135. /*!
  136. * @brief Reads raw temperature reading
  137. * @return Raw Temeperature from BMP183_REGISTER_TEMPDATA.
  138. */
  139. uint16_t Adafruit_BMP183::readRawTemperature() {
  140. write8(BMP183_REGISTER_CONTROL, BMP183_REGISTER_READTEMPCMD);
  141. _delay_ms(5);
  142. #if BMP183_DEBUG == 1
  143. Serial.print("Raw temp: ");
  144. Serial.println(read16(BMP183_REGISTER_TEMPDATA));
  145. #endif
  146. return read16(BMP183_REGISTER_TEMPDATA);
  147. }
  148. /*!
  149. * @brief Reads raw pressure reading
  150. * @return Raw Pressure from BMP183_REGISTER_PRESSUREDATA
  151. */
  152. uint32_t Adafruit_BMP183::readRawPressure() {
  153. uint32_t raw;
  154. write8(BMP183_REGISTER_CONTROL,
  155. BMP183_REGISTER_READPRESSURECMD + (oversampling << 6));
  156. if (oversampling == BMP183_MODE_ULTRALOWPOWER)
  157. _delay_ms(5);
  158. else if (oversampling == BMP183_MODE_STANDARD)
  159. _delay_ms(8);
  160. else if (oversampling == BMP183_MODE_HIGHRES)
  161. _delay_ms(14);
  162. else
  163. _delay_ms(26);
  164. raw = read16(BMP183_REGISTER_PRESSUREDATA);
  165. raw <<= 8;
  166. raw |= read8(BMP183_REGISTER_PRESSUREDATA + 2);
  167. raw >>= (8 - oversampling);
  168. /* this pull broke stuff, look at it later?
  169. if (oversampling==0) {
  170. raw <<= 8;
  171. raw |= read8(BMP183_PRESSUREDATA+2);
  172. raw >>= (8 - oversampling);
  173. }
  174. */
  175. #if BMP183_DEBUG == 1
  176. Serial.print("Raw pressure: ");
  177. Serial.println(raw);
  178. #endif
  179. return raw;
  180. }
  181. /*!
  182. * @brief Gets the compensated pressure level in hPa
  183. * @return Pressure value in hPa
  184. */
  185. int32_t Adafruit_BMP183::getPressure() {
  186. int32_t UT, UP, B3, B5, B6, X1, X2, X3, p;
  187. uint32_t B4, B7;
  188. UT = readRawTemperature();
  189. UP = readRawPressure();
  190. #if BMP183_DEBUG == 1
  191. // use datasheet numbers!
  192. UT = 27898;
  193. UP = 23843;
  194. ac6 = 23153;
  195. ac5 = 32757;
  196. mc = -8711;
  197. md = 2868;
  198. b1 = 6190;
  199. b2 = 4;
  200. ac3 = -14383;
  201. ac2 = -72;
  202. ac1 = 408;
  203. ac4 = 32741;
  204. oversampling = 0;
  205. #endif
  206. // do temperature calculations
  207. X1 = (UT - (int32_t)(ac6)) * ((int32_t)(ac5)) / pow(2, 15);
  208. X2 = ((int32_t)mc * pow(2, 11)) / (X1 + (int32_t)md);
  209. B5 = X1 + X2;
  210. #if BMP183_DEBUG == 1
  211. Serial.print("X1 = ");
  212. Serial.println(X1);
  213. Serial.print("X2 = ");
  214. Serial.println(X2);
  215. Serial.print("B5 = ");
  216. Serial.println(B5);
  217. #endif
  218. // do pressure calcs
  219. B6 = B5 - 4000;
  220. X1 = ((int32_t)b2 * ((B6 * B6) >> 12)) >> 11;
  221. X2 = ((int32_t)ac2 * B6) >> 11;
  222. X3 = X1 + X2;
  223. B3 = ((((int32_t)ac1 * 4 + X3) << oversampling) + 2) / 4;
  224. #if BMP183_DEBUG == 1
  225. Serial.print("B6 = ");
  226. Serial.println(B6);
  227. Serial.print("X1 = ");
  228. Serial.println(X1);
  229. Serial.print("X2 = ");
  230. Serial.println(X2);
  231. Serial.print("B3 = ");
  232. Serial.println(B3);
  233. #endif
  234. X1 = ((int32_t)ac3 * B6) >> 13;
  235. X2 = ((int32_t)b1 * ((B6 * B6) >> 12)) >> 16;
  236. X3 = ((X1 + X2) + 2) >> 2;
  237. B4 = ((uint32_t)ac4 * (uint32_t)(X3 + 32768)) >> 15;
  238. B7 = ((uint32_t)UP - B3) * (uint32_t)(50000UL >> oversampling);
  239. #if BMP183_DEBUG == 1
  240. Serial.print("X1 = ");
  241. Serial.println(X1);
  242. Serial.print("X2 = ");
  243. Serial.println(X2);
  244. Serial.print("B4 = ");
  245. Serial.println(B4);
  246. Serial.print("B7 = ");
  247. Serial.println(B7);
  248. #endif
  249. if (B7 < 0x80000000) {
  250. p = (B7 * 2) / B4;
  251. } else {
  252. p = (B7 / B4) * 2;
  253. }
  254. X1 = (p >> 8) * (p >> 8);
  255. X1 = (X1 * 3038) >> 16;
  256. X2 = (-7357 * p) >> 16;
  257. #if BMP183_DEBUG == 1
  258. Serial.print("p = ");
  259. Serial.println(p);
  260. Serial.print("X1 = ");
  261. Serial.println(X1);
  262. Serial.print("X2 = ");
  263. Serial.println(X2);
  264. #endif
  265. p = p + ((X1 + X2 + (int32_t)3791) >> 4);
  266. #if BMP183_DEBUG == 1
  267. Serial.print("p = ");
  268. Serial.println(p);
  269. #endif
  270. return p;
  271. }
  272. /*!
  273. * @brief Reads the temperatures in Celsius degrees
  274. * @return temperature in Celsius
  275. */
  276. float Adafruit_BMP183::getTemperature() {
  277. int32_t UT, X1, X2, B5; // following ds convention
  278. float temp;
  279. UT = readRawTemperature();
  280. #if BMP183_DEBUG == 1
  281. // use datasheet numbers!
  282. UT = 27898;
  283. ac6 = 23153;
  284. ac5 = 32757;
  285. mc = -8711;
  286. md = 2868;
  287. #endif
  288. // step 1
  289. X1 = (UT - (int32_t)ac6) * ((int32_t)ac5) / pow(2, 15);
  290. X2 = ((int32_t)mc * pow(2, 11)) / (X1 + (int32_t)md);
  291. B5 = X1 + X2;
  292. temp = (B5 + 8) / pow(2, 4);
  293. temp /= 10;
  294. return temp;
  295. }
  296. /*!
  297. * @brief Reads the altitude based on provided sea level pressure
  298. * @param sealevelPressure
  299. * pressure in hPa
  300. * @return altitude value in meters
  301. */
  302. float Adafruit_BMP183::getAltitude(float sealevelPressure) {
  303. float altitude;
  304. float pressure = getPressure(); // in Si units for Pascal
  305. pressure /= 100;
  306. altitude = 44330 * (1.0 - pow(pressure / sealevelPressure, 0.1903));
  307. return altitude;
  308. }
  309. /*********************************************************************/
  310. uint8_t Adafruit_BMP183::SPIxfer(uint8_t x) {
  311. if (_clk == -1) {
  312. return _spi->transfer(x);
  313. } else {
  314. // Serial.println("Software SPI");
  315. uint8_t reply = 0;
  316. for (int i = 7; i >= 0; i--) {
  317. reply <<= 1;
  318. digitalWrite(_clk, LOW);
  319. digitalWrite(_mosi, x & (1 << i));
  320. digitalWrite(_clk, HIGH);
  321. if (digitalRead(_miso))
  322. reply |= 1;
  323. }
  324. return reply;
  325. }
  326. }
  327. uint8_t Adafruit_BMP183::read8(uint8_t reg) {
  328. uint8_t value;
  329. digitalWrite(_cs, LOW);
  330. SPIxfer(0x80 | reg);
  331. value = SPIxfer(0x00);
  332. digitalWrite(_cs, HIGH);
  333. return value;
  334. }
  335. uint16_t Adafruit_BMP183::read16(uint8_t reg) {
  336. uint16_t value;
  337. digitalWrite(_cs, LOW);
  338. SPIxfer(0x80 | reg);
  339. value = SPIxfer(0x00);
  340. value <<= 8;
  341. value |= SPIxfer(0x00);
  342. digitalWrite(_cs, HIGH);
  343. return value;
  344. }
  345. void Adafruit_BMP183::write8(uint8_t reg, uint8_t value) {
  346. digitalWrite(_cs, LOW);
  347. SPIxfer(reg & 0x7F);
  348. SPIxfer(value);
  349. digitalWrite(_cs, HIGH);
  350. }