BMP280_DEV.cpp 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306
  1. /*
  2. BMP280_DEV is an I2C/SPI compatible library for the Bosch BMP280 barometer.
  3. Copyright (C) Martin Lindupp 2019
  4. V1.0.0 -- Initial release
  5. V1.0.1 -- Added ESP32 HSPI support and change library to unique name
  6. V1.0.2 -- Modification to allow external creation of HSPI object on ESP32
  7. V1.0.3 -- Changed library name in the library.properties file
  8. V1.0.5 -- Fixed bug in BMP280_DEV::getTemperature() function, thanks to Jon M.
  9. V1.0.6 -- Merged multiple instances and initialisation pull requests by sensslen
  10. V1.0.8 -- Used default arguments for begin() member function and
  11. added example using multiple BMP280 devices with SPI comms in NORMAL mode
  12. V1.0.9 -- Moved writeMask to Device class and improved measurement detection code
  13. V1.0.10 -- Modification to allow user-defined pins for I2C operation on the ESP8266
  14. V1.0.12 -- Allow sea level pressure calibration using setSeaLevelPressure() function
  15. V1.0.14 -- Fix uninitialised structures, thanks to David Jade investigating and
  16. flagging up this issue
  17. V1.0.16 -- Modification to allow user-defined pins for I2C operation on the ESP32
  18. V1.0.17 -- Added getCurrentTemperature(), getCurrentPressure(), getCurrentTempPres()
  19. getCurrentAltitude() and getCurrentMeasurements() functions,
  20. to allow the BMP280 to be read directly without checking the measuring bit
  21. V1.0.18 -- Initialise "device" constructor member variables in the same order they are declared
  22. The MIT License (MIT)
  23. Permission is hereby granted, free of charge, to any person obtaining a copy
  24. of this software and associated documentation files (the "Software"), to deal
  25. in the Software without restriction, including without limitation the rights
  26. to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  27. copies of the Software, and to permit persons to whom the Software is
  28. furnished to do so, subject to the following conditions:
  29. The above copyright notice and this permission notice shall be included in all
  30. copies or substantial portions of the Software.
  31. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  32. IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  33. FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  34. AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  35. LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  36. OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  37. SOFTWARE.
  38. */
  39. #include <BMP280_DEV.h>
  40. ////////////////////////////////////////////////////////////////////////////////
  41. // BMP280_DEV Class Constructors
  42. ////////////////////////////////////////////////////////////////////////////////
  43. BMP280_DEV::BMP280_DEV() { setI2CAddress(BMP280_I2C_ADDR); } // Constructor for I2C communications
  44. #ifdef ARDUINO_ARCH_ESP8266
  45. BMP280_DEV::BMP280_DEV(uint8_t sda, uint8_t scl) : Device(sda, scl) { setI2CAddress(BMP280_I2C_ADDR); } // Constructor for I2C comms on ESP8266
  46. #endif
  47. BMP280_DEV::BMP280_DEV(uint8_t cs) : Device(cs) {} // Constructor for SPI communications
  48. #ifdef ARDUINO_ARCH_ESP32
  49. BMP280_DEV::BMP280_DEV(uint8_t sda, uint8_t scl) : Device(sda, scl) { setI2CAddress(BMP280_I2C_ADDR); } // Constructor for I2C comms on ESP32
  50. BMP280_DEV::BMP280_DEV(uint8_t cs, uint8_t spiPort, SPIClass& spiClass) : Device(cs, spiPort, spiClass) {} // Constructor for SPI communications on the ESP32
  51. #endif
  52. ////////////////////////////////////////////////////////////////////////////////
  53. // BMP280_DEV Public Member Functions
  54. ////////////////////////////////////////////////////////////////////////////////
  55. uint8_t BMP280_DEV::begin(Mode mode, // Initialise BMP280 device settings
  56. Oversampling presOversampling,
  57. Oversampling tempOversampling,
  58. IIRFilter iirFilter,
  59. TimeStandby timeStandby)
  60. {
  61. initialise(); // Call the Device base class "initialise" function
  62. if (readByte(BMP280_DEVICE_ID) != DEVICE_ID) // Check the device ID
  63. {
  64. return 0; // If the ID is incorrect return 0
  65. }
  66. reset(); // Reset the BMP280 barometer
  67. readBytes(BMP280_TRIM_PARAMS, (uint8_t*)&params, sizeof(params)); // Read the trim parameters into the params structure
  68. setConfigRegister(iirFilter, timeStandby); // Initialise the BMP280 configuration register
  69. setCtrlMeasRegister(mode, presOversampling, tempOversampling); // Initialise the BMP280 control and measurement register
  70. return 1; // Report successful initialisation
  71. }
  72. uint8_t BMP280_DEV::begin(Mode mode, uint8_t addr) // Initialise BMP280 with default settings, but selected mode and
  73. { // I2C address
  74. setI2CAddress(addr);
  75. return begin(mode);
  76. }
  77. uint8_t BMP280_DEV::begin(uint8_t addr) // Initialise BMP280 with default settings and selected I2C address
  78. {
  79. setI2CAddress(addr);
  80. return begin();
  81. }
  82. void BMP280_DEV::reset() // Reset the BMP280 barometer
  83. {
  84. writeByte(BMP280_RESET, RESET_CODE);
  85. delay(10);
  86. }
  87. void BMP280_DEV::startNormalConversion() { setMode(NORMAL_MODE); } // Start continuous measurement in NORMAL_MODE
  88. void BMP280_DEV::startForcedConversion() // Start a one shot measurement in FORCED_MODE
  89. {
  90. ctrl_meas.reg = readByte(BMP280_CTRL_MEAS); // Read the control and measurement register
  91. if (ctrl_meas.bit.mode == SLEEP_MODE) // Only set FORCED_MODE if we're already in SLEEP_MODE
  92. {
  93. setMode(FORCED_MODE);
  94. }
  95. }
  96. void BMP280_DEV::stopConversion() { setMode(SLEEP_MODE); } // Stop the conversion and return to SLEEP_MODE
  97. void BMP280_DEV::setPresOversampling(Oversampling presOversampling) // Set the pressure oversampling rate
  98. {
  99. ctrl_meas.bit.osrs_p = presOversampling;
  100. writeByte(BMP280_CTRL_MEAS, ctrl_meas.reg);
  101. }
  102. void BMP280_DEV::setTempOversampling(Oversampling tempOversampling) // Set the temperature oversampling rate
  103. {
  104. ctrl_meas.bit.osrs_t = tempOversampling;
  105. writeByte(BMP280_CTRL_MEAS, ctrl_meas.reg);
  106. }
  107. void BMP280_DEV::setIIRFilter(IIRFilter iirFilter) // Set the IIR filter setting
  108. {
  109. config.bit.filter = iirFilter;
  110. writeByte(BMP280_CONFIG, config.reg);
  111. }
  112. void BMP280_DEV::setTimeStandby(TimeStandby timeStandby) // Set the time standby measurement interval
  113. {
  114. config.bit.t_sb = timeStandby;
  115. writeByte(BMP280_CONFIG, config.reg);
  116. }
  117. void BMP280_DEV::setSeaLevelPressure(float pressure) // Set the sea level pressure value
  118. {
  119. sea_level_pressure = pressure;
  120. }
  121. void BMP280_DEV::getCurrentTemperature(float &temperature) // Get the current temperature without checking the measuring bit
  122. {
  123. uint8_t data[3]; // Create a data buffer
  124. readBytes(BMP280_TEMP_MSB, &data[0], 3); // Read the temperature and pressure data
  125. int32_t adcTemp = (int32_t)data[0] << 12 | (int32_t)data[1] << 4 | (int32_t)data[2] >> 4; // Copy the temperature and pressure data into the adc variables
  126. int32_t temp = bmp280_compensate_T_int32(adcTemp); // Temperature compensation (function from BMP280 datasheet)
  127. temperature = (float)temp / 100.0f; // Calculate the temperature in degrees Celsius
  128. }
  129. uint8_t BMP280_DEV::getTemperature(float &temperature) // Get the temperature with measurement check
  130. {
  131. if (!dataReady()) // Check if a measurement is ready
  132. {
  133. return 0;
  134. }
  135. getCurrentTemperature(temperature); // Get the current temperature
  136. return 1;
  137. }
  138. void BMP280_DEV::getCurrentPressure(float &pressure) // Get the current pressure without checking the measuring bit
  139. {
  140. float temperature;
  141. getCurrentTempPres(temperature, pressure);
  142. }
  143. uint8_t BMP280_DEV::getPressure(float &pressure) // Get the pressure
  144. {
  145. float temperature;
  146. return getTempPres(temperature, pressure);
  147. }
  148. void BMP280_DEV::getCurrentTempPres(float &temperature, float &pressure) // Get the current temperature and pressure without checking the measuring bit
  149. {
  150. uint8_t data[6]; // Create a data buffer
  151. readBytes(BMP280_PRES_MSB, &data[0], 6); // Read the temperature and pressure data
  152. int32_t adcTemp = (int32_t)data[3] << 12 | (int32_t)data[4] << 4 | (int32_t)data[5] >> 4; // Copy the temperature and pressure data into the adc variables
  153. int32_t adcPres = (int32_t)data[0] << 12 | (int32_t)data[1] << 4 | (int32_t)data[2] >> 4;
  154. int32_t temp = bmp280_compensate_T_int32(adcTemp); // Temperature compensation (function from BMP280 datasheet)
  155. uint32_t pres = bmp280_compensate_P_int64(adcPres); // Pressure compensation (function from BMP280 datasheet)
  156. temperature = (float)temp / 100.0f; // Calculate the temperature in degrees Celsius
  157. pressure = (float)pres / 256.0f / 100.0f; // Calculate the pressure in millibar
  158. }
  159. uint8_t BMP280_DEV::getTempPres(float &temperature, float &pressure) // Get the temperature and pressure
  160. {
  161. if (!dataReady()) // Check if a measurement is ready
  162. {
  163. return 0;
  164. }
  165. getCurrentTempPres(temperature, pressure); // Get the current temperature and pressure
  166. return 1;
  167. }
  168. void BMP280_DEV::getCurrentAltitude(float &altitude) // Get the current altitude without checking the measuring bit
  169. {
  170. float temperature, pressure;
  171. getCurrentMeasurements(temperature, pressure, altitude);
  172. }
  173. uint8_t BMP280_DEV::getAltitude(float &altitude) // Get the altitude
  174. {
  175. float temperature, pressure;
  176. return getMeasurements(temperature, pressure, altitude);
  177. }
  178. void BMP280_DEV::getCurrentMeasurements(float &temperature, float &pressure, float &altitude) // Get all the measurements without checking the measuring bit
  179. {
  180. getCurrentTempPres(temperature, pressure);
  181. altitude = ((float)powf(sea_level_pressure / pressure, 0.190223f) - 1.0f) * (temperature + 273.15f) / 0.0065f; // Calculate the altitude in metres
  182. }
  183. uint8_t BMP280_DEV::getMeasurements(float &temperature, float &pressure, float &altitude) // Get all measurements temperature, pressue and altitude
  184. {
  185. if (getTempPres(temperature, pressure))
  186. {
  187. altitude = ((float)powf(sea_level_pressure / pressure, 0.190223f) - 1.0f) * (temperature + 273.15f) / 0.0065f; // Calculate the altitude in metres
  188. return 1;
  189. }
  190. return 0;
  191. }
  192. ////////////////////////////////////////////////////////////////////////////////
  193. // BMP280_DEV Private Member Functions
  194. ////////////////////////////////////////////////////////////////////////////////
  195. void BMP280_DEV::setMode(Mode mode) // Set the BMP280's mode
  196. {
  197. ctrl_meas.bit.mode = mode;
  198. writeByte(BMP280_CTRL_MEAS, ctrl_meas.reg);
  199. }
  200. // Set the BMP280 control and measurement register
  201. void BMP280_DEV::setCtrlMeasRegister(Mode mode, Oversampling presOversampling, Oversampling tempOversampling)
  202. {
  203. ctrl_meas.reg = tempOversampling << 5 | presOversampling << 2 | mode;
  204. writeByte(BMP280_CTRL_MEAS, ctrl_meas.reg);
  205. }
  206. // Set the BMP280 configuration register
  207. void BMP280_DEV::setConfigRegister(IIRFilter iirFilter, TimeStandby timeStandby)
  208. {
  209. config.reg = timeStandby << 5 | iirFilter << 2;
  210. writeByte(BMP280_CONFIG, config.reg);
  211. }
  212. uint8_t BMP280_DEV::dataReady() // Check if a measurement is ready
  213. {
  214. if (ctrl_meas.bit.mode == SLEEP_MODE) // If we're in SLEEP_MODE return immediately
  215. {
  216. return 0;
  217. }
  218. status.reg = readByte(BMP280_STATUS); // Read the status register
  219. if (status.bit.measuring ^ previous_measuring) // Edge detection: check if the measurement bit has been changed
  220. {
  221. previous_measuring = status.bit.measuring; // Update the previous measuring flag
  222. if (!status.bit.measuring) // Check if the measuring bit has been cleared
  223. {
  224. if (ctrl_meas.bit.mode == FORCED_MODE) // If we're in FORCED_MODE switch back to SLEEP_MODE
  225. {
  226. ctrl_meas.bit.mode = SLEEP_MODE;
  227. }
  228. return 1; // A measurement is ready
  229. }
  230. }
  231. return 0; // A measurement is still pending
  232. }
  233. ////////////////////////////////////////////////////////////////////////////////
  234. // Bosch BMP280_DEV (Private) Member Functions
  235. ////////////////////////////////////////////////////////////////////////////////
  236. // Returns temperature in DegC, resolution is 0.01 DegC. Output value of “5123” equals 51.23 DegC.
  237. // t_fine carries fine temperature as global value
  238. int32_t BMP280_DEV::bmp280_compensate_T_int32(int32_t adc_T)
  239. {
  240. int32_t var1, var2, T;
  241. var1 = ((((adc_T >> 3) - ((int32_t)params.dig_T1 << 1))) * ((int32_t)params.dig_T2)) >> 11;
  242. var2 = (((((adc_T >> 4) - ((int32_t)params.dig_T1)) * ((adc_T >> 4) - ((int32_t)params.dig_T1))) >> 12) *
  243. ((int32_t)params.dig_T3)) >> 14;
  244. t_fine = var1 + var2;
  245. T = (t_fine * 5 + 128) >> 8;
  246. return T;
  247. }
  248. // Returns pressure in Pa as unsigned 32 bit integer in Q24.8 format (24 integer bits and 8 fractional bits).
  249. // Output value of “24674867” represents 24674867/256 = 96386.2 Pa = 963.862 hPa
  250. uint32_t BMP280_DEV::bmp280_compensate_P_int64(int32_t adc_P)
  251. {
  252. int64_t var1, var2, p;
  253. var1 = ((int64_t)t_fine) - 128000;
  254. var2 = var1 * var1 * (int64_t)params.dig_P6;
  255. var2 = var2 + ((var1 * (int64_t)params.dig_P5) << 17);
  256. var2 = var2 + (((int64_t)params.dig_P4) << 35);
  257. var1 = ((var1 * var1 * (int64_t)params.dig_P3) >> 8) + ((var1 * (int64_t)params.dig_P2) << 12);
  258. var1 = (((((int64_t)1) << 47) + var1)) * ((int64_t)params.dig_P1) >> 33;
  259. if (var1 == 0)
  260. {
  261. return 0; // avoid exception caused by division by zero
  262. }
  263. p = 1048576 - adc_P;
  264. p = (((p << 31) - var2) * 3125) / var1;
  265. var1 = (((int64_t)params.dig_P9) * (p >> 13) * (p>>13)) >> 25;
  266. var2 = (((int64_t)params.dig_P8) * p) >> 19;
  267. p = ((p + var1 + var2) >> 8) + (((int64_t)params.dig_P7) << 4);
  268. return (uint32_t)p;
  269. }