MCP9808 High Precision Temperature Sensor

Discuss development of drivers for external hardware and components, such as LCD screens, sensors, motor drivers, etc.
Target audience: Users and developers of drivers.
User avatar
kfricke
Posts: 330
Joined: Mon May 05, 2014 9:13 am
Location: Germany

MCP9808 High Precision Temperature Sensor

Postby kfricke » Sun Feb 07, 2016 12:17 am

Feel free to use this for anything you want...

Code: Select all

REG_CFG    = const(1)
REG_A_TEMP = const(5)
REG_M_ID   = const(6)
REG_D_ID   = const(7)
REG_T_RES  = const(8)

T_RES_MIN = const(0)
T_RES_LOW = const(1)
T_RES_AVG = const(2)
T_RES_MAX = const(3)

class MCP9808(object):
    def __init__(self, i2c=None, addr=0x18):
        assert i2c != None, 'No I2C object given!'
        self._i2c = i2c
        self._addr = addr
        self._check_device()

    def _send(self, buf):
        self._i2c.send(buf, self._addr)
       
    def _recv(self, n=2):
        return self._i2c.recv(n, self._addr)
   
    def _check_device(self):
        self._send(REG_M_ID)
        self._m_id = self._recv(2)
        if not self._m_id == b'\x00T':
            raise Exception("Invalid manufacturer ID: '%s'!" % self._m_id)
        self._send(REG_D_ID)
        self._d_id = self._recv(2)
        if not self._d_id == b'\x04\x00':
            raise Exception("Invalid device or revision ID: '%s'!" % self._d_id)
       
    # Set sensor into shutdown mode to draw less than 1 uA and disable
    # continous temperature conversion. When not in shutdown mode the sensor
    # does draw 200-400 uA.
    def set_shutdown(self, shdn=True):       
        self._send(REG_CFG)
        cfg = self._recv(2)
        b = bytearray()
        b.append(REG_CFG)
        if shdn:
            b.append(cfg[0] | 1)
        else:
            b.append(cfg[0] & ~1)
        b.append(cfg[1])
        self._send(b)
       
    # Read temperature in degree celsius and return float value
    def read(self):
        self._send(REG_A_TEMP)
        raw = self._recv(2)
        u = (raw[0] & 0x0f) << 4
        l = raw[1] / 16
        if raw[0] & 0x10 == 0x10:
            temp = 256 - (u + l)
        else:
            temp = u + l
        return temp
   
    # Read a temperature in degree celsius and return a tuple of two parts.
    # The first part is the decimal patr and the second the fractional part
    # of the value.
    # This method does avoid floating point arithmetic completely to support
    # plattforms missing float support.
    def read_int(self):
        self._send(REG_A_TEMP)
        raw = self._recv(2)
        u = (raw[0] & 0xf) << 4
        l = raw[1] >> 4
        if raw[0] & 0x10 == 0x10:
            temp = 256 - (u + l)
            frac = 256 - (raw[1] & 0x0f) * 100 >> 4
        else:
            temp = u + l
            frac = (raw[1] & 0x0f) * 100 >> 4
        return temp, frac
       
    # Sets the temperature resolution. Higher resolutions do yield longer
    # conversion times:
    #   Mode        Resolution  Conversion time
    # ------------------------------------------
    #   T_RES_MIN   0.5°C        30 ms
    #   T_RES_LOW   0.25°C       65 ms
    #   T_RES_AVG   0.125°C     130 ms
    #   T_RES_MAX   0.0625°C    250 ms
    #
    # On power up the mode is set to maximum resolution.
    def set_resolution(self, r):
        assert r in [0, 1, 2, 3], 'Invalid temperature resolution requested!'
        b = bytearray()
        b.append(REG_T_RES)
        b.append(r)
        self._send(b)

User avatar
kfricke
Posts: 330
Joined: Mon May 05, 2014 9:13 am
Location: Germany

Re: MCP9808 High Precision Temperature Sensor

Postby kfricke » Mon Feb 08, 2016 7:43 am

Now reasonably checked in on GitHub https://github.com/kfricke/micropython-mcp9808

Damien
Site Admin
Posts: 530
Joined: Mon Dec 09, 2013 5:02 pm

Re: MCP9808 High Precision Temperature Sensor

Postby Damien » Tue Feb 09, 2016 5:05 pm

Awesome, thank you!

User avatar
kfricke
Posts: 330
Joined: Mon May 05, 2014 9:13 am
Location: Germany

Re: MCP9808 High Precision Temperature Sensor

Postby kfricke » Tue Feb 09, 2016 7:11 pm

Just the little bit I can contribute. Keep up the great work!

User avatar
patvdleer
Posts: 36
Joined: Mon Jun 13, 2016 11:52 am
Location: Maastricht, NL
Contact:

Re: MCP9808 High Precision Temperature Sensor

Postby patvdleer » Tue Jun 14, 2016 10:35 am

Thanks!

I'm getting mine today delivered, should be a huge improvement over the DHT11s.
NodeMCU v0.9
WeMos D1 Mini

User avatar
patvdleer
Posts: 36
Joined: Mon Jun 13, 2016 11:52 am
Location: Maastricht, NL
Contact:

Re: MCP9808 High Precision Temperature Sensor

Postby patvdleer » Tue Jun 14, 2016 10:19 pm

I've updated the code to work on an ESP8266 as well, the I2C works a bit different...
https://github.com/patvdleer/micropython-mcp9808
NodeMCU v0.9
WeMos D1 Mini

User avatar
Petri
Posts: 6
Joined: Sun Dec 11, 2016 11:29 am
Location: Helsinki, Finland
Contact:

Re: MCP9808 High Precision Temperature Sensor

Postby Petri » Sun Dec 11, 2016 12:38 pm

EDIT: solution found to the issues below: on WiThumb, the internal pull-up resistors have to be enabled by using Pin.PULL_UP. More details at https://github.com/ThomasCLee/funnyvale/issues/3

-----------------

I am trying to read from MCP9808 on a WiThumb (https://funnyvale.com/withumb/). I have managed to install and test MicroPython (build from http://www.kaltpost.de/~wendlers/micropython/) on it.

If you have a WiThumb, here's how to get MicroPython on it: https://koodaamo.wordpress.com/2016/12/ ... umb-on-osx.

From the schematics and some other docs it I determined the I2C address for the temperature sensor on WiThumb is 0x1F rather than the commonly used 0x18.

I first set up I2C: i2c = I2C(scl=Pin(5), sda=Pin(4), freq=10000). No problem.

But then, i2c.readfrom_mem(0x1F, 5, 2) always returns b'\x00\x00'. No matter what register I try instead of 5, same result (tried all 1-16). Shouldn't it return something else to represent a temperature value? And AFAIK the other registers should return a manufacturer id (register 6) and device id (7)... What am I doing wrong or missing?

For what it's worth, the i2c object has following methods available: ['init', 'scan', 'start', 'stop', 'readinto', 'write', 'readfrom', 'readfrom_into', 'writeto', 'readfrom_mem', 'readfrom_mem_into', 'writeto_mem']. Doing scan() returns a whole bunch of values (25 or so of them), including the 0x1F mentioned above.


Return to “Drivers for External Components”

Who is online

Users browsing this forum: No registered users and 1 guest