Adafruit_BMP183_U.cpp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444
  1. /*!
  2. * @file Adafruit_BMP183_U.cpp
  3. *
  4. * @mainpage Adafruit BMP183 Unified
  5. *
  6. * @section intro_sec Introduction
  7. *
  8. * This is a library for the BMP183 orientation sensor
  9. *
  10. * Designed specifically to work with the Adafruit BMP183 055 Breakout.
  11. *
  12. * Pick one up today in the adafruit shop!
  13. * ------> https://www.adafruit.com/product/1900
  14. *
  15. * These sensors use SPI to communicate, 4 pins are required to interface.
  16. *
  17. * Adafruit invests time and resources providing this open source code,
  18. * please support Adafruit andopen-source hardware by purchasing products
  19. * from Adafruit!
  20. *
  21. * @section author Author
  22. *
  23. * K.Townsend (Adafruit Industries)
  24. *
  25. * @section license License
  26. *
  27. * MIT license, all text above must be included in any redistribution
  28. */
  29. #include "Arduino.h"
  30. #include "SPI.h"
  31. #include <limits.h>
  32. #include <math.h>
  33. #include "Adafruit_BMP183_U.h"
  34. #define BMP183_USE_DATASHEET_VALS (0) /**< Set to 1 for sanity check **/
  35. /** SPI object **/
  36. SPIClass *_spi;
  37. /*!
  38. * @brief Instantiates a new Adafruit_BMP183_Unified class using hardware SPI
  39. * @param SPICS
  40. * cs pin
  41. * @param sensorID
  42. * id helpful to identify sensor
  43. * @param *theSPI
  44. * optional SPI object
  45. */
  46. Adafruit_BMP183_Unified::Adafruit_BMP183_Unified(int8_t SPICS, int32_t sensorID,
  47. SPIClass *theSPI) {
  48. _cs = SPICS;
  49. _clk = _miso = _mosi = -1;
  50. _sensorID = sensorID;
  51. _spi = theSPI;
  52. }
  53. /*!
  54. * @brief Instantiates a new Adafruit_BMP183_Unified class using hardware SPI
  55. * @param SPICLK
  56. * SPI chip clock
  57. * @param SPIMISO
  58. * SPI MISO (Data to microcontroller from sensor)
  59. * @param SPIMOSI
  60. * SPI MOSI (Data from microcontroller to sensor)
  61. * @param SPICS
  62. * SPI CS PIN
  63. * @param sensorID
  64. * id helpful to identify sensor
  65. */
  66. Adafruit_BMP183_Unified::Adafruit_BMP183_Unified(int8_t SPICLK, int8_t SPIMISO,
  67. int8_t SPIMOSI, int8_t SPICS,
  68. int32_t sensorID) {
  69. _cs = SPICS;
  70. _clk = SPICLK;
  71. _miso = SPIMISO;
  72. _mosi = SPIMOSI;
  73. _sensorID = sensorID;
  74. }
  75. /***************************************************************************
  76. PRIVATE FUNCTIONS
  77. ***************************************************************************/
  78. uint8_t Adafruit_BMP183_Unified::SPIxfer(uint8_t x) {
  79. if (_clk == -1) {
  80. return _spi->transfer(x);
  81. } else {
  82. // Serial.println("Software SPI");
  83. uint8_t reply = 0;
  84. for (int i = 7; i >= 0; i--) {
  85. reply <<= 1;
  86. digitalWrite(_clk, LOW);
  87. digitalWrite(_mosi, x & (1 << i));
  88. digitalWrite(_clk, HIGH);
  89. if (digitalRead(_miso))
  90. reply |= 1;
  91. }
  92. return reply;
  93. }
  94. }
  95. /*!
  96. * @brief Writes an 8 bit value over SPI
  97. */
  98. void Adafruit_BMP183_Unified::writeCommand(byte reg, byte value) {
  99. digitalWrite(_cs, LOW);
  100. SPIxfer(reg & 0x7F);
  101. SPIxfer(value);
  102. digitalWrite(_cs, HIGH);
  103. }
  104. /*!
  105. * @brief Reads an 8 bit value over I2C
  106. */
  107. uint8_t Adafruit_BMP183_Unified::read8(byte reg) {
  108. uint8_t value;
  109. digitalWrite(_cs, LOW);
  110. SPIxfer(0x80 | reg);
  111. value = SPIxfer(0x00);
  112. digitalWrite(_cs, HIGH);
  113. return value;
  114. }
  115. /*!
  116. * @brief Reads a 16 bit value over I2C
  117. */
  118. uint16_t Adafruit_BMP183_Unified::read16(byte reg) {
  119. uint16_t value;
  120. digitalWrite(_cs, LOW);
  121. SPIxfer(0x80 | reg);
  122. value = SPIxfer(0x00);
  123. value <<= 8;
  124. value |= SPIxfer(0x00);
  125. digitalWrite(_cs, HIGH);
  126. return value;
  127. }
  128. /*!
  129. * @brief Reads a signed 16 bit value over I2C
  130. */
  131. int16_t Adafruit_BMP183_Unified::readS16(byte reg) {
  132. return (int16_t)read16(reg);
  133. }
  134. /*!
  135. * @brief Reads the factory-set coefficients
  136. */
  137. void Adafruit_BMP183_Unified::readCoefficients(void) {
  138. #if BMP183_USE_DATASHEET_VALS
  139. _bmp183_coeffs.ac1 = 408;
  140. _bmp183_coeffs.ac2 = -72;
  141. _bmp183_coeffs.ac3 = -14383;
  142. _bmp183_coeffs.ac4 = 32741;
  143. _bmp183_coeffs.ac5 = 32757;
  144. _bmp183_coeffs.ac6 = 23153;
  145. _bmp183_coeffs.b1 = 6190;
  146. _bmp183_coeffs.b2 = 4;
  147. _bmp183_coeffs.mb = -32768;
  148. _bmp183_coeffs.mc = -8711;
  149. _bmp183_coeffs.md = 2868;
  150. _bmp183Mode = 0;
  151. #else
  152. _bmp183_coeffs.ac1 = readS16(BMP183_REGISTER_CAL_AC1);
  153. _bmp183_coeffs.ac2 = readS16(BMP183_REGISTER_CAL_AC2);
  154. _bmp183_coeffs.ac3 = readS16(BMP183_REGISTER_CAL_AC3);
  155. _bmp183_coeffs.ac4 = read16(BMP183_REGISTER_CAL_AC4);
  156. _bmp183_coeffs.ac5 = read16(BMP183_REGISTER_CAL_AC5);
  157. _bmp183_coeffs.ac6 = read16(BMP183_REGISTER_CAL_AC6);
  158. _bmp183_coeffs.b1 = readS16(BMP183_REGISTER_CAL_B1);
  159. _bmp183_coeffs.b2 = readS16(BMP183_REGISTER_CAL_B2);
  160. _bmp183_coeffs.mb = readS16(BMP183_REGISTER_CAL_MB);
  161. _bmp183_coeffs.mc = readS16(BMP183_REGISTER_CAL_MC);
  162. _bmp183_coeffs.md = readS16(BMP183_REGISTER_CAL_MD);
  163. #endif
  164. }
  165. int16_t Adafruit_BMP183_Unified::readRawTemperature() {
  166. #if BMP183_USE_DATASHEET_VALS
  167. return 27898;
  168. #else
  169. writeCommand(BMP183_REGISTER_CONTROL, BMP183_REGISTER_READTEMPCMD);
  170. delay(5);
  171. return read16(BMP183_REGISTER_TEMPDATA);
  172. #endif
  173. }
  174. int32_t Adafruit_BMP183_Unified::readRawPressure() {
  175. #if BMP183_USE_DATASHEET_VALS
  176. *pressure = 23843;
  177. #else
  178. uint8_t p8;
  179. uint16_t p16;
  180. int32_t p32;
  181. writeCommand(BMP183_REGISTER_CONTROL,
  182. BMP183_REGISTER_READPRESSURECMD + (_bmp183Mode << 6));
  183. switch (_bmp183Mode) {
  184. case BMP183_MODE_ULTRALOWPOWER:
  185. delay(5);
  186. break;
  187. case BMP183_MODE_STANDARD:
  188. delay(8);
  189. break;
  190. case BMP183_MODE_HIGHRES:
  191. delay(14);
  192. break;
  193. case BMP183_MODE_ULTRAHIGHRES:
  194. default:
  195. delay(26);
  196. break;
  197. }
  198. p16 = read16(BMP183_REGISTER_PRESSUREDATA);
  199. p32 = (uint32_t)p16 << 8;
  200. p8 = read8(BMP183_REGISTER_PRESSUREDATA + 2);
  201. p32 += p8;
  202. p32 >>= (8 - _bmp183Mode);
  203. return p32;
  204. #endif
  205. }
  206. /*!
  207. * @brief Setups the HW
  208. * @param mode
  209. * selected bmp183 mode
  210. * @return true if successful
  211. */
  212. bool Adafruit_BMP183_Unified::begin(bmp183_mode_t mode) {
  213. // Enable SPI
  214. if (_clk == -1) {
  215. _spi->begin();
  216. _spi->beginTransaction(SPISettings(500000, MSBFIRST, SPI_MODE0));
  217. } else {
  218. pinMode(_clk, OUTPUT);
  219. digitalWrite(_clk, HIGH);
  220. pinMode(_mosi, OUTPUT);
  221. digitalWrite(_mosi, HIGH);
  222. pinMode(_miso, INPUT);
  223. }
  224. pinMode(_cs, OUTPUT);
  225. digitalWrite(_cs, HIGH);
  226. /* Mode boundary check */
  227. if ((mode > BMP183_MODE_ULTRAHIGHRES) || (mode < 0)) {
  228. mode = BMP183_MODE_ULTRAHIGHRES;
  229. }
  230. /* Make sure we have the right device */
  231. uint8_t id;
  232. id = read8(BMP183_REGISTER_CHIPID);
  233. if (id != 0x55) {
  234. return false;
  235. }
  236. /* Set the mode indicator */
  237. _bmp183Mode = mode;
  238. /* Coefficients need to be read once */
  239. readCoefficients();
  240. getPressure();
  241. return true;
  242. }
  243. /*!
  244. * @brief Gets the compensated pressure level in kPa
  245. * @return pressure value in hPa
  246. */
  247. float Adafruit_BMP183_Unified::getPressure() {
  248. int32_t ut = 0, up = 0, compp = 0;
  249. int32_t x1, x2, b5, b6, x3, b3, p;
  250. uint32_t b4, b7;
  251. /* Get the raw pressure and temperature values */
  252. ut = readRawTemperature();
  253. up = readRawPressure();
  254. /* Temperature compensation */
  255. x1 = (ut - (int32_t)(_bmp183_coeffs.ac6)) * ((int32_t)(_bmp183_coeffs.ac5)) /
  256. pow(2, 15);
  257. x2 = ((int32_t)(_bmp183_coeffs.mc * pow(2, 11))) /
  258. (x1 + (int32_t)(_bmp183_coeffs.md));
  259. b5 = x1 + x2;
  260. /* Pressure compensation */
  261. b6 = b5 - 4000;
  262. x1 = (_bmp183_coeffs.b2 * ((b6 * b6) >> 12)) >> 11;
  263. x2 = (_bmp183_coeffs.ac2 * b6) >> 11;
  264. x3 = x1 + x2;
  265. b3 = (((((int32_t)_bmp183_coeffs.ac1) * 4 + x3) << _bmp183Mode) + 2) >> 2;
  266. x1 = (_bmp183_coeffs.ac3 * b6) >> 13;
  267. x2 = (_bmp183_coeffs.b1 * ((b6 * b6) >> 12)) >> 16;
  268. x3 = ((x1 + x2) + 2) >> 2;
  269. b4 = (_bmp183_coeffs.ac4 * (uint32_t)(x3 + 32768)) >> 15;
  270. b7 = ((uint32_t)(up - b3) * (50000 >> _bmp183Mode));
  271. if (b7 < 0x80000000) {
  272. p = (b7 << 1) / b4;
  273. } else {
  274. p = (b7 / b4) << 1;
  275. }
  276. x1 = (p >> 8) * (p >> 8);
  277. x1 = (x1 * 3038) >> 16;
  278. x2 = (-7357 * p) >> 16;
  279. compp = p + ((x1 + x2 + 3791) >> 4);
  280. /* Assign compensated pressure value */
  281. return compp;
  282. }
  283. /*!
  284. * @brief Reads the temperatures in degrees Celsius
  285. * @return temperature in Celsius
  286. */
  287. float Adafruit_BMP183_Unified::getTemperature() {
  288. int32_t UT, X1, X2, B5; // following ds convention
  289. float t;
  290. UT = readRawTemperature();
  291. #if BMP183_USE_DATASHEET_VALS
  292. // use datasheet numbers!
  293. UT = 27898;
  294. _bmp183_coeffs.ac6 = 23153;
  295. _bmp183_coeffs.ac5 = 32757;
  296. _bmp183_coeffs.mc = -8711;
  297. _bmp183_coeffs.md = 2868;
  298. #endif
  299. // step 1
  300. X1 = (UT - (int32_t)_bmp183_coeffs.ac6) * ((int32_t)_bmp183_coeffs.ac5) /
  301. pow(2, 15);
  302. X2 = ((int32_t)_bmp183_coeffs.mc * pow(2, 11)) /
  303. (X1 + (int32_t)_bmp183_coeffs.md);
  304. B5 = X1 + X2;
  305. t = (B5 + 8) / pow(2, 4);
  306. t /= 10;
  307. return t;
  308. }
  309. /*!
  310. * @brief Calculates the altitude (in meters) from the specified atmospheric
  311. * pressure (in hPa), sea-level pressure (in hPa), and temperature (in
  312. * �C)
  313. * @param seaLevel Sea-level pressure in hPa
  314. * @param atmospheric Atmospheric pressure in hPa
  315. * @param temp Temperature in degrees Celsius
  316. * @return Altitude value in meters
  317. */
  318. float Adafruit_BMP183_Unified::pressureToAltitude(float seaLevel,
  319. float atmospheric,
  320. float temp) {
  321. /* Hyposometric formula: */
  322. /* */
  323. /* ((P0/P)^(1/5.257) - 1) * (T + 273.15) */
  324. /* h = ------------------------------------- */
  325. /* 0.0065 */
  326. /* */
  327. /* where: h = height (in meters) */
  328. /* P0 = sea-level pressure (in hPa) */
  329. /* P = atmospheric pressure (in hPa) */
  330. /* T = temperature (in �C) */
  331. return (((float)pow((seaLevel / atmospheric), 0.190223F) - 1.0F) *
  332. (temp + 273.15F)) /
  333. 0.0065F;
  334. }
  335. /*!
  336. * @brief Calculates the Sea-level pressure (in hPa) from the specified
  337. * atmospheric pressure (in hPa), sea-level pressure (in hPa), and temperature
  338. * (in �C)
  339. * @param altitude Altitude in meters
  340. * @param atmospheric Atmospheric pressure in hPa
  341. * @param temp Temperature in degrees Celsius
  342. * @return Sea Level pressure (hPa)
  343. */
  344. float Adafruit_BMP183_Unified::seaLevelForAltitude(float altitude,
  345. float atmospheric,
  346. float temp) {
  347. /* Hyposometric formula: */
  348. /* */
  349. /* P0=((((h*0.0065)/(temp + 273.15F))+1)^(^/0.190223F))*P */
  350. /* */
  351. /* where: h = height (in meters) */
  352. /* P0 = sea-level pressure (in hPa) */
  353. /* P = atmospheric pressure (in hPa) */
  354. /* T = temperature (in �C) */
  355. return (float)pow((((altitude * 0.0065) / (temp + 273.15F)) + 1),
  356. (1.0 / 0.190223F)) *
  357. atmospheric;
  358. }
  359. /*!
  360. * @brief Provides the sensor_t data for this sensor
  361. */
  362. void Adafruit_BMP183_Unified::getSensor(sensor_t *sensor) {
  363. /* Clear the sensor_t object */
  364. memset(sensor, 0, sizeof(sensor_t));
  365. /* Insert the sensor name in the fixed length char array */
  366. strncpy(sensor->name, "BMP183", sizeof(sensor->name) - 1);
  367. sensor->name[sizeof(sensor->name) - 1] = 0;
  368. sensor->version = 1;
  369. sensor->sensor_id = _sensorID;
  370. sensor->type = SENSOR_TYPE_PRESSURE;
  371. sensor->min_delay = 0;
  372. sensor->max_value = 1100.0F; // 300..1100 hPa
  373. sensor->min_value = 300.0F;
  374. sensor->resolution = 0.01F; // Datasheet states 0.01 hPa resolution
  375. }
  376. /*!
  377. * @brief Reads the sensor and returns the data as a sensors_event_t
  378. * @param event
  379. * sensors_event_t event that you want to assign to
  380. * @return true if successful
  381. */
  382. bool Adafruit_BMP183_Unified::getEvent(sensors_event_t *event) {
  383. /* Clear the event */
  384. memset(event, 0, sizeof(sensors_event_t));
  385. event->version = sizeof(sensors_event_t);
  386. event->sensor_id = _sensorID;
  387. event->type = SENSOR_TYPE_PRESSURE;
  388. event->timestamp = 0;
  389. event->pressure = getPressure() / 100.0F;
  390. return true;
  391. }