Skip to content

Commit 292b7e6

Browse files
author
vsky
committed
DS18B20 integer version
1 parent 97b68ba commit 292b7e6

File tree

2 files changed

+213
-2
lines changed

2 files changed

+213
-2
lines changed

docs/lua-modules/ds18b20.md

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,9 @@
55

66
This Lua module provides access to [DS18B20](https://datasheets.maximintegrated.com/en/ds/DS18B20.pdf) 1-Wire digital thermometer.
77

8-
!!! note
9-
The module requires `ow` C module built into firmware.
8+
For integer version of firmware use [ds18b20-integer.lua](../../lua_modules/ds18b20/ds18b20-integer.lua) module - measured temperatures are multiplied by 10000.
9+
10+
The module requires `ow` C module built into firmware.
1011

1112
### Require
1213
```lua
Lines changed: 210 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,210 @@
1+
--------------------------------------------------------------------------------
2+
-- DS18B20 one wire module for NODEMCU
3+
-- NODEMCU TEAM
4+
-- LICENCE: http://opensource.org/licenses/MIT
5+
-- @voborsky, @devsaurus, TerryE 26 Mar 2017
6+
--------------------------------------------------------------------------------
7+
local modname = ...
8+
9+
-- Used modules and functions
10+
local type, tostring, pcall, ipairs =
11+
type, tostring, pcall, ipairs
12+
-- Local functions
13+
local ow_setup, ow_search, ow_select, ow_read, ow_read_bytes, ow_write, ow_crc8,
14+
ow_reset, ow_reset_search, ow_skip, ow_depower =
15+
ow.setup, ow.search, ow.select, ow.read, ow.read_bytes, ow.write, ow.crc8,
16+
ow.reset, ow.reset_search, ow.skip, ow.depower
17+
18+
local node_task_post, node_task_LOW_PRIORITY = node.task.post, node.task.LOW_PRIORITY
19+
local string_char, string_dump = string.char, string.dump
20+
local now, tmr_create, tmr_ALARM_SINGLE = tmr.now, tmr.create, tmr.ALARM_SINGLE
21+
local table_sort, table_concat = table.sort, table.concat
22+
local math_floor = math.floor
23+
local file_open = file.open
24+
local conversion
25+
26+
local DS18B20FAMILY = 0x28
27+
local DS1920FAMILY = 0x10 -- and DS18S20 series
28+
local CONVERT_T = 0x44
29+
local READ_SCRATCHPAD = 0xBE
30+
local READ_POWERSUPPLY= 0xB4
31+
local MODE = 1
32+
33+
local pin, cb, unit = 3
34+
local status = {}
35+
36+
local debugPrint = function() return end
37+
38+
--------------------------------------------------------------------------------
39+
-- Implementation
40+
--------------------------------------------------------------------------------
41+
local function enable_debug()
42+
debugPrint = function (...) print(now(),' ', ...) end
43+
end
44+
45+
local function to_string(addr, esc)
46+
if type(addr) == 'string' and #addr == 8 then
47+
return ( esc == true and
48+
'"\\%u\\%u\\%u\\%u\\%u\\%u\\%u\\%u"' or
49+
'%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X '):format(addr:byte(1,8))
50+
else
51+
return tostring(addr)
52+
end
53+
end
54+
55+
local function readout(self)
56+
local next = false
57+
local sens = self.sens
58+
local temp = self.temp
59+
for i, s in ipairs(sens) do
60+
if status[i] == 1 then
61+
ow_reset(pin)
62+
local addr = s:sub(1,8)
63+
ow_select(pin, addr) -- select the sensor
64+
ow_write(pin, READ_SCRATCHPAD, MODE)
65+
local data = ow_read_bytes(pin, 9)
66+
67+
local t=(data:byte(1)+data:byte(2)*256)
68+
-- t is actually signed so process the sign bit and adjust for fractional bits
69+
-- the DS18B20 family has 4 fractional bits and the DS18S20s, 1 fractional bit
70+
t = ((t <= 32767) and t or t - 65536) *
71+
((addr:byte(1) == DS18B20FAMILY) and 625 or 5000)
72+
local crc, b9 = ow_crc8(string.sub(data,1,8)), data:byte(9)
73+
74+
if unit == 'F' then
75+
t = (t * 18)/10 + 320000
76+
elseif unit == 'K' then
77+
t = t + 2731500
78+
end
79+
local sgn = t<0 and -1 or 1
80+
local tA = sgn*t
81+
local tH=tA/10000
82+
local tL=(tA%10000)/1000 + ((tA%1000)/100 >= 5 and 1 or 0)
83+
84+
if tH and (t~=850000) then
85+
debugPrint(to_string(addr),(sgn<0 and "-" or "")..tH.."."..tL, crc, b9)
86+
if crc==b9 then temp[addr]=t end
87+
status[i] = 2
88+
end
89+
end
90+
next = next or status[i] == 0
91+
end
92+
if next then
93+
node_task_post(node_task_LOW_PRIORITY, function() return conversion(self) end)
94+
else
95+
--sens = {}
96+
if cb then
97+
node_task_post(node_task_LOW_PRIORITY, function() return cb(temp) end)
98+
end
99+
end
100+
end
101+
102+
conversion = (function (self)
103+
local sens = self.sens
104+
local powered_only = true
105+
for _, s in ipairs(sens) do powered_only = powered_only and s:byte(9) ~= 1 end
106+
if powered_only then
107+
debugPrint("starting conversion: all sensors")
108+
ow_reset(pin)
109+
ow_skip(pin) -- skip ROM selection, talk to all sensors
110+
ow_write(pin, CONVERT_T, MODE) -- and start conversion
111+
for i, _ in ipairs(sens) do status[i] = 1 end
112+
else
113+
local started = false
114+
for i, s in ipairs(sens) do
115+
if status[i] == 0 then
116+
local addr, parasite = s:sub(1,8), s:byte(9) == 1
117+
if parasite and started then break end -- do not start concurrent conversion of powered and parasite
118+
debugPrint("starting conversion:", to_string(addr), parasite and "parasite" or "")
119+
ow_reset(pin)
120+
ow_select(pin, addr) -- select the sensor
121+
ow_write(pin, CONVERT_T, MODE) -- and start conversion
122+
status[i] = 1
123+
if parasite then break end -- parasite sensor blocks bus during conversion
124+
started = true
125+
end
126+
end
127+
end
128+
tmr_create():alarm(750, tmr_ALARM_SINGLE, function() return readout(self) end)
129+
end)
130+
131+
local function _search(self, lcb, lpin, search, save)
132+
self.temp = {}
133+
if search then self.sens = {}; status = {} end
134+
local sens = self.sens
135+
pin = lpin or pin
136+
137+
local addr
138+
if not search and #sens == 0 then
139+
-- load addreses if available
140+
debugPrint ("geting addreses from flash")
141+
local s,check,a = pcall(dofile, "ds18b20_save.lc")
142+
if s and check == "ds18b20" then
143+
for i = 1, #a do sens[i] = a[i] end
144+
end
145+
debugPrint (#sens, "addreses found")
146+
end
147+
148+
ow_setup(pin)
149+
if search or #sens == 0 then
150+
ow_reset_search(pin)
151+
-- ow_target_search(pin,0x28)
152+
-- search the first device
153+
addr = ow_search(pin)
154+
else
155+
for i, _ in ipairs(sens) do status[i] = 0 end
156+
end
157+
local function cycle()
158+
if addr then
159+
local crc=ow_crc8(addr:sub(1,7))
160+
if (crc==addr:byte(8)) and ((addr:byte(1)==DS1920FAMILY) or (addr:byte(1)==DS18B20FAMILY)) then
161+
ow_reset(pin)
162+
ow_select(pin, addr)
163+
ow_write(pin, READ_POWERSUPPLY, MODE)
164+
local parasite = (ow_read(pin)==0 and 1 or 0)
165+
sens[#sens+1]= addr..string_char(parasite)
166+
status[#sens] = 0
167+
debugPrint("contact: ", to_string(addr), parasite == 1 and "parasite" or "")
168+
end
169+
addr = ow_search(pin)
170+
node_task_post(node_task_LOW_PRIORITY, cycle)
171+
else
172+
ow_depower(pin)
173+
-- place powered sensors first
174+
table_sort(sens, function(a, b) return a:byte(9)<b:byte(9) end) -- parasite
175+
-- save sensor addreses
176+
if save then
177+
debugPrint ("saving addreses to flash")
178+
179+
local addr_list = {}
180+
for i =1, #sens do
181+
local s = sens[i]
182+
addr_list[i] = to_string(s:sub(1,8), true)..('.."\\%u"'):format(s:byte(9))
183+
end
184+
local save_statement = 'return "ds18b20", {' .. table_concat(addr_list, ',') .. '}'
185+
debugPrint (save_statement)
186+
local save_file = file_open("ds18b20_save.lc","w")
187+
save_file:write(string_dump(loadstring(save_statement)))
188+
save_file:close()
189+
end
190+
-- end save sensor addreses
191+
if lcb then node_task_post(node_task_LOW_PRIORITY, lcb) end
192+
end
193+
end
194+
cycle()
195+
end
196+
197+
local function read_temp(self, lcb, lpin, lunit, force_search, save_search)
198+
cb, unit = lcb, lunit or unit
199+
_search(self, function() return conversion(self) end, lpin, force_search, save_search)
200+
end
201+
202+
-- Set module name as parameter of require and return module table
203+
local M = {
204+
sens = {},
205+
temp = {},
206+
C = 'C', F = 'F', K = 'K',
207+
read_temp = read_temp, enable_debug = enable_debug
208+
}
209+
_G[modname or 'ds18b20'] = M
210+
return M

0 commit comments

Comments
 (0)