The MLX90614 measures the temperature of whatever it points at, without touching it — handy for motors, cooking surfaces and contactless thermometer projects. Over I2C it behaves like an SMBus device: one word read per temperature.
Wire the GY-906 to 3V3 and I2C0 (GP4/GP5) at 100 kHz. The script prints object and ambient temperature twice a second.
Wiring
| Raspberry Pi Pico W | MLX90614 IR thermometer (GY-906) | Wire | Notes |
|---|---|---|---|
| 3V3 | VIN | red | 3V3 is pin 36. Safe for both 3 V (BAA) and regulator boards. |
| GND | GND | black | |
| GP5 | SCL | yellow | GP5 is physical pin 7 (I2C0 SCL). |
| GP4 | SDA | blue | GP4 is physical pin 6 (I2C0 SDA). |
3.3 V (5 V versions with regulator) part, 3.3 V board. Check the chip marking: MLX90614BAA is a 3 V part, MLX90614AAA is 5 V. Most GY-906 boards with a regulator accept 3.3–5 V; power 3 V-only boards from 3.3 V.
Board quirks
- The MLX90614 is an SMBus device: keep the bus at 100 kHz. At 400 kHz it often drops off the bus.
readfrom_mem(0x5A, 0x07, 3)returns the object temperature (low byte, high byte, PEC); register 0x06 is the sensor’s own (ambient) temperature. Each bit is 0.02 K.- The field of view is about 90° on the GY-906: at 10 cm it averages a circle about 20 cm wide. Get close to measure a small spot.
- It reads skin a degree or two below body temperature — fine for a project, not a medical thermometer.
Code
# MLX90614 (GY-906) non-contact IR thermometer on a Raspberry Pi Pico W (MicroPython, no library).
# Wiring: VIN -> 3V3 (pin 36), GND -> GND, SCL -> GP5 (pin 7), SDA -> GP4 (pin 6). I2C0, 100 kHz.
from machine import Pin, I2C
import time
ADDR = 0x5A
i2c = I2C(0, sda=Pin(4), scl=Pin(5), freq=100_000) # SMBus device - keep it at 100 kHz
if ADDR not in i2c.scan():
raise SystemExit("No MLX90614 at 0x5A - found {}".format([hex(a) for a in i2c.scan()]))
def read_temp(ram_addr):
lo, hi, _pec = i2c.readfrom_mem(ADDR, ram_addr, 3) # data word + SMBus PEC byte
raw = (hi << 8) | lo
if raw & 0x8000:
raise OSError("error flag set")
return raw * 0.02 - 273.15 # 0.02 K per bit
print("MLX90614 at 0x5A")
while True:
try:
ambient = read_temp(0x06)
obj = read_temp(0x07)
print("Object {:.2f} C Ambient {:.2f} C".format(obj, ambient))
except OSError as e:
print("Read failed:", e)
time.sleep_ms(500)# MLX90614 (GY-906) non-contact IR thermometer on a Raspberry Pi Pico W (MicroPython, no library).
# Wiring: VIN -> 3V3 (pin 36), GND -> GND, SCL -> GP5 (pin 7), SDA -> GP4 (pin 6). I2C0, 100 kHz.
from machine import Pin, I2C
import time
ADDR = 0x5A
i2c = I2C(0, sda=Pin(4), scl=Pin(5), freq=100_000) # SMBus device - keep it at 100 kHz
if ADDR not in i2c.scan():
raise SystemExit("No MLX90614 at 0x5A - found {}".format([hex(a) for a in i2c.scan()]))
def read_temp(ram_addr):
lo, hi, _pec = i2c.readfrom_mem(ADDR, ram_addr, 3) # data word + SMBus PEC byte
raw = (hi << 8) | lo
if raw & 0x8000:
raise OSError("error flag set")
return raw * 0.02 - 273.15 # 0.02 K per bit
print("MLX90614 at 0x5A")
while True:
try:
ambient = read_temp(0x06)
obj = read_temp(0x07)
print("Object {:.2f} C Ambient {:.2f} C".format(obj, ambient))
except OSError as e:
print("Read failed:", e)
time.sleep_ms(500)Expected serial output
MLX90614 at 0x5A
Object 33.84 C Ambient 28.12 C
Object 61.02 C Ambient 28.14 CMLX90614 at 0x5A Object 33.84 C Ambient 28.12 C Object 61.02 C Ambient 28.14 C
Common errors
No MLX90614 at 0x5A
Drop the bus to 100 kHz, check SDA (GP4, pin 6) and SCL (GP5, pin 7). A 5 V-only (AAA) chip on 3.3 V may not answer.
Object temperature of shiny metal is far too low
Polished metal reflects IR instead of emitting it. Put a piece of matt black tape on the surface and measure the tape.