Connecting Infrared Thermometer MLX90614 to Wiring

From Wiring

Jump to: navigation, search

Infrared Thermometer MLX90614

by Jaime Patarroyo

MLX90614 is a very useful infrared thermometer (no contact needed) that gives you the average temperature reading of all objects in the view range. In addition to it’s principal temperature reading function, it can be used for movement or even presence detection.

There are two ways of interfacing this sensor, through PWM communication or SMBus (TWI or I²C) communication. I wasn’t able to get the first one working, so tried SMBus I²C that is not easier to code but gives you some advantages over PWM. Through I²C you can connect over 127 devices using just two Wiring pins and also, in this specific sensor (MLX90614) you get better resolution readings.

Wiring comes with a special library for interfacing I²C devices (wire library) but unfortunately this library is not compatible with MLX90614 because it doesn't support the use of the repeated start function (if you want to read further about this issue check this link). So, we are going to use the I²Cmaster library that has been modified by the guys at bildr.blog for working properly with the Wiring board.

Download MLX90614 Fritzing part.


Contents

Download and Install I²Cmaster library

The first thing that has to be done is to download and instal the the I²Cmaster library. As I said before, were using a version modified by the guys at bildr.blog.

I²Cmaster library download.

After downloading, unzip the folder and place it in the Wiring ‘libraries’ folder:
On Mac: Documents/Wiring/libraries
On PC: My Documents/Wiring/libraries

To check, open Wiring (if you had it open, close and reopen) and go to:
Sketch > Import Library… > Contributed
and there you should find I²Cmaster.


Connecting one MLX90614

Once you have the library installed, you can use the following setup diagram and code for reading temperature from one MLX90614 connected to the TWI pins (on the Wiring v1 board 0 (SCL) and 1 (SDA) and on Wiring S board 8 (SCL) and 9 (SDA)). Both (diagram and code) are based on the Is it hot? Arduino + MLX90614 IR Thermometer bildr.blog post.

Setup diagram

Both resistances are 3.7 k Ohm and the little sensor tab is in the upper right side in the diagram.

MLX90614.jpg

Code

/**
 * Infrared Thermometer MLX90614
 * by Jaime Patarroyo
 * based on 'Is it hot? Arduino + MLX90614 IR Thermometer' by bildr.blog
 * 
 * Returns the temperature in Celcius and Fahrenheit from a MLX90614 
 * Infrared Thermometer, connected to the TWI/I²C pins (on the Wiring v1 
 * board 0 (SCL) and 1 (SDA) and on Wiring S board 8 (SCL) and 9 (SDA)).
 */

#include <i2cmaster.h>


int deviceAddress = 0x5A<<1;    // From MLX906114 datasheet's, 0x5A is 
                                // the default address for I²C communication.
                                // Shift the address 1 bit right, the 
                                // I²Cmaster library only needs the 7 most 
                                // significant bits for the address.

float celcius = 0;              // Variable to hold temperature in Celcius.
float fahrenheit = 0;           // Variable to hold temperature in Fahrenheit.

void setup() {
  Serial.begin(9600);           // Start serial communication at 9600bps.

  i2c_init();                               // Initialise the i2c bus.
  PORTC = (1 << PORTC4) | (1 << PORTC5);    // Enable pullups.
}

void loop() {
  celcius = temperatureCelcius(deviceAddress);  // Read's data from MLX90614
                                                // with the given address,
                                                // transform's it into
                                                // temperature in Celcius and
                                                // store's it in the Celcius
                                                // variable.
  
  fahrenheit = (celcius*1.8) + 32;     // Converts celcius into Fahrenheit 
                                       // and stores in Fahrenheit variable.

  Serial.print("Celcius: ");           // Prints both readings in the Serial 
  Serial.println(celcius);             // port.
  Serial.print("Fahrenheit: ");
  Serial.println(fahrenheit);

  delay(1000);                         // Wait a second before printing again.
}

