MicroPython Driver for LM75A Sensor

LM75A Driver Code for micro:bit

Download as zip file

'''
LM75A temperature sensor
MicroPython driver for micro:bit

AUTHOR: fredscave.com
DATE  : 2025/04
VERSION : 1.10
'''

from microbit import i2c, sleep
from micropython import const

I2C_ADDR   = const(0x48) # A0, A1, A2 pins all to GND
REG_TEMP   = const(0x00)
REG_CONFIG = const(0x01)
REG_HYST   = const(0x02)
REG_OS     = const(0x03)

# Power-on default values
DEFAULT_CONFIG    = const(0x00)
DEFAULT_THYST_MSB = const(0x4B)
DEFAULT_THYST_LSB = const(0x00)
DEFAULT_OS_MSB    = const(0x50)
DEFAULT_OS_LSB    = const(0x00)

# Convert Centigrade to Fahrenheit
CtoF = lambda C: round((C * 9/5) +32, 1)

class LM75A():
    def __init__(self, Addr = I2C_ADDR):
        self.Addr = Addr

    #--------------------------------------------
    #               Public Methods
    #--------------------------------------------

    # Get temperature reading in Centigrade.
    # Resolution is 9-bits or 11-bits
    def Read(self, Res = 9):
        res = Res if (Res in [9, 11]) else 9
        i2c.write(self.Addr, bytes([REG_TEMP]))
        buf = i2c.read(self.Addr, 2)
        return LM75A._Convert(buf, res)

    #Resets configuration defaults to power-on values.
    def ResetDefaults(self):
        i2c.write(self.Addr, bytes([REG_CONFIG,
                                    DEFAULT_CONFIG]))
        i2c.write(self.Addr, bytes([REG_HYST,
                                    DEFAULT_THYST_MSB,
                                    DEFAULT_THYST_LSB]))
        i2c.write(self.Addr, bytes([REG_OS,
                                    DEFAULT_OS_MSB,
                                    DEFAULT_OS_LSB]))
                                    
    # Returns the Configuration register value
    def GetConfig(self):
        i2c.write(self.Addr, bytes([REG_CONFIG]))
        return i2c.read(self.Addr, 1)[0]                                

    # Sets the three user settable parameters in
    # the Configuration register.
    # Read the Datasheet for more details.
    def SetConfig(self, Queue = 1, Polarity = 0, CmpInt = 0):
        cmpint = CmpInt if (CmpInt in (0, 1)) else 0
        polarity = Polarity if (Polarity in (0, 1)) else 0
        t = (1, 2, 4, 6)
        if Queue in t:
            queue = t.index(Queue)
        else:
            queue = 0
        config = self.GetConfig()
        config = LM75A._ChangeBit(config, cmpint, 1)
        config = LM75A._ChangeBit(config, polarity, 2)
        config = LM75A._ChangeBit(config, queue & 0b01, 3)
        config = LM75A._ChangeBit(config, queue >> 1, 4)
        i2c.write(self.Addr, bytes([REG_CONFIG, config]))

    # Place the sensor in shutdown mode.
    def Off(self):
        i2c.write(self.Addr, bytes([REG_CONFIG]))
        config = i2c.read(self.Addr, 1)[0]
        config = config | 0x01
        i2c.write(self.Addr, bytes([REG_CONFIG, config]))

    # Wake the sensor if it is in shutdown mode.
    def On(self):
        i2c.write(self.Addr, bytes([REG_CONFIG]))
        config = i2c.read(self.Addr, 1)[0]
        config = config & 0b11111110
        i2c.write(self.Addr, bytes([REG_CONFIG, config]))
        sleep(300)

    # Set or get the Hysteresis Centigrade temperature.
    # This is used by the Watchdog. See the Datasheet
    # for more details.
    def Hyst(self, Temp = None):
        if Temp == None:
            i2c.write(self.Addr, bytes([REG_HYST]))
            binary = i2c.read(self.Addr, 2)[0]
            return LM75A._fromComp2(binary, 8)
        else:
            if isinstance(Temp, int):
                temp2comp = LM75A._toComp2(Temp, 8)
                buf = bytes([REG_HYST, temp2comp, 0])
                i2c.write(self.Addr, buf)

    # Set or get the Over-temperature shutdown
    # temperature (Centigrade).
    # This is used by the Watchdog. See the Datasheet
    # for more details.
    def OS(self, Temp = None):
        if Temp == None:
            i2c.write(self.Addr, bytes([REG_OS]))
            binary = i2c.read(self.Addr, 2)[0]
            return LM75A._fromComp2(binary, 8)
        else:
            if isinstance(Temp, int):
                temp2comp = LM75A._toComp2(Temp, 8)
                buf = bytes([REG_OS, temp2comp, 0])
                i2c.write(self.Addr, buf)

    #--------------------------------------------
    #               Private Methods
    #--------------------------------------------

    # Returns binary temperature reading as decimal.
    @staticmethod
    def _Convert(buf, res):
        b = LM75A._fromComp2(buf[0], 8)
        dec = buf[1] >> (16 - res)
        return b + dec/(2**(res-8))

    # Converts Twos Complementary binary
    # to decimal equivalent.
    @staticmethod
    def _fromComp2(binary, bits):
        mask = 1 << (bits-1)
        if not (binary & mask) >> (bits-1):
            return  binary
        else:
            return -((binary ^ 2**bits - 1) + 1)

    # Converts signed integer to Twos Complementary.
    @staticmethod
    def _toComp2(sint, bits):
        if sint >= 0:
            return sint
        else:
            return (abs(sint) ^ 2**bits - 1) + 1

    # Changes the value of a bit in a given position
    # of a byte.
    @staticmethod
    def _ChangeBit(byte, bit, pos):
        if bit == 1:
            return byte | (1 << pos)
        else:
            return byte & ~(1 << pos)

          

NXP Semiconductors' LM75A

The breakout board used while developing and testing this driver coincidentally used the NXP Semiconductor LM75A chip.

This wasn't discovered until it was viewed under a digital microscope. Even though it is possible to read the sensor's markings with a good magnifying glass we always have a look under the microscope.

Micrograph of LM75A breakout board using the NXP chip
LM75A breakout board using the NXP chip

As mentioned previously the NXP's LM75A has an 11-bit temperature reading resolution. The driver is fine to use with this chip for a 9-bit resolution reading. In which case it remains a direct drop-in replacement option for any other LM75A chip and doesn't require any firmware change.

However, this driver offers the option of obtaining the temperature reading at the full 11-bit resolution.


Example:
# Test the micro:bit's MicroPython driver
# for the NXP Semiconductors' LM75A
# temperature sensor.

# Temperature readings are taken at 
# both 9-bit and 11-bit resolution.

from fc_lm75a import *

lm75a = LM75A()
T_9bits = lm75a.Read(Res=9)
T_11bits = lm75a.Read(Res=11)
print('Temperature (9-bits):', T_9bits)
print('Temperature (11-bits):', T_11bits)

Output:
Temperature (9-bits): 26.5
Temperature (11-bits): 26.625
          
LM75A breakout board (NXP chip) and the micro:bit
LM75A breakout board (NXP chip) and the micro:bit