bme280_math.c 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357
  1. // ***************************************************************************
  2. // BMP280 module for ESP8266 with nodeMCU
  3. //
  4. // Written by Lukas Voborsky, @voborsky
  5. //
  6. // MIT license, http://opensource.org/licenses/MIT
  7. // ***************************************************************************
  8. // #define NODE_DEBUG
  9. #include "module.h"
  10. #include "lauxlib.h"
  11. #include "platform.h"
  12. #include "user_interface.h"
  13. #include <math.h>
  14. /****************************************************/
  15. /**\name registers definition */
  16. /***************************************************/
  17. #define BME280_REGISTER_CONTROL (0xF4)
  18. #define BME280_REGISTER_CONTROL_HUM (0xF2)
  19. #define BME280_REGISTER_CONFIG (0xF5)
  20. #define BME280_REGISTER_CHIPID (0xD0)
  21. #define BME280_REGISTER_VERSION (0xD1)
  22. #define BME280_REGISTER_SOFTRESET (0xE0)
  23. #define BME280_REGISTER_CAL26 (0xE1)
  24. #define BME280_REGISTER_PRESS (0xF7) // 0xF7-0xF9
  25. #define BME280_REGISTER_TEMP (0xFA) // 0xFA-0xFC
  26. #define BME280_REGISTER_HUM (0xFD) // 0xFD-0xFE
  27. #define BME280_REGISTER_DIG_T (0x88) // 0x88-0x8D ( 6)
  28. #define BME280_REGISTER_DIG_P (0x8E) // 0x8E-0x9F (18)
  29. #define BME280_REGISTER_DIG_H1 (0xA1) // 0xA1 ( 1)
  30. #define BME280_REGISTER_DIG_H2 (0xE1) // 0xE1-0xE7 ( 7)
  31. /****************************************************/
  32. /**\name I2C ADDRESS DEFINITIONS */
  33. /***************************************************/
  34. #define BME280_I2C_ADDRESS1 (0x76)
  35. #define BME280_I2C_ADDRESS2 (0x77)
  36. /****************************************************/
  37. /**\name POWER MODE DEFINITIONS */
  38. /***************************************************/
  39. /* Sensor Specific constants */
  40. #define BME280_SLEEP_MODE (0x00)
  41. #define BME280_FORCED_MODE (0x01)
  42. #define BME280_NORMAL_MODE (0x03)
  43. #define BME280_SOFT_RESET_CODE (0xB6)
  44. /****************************************************/
  45. /**\name OVER SAMPLING DEFINITIONS */
  46. /***************************************************/
  47. #define BME280_OVERSAMP_1X (0x01)
  48. #define BME280_OVERSAMP_2X (0x02)
  49. #define BME280_OVERSAMP_4X (0x03)
  50. #define BME280_OVERSAMP_8X (0x04)
  51. #define BME280_OVERSAMP_16X (0x05)
  52. /****************************************************/
  53. /**\name STANDBY TIME DEFINITIONS */
  54. /***************************************************/
  55. #define BME280_STANDBY_TIME_1_MS (0x00)
  56. #define BME280_STANDBY_TIME_63_MS (0x01)
  57. #define BME280_STANDBY_TIME_125_MS (0x02)
  58. #define BME280_STANDBY_TIME_250_MS (0x03)
  59. #define BME280_STANDBY_TIME_500_MS (0x04)
  60. #define BME280_STANDBY_TIME_1000_MS (0x05)
  61. #define BME280_STANDBY_TIME_10_MS (0x06)
  62. #define BME280_STANDBY_TIME_20_MS (0x07)
  63. /****************************************************/
  64. /**\name FILTER DEFINITIONS */
  65. /***************************************************/
  66. #define BME280_FILTER_COEFF_OFF (0x00)
  67. #define BME280_FILTER_COEFF_2 (0x01)
  68. #define BME280_FILTER_COEFF_4 (0x02)
  69. #define BME280_FILTER_COEFF_8 (0x03)
  70. #define BME280_FILTER_COEFF_16 (0x04)
  71. /****************************************************/
  72. /**\data type definition */
  73. /***************************************************/
  74. #define BME280_S32_t int32_t
  75. #define BME280_U32_t uint32_t
  76. #define BME280_S64_t int64_t
  77. #define BME280_SAMPLING_DELAY 113 //maximum measurement time in ms for maximum oversampling for all measures = 1.25 + 2.3*16 + 2.3*16 + 0.575 + 2.3*16 + 0.575 ms
  78. // #define r16s(reg) ((int16_t)r16u(reg))
  79. // #define r16sLE(reg) ((int16_t)r16uLE(reg))
  80. // #define bme280_adc_P(void) r24u(BME280_REGISTER_PRESS)
  81. // #define bme280_adc_T(void) r24u(BME280_REGISTER_TEMP)
  82. // #define bme280_adc_H(void) r16u(BME280_REGISTER_HUM)
  83. typedef struct {
  84. uint16_t dig_T1;
  85. int16_t dig_T2;
  86. int16_t dig_T3;
  87. uint16_t dig_P1;
  88. int16_t dig_P2;
  89. int16_t dig_P3;
  90. int16_t dig_P4;
  91. int16_t dig_P5;
  92. int16_t dig_P6;
  93. int16_t dig_P7;
  94. int16_t dig_P8;
  95. int16_t dig_P9;
  96. uint8_t dig_H1;
  97. int16_t dig_H2;
  98. uint8_t dig_H3;
  99. int16_t dig_H4;
  100. int16_t dig_H5;
  101. int8_t dig_H6;
  102. } bme280_data_t;
  103. typedef bme280_data_t* bme280_data_p;
  104. bme280_data_p bme280_data;
  105. BME280_S32_t bme280_t_fine;
  106. // Returns temperature in DegC, resolution is 0.01 DegC. Output value of “5123” equals 51.23 DegC.
  107. // t_fine carries fine temperature as global value
  108. BME280_S32_t bme280_compensate_T(BME280_S32_t adc_T) {
  109. BME280_S32_t var1, var2, T;
  110. var1 = ((((adc_T>>3) - ((BME280_S32_t)(*bme280_data).dig_T1<<1))) * ((BME280_S32_t)(*bme280_data).dig_T2)) >> 11;
  111. var2 = (((((adc_T>>4) - ((BME280_S32_t)(*bme280_data).dig_T1)) * ((adc_T>>4) - ((BME280_S32_t)(*bme280_data).dig_T1))) >> 12) *
  112. ((BME280_S32_t)(*bme280_data).dig_T3)) >> 14;
  113. bme280_t_fine = var1 + var2;
  114. T = (bme280_t_fine * 5 + 128) >> 8;
  115. return T;
  116. }
  117. // Returns pressure in Pa as unsigned 32 bit integer in Q24.8 format (24 integer bits and 8 fractional bits).
  118. // Output value of “24674867” represents 24674867/256 = 96386.2 Pa = 963.862 hPa
  119. BME280_U32_t bme280_compensate_P(BME280_S32_t adc_P) {
  120. BME280_S64_t var1, var2, p;
  121. var1 = ((BME280_S64_t)bme280_t_fine) - 128000;
  122. var2 = var1 * var1 * (BME280_S64_t)(*bme280_data).dig_P6;
  123. var2 = var2 + ((var1*(BME280_S64_t)(*bme280_data).dig_P5)<<17);
  124. var2 = var2 + (((BME280_S64_t)(*bme280_data).dig_P4)<<35);
  125. var1 = ((var1 * var1 * (BME280_S64_t)(*bme280_data).dig_P3)>>8) + ((var1 * (BME280_S64_t)(*bme280_data).dig_P2)<<12);
  126. var1 = (((((BME280_S64_t)1)<<47)+var1))*((BME280_S64_t)(*bme280_data).dig_P1)>>33;
  127. if (var1 == 0) {
  128. return 0; // avoid exception caused by division by zero
  129. }
  130. p = 1048576-adc_P;
  131. p = (((p<<31)-var2)*3125)/var1;
  132. var1 = (((BME280_S64_t)(*bme280_data).dig_P9) * (p>>13) * (p>>13)) >> 25;
  133. var2 = (((BME280_S64_t)(*bme280_data).dig_P8) * p) >> 19;
  134. p = ((p + var1 + var2) >> 8) + (((BME280_S64_t)(*bme280_data).dig_P7)<<4);
  135. p = (p * 10) >> 8;
  136. return (BME280_U32_t)p;
  137. }
  138. // Returns humidity in %RH as unsigned 32 bit integer in Q22.10 format (22 integer and 10 fractional bits).
  139. // Output value of “47445” represents 47445/1024 = 46.333 %RH
  140. BME280_U32_t bme280_compensate_H(BME280_S32_t adc_H) {
  141. BME280_S32_t v_x1_u32r;
  142. v_x1_u32r = (bme280_t_fine - ((BME280_S32_t)76800));
  143. v_x1_u32r = (((((adc_H << 14) - (((BME280_S32_t)(*bme280_data).dig_H4) << 20) - (((BME280_S32_t)(*bme280_data).dig_H5) * v_x1_u32r)) +
  144. ((BME280_S32_t)16384)) >> 15) * (((((((v_x1_u32r * ((BME280_S32_t)(*bme280_data).dig_H6)) >> 10) * (((v_x1_u32r *
  145. ((BME280_S32_t)(*bme280_data).dig_H3)) >> 11) + ((BME280_S32_t)32768))) >> 10) + ((BME280_S32_t)2097152)) *
  146. ((BME280_S32_t)(*bme280_data).dig_H2) + 8192) >> 14));
  147. v_x1_u32r = (v_x1_u32r - (((((v_x1_u32r >> 15) * (v_x1_u32r >> 15)) >> 7) * ((BME280_S32_t)(*bme280_data).dig_H1)) >> 4));
  148. v_x1_u32r = (v_x1_u32r < 0 ? 0 : v_x1_u32r);
  149. v_x1_u32r = (v_x1_u32r > 419430400 ? 419430400 : v_x1_u32r);
  150. v_x1_u32r = v_x1_u32r>>12;
  151. return (BME280_U32_t)((v_x1_u32r * 1000)>>10);
  152. }
  153. double ln(double x) {
  154. double y = (x-1)/(x+1);
  155. double y2 = y*y;
  156. double r = 0;
  157. for (int8_t i=33; i>0; i-=2) { //we've got the power
  158. r = 1.0/(double)i + y2 * r;
  159. }
  160. return 2*y*r;
  161. }
  162. uint32_t bme280_h = 0; // buffer last qfe2qnh calculation
  163. double bme280_hc = 1.0;
  164. double bme280_qfe2qnh(double qfe, double h) {
  165. double hc;
  166. if (bme280_h == h) {
  167. hc = bme280_hc;
  168. } else {
  169. hc = pow((double)(1.0 - 2.25577e-5 * h), (double)(-5.25588));
  170. bme280_hc = hc; bme280_h = h;
  171. }
  172. double qnh = (double)qfe * hc;
  173. return qnh;
  174. }
  175. int bme280_lua_setup(lua_State* L) {
  176. uint8_t bme280_mode = 0; // stores oversampling settings
  177. uint8_t bme280_ossh = 0; // stores humidity oversampling settings
  178. uint8_t config;
  179. uint8_t const bit3 = 0b111;
  180. uint8_t const bit2 = 0b11;
  181. bme280_mode = (!lua_isnumber(L, 5)?BME280_NORMAL_MODE:(luaL_checkinteger(L, 5)&bit2)) // 4-th parameter: power mode
  182. | ((!lua_isnumber(L, 3)?BME280_OVERSAMP_16X:(luaL_checkinteger(L, 3)&bit3)) << 2) // 2-nd parameter: pressure oversampling
  183. | ((!lua_isnumber(L, 2)?BME280_OVERSAMP_16X:(luaL_checkinteger(L, 2)&bit3)) << 5); // 1-st parameter: temperature oversampling
  184. bme280_ossh = (!lua_isnumber(L, 4))?BME280_OVERSAMP_16X:(luaL_checkinteger(L, 4)&bit3); // 3-rd parameter: humidity oversampling
  185. config = ((!lua_isnumber(L, 6)?BME280_STANDBY_TIME_20_MS:(luaL_checkinteger(L, 6)&bit3))<< 5) // 5-th parameter: inactive duration in normal mode
  186. | ((!lua_isnumber(L, 7)?BME280_FILTER_COEFF_16:(luaL_checkinteger(L, 7)&bit3)) << 2); // 6-th parameter: IIR filter
  187. // NODE_DBG("mode: %x\nhumidity oss: %x\nconfig: %x\n", bme280_mode, bme280_ossh, config);
  188. #define r16uLE_buf(reg) (uint16_t)((reg[1] << 8) | reg[0])
  189. #define r16sLE_buf(reg) (int16_t)(r16uLE_buf(reg))
  190. size_t reg_len;
  191. const char *buf = luaL_checklstring(L, 1, &reg_len);
  192. bme280_data = (bme280_data_p) memset(lua_newuserdata(L, sizeof(*bme280_data)), 0, sizeof(*bme280_data)); // first parameter to be returned
  193. const uint8_t *reg;
  194. reg = buf;
  195. (*bme280_data).dig_T1 = r16uLE_buf(reg); reg+=2;
  196. (*bme280_data).dig_T2 = r16sLE_buf(reg); reg+=2;
  197. (*bme280_data).dig_T3 = r16sLE_buf(reg); reg+=2;
  198. // NODE_DBG("dig_T: %d\t%d\t%d\n", (*bme280_data).dig_T1, (*bme280_data).dig_T2, (*bme280_data).dig_T3);
  199. (*bme280_data).dig_P1 = r16uLE_buf(reg); reg+=2;
  200. (*bme280_data).dig_P2 = r16sLE_buf(reg); reg+=2;
  201. (*bme280_data).dig_P3 = r16sLE_buf(reg); reg+=2;
  202. (*bme280_data).dig_P4 = r16sLE_buf(reg); reg+=2;
  203. (*bme280_data).dig_P5 = r16sLE_buf(reg); reg+=2;
  204. (*bme280_data).dig_P6 = r16sLE_buf(reg); reg+=2;
  205. (*bme280_data).dig_P7 = r16sLE_buf(reg); reg+=2;
  206. (*bme280_data).dig_P8 = r16sLE_buf(reg); reg+=2;
  207. (*bme280_data).dig_P9 = r16sLE_buf(reg); reg+=2;
  208. // NODE_DBG("dig_P: %d\t%d\t%d\t%d\t%d\t%d\t%d\t%d\t%d\n", (*bme280_data).dig_P1, (*bme280_data).dig_P2,(*bme280_data).dig_P3, (*bme280_data).dig_P4, (*bme280_data).dig_P5, (*bme280_data).dig_P6, (*bme280_data).dig_P7,(*bme280_data).dig_P8, (*bme280_data).dig_P9);
  209. if (reg_len>=6+18) { // is BME?
  210. (*bme280_data).dig_H1 = (uint8)reg[0]; reg+=1;
  211. (*bme280_data).dig_H2 = r16sLE_buf(reg); reg+=2;
  212. (*bme280_data).dig_H3 = reg[0]; reg++;
  213. (*bme280_data).dig_H4 = (int16_t)reg[0] << 4 | (reg[1] & 0x0F); reg+=1; // H4[11:4 3:0] = 0xE4[7:0] 0xE5[3:0] 12-bit signed
  214. (*bme280_data).dig_H5 = (int16_t)reg[1] << 4 | (reg[0] >> 4); reg+=2; // H5[11:4 3:0] = 0xE6[7:0] 0xE5[7:4] 12-bit signed
  215. (*bme280_data).dig_H6 = (int8_t)reg[0];
  216. NODE_DBG("dig_H: %d\t%d\t%d\t%d\t%d\t%d\n", (*bme280_data).dig_H1, (*bme280_data).dig_H2, (*bme280_data).dig_H3, (*bme280_data).dig_H4, (*bme280_data).dig_H5, (*bme280_data).dig_H6);
  217. }
  218. #undef r16uLE_buf
  219. #undef r16sLE_buf
  220. int i = 1;
  221. char cfg[2]={'\0', '\0'};
  222. lua_createtable(L, 3, 0); /* configuration table */
  223. cfg[0]=(char)config;
  224. lua_pushstring(L, cfg);
  225. lua_rawseti(L, -2, i++);
  226. cfg[0]=(char)bme280_ossh;
  227. lua_pushstring(L, cfg);
  228. lua_rawseti(L, -2, i++);
  229. cfg[0]=(char)bme280_mode;
  230. lua_pushstring(L, cfg);
  231. lua_rawseti(L, -2, i);
  232. return 2;
  233. }
  234. // Return T, QFE, H if no altitude given
  235. // Return T, QFE, H, QNH if altitude given
  236. int bme280_lua_read(lua_State* L) {
  237. double qfe;
  238. bme280_data = (bme280_data_p)lua_touserdata(L, 1);
  239. size_t reg_len;
  240. const char *buf = luaL_checklstring(L, 2, &reg_len); // registers are P[3], T[3], H[2]
  241. if (reg_len != 8 && reg_len !=6) {
  242. luaL_error(L, "invalid readout data");
  243. }
  244. uint8_t calc_qnh = lua_isnumber(L, 3);
  245. // Must do Temp first since bme280_t_fine is used by the other compensation functions
  246. uint32_t adc_T = (uint32_t)(((buf[3] << 16) | (buf[4] << 8) | buf[5]) >> 4);
  247. if (adc_T == 0x80000 || adc_T == 0xfffff)
  248. return 0;
  249. lua_pushnumber(L, bme280_compensate_T(adc_T)/100.0);
  250. uint32_t adc_P = (uint32_t)(((buf[0] << 16) | (buf[1] << 8) | buf[2]) >> 4);
  251. NODE_DBG("adc_P: %d\n", adc_P);
  252. if (adc_P ==0x80000 || adc_P == 0xfffff) {
  253. lua_pushnil(L);
  254. calc_qnh = 0;
  255. } else {
  256. qfe = bme280_compensate_P(adc_P)/1000.0;
  257. lua_pushnumber (L, qfe);
  258. }
  259. uint32_t adc_H = (uint32_t)((buf[6] << 8) | buf[7]);
  260. if (reg_len!=8 || adc_H == 0x8000 || adc_H == 0xffff)
  261. lua_pushnil(L);
  262. else
  263. lua_pushnumber (L, bme280_compensate_H(adc_H)/1000.0);
  264. if (calc_qnh) { // have altitude
  265. int32_t h = luaL_checknumber(L, 3);
  266. double qnh = bme280_qfe2qnh(qfe, h);
  267. lua_pushnumber (L, qnh);
  268. return 4;
  269. }
  270. return 3;
  271. }
  272. int bme280_lua_qfe2qnh(lua_State* L) {
  273. if (lua_isuserdata(L, 1) || lua_istable(L, 1)) { // allow to call it as object method, userdata have no use here
  274. lua_remove(L, 1);
  275. }
  276. double qfe = luaL_checknumber(L, 1);
  277. double h = luaL_checknumber(L, 2);
  278. double qnh = bme280_qfe2qnh(qfe, h);
  279. lua_pushnumber(L, qnh);
  280. return 1;
  281. }
  282. int bme280_lua_altitude(lua_State* L) {
  283. if (lua_isuserdata(L, 1) || lua_istable(L, 1)) { // allow to call it as object method, userdata have no use here
  284. lua_remove(L, 1);
  285. }
  286. double P = luaL_checknumber(L, 1);
  287. double qnh = luaL_checknumber(L, 2);
  288. double h = (1.0 - pow((double)P/(double)qnh, 1.0/5.25588)) / 2.25577e-5;
  289. lua_pushnumber (L, h);
  290. return 1;
  291. }
  292. int bme280_lua_dewpoint(lua_State* L) {
  293. if (lua_isuserdata(L, 1) || lua_istable(L, 1)) { // allow to call it as object method, userdata have no use here
  294. lua_remove(L, 1);
  295. }
  296. double H = luaL_checknumber(L, 1)/100.0; // percent
  297. double T = luaL_checknumber(L, 2);
  298. const double c243 = 243.5;
  299. const double c17 = 17.67;
  300. double c = ln(H) + ((c17 * T) / (c243 + T));
  301. double d = (c243 * c)/(c17 - c);
  302. lua_pushnumber (L, d);
  303. return 1;
  304. }
  305. LROT_BEGIN(bme280_math, NULL, 0)
  306. LROT_FUNCENTRY( setup, bme280_lua_setup )
  307. LROT_FUNCENTRY( read, bme280_lua_read )
  308. LROT_FUNCENTRY( qfe2qnh, bme280_lua_qfe2qnh )
  309. LROT_FUNCENTRY( altitude, bme280_lua_altitude )
  310. LROT_FUNCENTRY( dewpoint, bme280_lua_dewpoint )
  311. LROT_END(bme280_math, NULL, 0)
  312. NODEMCU_MODULE(BME280_MATH, "bme280_math", bme280_math, NULL);