si7021.c 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265
  1. //***************************************************************************
  2. // Si7021 module for ESP8266 with nodeMCU
  3. // fetchbot @github
  4. // MIT license, http://opensource.org/licenses/MIT
  5. //***************************************************************************
  6. #include "module.h"
  7. #include "lauxlib.h"
  8. #include "platform.h"
  9. #include "osapi.h"
  10. //***************************************************************************
  11. // I2C ADDRESS DEFINITON
  12. //***************************************************************************
  13. #define SI7021_I2C_ADDRESS (0x40)
  14. //***************************************************************************
  15. // COMMAND DEFINITON
  16. //***************************************************************************
  17. #define SI7021_CMD_MEASURE_RH_HOLD (0xE5)
  18. #define SI7021_CMD_MEASURE_RH_NOHOLD (0xF5)
  19. #define SI7021_CMD_MEASURE_TEMP_HOLD (0xE3)
  20. #define SI7021_CMD_MEASURE_TEMP_NOHOLD (0xF3)
  21. #define SI7021_CMD_READ_PREV_TEMP (0xE0)
  22. #define SI7021_CMD_RESET (0xFE)
  23. #define SI7021_CMD_WRITE_RHT_REG (0xE6)
  24. #define SI7021_CMD_READ_RHT_REG (0xE7)
  25. #define SI7021_CMD_WRITE_HEATER_REG (0x51)
  26. #define SI7021_CMD_READ_HEATER_REG (0x11)
  27. #define SI7021_CMD_ID1 (0xFA0F)
  28. #define SI7021_CMD_ID2 (0xFCC9)
  29. #define SI7021_CMD_FIRM_REV (0x84B8)
  30. //***************************************************************************
  31. // REGISTER DEFINITON
  32. //***************************************************************************
  33. #define SI7021_RH12_TEMP14 (0x00)
  34. #define SI7021_RH08_TEMP12 (0x01)
  35. #define SI7021_RH10_TEMP13 (0x80)
  36. #define SI7021_RH11_TEMP11 (0x81)
  37. #define SI7021_HEATER_ENABLE (0x04)
  38. #define SI7021_HEATER_DISABLE (0x00)
  39. //***************************************************************************
  40. static const uint32_t si7021_i2c_id = 0;
  41. static uint8_t si7021_i2c_addr = SI7021_I2C_ADDRESS;
  42. static uint8_t si7021_res = 0x00;
  43. static uint8_t si7021_config = 0x3A;
  44. static uint8_t si7021_heater = 0x00;
  45. static uint8_t si7021_heater_setting = 0x00;
  46. static uint8_t write_byte(uint8_t reg) {
  47. platform_i2c_send_start(si7021_i2c_id);
  48. platform_i2c_send_address(si7021_i2c_id, si7021_i2c_addr, PLATFORM_I2C_DIRECTION_TRANSMITTER);
  49. platform_i2c_send_byte(si7021_i2c_id, reg);
  50. platform_i2c_send_stop(si7021_i2c_id);
  51. }
  52. static uint8_t write_reg(uint8_t reg, uint8_t data) {
  53. platform_i2c_send_start(si7021_i2c_id);
  54. platform_i2c_send_address(si7021_i2c_id, si7021_i2c_addr, PLATFORM_I2C_DIRECTION_TRANSMITTER);
  55. platform_i2c_send_byte(si7021_i2c_id, reg);
  56. platform_i2c_send_byte(si7021_i2c_id, data);
  57. platform_i2c_send_stop(si7021_i2c_id);
  58. }
  59. static uint8_t read_reg(uint8_t reg, uint8_t *buf, uint8_t size) {
  60. platform_i2c_send_start(si7021_i2c_id);
  61. platform_i2c_send_address(si7021_i2c_id, si7021_i2c_addr, PLATFORM_I2C_DIRECTION_TRANSMITTER);
  62. platform_i2c_send_byte(si7021_i2c_id, reg);
  63. platform_i2c_send_stop(si7021_i2c_id);
  64. platform_i2c_send_start(si7021_i2c_id);
  65. platform_i2c_send_address(si7021_i2c_id, si7021_i2c_addr, PLATFORM_I2C_DIRECTION_RECEIVER);
  66. os_delay_us(25000);
  67. while (size-- > 0)
  68. *buf++ = platform_i2c_recv_byte(si7021_i2c_id, size > 0);
  69. platform_i2c_send_stop(si7021_i2c_id);
  70. return 1;
  71. }
  72. static uint8_t read_serial(uint16_t reg, uint8_t *buf, uint8_t size) {
  73. platform_i2c_send_start(si7021_i2c_id);
  74. platform_i2c_send_address(si7021_i2c_id, si7021_i2c_addr, PLATFORM_I2C_DIRECTION_TRANSMITTER);
  75. platform_i2c_send_byte(si7021_i2c_id, (uint8_t)(reg >> 8));
  76. platform_i2c_send_byte(si7021_i2c_id, (uint8_t)(reg & 0xFF));
  77. // platform_i2c_send_stop(si7021_i2c_id);
  78. platform_i2c_send_start(si7021_i2c_id);
  79. platform_i2c_send_address(si7021_i2c_id, si7021_i2c_addr, PLATFORM_I2C_DIRECTION_RECEIVER);
  80. while (size-- > 0)
  81. *buf++ = platform_i2c_recv_byte(si7021_i2c_id, size > 0);
  82. platform_i2c_send_stop(si7021_i2c_id);
  83. return 1;
  84. }
  85. // CRC8
  86. uint8_t si7021_crc8(uint8_t crc, uint8_t *buf, uint8_t size) {
  87. while (size--) {
  88. crc ^= *buf++;
  89. for (uint8_t i = 0; i < 8; i++) {
  90. if (crc & 0x80) {
  91. crc = (crc << 1) ^ 0x31;
  92. } else crc <<= 1;
  93. }
  94. }
  95. return crc;
  96. }
  97. static int si7021_lua_setup(lua_State* L) {
  98. write_byte(SI7021_CMD_RESET);
  99. os_delay_us(50000);
  100. // check for device on i2c bus
  101. uint8_t buf_r[1];
  102. read_reg(SI7021_CMD_READ_RHT_REG, buf_r, 1);
  103. if (buf_r[0] != 0x3A)
  104. return luaL_error(L, "found no device");
  105. return 0;
  106. }
  107. // Change sensor settings and returns them
  108. // Lua: res, vdds, heater[, heater_set] = si7021.settings(RESOLUTION[,HEATER,HEATER_SETTING])
  109. static int si7021_lua_setting(lua_State* L) {
  110. // check variable
  111. if (!lua_isnumber(L, 1)) {
  112. return luaL_error(L, "wrong arg range");
  113. }
  114. si7021_res = luaL_checkinteger(L, 1);
  115. if (!((si7021_res == SI7021_RH12_TEMP14) || (si7021_res == SI7021_RH08_TEMP12) || (si7021_res == SI7021_RH10_TEMP13) || (si7021_res == SI7021_RH11_TEMP11))) {
  116. return luaL_error(L, "Invalid argument: resolution");
  117. }
  118. si7021_config = (si7021_res | 0x3A);
  119. write_reg(SI7021_CMD_WRITE_RHT_REG,si7021_config);
  120. // Parse optional parameters
  121. if (lua_isnumber(L, 2)) {
  122. if (!lua_isnumber(L, 2) || !lua_isnumber(L, 3)) {
  123. return luaL_error(L, "wrong arg range");
  124. }
  125. si7021_heater = luaL_checkinteger(L, 2);
  126. if (!((si7021_heater == SI7021_HEATER_ENABLE) || (si7021_heater == SI7021_HEATER_DISABLE))) {
  127. return luaL_error(L, "Invalid argument: heater");
  128. }
  129. si7021_heater_setting = luaL_checkinteger(L, 3);
  130. if ((si7021_heater_setting < 0x00) || (si7021_heater_setting > 0x0F)) {
  131. return luaL_error(L, "Invalid argument: heater_setting");
  132. }
  133. si7021_config = (si7021_res | si7021_heater | 0x3A);
  134. write_reg(SI7021_CMD_WRITE_RHT_REG,si7021_config);
  135. write_reg(SI7021_CMD_WRITE_HEATER_REG,(si7021_heater_setting & 0x0F));
  136. }
  137. uint8_t buf_c[1];
  138. uint8_t buf_h[1];
  139. read_reg(SI7021_CMD_READ_RHT_REG, buf_c, 1);
  140. read_reg(SI7021_CMD_READ_HEATER_REG, buf_h, 1);
  141. lua_pushinteger(L, ((buf_c[0] >> 6) + (buf_c[0] & 0x01)));
  142. lua_pushinteger(L, ((buf_c[0] >> 6) & 0x01));
  143. lua_pushinteger(L, ((buf_c[0] >> 2) & 0x01));
  144. lua_pushinteger(L, (buf_h[0] & 0x0F));
  145. return 4;
  146. }
  147. // Reads sensor values from device and returns them
  148. // Lua: hum, temp, humdec, tempdec = si7021.read()
  149. static int si7021_lua_read(lua_State* L) {
  150. uint8_t buf_h[3]; // first two byte data, third byte crc
  151. read_reg(SI7021_CMD_MEASURE_RH_HOLD, buf_h, 3);
  152. if (buf_h[2] != si7021_crc8(0, buf_h, 2)) //crc check
  153. return luaL_error(L, "crc error");
  154. lua_Float hum = (uint16_t)((buf_h[0] << 8) | buf_h[1]);
  155. hum = ((hum * 125) / 65536 - 6);
  156. int humdec = (int)((hum - (int)hum) * 1000);
  157. uint8_t buf_t[2]; // two byte data, no crc on combined temp measurement
  158. read_reg(SI7021_CMD_READ_PREV_TEMP, buf_t, 2);
  159. lua_Float temp = (uint16_t)((buf_t[0] << 8) | buf_t[1]);
  160. temp = ((temp * 175.72) / 65536 - 46.85);
  161. int tempdec = (int)((temp - (int)temp) * 1000);
  162. lua_pushnumber(L, hum);
  163. lua_pushnumber(L, temp);
  164. lua_pushinteger(L, humdec);
  165. lua_pushinteger(L, tempdec);
  166. return 4;
  167. }
  168. // Reads electronic serial number from device and returns them
  169. // Lua: serial = si7021.serial()
  170. static int si7021_lua_serial(lua_State* L) {
  171. uint32_t serial_a;
  172. uint8_t crc = 0;
  173. uint8_t buf_s_1[8]; // every second byte contains crc
  174. read_serial(SI7021_CMD_ID1, buf_s_1, 8);
  175. for(uint8_t i = 0; i <= 6; i+=2) {
  176. crc = si7021_crc8(crc, buf_s_1+i, 1);
  177. if (buf_s_1[i+1] != crc)
  178. return luaL_error(L, "crc error");
  179. serial_a = (serial_a << 8) + buf_s_1[i];
  180. }
  181. uint32_t serial_b;
  182. crc = 0;
  183. uint8_t buf_s_2[6]; // every third byte contains crc
  184. read_serial(SI7021_CMD_ID2, buf_s_2, 6);
  185. for(uint8_t i = 0; i <=3; i+=3) {
  186. crc = si7021_crc8(crc, buf_s_2+i, 2);
  187. if (buf_s_2[i+2] != crc)
  188. return luaL_error(L, "crc error");
  189. serial_b = (serial_b << 16) + (buf_s_2[i] << 8) + buf_s_2[i+1];
  190. }
  191. lua_pushinteger(L, serial_a);
  192. lua_pushinteger(L, serial_b);
  193. return 2;
  194. }
  195. // Reads electronic firmware revision from device and returns them
  196. // Lua: firmware = si7021.firmware()
  197. static int si7021_lua_firmware(lua_State* L) {
  198. uint8_t firmware;
  199. uint8_t buf_f[1];
  200. read_serial(SI7021_CMD_FIRM_REV, buf_f, 1);
  201. firmware = buf_f[0];
  202. lua_pushinteger(L, firmware);
  203. return 1;
  204. }
  205. LROT_BEGIN(si7021, NULL, 0)
  206. LROT_FUNCENTRY( setup, si7021_lua_setup )
  207. LROT_FUNCENTRY( setting, si7021_lua_setting )
  208. LROT_FUNCENTRY( read, si7021_lua_read )
  209. LROT_FUNCENTRY( serial, si7021_lua_serial )
  210. LROT_FUNCENTRY( firmware, si7021_lua_firmware )
  211. LROT_NUMENTRY( RH12_TEMP14, SI7021_RH12_TEMP14 )
  212. LROT_NUMENTRY( RH08_TEMP12, SI7021_RH08_TEMP12 )
  213. LROT_NUMENTRY( RH10_TEMP13, SI7021_RH10_TEMP13 )
  214. LROT_NUMENTRY( RH11_TEMP11, SI7021_RH11_TEMP11 )
  215. LROT_NUMENTRY( HEATER_ENABLE, SI7021_HEATER_ENABLE )
  216. LROT_NUMENTRY( HEATER_DISABLE, SI7021_HEATER_DISABLE )
  217. LROT_END(si7021, NULL, 0)
  218. NODEMCU_MODULE(SI7021, "si7021", si7021, NULL);