Skip to content

Commit d079b84

Browse files
fetchbotmarcelstoer
authored andcommitted
add ds18b20 module (#2003)
* add ds18b20 module * add intitial eeprom value definition * adjust read() function and address handling
1 parent fee5608 commit d079b84

File tree

4 files changed

+427
-0
lines changed

4 files changed

+427
-0
lines changed

app/include/user_modules.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
//#define LUA_USE_MODULES_CRON
3030
//#define LUA_USE_MODULES_CRYPTO
3131
#define LUA_USE_MODULES_DHT
32+
//#define LUA_USE_MODULES_DS18B20
3233
//#define LUA_USE_MODULES_ENCODER
3334
//#define LUA_USE_MODULES_ENDUSER_SETUP // USE_DNS in dhcpserver.h needs to be enabled for this module to work.
3435
#define LUA_USE_MODULES_FILE

app/modules/ds18b20.c

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

0 commit comments

Comments
 (0)