float temperatureCelcius(int address) {
  int dev = address;
  int data_low = 0;
  int data_high = 0;
  int pec = 0;

  // Write
  i2c_start_wait(dev+I2C_WRITE);
  i2c_write(0x07);

  // Read
  i2c_rep_start(dev+I2C_READ);
  data_low = i2c_readAck();       // Read 1 byte and then send ack.
  data_high = i2c_readAck();      // Read 1 byte and then send ack.
  pec = i2c_readNak();
  i2c_stop();

  // This converts high and low bytes together and processes temperature, 
  // MSB is a error bit and is ignored for temps.
  double tempFactor = 0.02;       // 0.02 degrees per LSB (measurement 
                                  // resolution of the MLX90614).
  double tempData = 0x0000;       // Zero out the data
  int frac;                       // Data past the decimal point

  // This masks off the error bit of the high byte, then moves it left 
  // 8 bits and adds the low byte.
  tempData = (double)(((data_high & 0x007F) << 8) + data_low);
  tempData = (tempData * tempFactor)-0.01;
  float celcius = tempData - 273.15;
  
  // Returns temperature un Celcius.
  return celcius;
}


Connecting two or more MLX90614

Connecting two or more MLX90614 it’s a little harder because as you could see, they come from factory with the same communication address (0x5A). If you try to plug them both at the same time just out of the box, the Wiring board is not going to know the difference between them and it’s going to return the measure of only one of them. The universal address (0) always allows you to access the device even if you have change or assigned a new address, then, if you forget the new address, you can always use 0.

Address Changing

You have to assign an address to each of the MLX90614 that you what to plug at the same time. You can change only one address at a time. DON’T PLUG MORE THAN ONE DEVICE WHILE CHANGING AN ADDRESS.

Code here is based on paulrd reply #6 on topic Multiple Melexis MLX90614 on the same i2c, how to change addresses? at Arduino's forum and it’s only for changing the device address, for reading temperature from sensors we’ll use other code.

Remember to change the address for each device in code line 14, in this example I’ll use 0x50 and 0x55.

Setup diagram

Both resistances are 3.7 k Ohm and the little sensor tab is in the upper right side in the diagram.

MLX90614.jpg

Code

/**
 * Change I²C Device Address
 * by Jaime Patarroyo
 * based on paulrd reply #6 on topic 'Multiple Melexis MLX90614 on the 
 * same i2c, how to change addresses?' at Arduino's forum.
 * 
 * Assigns a new address to a TWI/I²C device connected to the TWI/I²C 
 * pins (on the Wiring v1 board 0 (SCL) and 1 (SDA) and on Wiring S 
 * board 8 (SCL) and 9 (SDA)).
 */

#include <i2cmaster.h>

byte newAddress = 0x55<<1;      // Write here the new address you want
                                // to assign. In this example, the new
                                // address will be 0x55.
                                // Shift the address 1 bit right, the 
                                // I²Cmaster library only needs the 7 most 
                                // significant bits for the address.

void setup()
{
  Serial.begin(9600);                      // Start serial communication 
                                           // at 9600bps.

  i2c_init();                              // Initialise the i2c bus.
  PORTC = (1 << PORTC4) | (1 << PORTC5);   // Enable pullups.

  delay(5000);                             // Wait to allow serial connection.
  ChangeAddress(newAddress, 0x00);         // Changes address to new value.
}

void loop()
{
}

word ChangeAddress(byte NewAddr1, byte NewAddr2) {
  Serial.println("> Change address");

  i2c_start_wait(0 + I2C_WRITE);      // Send start condition and write bit.
  i2c_write(0x2E);                    // Send command for device to return 
                                      // address (0x2E).
  i2c_write(0x00);                    // Send low byte zero to erase.
  i2c_write(0x00);                    // Send high byte zero to erase.
  if (i2c_write(0x6F) == 0) {
    i2c_stop();                       // Release bus, end transaction.
    Serial.println("  Data erased."); // Address erase confirmation message.
  }
  else {
    i2c_stop();                       // Release bus, end transaction.
    Serial.println("  Failed to erase data");
    return -1;
  }

  Serial.print("  Writing data: ");
  Serial.print(NewAddr1, HEX);
  Serial.print(", ");
  Serial.println(NewAddr2, HEX);

  for (int a = 0; a != 256; a++) {
    i2c_start_wait(0 + I2C_WRITE);    // Send start condition and write bit.
    i2c_write(0x2E);                  // Send command for device to return 
                                      // address (0x2E).
    i2c_write(NewAddr1);              // Send low byte zero to assign new address.
    i2c_write(NewAddr2);              // Send high byte zero to assign new address.
    if (i2c_write(a) == 0) {
      i2c_stop();                     // Release bus, end transaction.
      delay(100);                     // Wait 10ms.
      Serial.print("Found correct CRC: 0x");
      Serial.println(a, HEX);
      return a;
    }
  }
  i2c_stop();                         // Release bus, end transaction.
  Serial.println("Correct CRC not found");
  return -1;
}

