Reading Temperature Data from a MCP9808 using a Raspberry Pi

The MCP9808 is a temperature sensor that uses the I2C communication standard to transmit a continuously polled temperature. It supports an alarm function and a standby mode to save on power when called for. In this explaination we perform a few python comands to get the temperature from the sensor.

I2C on MCP9808
Microchip uses 0x18 for its primary address on this board, with 3 pins available on the chip to alter the address for I2C address collisions. When calling any register in the sensor you should expect to write or get a two byte response (MSB first, LSB last). I used the breakout board from Adafruit 1528-1032-ND, which already has some pullup resistors.

Registers to note:
0x01 : 0000000X 00011111: X here is the standby bit in the configuration, it defaults to 0, which is continuous polling mode. The temperature register is always updated, with a drawback to power consumption. Setting this bit to 1 will stop polling and conserve power.

0x05 : AAASMMMM LLLLLLLL: This register contains the 12bit floating point temperature where “A” is the alert information, “S” is the sign bit, and “M” and “L” stand for MSB and LSB respectively. The final output will appear as MMMMLLLL.LLLL.

Note that for this explanation I leave the Sign bit and Alert bits unimplemented, but it is needed if you are going to expect to measure subzero temperatures.

Implementation on a Raspberry PI:

What is nice about using Raspberry Pi to interface with I2C is the interactivity of a Python terminal. I used a Raspberry Pi 4 with the I2C enabled on a Raspbian distribution. Make sure your GPIOs going to 3V3, GND, SDA, and SCL going to the correct pins on the MCP9808. Open a terminal in Raspbian and perform the following three commands:

python
from smbus import SMBus
bus = SMBus(1)

This will create a bus object we will interface to, which will in turn collect the I2C data we request. Next, ask the chip for its temperature data:

temp_binary = format(bus.read_word_data(0x18, 0x05),‘016b’)

The bus.read_byte_data(Address, Register) will retrieve the data from the sensor, we use the enclosing format() function to read the information as a binary number, we do this to make pulling out the two bytes trivial. Python likes to use int or float normally and this gets in the way with more than one byte return values. We will index these in [0:8][8:16] order, with MSB existing at the latter half of the array.

image

Making Sense of the Output:
We can implement the following function to give us the Output correctly

def word_To_LSB_MSB(word):
return word[0:8], word[12 :16] // note that word indices [8,9,10,11] are not used in this example.

See this diagram for our desired output.

All that is left is putting the two back together and a little floating point math

LSB, MSB = word_To_LSB_MSB(temp_binary)
float(int(MSB + LSB,2)) / 16

image

Division by 16 will shift the result to MMMMLLLL.LLLL and give us decimal precision. Note that the result should come back in Celsius. In the case pictured above, the temperature we calculated was 23.3125 degrees Celsius from the binary floating number 00010111.0101

Saving power when you are done:
If you want to turn the device off when you are done simply set the standby bit for power a power saving mode:

bus.write_byte_data(0x18,0x01,0b00000001)

We write a byte since we only need to change the MSB in the MCP9809’s configuration register, by cutting the word short we don’t change what is in the LSB of the register.

You will have to power cycle the sensor or flush the register with a zero to return the MCP9808 to full operational functionality.

The datasheet from Microchip continues to be useful in application with this sensor, reference it regularly if you decide to implemnt the MCP9808. Note that some important features of the sensor have not been touched on, such as interrupts, the sign bit for negative temperatures, and standby operation.

Items used:

Raspberry Pi: 1690-RASPBERRYPI4B/4GB-ND
Breadboard wire in the female to male: 1568-1511-ND
Adafruit breakout board for the MCP9808: 1528-1032-ND

1 Like

Hey,
Can we use this temperature sensor in place of thermostats?
Does it work same as thermostats? and Is it possible to monitor its data?

Welcome to the community.

Assuming you mean a thermostat for a building’s heating.

It’s possible but it will cost more than a commercially available unit once you add the microcontroller, display, keypad and housing. Also, depending on your building insurance company, use of a roll your own thermostat may cause difficulties when making a claim for frozen pipe damage.

1 Like

Does anyone have a working copy of the code used in this example. Something I can copy and past from, not a picture. I have tried, many many times, typing it in but always get error messages. I feel something is missing. Variables being defined ahead of time, something.

MCP9808.txt (1.7 KB)

Here you go David, I haven’t run the code in awhile but if the Raspberry Pi foundation is on top of things it may not work due to this implementation using the Python 2.7 terminal.

I vaguely remember the Python 3 terminal run I did working though. Let me know if you have issues (With Pictures!) and I’d be happy to help step you though.

1 Like

The latest Raspberry Pi OS (formerly known as Raspbian) still has Python 2.7.16 installed.

Prefect and thank you very much. I am just learning Python and am using this project as a way of trying things out. I hope to make this into an emailing alarm if the freezer temp goes to low.

Again thanks. I am downloading a fresh copy of Raspian now.

David G.

1 Like

That code worked fine. All I needed to do is put in the correct address. 0x18

In the new code’

#Pool the contents of Register 0x05 for temperature data as a MSB, LSB pair;
#This comes back as a 16bits, so we use 16bit_to_MSB_LSB above to separate the binary string data
temp_MSB, temp_LSB = a16bit_to_MSB_LSB(format(bus.read_word_data(MCP9808,0x5), “016b”))

How are you removing the bits 12 - 15 , sign and the Temp alarm bits, so they don’t factor into the display temp?

In the first code listed in the above instructions you did the following

def word_To_LSB_MSB(word):
return word[0:8], word[12 :16] // note that word indices [8,9,10,11] are not used in this example.

Which looks like we left out the upper temp but read the alarm bits.

1 Like

That’s great, since you’re learning Python I recommend doing what I did when I started learning Python a couple years ago.

Try out the code in Python 3 and if it doesn’t work modify the code so that it runs. It’s generally been very easy for me. About 90% of the code I’ve converted from 2 to 3 has required either no conversion, or simply putting parenthesis around the print statement parameters.

Python 2 was terminated in January, it won’t even get fixes for dangerous security bugs from the Python team anymore. https://www.python.org/doc/sunset-python-2/
(They gave everybody a 9 year deadline in 2006 then extended it another 5 years)

I’m hoping Debian and everyone downstream, like Raspberry Pi OS, will change the default Python to 3 soon and even better remove Python 2 completely from the default distro (the few dinosaurs who still feel Python 2 is necessary can always install it themselves).

1 Like