BMP280_ATY.c 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483
  1. /**
  2. * @file BMP280_ATY.c
  3. *
  4. * @param Project DEVICE_GENERAL_ATY_LIB
  5. *
  6. * @author ATY
  7. *
  8. * @copyright
  9. * - Copyright 2017 - 2023 MZ-ATY
  10. * - This code follows:
  11. * - MZ-ATY Various Contents Joint Statement -
  12. * <a href="https://mengze.top/MZ-ATY_VCJS">
  13. * https://mengze.top/MZ-ATY_VCJS</a>
  14. * - CC 4.0 BY-NC-SA -
  15. * <a href="https://creativecommons.org/licenses/by-nc-sa/4.0/">
  16. * https://creativecommons.org/licenses/by-nc-sa/4.0/</a>
  17. * - Your use will be deemed to have accepted the terms of this statement.
  18. *
  19. * @brief Familiar functions of BMP280 for all embedded device
  20. *
  21. * @version
  22. * - 1_01_220804 > ATY
  23. * -# Preliminary version, first Release
  24. * - 1_02_231229 > ATY
  25. * -# add multy addr and channel
  26. ********************************************************************************
  27. */
  28. #ifndef __BMP280_ATY_C
  29. #define __BMP280_ATY_C
  30. #include "BMP280_ATY.h"
  31. /******************************* For user *************************************/
  32. /******************************************************************************/
  33. /**
  34. * @brief BMP280 read id
  35. * @param addr chip address
  36. * @param channel chip channel
  37. * @return id number like 0x58, 0x88
  38. */
  39. uint8_t BMP280_ReadId(uint8_t addr, uint8_t channel)
  40. {
  41. uint8_t temp_uint8;
  42. I2C_ReadReg(addr, BMP280_CHIPID_REG, &temp_uint8, 1, channel);
  43. return temp_uint8;
  44. }
  45. /**
  46. * @brief BMP280 get status
  47. * @param status_flag the bit to get
  48. * @param addr chip address
  49. * @param channel chip channel
  50. * @return 1 or 0 at bit status_flag
  51. */
  52. uint8_t BMP280_GetStatus(uint8_t status_flag, uint8_t addr, uint8_t channel)
  53. {
  54. uint8_t flag;
  55. I2C_ReadReg(addr, BMP280_STATUS_REG, &flag, 1, channel);
  56. // status_flag = BMP280_MEASURING || BMP280_IM_UPDATE
  57. // if(flag & status_flag) return 1;
  58. // else return 0;
  59. return flag & status_flag;
  60. }
  61. /**
  62. * @brief BMP280 set oversamp
  63. * @param config Oversample_Mode value
  64. * @param addr chip address
  65. * @param channel chip channel
  66. */
  67. void BMP280_SetOversamp(BMP280_OVERSAMPLE_MODE* config, uint8_t addr, uint8_t channel)
  68. {
  69. uint8_t temp_uint8;
  70. temp_uint8 = ((config->T_Osample) << 5) |
  71. ((config->P_Osample) << 2) |
  72. ((config)->WORKMODE);
  73. I2C_WriteReg(addr, BMP280_CTRLMEAS_REG, &temp_uint8, 1, channel);
  74. }
  75. /**
  76. * @brief BMP280 set standby filter
  77. * @param config bmp280 config
  78. * @param addr chip address
  79. * @param channel chip channel
  80. */
  81. void BMP280_SetStandbyFilter(BMP280_CONFIG* config, uint8_t addr, uint8_t channel)
  82. {
  83. uint8_t temp_uint8;
  84. temp_uint8 = ((config->T_SB) << 5) |
  85. ((config->FILTER_COEFFICIENT) << 2) |
  86. ((config->SPI_EN));
  87. I2C_WriteReg(addr, BMP280_CONFIG_REG, &temp_uint8, 1, channel);
  88. }
  89. BMP280_S32_t t_fine; // Use to calc compensation
  90. #ifdef BMP280_USE_FIXED_POINT_COMPENSATE
  91. /**
  92. * @brief BMP280 calculate temperature compensate for signed 32
  93. * @param adc_T temperature adc origin data
  94. * @return signed 32 value of temperature
  95. * @note Returns temperature in DegC, resolution is 0.01 DegC. Output value of "5123" equals 51.23 DegC.
  96. * t_fine carries fine temperature as global value
  97. */
  98. BMP280_S32_t BM280_CompensateT(BMP280_S32_t adc_T)
  99. {
  100. BMP280_S32_t var1, var2, T;
  101. var1 = ((((adc_T >> 3) - ((BMP280_S32_t)bmp280Cc.T1 << 1))) * ((BMP280_S32_t)bmp280Cc.T2)) >> 11;
  102. var2 = (((((adc_T >> 4) - ((BMP280_S32_t)bmp280Cc.T1)) * ((adc_T >> 4) - ((BMP280_S32_t)bmp280Cc.T1))) >> 12) *
  103. ((BMP280_S32_t)bmp280Cc.T3)) >> 14;
  104. t_fine = var1 + var2;
  105. T = (t_fine * 5 + 128) >> 8;
  106. return T;
  107. }
  108. /**
  109. * @brief BMP280 calculate pressure compensate for unsigned 32
  110. * @param adc_P pressure adc origin data
  111. * @return unsigned 32 value of pressure
  112. * @note Returns pressure in Pa as unsigned 32 bit integer in Q24.8 format (24 integer bits and 8 fractional bits).
  113. * Output value of "24674867" represents 24674867/256 = 96386.2 Pa = 963.862 hPa
  114. */
  115. BMP280_U32_t BM280_CompensateP(BMP280_S32_t adc_P)
  116. {
  117. BMP280_S64_t var1, var2, p;
  118. var1 = ((BMP280_S64_t)t_fine) - 128000;
  119. var2 = var1 * var1 * (BMP280_S64_t)bmp280Cc.P6;
  120. var2 = var2 + ((var1 * (BMP280_S64_t)bmp280Cc.P5) << 17);
  121. var2 = var2 + (((BMP280_S64_t)bmp280Cc.P4) << 35);
  122. var1 = ((var1 * var1 * (BMP280_S64_t)bmp280Cc.P3) >> 8) + ((var1 * (BMP280_S64_t)bmp280Cc.P2) << 12);
  123. var1 = (((((BMP280_S64_t)1) << 47) + var1)) * ((BMP280_S64_t)bmp280Cc.P1) >> 33;
  124. if(var1 == 0)
  125. {
  126. return 0; // avoid exception caused by division by zero
  127. }
  128. p = 1048576 - adc_P;
  129. p = (((p << 31) - var2) * 3125) / var1;
  130. var1 = (((BMP280_S64_t)bmp280Cc.P9) * (p >> 13) * (p >> 13)) >> 25;
  131. var2 = (((BMP280_S64_t)bmp280Cc.P8) * p) >> 19;
  132. p = ((p + var1 + var2) >> 8) + (((BMP280_S64_t)bmp280Cc.P7) << 4);
  133. return (BMP280_U32_t)p;
  134. }
  135. /**
  136. * @brief BMP280 get temperature
  137. * @param addr chip address
  138. * @param channel chip channel
  139. * @return temperature real value in int32
  140. */
  141. BMP280_S32_t BMP280_GetTemperature(uint8_t addr, uint8_t channel)
  142. {
  143. uint8_t xlsb, lsb, msb;
  144. long signed bit32;
  145. BMP280_S32_t temperature;
  146. I2C_ReadReg(addr, BMP280_TEMPERATURE_XLSB_REG, &xlsb, 1, channel);
  147. I2C_ReadReg(addr, BMP280_TEMPERATURE_LSB_REG, &lsb, 1, channel);
  148. I2C_ReadReg(addr, BMP280_TEMPERATURE_MSB_REG, &msb, 1, channel);
  149. // The value of a register forming a floating point number
  150. bit32 = ((long)(msb << 12)) | ((long)(lsb << 4)) | (xlsb >> 4);
  151. temperature = BM280_CompensateT(bit32);
  152. return temperature;
  153. }
  154. /**
  155. * @brief BMP280 get pressure
  156. * @param addr chip address
  157. * @param channel chip channel
  158. * @return pressure real value in uint32
  159. */
  160. BMP280_U32_t BMP280_GetPressure(uint8_t addr, uint8_t channel)
  161. {
  162. uint8_t xlsb, lsb, msb;
  163. long signed bit32;
  164. BMP280_U32_t pressure;
  165. I2C_ReadReg(addr, BMP280_PRESSURE_XLSB_REG, &xlsb, 1);
  166. I2C_ReadReg(addr, BMP280_PRESSURE_LSB_REG, &lsb, 1);
  167. I2C_ReadReg(addr, BMP280_PRESSURE_MSB_REG, &msb, 1);
  168. // The value of a register forming a floating point number
  169. bit32 = ((long)(msb << 12)) | ((long)(lsb << 4)) | (xlsb >> 4);
  170. pressure = BM280_CompensateP(bit32);
  171. return pressure;
  172. }
  173. #else
  174. /**
  175. * @brief BMP280 calculate temperature compensate for double
  176. * @param adc_T temperature adc origin data
  177. * @return double value of temperature
  178. * @note Returns temperature in DegC, double precision. Output value of "51.23" equals 51.23 DegC.
  179. * t_fine carries fine temperature as global value
  180. */
  181. double BM280_CompensateT(BMP280_S32_t adc_T)
  182. {
  183. double var1, var2, T;
  184. var1 = (((double)adc_T) / 16384.0 - ((double)bmp280Cc.T1) / 1024.0) * ((double)bmp280Cc.T2);
  185. var2 = ((((double)adc_T) / 131072.0 - ((double)bmp280Cc.T1) / 8192.0) *
  186. (((double)adc_T) / 131072.0 - ((double)bmp280Cc.T1) / 8192.0)) * ((double)bmp280Cc.T3);
  187. t_fine = (BMP280_S32_t)(var1 + var2);
  188. T = (var1 + var2) / 5120.0;
  189. return T;
  190. }
  191. /**
  192. * @brief BMP280 calculate pressure compensate for double
  193. * @param adc_P pressure adc origin data
  194. * @return double value of pressure
  195. * @note Returns pressure in Pa as double. Output value of "96386.2" equals 96386.2 Pa = 963.862 hPa
  196. */
  197. double BM280_CompensateP(BMP280_S32_t adc_P)
  198. {
  199. double var1, var2, p;
  200. var1 = ((double)t_fine / 2.0) - 64000.0;
  201. var2 = var1 * var1 * ((double)bmp280Cc.P6) / 32768.0;
  202. var2 = var2 + var1 * ((double)bmp280Cc.P5) * 2.0;
  203. var2 = (var2 / 4.0) + (((double)bmp280Cc.P4) * 65536.0);
  204. var1 = (((double)bmp280Cc.P3) * var1 * var1 / 524288.0 + ((double)bmp280Cc.P2) * var1) / 524288.0;
  205. var1 = (1.0 + var1 / 32768.0) * ((double)bmp280Cc.P1);
  206. if(var1 == 0.0)
  207. {
  208. return 0; // avoid exception caused by division by zero
  209. }
  210. p = 1048576.0 - (double)adc_P;
  211. p = (p - (var2 / 4096.0)) * 6250.0 / var1;
  212. var1 = ((double)bmp280Cc.P9) * p * p / 2147483648.0;
  213. var2 = p * ((double)bmp280Cc.P8) / 32768.0;
  214. p = p + (var1 + var2 + ((double)bmp280Cc.P7)) / 16.0;
  215. return p;
  216. }
  217. /**
  218. * @brief BMP280 get temperature
  219. * @param addr chip address
  220. * @param channel chip channel
  221. * @return temperature real value in double
  222. */
  223. double BMP280_GetTemperature(uint8_t addr, uint8_t channel)
  224. {
  225. uint8_t xlsb, lsb, msb;
  226. long signed bit32;
  227. double temperature;
  228. I2C_ReadReg(addr, BMP280_TEMPERATURE_XLSB_REG, &xlsb, 1, channel);
  229. I2C_ReadReg(addr, BMP280_TEMPERATURE_LSB_REG, &lsb, 1, channel);
  230. I2C_ReadReg(addr, BMP280_TEMPERATURE_MSB_REG, &msb, 1, channel);
  231. // The value of a register forming a floating point number
  232. bit32 = ((long)(msb << 12)) | ((long)(lsb << 4)) | (xlsb >> 4);
  233. temperature = BM280_CompensateT(bit32);
  234. return temperature;
  235. }
  236. /**
  237. * @brief BMP280 get pressure
  238. * @param addr chip address
  239. * @param channel chip channel
  240. * @return pressure real value in double
  241. */
  242. double BMP280_GetPressure(uint8_t addr, uint8_t channel)
  243. {
  244. uint8_t xlsb, lsb, msb;
  245. long signed bit32;
  246. double pressure;
  247. I2C_ReadReg(addr, BMP280_PRESSURE_XLSB_REG, &xlsb, 1, channel);
  248. I2C_ReadReg(addr, BMP280_PRESSURE_LSB_REG, &lsb, 1, channel);
  249. I2C_ReadReg(addr, BMP280_PRESSURE_MSB_REG, &msb, 1, channel);
  250. // The value of a register forming a floating point number
  251. bit32 = ((long)(msb << 12)) | ((long)(lsb << 4)) | (xlsb >> 4);
  252. pressure = BM280_CompensateP(bit32);
  253. return pressure;
  254. }
  255. #endif
  256. struct _BMP280_CC bmp280Cc = {0}; // Used to store the compensation parameters stored in the chip ROM
  257. /**
  258. * @brief BMP280 initialize
  259. * @param addr chip address
  260. * @param channel chip channel
  261. */
  262. void BM280_Init(uint8_t addr, uint8_t channel)
  263. {
  264. uint8_t lsb, msb;
  265. // Correction value of the temperature
  266. I2C_ReadReg(addr, BMP280_DIG_T1_LSB_REG, &lsb, 1, channel);
  267. I2C_ReadReg(addr, BMP280_DIG_T1_MSB_REG, &msb, 1, channel);
  268. bmp280Cc.T1 = (((uint16_t)msb) << 8) + lsb;
  269. I2C_ReadReg(addr, BMP280_DIG_T2_LSB_REG, &lsb, 1, channel);
  270. I2C_ReadReg(addr, BMP280_DIG_T2_MSB_REG, &msb, 1, channel);
  271. bmp280Cc.T2 = (((uint16_t)msb) << 8) + lsb;
  272. I2C_ReadReg(addr, BMP280_DIG_T3_LSB_REG, &lsb, 1, channel);
  273. I2C_ReadReg(addr, BMP280_DIG_T3_MSB_REG, &msb, 1, channel);
  274. bmp280Cc.T3 = (((uint16_t)msb) << 8) + lsb;
  275. // Correction value of the pressure
  276. I2C_ReadReg(addr, BMP280_DIG_P1_LSB_REG, &lsb, 1, channel);
  277. I2C_ReadReg(addr, BMP280_DIG_P1_MSB_REG, &msb, 1, channel);
  278. bmp280Cc.P1 = (((uint16_t)msb) << 8) + lsb;
  279. I2C_ReadReg(addr, BMP280_DIG_P2_LSB_REG, &lsb, 1, channel);
  280. I2C_ReadReg(addr, BMP280_DIG_P2_MSB_REG, &msb, 1, channel);
  281. bmp280Cc.P2 = (((uint16_t)msb) << 8) + lsb;
  282. I2C_ReadReg(addr, BMP280_DIG_P3_LSB_REG, &lsb, 1, channel);
  283. I2C_ReadReg(addr, BMP280_DIG_P3_MSB_REG, &msb, 1, channel);
  284. bmp280Cc.P3 = (((uint16_t)msb) << 8) + lsb;
  285. I2C_ReadReg(addr, BMP280_DIG_P4_LSB_REG, &lsb, 1, channel);
  286. I2C_ReadReg(addr, BMP280_DIG_P4_MSB_REG, &msb, 1, channel);
  287. bmp280Cc.P4 = (((uint16_t)msb) << 8) + lsb;
  288. I2C_ReadReg(addr, BMP280_DIG_P5_LSB_REG, &lsb, 1, channel);
  289. I2C_ReadReg(addr, BMP280_DIG_P5_MSB_REG, &msb, 1, channel);
  290. bmp280Cc.P5 = (((uint16_t)msb) << 8) + lsb;
  291. I2C_ReadReg(addr, BMP280_DIG_P6_LSB_REG, &lsb, 1, channel);
  292. I2C_ReadReg(addr, BMP280_DIG_P6_MSB_REG, &msb, 1, channel);
  293. bmp280Cc.P6 = (((uint16_t)msb) << 8) + lsb;
  294. I2C_ReadReg(addr, BMP280_DIG_P7_LSB_REG, &lsb, 1, channel);
  295. I2C_ReadReg(addr, BMP280_DIG_P7_MSB_REG, &msb, 1, channel);
  296. bmp280Cc.P7 = (((uint16_t)msb) << 8) + lsb;
  297. I2C_ReadReg(addr, BMP280_DIG_P8_LSB_REG, &lsb, 1, channel);
  298. I2C_ReadReg(addr, BMP280_DIG_P8_MSB_REG, &msb, 1, channel);
  299. bmp280Cc.P8 = (((uint16_t)msb) << 8) + lsb;
  300. I2C_ReadReg(addr, BMP280_DIG_P9_LSB_REG, &lsb, 1, channel);
  301. I2C_ReadReg(addr, BMP280_DIG_P9_MSB_REG, &msb, 1, channel);
  302. bmp280Cc.P9 = (((uint16_t)msb) << 8) + lsb;
  303. // Reset
  304. I2C_WriteReg(addr, BMP280_RESET_REG, (uint8_t*)BMP280_RESET_VALUE, 1, channel);
  305. BMP280_OVERSAMPLE_MODE BMP_OVERSAMPLE_MODEStructure;
  306. BMP_OVERSAMPLE_MODEStructure.P_Osample = BMP280_P_MODE_3;
  307. BMP_OVERSAMPLE_MODEStructure.T_Osample = BMP280_T_MODE_1;
  308. BMP_OVERSAMPLE_MODEStructure.WORKMODE = BMP280_NORMAL_MODE;
  309. BMP280_SetOversamp(&BMP_OVERSAMPLE_MODEStructure, addr, channel);
  310. BMP280_CONFIG BMP_CONFIGStructure;
  311. BMP_CONFIGStructure.T_SB = BMP280_T_SB1;
  312. BMP_CONFIGStructure.FILTER_COEFFICIENT = BMP280_FILTER_MODE_4;
  313. BMP_CONFIGStructure.SPI_EN = DISABLE;
  314. BMP280_SetStandbyFilter(&BMP_CONFIGStructure, addr, channel);
  315. }
  316. /**
  317. * @brief BMP280 check whether the device exists
  318. * @param addr chip address
  319. * @param channel chip channel
  320. * @return errCode, 0: success, !0: error
  321. */
  322. uint8_t BMP280_InitAndCheck(uint8_t addr, uint8_t channel)
  323. {
  324. BM280_Init(addr, channel);
  325. DelayMs(50);
  326. uint8_t bmp280Id = 0;
  327. bmp280Id = BMP280_ReadId(addr, channel);
  328. #ifdef __DEBUG_BMP280_ATY
  329. printf("\r\nBMP280 ID: 0x%02X", bmp280Id);
  330. #endif /* __DEBUG_BMP280_ATY */
  331. // 0xD8 = 0x88 | 0x58
  332. if(bmp280Id & 0xD8 != 0xD8)
  333. return 1;
  334. DelayMs(200);
  335. return 0;
  336. }
  337. /**
  338. * @brief BMP280 read temperature and pressure
  339. * @param tp data group to save tp value
  340. * @param addr chip address
  341. * @param channel chip channel
  342. * @return errCode, 0: success, !0: error
  343. */
  344. uint8_t BMP280_ReadTP(double* tp, uint8_t addr, uint8_t channel)
  345. {
  346. uint16_t errCount = 1000;
  347. for(uint8_t i = 0; i < errCount; i++)
  348. {
  349. if(BMP280_GetStatus(BMP280_MEASURING, addr, channel) == 0)
  350. break;
  351. if(i == errCount - 1)
  352. return 2;
  353. DelayMs(1);
  354. }
  355. for(uint8_t i = 0; i < errCount; i++)
  356. {
  357. if(BMP280_GetStatus(BMP280_IM_UPDATE, addr, channel) == 0)
  358. break;
  359. if(i == errCount - 1)
  360. return 3;
  361. DelayMs(1);
  362. }
  363. tp[0] = BMP280_GetTemperature(addr, channel);
  364. tp[1] = BMP280_GetPressure(addr, channel);
  365. return 0;
  366. }
  367. uint8_t bmp280InitFlag = 0;
  368. /**
  369. * @brief BMP280 get data flow path
  370. * @param tp data group to save tp value
  371. * @param addr chip address
  372. * @param channel chip channel
  373. * @return errCode, 0: success, !0: error
  374. */
  375. uint8_t BMP280_TempPreGet(uint16_t* tp, uint8_t addr, uint8_t channel)
  376. {
  377. double bmp280Value[2];
  378. if(bmp280InitFlag == 0)
  379. {
  380. if(BMP280_InitAndCheck(addr, channel))
  381. {
  382. bmp280InitFlag = 2;
  383. }
  384. else
  385. {
  386. bmp280InitFlag = 1;
  387. }
  388. }
  389. if(bmp280InitFlag == 2)
  390. {
  391. #ifdef __DEBUG_BMP280_ATY
  392. printf("\r\nDevice wrong!");
  393. #endif /* __DEBUG_BMP280_ATY */
  394. return 0xFF;
  395. }
  396. else if(bmp280InitFlag == 1)
  397. {
  398. uint8_t errValue = 0;
  399. errValue = BMP280_ReadTP(bmp280Value, addr, channel);
  400. if(errValue == 0)
  401. {
  402. if(bmp280Value[1] != 0)
  403. {
  404. tp[0] = ((bmp280Value[0] * 1000) + 5) / 10;
  405. tp[1] = (((bmp280Value[1] - 90000) * 10) + 5) / 10;
  406. #ifdef __DEBUG_BMP280_ATY
  407. printf("\r\nTemperature %f C Pressure %f Pa", bmp280Value[0], bmp280Value[1]);
  408. #endif /* __DEBUG_BMP280_ATY */
  409. }
  410. else
  411. {
  412. #ifdef __DEBUG_BMP280_ATY
  413. printf("\r\nData get wrong!");
  414. #endif /* __DEBUG_AHT20_ATY */
  415. return 0xFD;
  416. }
  417. }
  418. else
  419. {
  420. #ifdef __DEBUG_BMP280_ATY
  421. printf("\r\nBMP280 timeout! Err: %d", errValue);
  422. #endif /* __DEBUG_BMP280_ATY */
  423. return 0xFE;
  424. }
  425. }
  426. return 0;
  427. }
  428. // todo: not tested
  429. #endif /* __BMP280_ATY_C */
  430. /******************************** End Of File *********************************/