Re-write DS18B20 asynchronous example (#1820)

This commit is contained in:
vsky 2017-02-25 22:56:45 +01:00 committed by Marcel Stör
parent 8931f09ce4
commit 5feae3fee1
5 changed files with 182 additions and 461 deletions

View File

@ -1,27 +1,26 @@
-- encoder module is needed only for debug output; lines can be removed if no
-- debug output is needed and/or encoder module is missing
t = require("ds18b20")
pin = 3 -- gpio0 = 3, gpio2 = 4
-- ESP-01 GPIO Mapping
gpio0 = 3
gpio2 = 4
function readout(temp)
for addr, temp in pairs(temp) do
-- print(string.format("Sensor %s: %s 'C", addr, temp))
print(string.format("Sensor %s: %s 'C", encoder.toBase64(addr), temp)) -- readable address with base64 encoding is preferred when encoder module is available
end
t.setup(gpio0)
addrs = t.addrs()
if (addrs ~= nil) then
print("Total DS18B20 sensors: "..table.getn(addrs))
-- Module can be released when it is no longer needed
t = nil
package.loaded["ds18b20"]=nil
end
-- Just read temperature
print("Temperature: "..t.read().."'C")
-- Get temperature of first detected sensor in Fahrenheit
print("Temperature: "..t.read(nil,t.F).."'F")
-- Query the second detected sensor, get temperature in Kelvin
if (table.getn(addrs) >= 2) then
print("Second sensor: "..t.read(addrs[2],t.K).."'K")
-- t:readTemp(readout) -- default pin value is 3
t:readTemp(readout, pin)
if t.sens then
print("Total number of DS18B20 sensors: "..table.getn(t.sens))
for i, s in ipairs(t.sens) do
-- print(string.format(" sensor #%d address: %s%s", i, s.addr, s.parasite == 1 and " (parasite)" or ""))
print(string.format(" sensor #%d address: %s%s", i, encoder.toBase64(s.addr), s.parasite == 1 and " (parasite)" or "")) -- readable address with base64 encoding is preferred when encoder module is available
end
end
-- Don't forget to release it after use
t = nil
ds18b20 = nil
package.loaded["ds18b20"]=nil

View File

@ -1,27 +1,36 @@
require('ds18b20')
t = require('ds18b20')
port = 80
pin = 3 -- gpio0 = 3, gpio2 = 4
gconn = {} -- global variable for connection
-- ESP-01 GPIO Mapping
gpio0, gpio2 = 3, 4
function readout(temp)
local resp = "HTTP/1.1 200 OK\nContent-Type: text/html\nRefresh: 5\n\n" ..
"<!DOCTYPE HTML>" ..
"<html><body>" ..
"<b>ESP8266</b></br>"
for addr, temp in pairs(temp) do
-- resp = resp .. string.format("Sensor %s: %s &#8451</br>", addr, temp)
resp = resp .. string.format("Sensor %s: %s &#8451</br>", encoder.toBase64(addr), temp) -- readable address with base64 encoding is preferred when encoder module is available
end
resp = resp ..
"Node ChipID: " .. node.chipid() .. "<br>" ..
"Node MAC: " .. wifi.sta.getmac() .. "<br>" ..
"Node Heap: " .. node.heap() .. "<br>" ..
"Timer Ticks: " .. tmr.now() .. "<br>" ..
"</html></body>"
ds18b20.setup(gpio0)
gconn:send(resp)
gconn:on("sent",function(conn) conn:close() end)
end
srv=net.createServer(net.TCP)
srv:listen(port,
function(conn)
conn:send("HTTP/1.1 200 OK\nContent-Type: text/html\nRefresh: 5\n\n" ..
"<!DOCTYPE HTML>" ..
"<html><body>" ..
"<b>ESP8266</b></br>" ..
"Temperature : " .. ds18b20.read() .. "<br>" ..
"Node ChipID : " .. node.chipid() .. "<br>" ..
"Node MAC : " .. wifi.sta.getmac() .. "<br>" ..
"Node Heap : " .. node.heap() .. "<br>" ..
"Timer Ticks : " .. tmr.now() .. "<br>" ..
"</html></body>")
conn:on("sent",function(conn) conn:close() end)
gconn = conn
-- t:readTemp(readout) -- default pin value is 3
t:readTemp(readout, pin)
end
)

View File

@ -8,150 +8,47 @@ ds18b20 = require("ds18b20")
ds18b20 = nil
package.loaded["ds18b20"]=nil
```
##Constant
C, F, K
<a id="ds18b20_setup"></a>
##setup()
####Description
Setting the pin of DS18B20.<br />
##readTemp()
Scans the bus for DS18B20 sensors, starts a readout (conversion) for all sensors and calls a callback function when all temperatures are available. Powered sensors are read at once first. Parasit-powered sensors are read one by one. The first parasit-powered sensor is read together with all powered sensors.
The module requires `ow` module.
The also module uses `encoder` module for printing debug information with more readable representation of sensor address (`encoder.toBase64()`).
####Syntax
setup(pin)
`readTemp(callback, pin)`
####Parameters
pin: 1~10, IO index. If parameter is nil, it will use pin 9(GPIO2) automatically.<br />
- `callback` function that receives all results when all conversions finish. The callback funciton has one parameter - an array addressed by sensor addresses and a value of the temperature (string for integer version).
- `pin` pin of the one-wire bus. If nil, GPIO0 (3) is used.
####Returns
nil
####Example
```lua
ds18b20 = require("ds18b20")
ds18b20.setup(9)
-- Don't forget to release it after use
ds18b20 = nil
package.loaded["ds18b20"]=nil
```
t = require("ds18b20")
pin = 3 -- gpio0 = 3, gpio2 = 4
####See also
**-** []()
function readout(temp)
for addr, temp in pairs(temp) do
print(string.format("Sensor %s: %s 'C", encoder.toBase64(addr), temp))
end
<a id="ds18b20_addrs"></a>
## addrs()
####Description
Return a table contain all of the addresses of DS18B20 on one-wire. If the setup(pin) function not executed, the pin 9(GPIO2) will be initialized as one-wire mode automatically. <br />
####Syntax
addrs()
####Parameters
nil
####Returns
addrs: A table contain all of the addresses of DS18B20 on one-wire. Every address is a string. If failed, it will be nil. <br />
####Example
```lua
ds18b20 = require("ds18b20")
ds18b20.setup(9)
addrs = ds18b20.addrs()
if (addrs ~= nil) then
print("Total DS18B20 sensors: "..table.getn(addrs))
-- Module can be released when it is no longer needed
t = nil
package.loaded["ds18b20"]=nil
end
-- t:readTemp(readout) -- default pin value is 3
t:readTemp(readout, pin)
if t.sens then
print("Total number of DS18B20 sensors: "..table.getn(t.sens))
for i, s in ipairs(t.sens) do
-- print(string.format(" sensor #%d address: %s%s", i, s.addr, s.parasite == 1 and " (parasite)" or ""))
print(string.format(" sensor #%d address: %s%s", i, encoder.toBase64(s.addr), s.parasite == 1 and " (parasite)" or "")) -- readable address with base64 encoding is preferred when encoder module is available
end
end
-- Don't forget to release it after use
ds18b20 = nil
package.loaded["ds18b20"]=nil
```
####See also
**-** []()
<a id="ds18b20_readNumber"></a>
## readNumber()
####Description
Read the value of temperature. If the setup(pin) function not executed, the pin 9(GPIO2) will be initialized as one-wire mode automatically. <br />
####Syntax
readNumber(addr, unit)
####Parameters
addr: string, the address of DS18B20. It will select the first address which be found when this parameter is nil.<br />
unit: integer, unit conversion. Only Constant is acceptable, such as C(Celsius),F(Fahrenheit) and K(Kelvin). If this parameter is nil, the constant C(Celsius) will be selected automatically. <br />
####Returns
t1: integer. The integer part of the temperature. If it read fails, return nil. <br />
t2: integer. The fractional part of the temperature. If it read fails, return nil. <br />
####Example
```lua
t=require("ds18b20")
t.setup(9)
addrs=t.addrs()
-- Total DS18B20 numbers, assume it is 2
print(table.getn(addrs))
-- The first DS18B20
print(t.readNumber(addrs[1],t.C))
print(t.readNumber(addrs[1],t.F))
print(t.readNumber(addrs[1],t.K))
-- The second DS18B20
print(t.readNumber(addrs[2],t.C))
print(t.readNumber(addrs[2],t.F))
print(t.readNumber(addrs[2],t.K))
-- Just read
print(t.readNumber())
-- Just read as fahrenheit
print(t.readNumber(nil,t.F))
-- Read as values
t1, t2 = t.readNumber()
-- Don't forget to release it after use
t = nil
ds18b20 = nil
package.loaded["ds18b20"]=nil
```
####See also
**-** []()
<a id="ds18b20_read"></a>
## read()
####Description
Read the string of temperature. If the setup(pin) function not executed, the pin 9(GPIO2) will be initialized as one-wire mode automatically. <br />
####Syntax
read(addr, unit)
####Parameters
addr: string, the address of DS18B20. It will select the first address which be found when this parameter is nil.<br />
unit: integer, unit conversion. Only Constant is acceptable, such as C(Celsius),F(Fahrenheit) and K(Kelvin). If this parameter is nil, the constant C(Celsius) will be selected automatically. <br />
####Returns
t: string. The string of the temperature. If it read fails, return nil.<br />
####Example
```lua
t=require("ds18b20")
t.setup(9)
addrs=t.addrs()
-- Total DS18B20 numbers, assume it is 2
print(table.getn(addrs))
-- The first DS18B20
print(t.read(addrs[1],t.C))
print(t.read(addrs[1],t.F))
print(t.read(addrs[1],t.K))
-- The second DS18B20
print(t.read(addrs[2],t.C))
print(t.read(addrs[2],t.F))
print(t.read(addrs[2],t.K))
-- Just read
print(t.read())
-- Just read as centigrade
print(t.read(nil,t.C))
-- Don't forget to release it after use
t = nil
ds18b20 = nil
package.loaded["ds18b20"]=nil
```
####See also
**-** []()

View File

@ -1,160 +0,0 @@
#DS18B20 模块
##引用
```lua
ds18b20 = require("ds18b20")
```
#释放
```lua
ds18b20 = nil
package.loaded["ds18b20"]=nil
```
##常量
C, F, K
<a id="ds18b20_setup"></a>
##setup()
####描述
设置DS18B20所在的管脚(pin)。<br />
####语法
setup(pin)
####参数
pin: 1~10, IO 编号。如果参数为nil会自动设定为9(GPIO2).<br />
####返回值
nil
####示例
```lua
ds18b20 = require("ds18b20")
ds18b20.setup(9)
-- Don't forget to release it after use
ds18b20 = nil
package.loaded["ds18b20"]=nil
```
####参见
**-** []()
<a id="ds18b20_addrs"></a>
## addrs()
####描述
返回单总线上所有DS18B20器件的地址列表(table)。如果没有执行过setup(pin)则会自动对引脚9(GPIO2)进行单总线模式初始化。<br />
####语法
addrs()
####参数
nil
####返回值
addrs: 返回包含单总线上所有DS18B20器件的地址列表(table)。其中地址是字符串类型(String)。如果失败则返回nil. <br />
####示例
```lua
ds18b20 = require("ds18b20")
ds18b20.setup(9)
addrs = ds18b20.addrs()
if (addrs ~= nil) then
print("Total DS18B20 sensors: "..table.getn(addrs))
end
-- Don't forget to release it after use
ds18b20 = nil
package.loaded["ds18b20"]=nil
```
####参见
**-** []()
<a id="ds18b20_readNumber"></a>
## readNumber()
####描述
读取温度数值。如果没有执行过setup(pin)则会自动对引脚9(GPIO2)进行单总线模式初始化。 <br />
####语法
readNumber(addr, unit)
####参数
addr: 字符串, DS18B20地址。 如果该参数为nil会自动选择第一个发现的地址。<br />
unit: 单位转换只接受常量C(摄氏度)F(华氏度) K(开氏度)。如果该参数为nil会自动选择常量C(摄氏度) 。<br />
####返回值
t1: 数值温度的整数部分。如果读取失败返回nil.<br />
t2: 数值温度的小数部分。如果读取失败返回nil.<br />
####示例
```lua
t=require("ds18b20")
t.setup(9)
addrs=t.addrs()
-- Total DS18B20 numbers, assume it is 2
print(table.getn(addrs))
-- The first DS18B20
print(t.readNumber(addrs[1],t.C))
print(t.readNumber(addrs[1],t.F))
print(t.readNumber(addrs[1],t.K))
-- The second DS18B20
print(t.readNumber(addrs[2],t.C))
print(t.readNumber(addrs[2],t.F))
print(t.readNumber(addrs[2],t.K))
-- Just read
print(t.readNumber())
-- Just read as fahrenheit
print(t.readNumber(nil,t.F))
-- Read as values
t1, t2 = t.readNumber()
-- Don't forget to release it after use
t = nil
ds18b20 = nil
package.loaded["ds18b20"]=nil
```
####参见
**-** []()
<a id="ds18b20_read"></a>
## read()
####描述
读取温度字符串。如果没有执行过setup(pin)则会自动对引脚9(GPIO2)进行单总线模式初始化。 <br />
####语法
read(addr, unit)
####参数
addr: 字符串, DS18B20地址。 如果该参数为nil会自动选择第一个发现的地址。<br />
unit: 单位转换只接受常量C(摄氏度)F(华氏度) K(开氏度)。如果该参数为nil会自动选择常量C(摄氏度) 。<br />
####返回值
t: 字符串表示成字符串形式的温度。如果读取失败返回nil.<br />
####示例
```lua
t=require("ds18b20")
t.setup(9)
addrs=t.addrs()
-- Total DS18B20 numbers, assume it is 2
print(table.getn(addrs))
-- The first DS18B20
print(t.read(addrs[1],t.C))
print(t.read(addrs[1],t.F))
print(t.read(addrs[1],t.K))
-- The second DS18B20
print(t.read(addrs[2],t.C))
print(t.read(addrs[2],t.F))
print(t.read(addrs[2],t.K))
-- Just read
print(t.read())
-- Just read as centigrade
print(t.read(nil,t.C))
-- Don't forget to release it after use
t = nil
ds18b20 = nil
package.loaded["ds18b20"]=nil
```
####参见
**-** []()

View File

@ -1,143 +1,119 @@
--------------------------------------------------------------------------------
-- DS18B20 one wire module for NODEMCU
-- NODEMCU TEAM
-- LICENCE: http://opensource.org/licenses/MIT
-- Vowstar <vowstar@nodemcu.com>
-- 2015/02/14 sza2 <sza2trash@gmail.com> Fix for negative values
-- by @voborsky, @devsaurus
-- encoder module is needed only for debug output; lines can be removed if no
-- debug output is needed and/or encoder module is missing
--
-- by default the module is for integer version, comment integer version and
-- uncomment float version part for float version
--------------------------------------------------------------------------------
-- Set module name as parameter of require
local modname = ...
local M = {}
_G[modname] = M
--------------------------------------------------------------------------------
-- Local used variables
--------------------------------------------------------------------------------
-- DS18B20 dq pin
local pin = nil
-- DS18B20 default pin
local defaultPin = 9
--------------------------------------------------------------------------------
-- Local used modules
--------------------------------------------------------------------------------
-- Table module
local table = table
-- String module
local string = string
-- One wire module
local ow = ow
-- Timer module
local tmr = tmr
-- Limited to local environment
setfenv(1,M)
--------------------------------------------------------------------------------
-- Implementation
--------------------------------------------------------------------------------
C = 'C'
F = 'F'
K = 'K'
function setup(dq)
pin = dq
if(pin == nil) then
pin = defaultPin
end
ow.setup(pin)
end
function addrs()
setup(pin)
tbl = {}
ow.reset_search(pin)
repeat
addr = ow.search(pin)
if(addr ~= nil) then
table.insert(tbl, addr)
return({
pin=3,
sens={},
temp={},
conversion = function(self)
local pin = self.pin
for i,s in ipairs(self.sens) do
if s.status == 0 then
print("starting conversion:", encoder.toBase64(s.addr), s.parasite == 1 and "parasite" or " ")
ow.reset(pin)
ow.select(pin, s.addr) -- select the sensor
ow.write(pin, 0x44, 1) -- and start conversion
s.status = 1
if s.parasite == 1 then break end -- parasite sensor blocks bus during conversion
end
end
tmr.wdclr()
until (addr == nil)
ow.reset_search(pin)
return tbl
end
function readNumber(addr, unit)
result = nil
setup(pin)
flag = false
if(addr == nil) then
tmr.alarm(tmr.create(), 750, tmr.ALARM_SINGLE, function() self:readout() end)
end,
readTemp = function(self, cb, lpin)
local pin = self.pin
self.cb = cb
self.temp={}
if lpin then pin = lpin end
ow.setup(pin)
self.sens={}
ow.reset_search(pin)
count = 0
repeat
count = count + 1
-- ow.target_search(pin,0x28)
-- search the first device
local addr = ow.search(pin)
-- and loop through all devices
while addr do
-- search next device
local crc=ow.crc8(string.sub(addr,1,7))
if (crc==addr:byte(8)) and ((addr:byte(1)==0x10) or (addr:byte(1)==0x28)) then
ow.reset(pin)
ow.select(pin, addr) -- select the found sensor
ow.write(pin, 0xB4, 1) -- Read Power Supply [B4h]
local parasite = (ow.read(pin)==0 and 1 or 0)
table.insert(self.sens,{addr=addr, parasite=parasite, status=0})
print("contact: ", encoder.toBase64(addr), parasite == 1 and "parasite" or " ")
end
addr = ow.search(pin)
tmr.wdclr()
until((addr ~= nil) or (count > 100))
ow.reset_search(pin)
end
if(addr == nil) then
return result
end
crc = ow.crc8(string.sub(addr,1,7))
if (crc == addr:byte(8)) then
if ((addr:byte(1) == 0x10) or (addr:byte(1) == 0x28)) then
-- print("Device is a DS18S20 family device.")
ow.reset(pin)
ow.select(pin, addr)
ow.write(pin, 0x44, 1)
-- tmr.delay(1000000)
present = ow.reset(pin)
ow.select(pin, addr)
ow.write(pin,0xBE,1)
-- print("P="..present)
data = nil
data = string.char(ow.read(pin))
for i = 1, 8 do
data = data .. string.char(ow.read(pin))
end
-- print(data:byte(1,9))
crc = ow.crc8(string.sub(data,1,8))
-- print("CRC="..crc)
if (crc == data:byte(9)) then
t = (data:byte(1) + data:byte(2) * 256)
if (t > 32767) then
t = t - 65536
end
if (addr:byte(1) == 0x28) then
t = t * 625 -- DS18B20, 4 fractional bits
else
t = t * 5000 -- DS18S20, 1 fractional bit
end
if(unit == nil or unit == 'C') then
-- do nothing
elseif(unit == 'F') then
t = t * 1.8 + 320000
elseif(unit == 'K') then
t = t + 2731500
else
return nil
end
t = t / 10000
return t
end
tmr.wdclr()
else
-- print("Device family is not recognized.")
end
else
-- print("CRC is not valid!")
end
return result
end
-- place powered sensors first
table.sort(self.sens, function(a,b) return a.parasite<b.parasite end)
node.task.post(node.task.MEDIUM_PRIORITY, function() self:conversion() end)
end,
readout=function(self)
local pin = self.pin
local next = false
if not self.sens then return 0 end
for i,s in ipairs(self.sens) do
-- print(encoder.toBase64(s.addr), s.status)
if s.status == 1 then
ow.reset(pin)
ow.select(pin, s.addr) -- select the sensor
ow.write(pin, 0xBE, 0) -- READ_SCRATCHPAD
data = ow.read_bytes(pin, 9)
function read(addr, unit)
t = readNumber(addr, unit)
if (t == nil) then
return nil
else
return t
local t=(data:byte(1)+data:byte(2)*256)
if (t > 0x7fff) then t = t - 0x10000 end
if (s.addr:byte(1) == 0x28) then
t = t * 625 -- DS18B20, 4 fractional bits
else
t = t * 5000 -- DS18S20, 1 fractional bit
end
-- integer version
local sgn = t<0 and -1 or 1
local tA = sgn*t
local tH=tA/10000
local tL=(tA%10000)/1000 + ((tA%1000)/100 >= 5 and 1 or 0)
if tH and (tH~=85) then
self.temp[s.addr]=(sgn<0 and "-" or "")..tH.."."..tL
print(encoder.toBase64(s.addr),(sgn<0 and "-" or "")..tH.."."..tL)
s.status = 2
end
-- end integer version
-- -- float version
-- if t and (math.floor(t/10000)~=85) then
-- self.temp[s.addr]=t
-- print(encoder.toBase64(s.addr), t)
-- s.status = 2
-- end
-- -- end float version
end
next = next or s.status == 0
end
if next then
node.task.post(node.task.MEDIUM_PRIORITY, function() self:conversion() end)
else
self.sens = nil
if self.cb then
node.task.post(node.task.MEDIUM_PRIORITY, function() self.cb(self.temp) end)
end
end
end
end
})
-- Return module table
return M