As it was requested from you, my readers, in Part 3 of our CBDB saga, we will start building a simple, high precision, Temperature Data logger based on the MCP9808 chip, a ±0.5°C Maximum Accuracy Digital Temperature Sensor. As far as I know this is the first time NodeMCU float version I2C Driver for MCP9808.
Features
• Accuracy:
- ±0.25 (typical) from -40°C to +125°C
- ±0.5°C (maximum) from -20°C to 100°C
- ±1°C (maximum) from -40°C to +125°C
• User-Selectable Measurement Resolution:
- +0.5°C, +0.25°C, +0.125°C, +0.0625°C
• User-Programmable Temperature Limits:
- Temperature Window Limit
- Critical Temperature Limit
• User-Programmable Temperature Alert Output
• Operating Voltage Range: 2.7V to 5.5V
• Operating Current: 200 μA (typical)
• Shutdown Current: 0.1 μA (typical)
• 2-wire Interface: I2C/SMBus Compatible
• Available Packages: 2x3 DFN-8, MSOP-8
For more details, please see MCP9008 Datasheet
Don't be scared by the MSOP-8 package, with a small MSOP to DIP adapter will fit great in our CBDB extension slots it will not matter at all.
MSSOP8-DIP8 package adapter |
What we will need:
- CBDB Board
- USB adapter (take a look on Part 1 for details how to connect them together)
- MCP9808 Module from above
- LED module (if you want maybe a LED ticker)
CBDB with MCP9808 Temperture module |
CBDB with MCP9808 Temperature module + LED ticker |
For programming and uploading the driver and the software we will continue to use the LuaUploader as before.
Driver implementation.
As MCP9808 has a I2C compatible compatible interface, building a driver for it it's a pretty straigh forward process:
1. Init I2C bus/interface
dev_addr = 0x1F,
init = function (self, sda, scl)
self.id = 0
i2c.setup(self.id, sda, scl, i2c.SLOW)
end
2. Read / Write to/from the desired register location.
- READ Register function
i2c.start(self.id)
i2c.address(self.id, dev_addr ,i2c.TRANSMITTER)
i2c.write(self.id,reg_addr)
i2c.stop(self.id)
i2c.start(self.id)
i2c.address(self.id, dev_addr,i2c.RECEIVER)
c=i2c.read(self.id,2)
i2c.stop(self.id)
return c
end
- READ Temperature function
h, l = string.byte(self:read_reg(0x1F, 0x05), 1, 2)
h1=bit.band(h,0x1F)
--check if Ta > 0C or Ta<0C
Sgn = bit.band(h,0x10)
-- transform - CLEAR Sing BIT if Ta < 0C
h2 = bit.band(h1,0x0F)
tp = h2*16+l/16
--END calculate temperature for Ta > 0
return tp
end
NOTE: This is for Tambient > 0°C only. Take a look in the MCP9008 Datasheet . If you need it also on the negative temperature scale then you need to do some extra transformations as the temperature data is stored in the 16-bit read-only Ambient Temperature register Ta as 13-bit data in two’s complement format.
For testing, just save the code on ESP as 'mcp9808.lua', restart ESP and run:
require('mcp9808') --call for new created MCP9808 Module Driver
sda=2 --GPIO4 -- declare your I2C interface PIN's
scl=1 --GPIO5
mcp9808:init(sda, scl) -- initialize I2C
sda=2 --GPIO4 -- declare your I2C interface PIN's
scl=1 --GPIO5
mcp9808:init(sda, scl) -- initialize I2C
tp1 = mcp9808:readTemp() -- read temperature
=print(tp1) -- print it
=print(tp1) -- print it
Let's put it together :
If all ok, we can move to the next step, how to make the data available on the web.
For this one we will need
• WEB Server
srv=net.createServer(net.TCP)
srv:listen(80,
function(conn)
conn:on("receive",function(conn,payload) print(payload)
conn:send("HTTP/1.1 200 OK\n\n")
conn:send("<META HTTP-EQUIV=\"REFRESH\" CONTENT=\"5\">")
conn:send("<html><title>MCP9808 - Temperature Log Server - ESP8266</title><body>")
conn:send("<h1>ESP8266 Temperature Log Server - MCP9808</h1><BR>")
conn:send("Temperature : <b>" .. tp1 .. "°C</b><BR><BR>")
conn:send("Node.HEAP : <b>" .. node.heap() .. "</b><BR><BR>")
conn:send("IP ADDR : <b>".. wifi.sta.getip() .. "</b><BR>")
conn:send("Node MAC : <b>" .. wifi.sta.getmac() .. "</b><br>")
conn:send("TMR.NOW : <b>" .. tmr.now() .. "</b><BR<BR><BR>")
conn:send("</html></body>")
conn:on("sent",function(conn) conn:close() end)
end)
end)
srv:listen(80,
function(conn)
conn:on("receive",function(conn,payload) print(payload)
conn:send("HTTP/1.1 200 OK\n\n")
conn:send("<META HTTP-EQUIV=\"REFRESH\" CONTENT=\"5\">")
conn:send("<html><title>MCP9808 - Temperature Log Server - ESP8266</title><body>")
conn:send("<h1>ESP8266 Temperature Log Server - MCP9808</h1><BR>")
conn:send("Temperature : <b>" .. tp1 .. "°C</b><BR><BR>")
conn:send("Node.HEAP : <b>" .. node.heap() .. "</b><BR><BR>")
conn:send("IP ADDR : <b>".. wifi.sta.getip() .. "</b><BR>")
conn:send("Node MAC : <b>" .. wifi.sta.getmac() .. "</b><br>")
conn:send("TMR.NOW : <b>" .. tmr.now() .. "</b><BR<BR><BR>")
conn:send("</html></body>")
conn:on("sent",function(conn) conn:close() end)
end)
end)
• READ Temperature function
function readTMP()
mcp9808:init(sda, scl)
tp1 = mcp9808:readTemp()
print(tp1)
end
mcp9808:init(sda, scl)
tp1 = mcp9808:readTemp()
print(tp1)
end
• TIMER to establish how often we want the reading process to be done.
-- read data every 1sec for direct web reading
tmr.alarm(0, 1000, 1, function() readTMP() end )
tmr.alarm(0, 1000, 1, function() readTMP() end )
Save the code on ESP as 'web_temp.lua', restart ESP and run:
=wifi.sta.getip() -- find the IP Address where your Web Server will be
dofile("web_temp.lua") -- Start the Web Server
Open your favorite Web browser and type your nre Web Server IP address. If all ok, should look something like below :
tmr.now() -- for debug only, you can skip it
wifi.sta.getmac() -- for debug only, you can skip it
wifi.sta.getip() -- for debug only, you can skip itnode.heap()
dofile("web_temp.lua") -- needed to start Web Server and Temperature logger
Save the code on ESP as 'init.lua', restart ESP. It should reboot and restart the program and reinitialize the Web Server.
That's all for today, thank you for your great feedback and looking forward for your suggestions!