Mastering the MLX90614 with MicroPython

The MLX90614 is a non - contact infrared temperature sensor produced by Melexis. It can measure the temperature of an object without physical contact, making it ideal for a wide range of applications such as industrial temperature monitoring, smart home systems, and medical devices. MicroPython, on the other hand, is a lean and efficient implementation of the Python 3 programming language that includes a small subset of the Python standard library and is optimized to run on microcontrollers. Combining the MLX90614 with MicroPython allows developers to quickly and easily integrate temperature sensing capabilities into their projects.

Table of Contents#

  1. Fundamental Concepts of MLX90614
  2. MicroPython Basics for MLX90614
  3. Usage Methods
  4. Common Practices
  5. Best Practices
  6. Conclusion
  7. References

Fundamental Concepts of MLX90614#

How it Works#

The MLX90614 operates based on the principle of detecting infrared radiation emitted by an object. Every object above absolute zero emits infrared radiation, and the intensity of this radiation is related to the object's temperature. The sensor has an infrared thermopile detector that converts the incoming infrared radiation into an electrical signal. This signal is then processed by an internal analog - to - digital converter (ADC) and calibrated to provide temperature readings.

Key Features#

  • Non - contact measurement: It can measure the temperature of an object without touching it, which is useful in applications where contact measurement is not possible or desirable.
  • Wide temperature range: It can measure both ambient temperature and object temperature in a relatively wide range. For example, the ambient temperature range is typically from - 40°C to 125°C, and the object temperature range can be from - 70°C to 380°C depending on the model.
  • I2C Interface: It communicates with the microcontroller using the I2C (Inter - Integrated Circuit) protocol, which is a widely used serial communication protocol for connecting low - speed devices.

MicroPython Basics for MLX90614#

I2C Communication#

MicroPython provides a built - in machine module that can be used to interact with the I2C interface. The basic steps to set up I2C communication in MicroPython are as follows:

from machine import I2C, Pin
 
# Initialize I2C bus
i2c = I2C(scl=Pin(5), sda=Pin(4))
 
# Scan for I2C devices
devices = i2c.scan()
if len(devices) == 0:
    print("No I2C devices found!")
else:
    print("I2C devices found:", devices)

In this code, we first import the I2C and Pin classes from the machine module. Then we initialize the I2C bus by specifying the clock (scl) and data (sda) pins. Finally, we scan for I2C devices on the bus and print the addresses of the found devices.

Usage Methods#

Reading Temperature Data#

To read the temperature data from the MLX90614, we need to know the I2C address of the sensor and the memory addresses where the temperature data is stored. The default I2C address of the MLX90614 is 0x5A. The ambient temperature data is stored at address 0x06, and the object temperature data is stored at address 0x07.

from machine import I2C, Pin
import time
 
# Initialize I2C bus
i2c = I2C(scl=Pin(5), sda=Pin(4))
MLX90614_ADDR = 0x5A
AMB_TEMP_REG = 0x06
OBJ_TEMP_REG = 0x07
 
def read_temp(reg_addr):
    # Read two bytes from the specified register
    data = i2c.readfrom_mem(MLX90614_ADDR, reg_addr, 2)
    # Convert the data to temperature in Celsius
    temp = (data[1] << 8 | data[0]) * 0.02 - 273.15
    return temp
 
while True:
    amb_temp = read_temp(AMB_TEMP_REG)
    obj_temp = read_temp(OBJ_TEMP_REG)
    print(f"Ambient Temperature: {amb_temp:.2f}°C")
    print(f"Object Temperature: {obj_temp:.2f}°C")
    time.sleep(1)

In this code, we define a function read_temp that takes the register address as an argument. Inside the function, we read two bytes from the specified register using the readfrom_mem method of the I2C object. Then we convert the raw data to temperature in Celsius according to the sensor's datasheet. Finally, we continuously read and print the ambient and object temperatures every second.

Common Practices#

Error Handling#

When working with the MLX90614, it's important to handle potential errors such as I2C communication errors. For example, if the sensor is not connected properly or there is an issue with the I2C bus, the readfrom_mem method may raise an exception. We can add error handling code to our previous example:

from machine import I2C, Pin
import time
 
i2c = I2C(scl=Pin(5), sda=Pin(4))
MLX90614_ADDR = 0x5A
AMB_TEMP_REG = 0x06
OBJ_TEMP_REG = 0x07
 
def read_temp(reg_addr):
    try:
        data = i2c.readfrom_mem(MLX90614_ADDR, reg_addr, 2)
        temp = (data[1] << 8 | data[0]) * 0.02 - 273.15
        return temp
    except OSError:
        print("I2C communication error!")
        return None
 
while True:
    amb_temp = read_temp(AMB_TEMP_REG)
    obj_temp = read_temp(OBJ_TEMP_REG)
    if amb_temp is not None and obj_temp is not None:
        print(f"Ambient Temperature: {amb_temp:.2f}°C")
        print(f"Object Temperature: {obj_temp:.2f}°C")
    time.sleep(1)

Calibration#

Although the MLX90614 is factory - calibrated, in some applications, you may need to perform additional calibration to improve the accuracy of the temperature readings. This can be done by comparing the sensor readings with a known reference temperature source and applying a correction factor.

Best Practices#

Power Management#

To reduce power consumption, especially in battery - powered applications, you can put the MLX90614 into standby mode when it's not needed. The sensor has a standby mode that can be activated by writing a specific value to a control register. However, implementing standby mode requires a more in - depth understanding of the sensor's datasheet.

Data Filtering#

The temperature readings from the MLX90614 may contain some noise. You can apply data filtering techniques such as moving average filtering to smooth out the readings. Here is an example of implementing a simple moving average filter:

class MovingAverage:
    def __init__(self, window_size):
        self.window_size = window_size
        self.data = []
 
    def add_data(self, value):
        self.data.append(value)
        if len(self.data) > self.window_size:
            self.data.pop(0)
 
    def get_average(self):
        if len(self.data) == 0:
            return 0
        return sum(self.data) / len(self.data)
 
# Initialize moving average filters
amb_avg = MovingAverage(window_size = 5)
obj_avg = MovingAverage(window_size = 5)
 
while True:
    amb_temp = read_temp(AMB_TEMP_REG)
    obj_temp = read_temp(OBJ_TEMP_REG)
    if amb_temp is not None and obj_temp is not None:
        amb_avg.add_data(amb_temp)
        obj_avg.add_data(obj_temp)
        print(f"Ambient Temperature (filtered): {amb_avg.get_average():.2f}°C")
        print(f"Object Temperature (filtered): {obj_avg.get_average():.2f}°C")
    time.sleep(1)

Conclusion#

In this blog, we have explored the fundamental concepts of the MLX90614 infrared temperature sensor and how to use it with MicroPython. We covered the basics of I2C communication, reading temperature data, common practices such as error handling and calibration, and best practices like power management and data filtering. By following these guidelines, you can effectively integrate the MLX90614 into your MicroPython projects and obtain accurate temperature readings.

References#