MicroPython Driver for LM75A Sensor
Contents
Introduction
This a MicroPython driver written specifically for the BBC micro:bit that will work with the LM75A ambient temperature sensor.
The LM75A is a digital temperature only sensor. As well as returning temperature readings it also has a fairly standard (for this style of sensor) watchdog which provides over-temperature alerting.
The LM75A sensor is discussed in some detail here. Additionally, if the watchdog is to be used in a serious manner then the product datasheet should also be carefully consulted.


The SMT packaging of this sensor is definitely not breadboard friendly. Fortunately inexpensive breakout boards are widely available.
Connecting the LM75A
The LM75A communicates via I2C. Hooking it up to the micro:bit is easy:
micro:bit | LM75A |
---|---|
3.3V | VCC |
GND | GND |
Pin 20 | SDA |
Pin 19 | SCL |
Any available digital pin (Optional) |
OS |
This utilises the standard I2C pins of the micro:bit.
Connecting the OS pin is only necessary if the temperature watchdog will be used. The driver however does provides the full watchdog functionality if the user's MicroPython program chooses to take advantage of it.
Driver Overview
The driver code can be:
- Copied from this webpage onto the clipboard then pasted into the MicroPython editor e.g. the Mu Editor. It should be saved as fc_lm75a.py - OR -
- Download as a zip file using the link. Unzip the file and save it as fc_lm75a.py into the default directory where the MicroPython editor e.g. Mu Editor saves python code files.
After saving the fc_lm75a.py file to the computer it should be copied to the small filesystem on the micro:bit. The examples on this page will not work if this step is omitted. Any MicroPython editor that recognises the micro:bit will have an option to do this.
The Mu Editor is recommended for its simplicity. It provides a Files button on the toolbar for just this purpose.
I2C addressThe LM75A chip has three pins; A0, A1, A2 for setting the I2C address. Each pin is connected independently to either VCC or GND. This gives a choice of eight addresses.
The breakout board exposes these three pins as solderable jumpers on the back of the board. All three pins by default are connected to GND which gives an I2C address of 0x48.
Class constructorThe driver is implemented as a class. The first thing to do is call the constructor. This provides an instance of the class.
Syntax:
instance = LM75A(Addr = 0x48)
Where:
Addr : The I2C address. It will be in
the range: 0x48 to 0x4F.
Example
from fc_lm75a import *
Declare a sensor with default address
my_sensor1 = LM75A()
Declare a sensor with a different address
my_sensor1 = LM75A(0x49)
This assumes that the file fc_aht1x.py has been successfully copied to the micro:bit's filesystem as described above.
Methods and FunctionsThe driver provides methods to:
- Read the temperature
- Set (and get) watchdog parameters
- Set the power mode
Reading Temperature
Syntax:
Read(Res = 9)
CtoF(C)
Purpose:
Read() is a method that returns the most
recent temperature reading in °C.
CtoF() is a function that converts a
centigrade temperature to fahrenheit.
Where:
Res : The resolution of the temperature
reading. The traditional LM75A sensor has
a resolution of 9-bits. The NXP version
of the LM75A has an 11-bit resolution.
C : Temperature in centigrade to be
converted to fahrenheit.
Example:
# Test the LM75A MicroPython
# driver for the micro:bit.
# Take a temperature reading.
# Convert from C to F.
from fc_lm75a import *
lm75a = LM75A()
C = lm75a.Read()
F = CtoF(C)
print('Centigrade:', C, 'Fahrenheit:', F)
Sample Output:
Centigrade: 29.5 Fahrenheit: 85.1
Note:
The LM75A self-initiates a new temperature reading and conversion on a periodic basis. The datasheet does not provide the frequency of the readings. The Temperature register can be read at any time. However the same stale temperature value will be returned if the register is repeatedly read between sensor temperature measurement updates.
Using the Watchdog
The product datasheet should be read in conjunction with this section. The following methods are provided to allow the user to get the full benefit of the watchdog:
- OS() : Set (or get) the TOS temperature.
- Hyst() : Set (or get) the THYST temperature.
- SetConfig() : Set the CmpInt, Polarity and Queue parameters.
- GetConfig() : Returns the Configuration register's byte.
Syntax: OS(Temp = None) Hyst(Temp = None) Where: Temp : The temperature in °C to set TOS and THYST. The default is None which returns the current value. Refer to the product datasheet for the meaning. of TOS and THYST.
Syntax: SetConfig(Queue = 1, Polarity = 0, CmpInt = 0) Where: Queue : Allowable values are 1, 2, 4, 6 Polarity : 0 = active low 1 = active high CmpInt : 0 = Comparator mode 1 = Interrupt mode Refer to the product datasheet for the meaning. of Queue, Polarity and CmpInt.
Syntax: GetConfig() Where: This method returns the Configuration register's value. Refer to the product datasheet for the meaning of each bit in the Configuration register's byte.
Example: # Tests the watchdog methods. from fc_lm75a import * lm75a = LM75A() # Test setting OS and HYST temperatures # Get current values print('Test setting OS and HYST temperatures') print('Current OS temperature:', lm75a.OS()) print('Current HYST temperature:', lm75a.Hyst()) # Set new OS temperature lm75a.OS(35) # Set new HYST temperature lm75a.Hyst(30) print('New OS temperature:', lm75a.OS()) print('New HYST temperature:', lm75a.Hyst()) # Test setting watchdog parameters. print('\nTest setting watchdog parameters') # Get Configuration register. CR = lm75a.GetConfig() fCR = "{:08b}".format(CR) print('Configuration register:', fCR) # Set the following: # : Queue faults = 6 # : Polarity = active high # : CmpInt = Interrupt mode print('Queue=6 faults, Active high, Interrupt mode') lm75a.SetConfig(Queue=6, Polarity=1, CmpInt=1) # Get Configuration register. CR = lm75a.GetConfig() fCR = "{:08b}".format(CR) print('Configuration register:', fCR)
Output: Test setting OS and HYST temperatures Current OS temperature: 80 Current HYST temperature: 75 New OS temperature: 35 New HYST temperature: 30 Test setting watchdog parameters Configuration register: 00000000 Queue=6 faults, Active high, Interrupt mode Configuration register: 00011110
Power Modes
The LM75A has a Shutdown mode which reduces power supply current significantly. While in this low power mode only the I2C interface is still operational. A stale value will be returned if the Temperature register is read.
Syntax: Off() Where: This method forces the LM75A into Shutdown mode.
Syntax: On() Where: This method brings the LM75A out of Shutdown mode. Temperature readings resume and the watchdog becomes active.
Example: # Demonstrate Shutdown mode on the LM75A # temperature sensor. from fc_lm75a import * from microbit import sleep lm75a = LM75A() # Get temperature print('Temperature:', lm75a.Read()) # Put sensor into Shutdown mode print('Going into Shutdown mode...') lm75a.Off() # Get temperature print('Temperature:', lm75a.Read()) # Wait 2 minutes print('Wait 2 minutes...') sleep(120000) # Get temperature print('Temperature:', lm75a.Read()) # Wake sensor up. print('Waking up...') lm75a.On() # Get temperature print('Temperature:', lm75a.Read())
Typical Output: Temperature: 27.0 Going into Shutdown mode... Temperature: 27.0 Wait 2 minutes... Temperature: 27.0 Waking up... Temperature: 28.0
In the example above the temperature sensor was placed in Shutdown mode for two minutes. Warm air was lightly blown across the front of the sensor during this time. The increase in temperature (1.0 °C) was not detected till the sensor was woken up.
The temperature readings returned while the sensor was in its low power state were stale and came from the sensor's last conversion before being powered down.
Enjoy!
LM75A Driver Code for micro:bit
Download as zip file
'''
LM75A temperature sensor
MicroPython driver for micro:bit
AUTHOR: fredscave.com
DATE : 2025/01
VERSION : 1.00
'''
from microbit import i2c, sleep
from micropython import const
I2C_ADDR = const(0x48)
REG_TEMP = const(0x00)
REG_CONFIG = const(0x01)
REG_HYST = const(0x02)
REG_OS = const(0x03)
CtoF = lambda C: round((C * 9/5) +32, 1)
class LM75A():
def __init__(self, Addr = I2C_ADDR):
self.Addr = Addr
def Read(self, Res = 9):
res = Res if (Res in [9, 11]) else 8
i2c.write(self.Addr, bytes([REG_TEMP]))
buf = i2c.read(self.Addr, 2)
return LM75A._Convert(buf, res)
def GetConfig(self):
i2c.write(self.Addr, bytes([REG_CONFIG]))
return i2c.read(self.Addr, 1)[0]
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]))
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]))
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)
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)
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)
@staticmethod
def _Convert(buf, res):
b = LM75A._fromComp2(buf[0], 8)
dec = buf[1] >> (16 - res)
return b + dec/(2**(res-8))
@staticmethod
def _fromComp2(binary, bits):
mask = 1 << (bits-1)
if not (binary & mask) >> (bits-1):
return binary
else:
return -((binary ^ 2**bits - 1) + 1)
@staticmethod
def _toComp2(sint, bits):
if sint >= 0:
return sint
else:
return (abs(sint) ^ 2**bits - 1) + 1
@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.

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