Reading Sensors

Now that we have a different address for each device we can wire both sensors at the same time and read their temperature separately.

Setup diagram

Both resistances are 3.7 k Ohm and the little sensor tab is in the upper right side in the diagram.

TwoMLX90614.jpg

Code

/**
 * Two Infrared Thermometers MLX906114
 * by Jaime Patarroyo
 * based on 'Is it hot? Arduino + MLX90614 IR Thermometer' by bildr.blog
 * 
 * Returns the temperature in Celcius and Fahrenheit from two MLX90614 
 * Infrared Thermometers, connected to the TWI/I²C pins (on the Wiring v1 
 * board 0 (SCL) and 1 (SDA) and on Wiring S board 8 (SCL) and 9 (SDA)).
 */

#include <i2cmaster.h>

int device1Address = 0x50<<1;   // 0x50 is the assigned address for I²C 
                                // communication for sensor 1.
                                // Shift the address 1 bit right, the 
                                // I²Cmaster library only needs the 7 most 
                                // significant bits for the address.
int device2Address = 0x55<<1;   // 0x55 is the assigned address for I²C 
                                // communication for sensor 2.
                                // Shift the address 1 bit right, the 
                                // I²Cmaster library only needs the 7 most 
                                // significant bits for the address.

float celcius1 = 0;             // Variable to hold temperature in Celcius
                                // for sensor 1.
float fahrenheit1 = 0;          // Variable to hold temperature in Fahrenheit
                                // for sensor 1.
float celcius2 = 0;             // Variable to hold temperature in Celcius
                                // for sensor 2.
float fahrenheit2 = 0;          // Variable to hold temperature in Fahrenheit
                                // for sensor 2.

void setup()
{
  Serial.begin(9600);           // Start serial communication at 9600bps.
  
  i2c_init();                               // Initialise the i2c bus.
  PORTC = (1 << PORTC4) | (1 << PORTC5);    // Enable pullups.
}

void loop()
{
  celcius1 = temperatureCelcius(device1Address);// Read's data from MLX90614
  celcius2 = temperatureCelcius(device2Address);// with the given address,
                                                // transform's it into
                                                // temperature in Celcius and
                                                // store's it in the celcius1
                                                // or celcius2 variables.
 
  fahrenheit1 = (celcius1*1.8) + 32;     // Converts celcius into Fahrenheit 
  fahrenheit2 = (celcius2*1.8) + 32;     // and stores in Fahrenheit1 or 
                                         // Fahrenheit2 variables.

  Serial.print("Sensor 1: Celcius: ");   // Prints all readings in the Serial 
  Serial.print(celcius1);                // port.
  Serial.print("  Fahrenheit: ");
  Serial.println(fahrenheit1);
  Serial.print("Sensor 2: Celcius: ");
  Serial.print(celcius2);
  Serial.print("  Fahrenheit: ");
  Serial.println(fahrenheit2);

  delay(1000);                         // Wait a second before printing again.
}

float temperatureCelcius(int address) {
  int dev = address;
  int data_low = 0;
  int data_high = 0;
  int pec = 0;

  // Write
  i2c_start_wait(dev+I2C_WRITE);
  i2c_write(0x07);

  // Read
  i2c_rep_start(dev+I2C_READ);
  data_low = i2c_readAck();       // Read 1 byte and then send ack.
  data_high = i2c_readAck();      // Read 1 byte and then send ack.
  pec = i2c_readNak();
  i2c_stop();

  // This converts high and low bytes together and processes temperature, 
  // MSB is a error bit and is ignored for temps.
  double tempFactor = 0.02;       // 0.02 degrees per LSB (measurement 
                                  // resolution of the MLX90614).
  double tempData = 0x0000;       // Zero out the data
  int frac;                       // Data past the decimal point

  // This masks off the error bit of the high byte, then moves it left 
  // 8 bits and adds the low byte.
  tempData = (double)(((data_high & 0x007F) << 8) + data_low);
  tempData = (tempData * tempFactor)-0.01;
  float celcius = tempData - 273.15;
  
  // Returns temperature un Celcius.
  return celcius;
}


Language: English  • Español
Personal tools