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!
23 comments:
Hi,
Thank you for sharing teh code.
I tried it but I always get 255 as output (for h and l values)
I wonder if it is due to the lack of pull up resistors on SDA and SCL
Any idea please ?
Thanks
JP
Hi Jean-Pierre, If you receive always 255 it's a problem with your I2C bus communication. Be sure you have in place proper pullup resistors and also check that SDA and SCL properly connected and defined for your setup.
Thank you for your reply.
I had at least two bugs :
GPIO0 and GPIO2 have now changed their numbering in lua's latest release.
and my device has not the 0x18 classical address but 0x48 (it was a sample device...)
Now seems to work (at least when adressing the device I get a "true" answer.)
Thank you
Good news, indeed. If you have proper communication with it on I2C the rest it's easy.
For the records: Accordigly with the datasheet for obtaining device I2C address (A6A5A4A3A2A1A0) you have 2 variants for address code - A6, A5, A4, A3 = 0x18 or 0x48 + Add your own choice of user selectable slave address with A2,A1,A0 pins and the result it's your device address.
Hi
Can you please make code for MPU6050 modul to get accelerometer, gyroscope and temperature values.
Thank you
Unfortunately I don't have a MPU6050 module.
Are you talking about something like this one? http://www.ebay.com/itm/171907295226
Yes. Thats the one, and I can't make it to work.
Cannot find anybody with one MPU6050 around, ordered one from Ebay, but it will take some time ...
Okay, If you get it working please let me know.
Thank you.
I have received the MPU6050 Modules. I will post a related article this days, start it already. It's working OK.
And the related MPU6050 Article : http://www.esp8266-projects.com/2015/12/mailbag-mpu6050-module-i2c-driver-init.html
Do you have any experience using the MLX90614. I've been trying it using the same procedure you documented here but it's just not working out. From what I've found it should work with normal I2C...
I don't have such a module but if is for interest for many of you, I can order some. What's more exactly behind the "not working"? is it not responding at all or just cannot obtain the right values from it?
I just get 255 on all reads which I'm not even sure is right because when I test scanning for I2C devices for all device names on all pins my device doesn't even show up. I thought it showed up once but I can't get to that again. I also purchased 5, and all 5 of them cannot be found....
I purchased the breakout board so it has all the capacitors and resistors on it already, so I don't think I need any more pull-ups
I think its "not responding at all" rather than just returning bad values.
255 looks like as you said, no response at all. I will suggest you to check your I2C bus connections and also might be a good idea to take a look at this tutorial, that is explaining a lot about some I2C init errors: http://www.esp8266-projects.com/2015/12/mailbag-mpu6050-module-i2c-driver-init.html.
AND
also check your MLX90614 IC version! From datasheet it looks like they are 2 available models, 3.3V and 5V!
I'm not able to find any MLX90614 close around but will do my best to grab some :)
If anybody want to donate modules, devices, etc, for evaluations and tests requests, please feel free to drop a line.
Hi, can you explain me, how i should obtain the values of dev_addr and reg_addr. I´m working for first time with SparkFun Analog to Digital Stereo Converter Breakout - PCM1803A to sample audio signals and to send to another NodeMCU ESP8266.
First, i have done this:
id = 0 -- Numero del Bus
sda = 1
gpio.mode(sda,gpio.OUTPUT)
scl = 2
gpio.mode(scl,gpio.OUTPUT)
-- Inicializa i2c, configura pin1 como sda, y el pin2 como scl
i2c.setup(id, sda, scl, i2c.SLOW)
-- user defined function: read from reg_addr content of dev_addr
function read_reg(dev_addr, reg_addr)
i2c.start(id)
i2c.address(id, dev_addr, i2c.TRANSMITTER)
i2c.write(id, reg_addr)
i2c.stop(id)
i2c.start(id)
i2c.address(id, dev_addr, i2c.RECEIVER)
c = i2c.read(id, 3)
i2c.stop(id)
return c
end
-- get content of register 0xAA of device 0x77
reg = read_reg(0x77, 0xAA) --read_reg(dev_addr, reg_addr)
--print(string.byte(reg))
How, I know the right values for this device, and how i can see the samples in real time.
Thanks for share
Hi Andres,
I don't have such a board or chip around, but I think you are looking in the wrong direction. From the datasheet it looks like that PCM1803A ADC is using a I2S ( inter-IC SOUND bus) – a serial link especially for digital audio interface, not I2C. And it makes more sense to be so, as high speed audio sampling can be done on I2S interface.
Thanks Tracker J, I was doing a grand mistake. Now i have to redo how to conect these devices or definetly change it.
Do you know some device that i can use for this objetive? I need to sample audio signals but the maximum sample rate that has the ESP8266 is not enough. First i used MCP3201 (ADC with SPI) But it does not work. I could not make the connection between them. Now, i´m going to research how do it in a diferent way, so i hear Tips.
The general idea is to then send the audio data over Wi - Fi using a UDP protocol. I already did , but I fail even sampling
Thanks for share
Andres
Can anyone explain what this following script does.
I can not understand how it identifie dev_addr,reg_addr. are they variables?
read_reg = function(self, dev_addr, reg_addr)
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
I have nfc board(PN532) which I want to interface with ESP8266-12e board through I2C communication. can anybody help me out with the code. any similer example will be helpful to make it happen.
Hi Axit,
Yes, they are variables and are defined above as needed.
Regarding the NFC Board I will be more than happy to help you with a driver for it but I don't have any around. If somebody can provide one and a decent datasheet will will give it a try :)
Happy breadboarding,
TJ.
Post a Comment