ds18b20.c 9.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295
  1. //***************************************************************************
  2. // DS18B20 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. #include "driver/onewire.h"
  11. #include "c_stdio.h"
  12. #include "c_stdlib.h"
  13. //***************************************************************************
  14. // OW ROM COMMANDS
  15. //***************************************************************************
  16. #define DS18B20_ROM_SEARCH (0xF0)
  17. #define DS18B20_ROM_READ (0x33)
  18. #define DS18B20_ROM_MATCH (0x55)
  19. #define DS18B20_ROM_SKIP (0xCC)
  20. #define DS18B20_ROM_SEARCH_ALARM (0xEC)
  21. //***************************************************************************
  22. // OW FUNCTION COMMANDS
  23. //***************************************************************************
  24. #define DS18B20_FUNC_CONVERT (0x44)
  25. #define DS18B20_FUNC_SCRATCH_WRITE (0x4E)
  26. #define DS18B20_FUNC_SCRATCH_READ (0xBE)
  27. #define DS18B20_FUNC_SCRATCH_COPY (0x48)
  28. #define DS18B20_FUNC_E2_RECALL (0xB8)
  29. #define DS18B20_FUNC_POWER_READ (0xB4)
  30. //***************************************************************************
  31. // Initial EEPROM values
  32. //***************************************************************************
  33. #define DS18B20_EEPROM_TH (0x4B) // 75 degree
  34. #define DS18B20_EEPROM_TL (0x46) // 70 degree
  35. #define DS18B20_EEPROM_RES (0x7F) // 12 bit resolution
  36. //***************************************************************************
  37. static uint8_t ds18b20_bus_pin;
  38. static uint8_t ds18b20_device_family;
  39. static uint8_t ds18b20_device_search = 0;
  40. static uint8_t ds18b20_device_index;
  41. static uint8_t ds18b20_device_par;
  42. static uint8_t ds18b20_device_conf[3];
  43. static uint8_t ds18b20_device_rom[8];
  44. static uint8_t ds18b20_device_scratchpad[9];
  45. static double ds18b20_device_scratchpad_temp;
  46. static int ds18b20_device_scratchpad_temp_dec;
  47. static uint8_t ds18b20_device_scratchpad_conf;
  48. static uint8_t ds18b20_device_res = 12; // 12 bit resolution (750ms conversion time)
  49. os_timer_t ds18b20_timer; // timer for conversion delay
  50. int ds18b20_timer_ref; // callback when readout is ready
  51. int ds18b20_table_ref;
  52. static int ds18b20_table_offset;
  53. static int ds18b20_lua_readoutdone(void);
  54. // Setup onewire bus for DS18B20 temperature sensors
  55. // Lua: ds18b20.setup(OW_BUS_PIN)
  56. static int ds18b20_lua_setup(lua_State *L) {
  57. // check ow bus pin value
  58. if (!lua_isnumber(L, 1) || lua_isnumber(L, 1) == 0) {
  59. return luaL_error(L, "wrong 1-wire pin");
  60. }
  61. ds18b20_bus_pin = luaL_checkinteger(L, 1);
  62. MOD_CHECK_ID(ow, ds18b20_bus_pin);
  63. onewire_init(ds18b20_bus_pin);
  64. }
  65. static int ds18b20_set_device(uint8_t *ds18b20_device_rom) {
  66. onewire_reset(ds18b20_bus_pin);
  67. onewire_select(ds18b20_bus_pin, ds18b20_device_rom);
  68. onewire_write(ds18b20_bus_pin, DS18B20_FUNC_SCRATCH_WRITE, 0);
  69. onewire_write_bytes(ds18b20_bus_pin, ds18b20_device_conf, 3, 0);
  70. }
  71. // Change sensor settings
  72. // Lua: ds18b20.setting(ROM, RES)
  73. static int ds18b20_lua_setting(lua_State *L) {
  74. // check rom table and resolution setting
  75. if (!lua_istable(L, 1) || !lua_isnumber(L, 2)) {
  76. return luaL_error(L, "wrong arg range");
  77. }
  78. ds18b20_device_res = luaL_checkinteger(L, 2);
  79. if (!((ds18b20_device_res == 9) || (ds18b20_device_res == 10) || (ds18b20_device_res == 11) || (ds18b20_device_res == 12))) {
  80. return luaL_error(L, "Invalid argument: resolution");
  81. }
  82. // no change to th and tl setting
  83. ds18b20_device_conf[0] = DS18B20_EEPROM_TH;
  84. ds18b20_device_conf[1] = DS18B20_EEPROM_TL;
  85. ds18b20_device_conf[2] = ((ds18b20_device_res - 9) << 5) + 0x1F;
  86. uint8_t table_len = lua_objlen(L, 1);
  87. const char *str[table_len];
  88. const char *sep = ":";
  89. uint8_t string_index = 0;
  90. lua_pushnil(L);
  91. while (lua_next(L, -3)) {
  92. str[string_index] = lua_tostring(L, -1);
  93. lua_pop(L, 1);
  94. string_index++;
  95. }
  96. lua_pop(L, 1);
  97. for (uint8_t i = 0; i < string_index; i++) {
  98. for (uint8_t j = 0; j < 8; j++) {
  99. ds18b20_device_rom[j] = strtoul(str[i], NULL, 16);
  100. str[i] = strchr(str[i], *sep);
  101. if (str[i] == NULL || *str[i] == '\0') break;
  102. str[i]++;
  103. }
  104. ds18b20_set_device(ds18b20_device_rom);
  105. }
  106. // set conversion delay once to max if sensors with higher resolution still on the bus
  107. ds18b20_device_res = 12;
  108. return 0;
  109. }
  110. // Reads sensor values from all devices
  111. // Lua: ds18b20.read(function(INDEX, ROM, RES, TEMP, TEMP_DEC, PAR) print(INDEX, ROM, RES, TEMP, TEMP_DEC, PAR) end, ROM[, FAMILY])
  112. static int ds18b20_lua_read(lua_State *L) {
  113. luaL_argcheck(L, (lua_type(L, 1) == LUA_TFUNCTION || lua_type(L, 1) == LUA_TLIGHTFUNCTION), 1, "Must be function");
  114. lua_pushvalue(L, 1);
  115. ds18b20_timer_ref = luaL_ref(L, LUA_REGISTRYINDEX);
  116. if (!lua_istable(L, 2)) {
  117. return luaL_error(L, "wrong arg range");
  118. }
  119. if (lua_isnumber(L, 3)) {
  120. ds18b20_device_family = luaL_checkinteger(L, 3);
  121. onewire_target_search(ds18b20_bus_pin, ds18b20_device_family);
  122. ds18b20_table_offset = -3;
  123. } else {
  124. ds18b20_table_offset = -2;
  125. }
  126. lua_pushvalue(L, 2);
  127. ds18b20_table_ref = luaL_ref(L, LUA_REGISTRYINDEX);
  128. lua_pushnil(L);
  129. if (lua_next(L, ds18b20_table_offset)) {
  130. lua_pop(L, 2);
  131. ds18b20_device_search = 0;
  132. } else {
  133. ds18b20_device_search = 1;
  134. }
  135. os_timer_disarm(&ds18b20_timer);
  136. // perform a temperature conversion for all sensors and set timer
  137. onewire_reset(ds18b20_bus_pin);
  138. onewire_write(ds18b20_bus_pin, DS18B20_ROM_SKIP, 0);
  139. onewire_write(ds18b20_bus_pin, DS18B20_FUNC_CONVERT, 1);
  140. os_timer_setfn(&ds18b20_timer, (os_timer_func_t *)ds18b20_lua_readoutdone, NULL);
  141. switch (ds18b20_device_res) {
  142. case (9):
  143. os_timer_arm(&ds18b20_timer, 95, 0);
  144. break;
  145. case (10):
  146. os_timer_arm(&ds18b20_timer, 190, 0);
  147. break;
  148. case (11):
  149. os_timer_arm(&ds18b20_timer, 380, 0);
  150. break;
  151. case (12):
  152. os_timer_arm(&ds18b20_timer, 760, 0);
  153. break;
  154. }
  155. }
  156. static int ds18b20_read_device(uint8_t *ds18b20_device_rom) {
  157. lua_State *L = lua_getstate();
  158. if (onewire_crc8(ds18b20_device_rom,7) == ds18b20_device_rom[7]) {
  159. onewire_reset(ds18b20_bus_pin);
  160. onewire_select(ds18b20_bus_pin, ds18b20_device_rom);
  161. onewire_write(ds18b20_bus_pin, DS18B20_FUNC_POWER_READ, 0);
  162. if (onewire_read(ds18b20_bus_pin)) ds18b20_device_par = 0;
  163. else ds18b20_device_par = 1;
  164. onewire_reset(ds18b20_bus_pin);
  165. onewire_select(ds18b20_bus_pin, ds18b20_device_rom);
  166. onewire_write(ds18b20_bus_pin, DS18B20_FUNC_SCRATCH_READ, 0);
  167. onewire_read_bytes(ds18b20_bus_pin, ds18b20_device_scratchpad, 9);
  168. if (onewire_crc8(ds18b20_device_scratchpad,8) == ds18b20_device_scratchpad[8]) {
  169. lua_rawgeti(L, LUA_REGISTRYINDEX, ds18b20_timer_ref);
  170. lua_pushinteger(L, ds18b20_device_index);
  171. lua_pushfstring(L, "%d:%d:%d:%d:%d:%d:%d:%d", ds18b20_device_rom[0], ds18b20_device_rom[1], ds18b20_device_rom[2], ds18b20_device_rom[3], ds18b20_device_rom[4], ds18b20_device_rom[5], ds18b20_device_rom[6], ds18b20_device_rom[7]);
  172. ds18b20_device_scratchpad_conf = (ds18b20_device_scratchpad[4] >> 5) + 9;
  173. ds18b20_device_scratchpad_temp = ((int8_t)(ds18b20_device_scratchpad[1] << 4) + (ds18b20_device_scratchpad[0] >> 4) + ((double)(ds18b20_device_scratchpad[0] & 0x0F) / 16));
  174. ds18b20_device_scratchpad_temp_dec = ((double)(ds18b20_device_scratchpad[0] & 0x0F) / 16 * 1000);
  175. if (ds18b20_device_scratchpad_conf >= ds18b20_device_res) {
  176. ds18b20_device_res = ds18b20_device_scratchpad_conf;
  177. }
  178. lua_pushinteger(L, ds18b20_device_scratchpad_conf);
  179. lua_pushnumber(L, ds18b20_device_scratchpad_temp);
  180. lua_pushinteger(L, ds18b20_device_scratchpad_temp_dec);
  181. lua_pushinteger(L, ds18b20_device_par);
  182. lua_pcall(L, 6, 0, 0);
  183. ds18b20_device_index++;
  184. }
  185. }
  186. }
  187. static int ds18b20_lua_readoutdone(void) {
  188. lua_State *L = lua_getstate();
  189. os_timer_disarm(&ds18b20_timer);
  190. ds18b20_device_index = 1;
  191. // set conversion delay to min and change it after finding the sensor with the highest resolution setting
  192. ds18b20_device_res = 9;
  193. if (ds18b20_device_search) {
  194. // iterate through all sensors on the bus and read temperature, resolution and parasitc settings
  195. while (onewire_search(ds18b20_bus_pin, ds18b20_device_rom)) {
  196. ds18b20_read_device(ds18b20_device_rom);
  197. }
  198. } else {
  199. lua_rawgeti(L, LUA_REGISTRYINDEX, ds18b20_table_ref);
  200. uint8_t table_len = lua_objlen(L, -1);
  201. const char *str[table_len];
  202. const char *sep = ":";
  203. uint8_t string_index = 0;
  204. lua_pushnil(L);
  205. while (lua_next(L, -2)) {
  206. str[string_index] = lua_tostring(L, -1);
  207. lua_pop(L, 1);
  208. string_index++;
  209. }
  210. lua_pop(L, 1);
  211. for (uint8_t i = 0; i < string_index; i++) {
  212. for (uint8_t j = 0; j < 8; j++) {
  213. ds18b20_device_rom[j] = strtoul(str[i], NULL, 16);
  214. str[i] = strchr(str[i], *sep);
  215. if (str[i] == NULL || *str[i] == '\0') break;
  216. str[i]++;
  217. }
  218. ds18b20_read_device(ds18b20_device_rom);
  219. }
  220. }
  221. luaL_unref(L, LUA_REGISTRYINDEX, ds18b20_table_ref);
  222. ds18b20_table_ref = LUA_NOREF;
  223. luaL_unref(L, LUA_REGISTRYINDEX, ds18b20_timer_ref);
  224. ds18b20_timer_ref = LUA_NOREF;
  225. }
  226. static const LUA_REG_TYPE ds18b20_map[] = {
  227. { LSTRKEY( "read" ), LFUNCVAL(ds18b20_lua_read) },
  228. { LSTRKEY( "setting" ), LFUNCVAL(ds18b20_lua_setting) },
  229. { LSTRKEY( "setup" ), LFUNCVAL(ds18b20_lua_setup) },
  230. { LNILKEY, LNILVAL }
  231. };
  232. NODEMCU_MODULE(DS18B20, "ds18b20", ds18b20_map, NULL);