CCS C Software and Maintenance Offers
FAQFAQ   FAQForum Help   FAQOfficial CCS Support   SearchSearch  RegisterRegister 

ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

CCS does not monitor this forum on a regular basis.

Please do not post bug reports on this forum. Send them to support@ccsinfo.com

MLX90614 Driver

 
Post new topic   Reply to topic    CCS Forum Index -> Code Library
View previous topic :: View next topic  
Author Message
Gabriel



Joined: 03 Aug 2009
Posts: 1067
Location: Panama

View user's profile Send private message

MLX90614 Driver
PostPosted: Mon Sep 19, 2016 9:27 pm     Reply with quote

Hi All,

In the spirit of expanding this library I am sharing my MLX90614 driver.
I needed the sensor recently and noticed there is no driver on this library.

The driver below does pretty much everything needed for this chip.
Including writing to the EEPROM for configuration.
Be careful when changing stuff or factory calibration will be lost.

The CRC functions work for both checking the incoming data and obviously for writing to the chip.

I will not post a sample program as I don't think its necessary for this as its pretty simple. I've included some examples on the driver itself.

Code:

//**********************************************************************************
//                        MLX90614 Driver
//**********************************************************************************
// By: Gabriel E. Barrios F.
// Date: 19/09/2016
// Panama, Panama
////////////////////////////////////////////////////////////////////////////////////
// This is a driver for the MLX90614ESF-BAA Single Zone IR Thermometer.
// Read and Write functions are provided and all the pertinent CRC stuff is included.
// This driver can read EEPROM and RAM on the MLX, and can also Write to EEPROM.
// This driver is for a Single Sensor on the I2C BUS
////////////////////////////////////////////////////////////////////////////////////

//SMBUS Device Address
#define Device_Address 0x5A

//RAM Addresses for Temperatures
#define AT_Address 0x06   // Ambien Temperature - The Sensor's internal temperature
#define OT_Address 0x07   // Object Temperature - Whats in the Sensor's FOV

//EEPROM Addresses for Configuration/Writing
#define TO_Max 0x20
#define TO_Min 0x21
#define PWM_Control 0x22
#define TA_Range 0x23
#define Emissivity_Address 0x24
#define Config_Address 0x25
#define SMBUS_Address 0x2E

//Other Stuff for code Readability
#define Write_Bit 0x00
#define Read_Bit 0x01
#define ACK 0x00
#define NACK 0x01

//Function Declarations
int16 MLX_Read_Transaction(int);      // Needs Address to read from
void MLX_Write_Transaction(int,int,int);// Needs Address to write to, lo and hi bytes.
int Create_CRC(int,int,int);         // Needs Address to write to, lo and hi bytes.
int Check_CRC(int,int,int,int);         // Needs Read address,hi, lo and CRC Bytes
int CRC8_CCITT(int, int);            // Starting CRC and Byte to encode/decode



//**********************************************************************************
//                        EXAMPLE FUNCTIONS
//**********************************************************************************
// These are not really part of the driver, just examples of how to call things from
// your program:
//
//   void main()
//   {
//      Read_Object();                     //Gets you Temp of objects in FOV
//      Read_Ambient();                     //Gets you Ambient Temp
//   
//      //LETS EDIT SOME EEPROM VALUES!!!
//      Read_TOMAX();                      //Will read default value - probably 9993
//      MLX_Write_Transaction(TO_Max,0x00,0x00);//Need to erase EEPROM first with 0x0000
//      Read_TOMAX();                      //Will now read 0x0000
//      MLX_Write_Transaction(TO_Max,0xFF,0xFF);//Write desired values
//      Read_TOMAX();                      //Will now read 0xFFFF
//   }

void Read_Object()
{
   fprintf(lcd_putc,"Object Temp:%3.2f\r\n",((MLX_Read_Transaction(OT_Address)*0.02)-273));
   delay_ms(500);
}

void Read_Ambient()
{
   fprintf(lcd_putc,"Ambient Temp:%3.2f\r\n",((MLX_Read_Transaction(AT_Address)*0.02)-273));
   delay_ms(500);
}

void Read_Config()
{
   fprintf(lcd_putc,"MLX Configuration:%LX\r\n",MLX_Read_Transaction(Config_Address));
   delay_ms(500);
}

void Read_Emissivity()
{
   fprintf(lcd_putc,"Emissivity Value:%LX\r\n",MLX_Read_Transaction(Emissivity_Address));
   delay_ms(500);
}
void Read_TOMAX()
{
   fprintf(lcd_putc,"TO_MAX:%LX\r\n",MLX_Read_Transaction(TO_Max));
   delay_ms(500);
}

//**********************************************************************************
//                        READ MLX DATA
//**********************************************************************************
// This functions works for both EEPROM and RAM Data from the MLX Sensor.
// A Checksum check is included to confirm Data integrity
int16 MLX_Read_Transaction(int Read_Address)
{
   int16 MLX_Response;            // Stores the 16 bit responses from the MLX
   int Command=0;               // stores the Address+write/read bit
   int Lo_Byte=0;
   int Hi_Byte=0;
   int CRC=0;

   Command=Device_Address<<1;      // Prepare Command: shift address 1 bit
   Command|=Write_Bit;            // Shifted Address with W/R Bit set or cleared
   i2c_start();               // Send Start Bit
   if (i2c_write(Command)==ACK)   // Send "Write" Command to the Device Address
   { 
      i2c_write(Read_Address);   // Write Address to be read
      Command=Device_Address<<1;   // Prepare Command: byte shift address 1 bit
      Command|=Read_Bit;         // Shifted Address with W/R Bit set or cleared
      i2c_start();            // Send Re-Start Bit
      i2c_write(Command);           // Send "Read" Command to the Device Address
      Lo_Byte = i2c_read(ACK);   // Get Low Byte and ACK the read
      Hi_Byte = i2c_read(ACK);   // Get High Byte and ACK the read
      CRC = i2c_read(ACK);      // Get CRC and ACK the Read      
   }
   i2c_stop();                  // Hammer Time

   if(Check_CRC(Read_Address,Lo_Byte,Hi_Byte,CRC)==0)
   {
      MLX_Response= make16(Hi_Byte,Lo_Byte);
      return(MLX_Response);
   }
}

//**********************************************************************************
//                        WRITE DATA TO MLX
//**********************************************************************************
// This function writes to the EEPROM of the MLX. It calculates the CRC automatically.
// There is a small delay at the end as "settling time" after the write.
// During testing this delay was required if reading the data Immediatly after the write
void MLX_Write_Transaction(int Write_Address,int Lo_Byte,int Hi_Byte)
{
   int CRC=0;                     // Holds the CRC of data to be sent
   int Command=0;                  //

   CRC=Create_CRC(Write_Address,Lo_Byte,Hi_Byte);

   Command=Device_Address<<1;         // Prepare Command: shift address 1 bit
   Command|=Write_Bit;               // Shifted Address with W/R Bit set or cleared

   i2c_start();                  // Send Start Bit
   if (i2c_write(Command)==ACK)      // Send Device Address
   { 
      i2c_write(Write_Address);      // Write Address to be Written onto
      i2c_write(Lo_Byte);            // Send Low Byte
      i2c_write(Hi_Byte);            // Send Hi Byte   
      i2c_write(CRC);               // Send CRC/PEC   
   }
   i2c_stop();                     // Hammer Time
   delay_ms(10);                  // Allow time after write
}

//**********************************************************************************
//                        CREATE A CRC
//**********************************************************************************
// Calculates the CRC of the DATA to be sent to EEPROM
int Create_CRC(int Write_Address,int Lo_Byte,int Hi_Byte)
{
   int Temp_CRC=0;                        // Holds the intermediate CRC Calculations
   int Command=0;                        //

   Command=Device_Address<<1;               // Prepare Command: shift address 1 bit
   Command|=Write_Bit;                     // Shifted Address with W/R Bit set or cleared

   Temp_CRC=CRC8_CCITT(0x00,Command);         // Device Address
   Temp_CRC=CRC8_CCITT(Temp_CRC,Write_Address);// Memory Address
   Temp_CRC=CRC8_CCITT(Temp_CRC,Lo_Byte);       // LSB Byte
   Temp_CRC=CRC8_CCITT(Temp_CRC,Hi_Byte);       // MSB Byte
   //fprintf(lcd_putc,"New CRC:%X\r\n",Temp_CRC); //DEBUG
   return (Temp_CRC);
}

//**********************************************************************************
//                     CHECK INCOMMING DATA'S CRC
//**********************************************************************************
// Takes the data read from the sensor and checks if the Checksum is Right
int Check_CRC(int Read_Address,int Lo_Byte,int Hi_Byte,int CRC)
{
   int Temp_CRC=0;
   int Command=0;

   Command=Device_Address<<1;               // Prepare Command: shift address 1 bit
   Command|=Write_Bit;                     // Shifted Address with W/R Bit set or cleared
   Temp_CRC=CRC8_CCITT(0x00,Command);         // Device Address
   Temp_CRC=CRC8_CCITT(Temp_CRC,Read_Address); // Memory Address
   Command=Device_Address<<1;               // Prepare Command: shift address 1 bit
   Command|=Read_Bit;                     // Shifted Address with W/R Bit set or cleared
   Temp_CRC=CRC8_CCITT(Temp_CRC,Command);      // Device Address with Read Bit Set
   Temp_CRC=CRC8_CCITT(Temp_CRC,Lo_Byte);       // LSB Byte
   Temp_CRC=CRC8_CCITT(Temp_CRC,Hi_Byte);       // MSB Byte
   Temp_CRC=CRC8_CCITT(Temp_CRC,CRC);          // Received CRC Value
   //fprintf(lcd_putc,"CRC Check:%X\r\n",Temp_CRC); //DEBUG
   return (Temp_CRC);
}

//**********************************************************************************
//                     CRC8-CCITT CALCULATION
//**********************************************************************************
// This function was taken from "AVR Libc Reference Manual" and some names changed.
// Full credit to those involved in its creation.
int CRC8_CCITT(int inCrc, int inData)
{
    int   i;
    int   data;

    data = inCrc ^ inData;

    for ( i = 0; i < 8; i++ )
    {
        if (( data & 0x80 ) != 0 )
        {
            data <<= 1;
            data ^= 0x07;
        }
        else
        {
            data <<= 1;
        }
    }
    return data;
}


Hope this helps some of you.

G.
_________________
CCS PCM 5.078 & CCS PCH 5.093
mohammad3d



Joined: 28 Mar 2009
Posts: 17

View user's profile Send private message Send e-mail

PostPosted: Fri Jun 30, 2017 4:55 am     Reply with quote

Dear Gabriel,
Thanks for your driver sharing...
This is great.
Very Happy
Can you send a complete program on specified PIC like 16F or 18F series, that uses your driver for sending object temperature on serial port?

Very thanks again for your great work.
Regards.
Gabriel



Joined: 03 Aug 2009
Posts: 1067
Location: Panama

View user's profile Send private message

PostPosted: Fri Jun 30, 2017 10:52 am     Reply with quote

Examples of what you ask are already provided on the driver.

Literally, include the driver in your file and do this:

Code:

//**********************************************************************************
//                        EXAMPLE FUNCTIONS
//**********************************************************************************
// These are not really part of the driver, just examples of how to call things from
// your program:
//
//   void main()
//   {
//      Read_Object();                     //Gets you Temp of objects in FOV
//      Read_Ambient();                     //Gets you Ambient Temp
//   
//      //LETS EDIT SOME EEPROM VALUES!!!
//      Read_TOMAX();                      //Will read default value - probably 9993
//      MLX_Write_Transaction(TO_Max,0x00,0x00);//Need to erase EEPROM first with 0x0000
//      Read_TOMAX();                      //Will now read 0x0000
//      MLX_Write_Transaction(TO_Max,0xFF,0xFF);//Write desired values
//      Read_TOMAX();                      //Will now read 0xFFFF
//   }

_________________
CCS PCM 5.078 & CCS PCH 5.093
ep.hobbyiest



Joined: 08 Oct 2014
Posts: 20

View user's profile Send private message Send e-mail

PostPosted: Wed Oct 25, 2017 12:23 pm     Reply with quote

Hi,
I am using your code. But data is not being read correctly.
I could see some variation in temperature. But not correct.
Code:
Object Temp:-272.01
Ambient Temp:-270.98
Object Temp:-272.79
Ambient Temp:-270.02


What could be the problem ?

I am using PIC16F886 and connected SDA to PC3 and SCL to PC4.
Pull-up are provided.
My circuits work on 3.3 Volt.

Following is my main.h file.
Code:
#include <16F886.h>
#device ADC=16

#FUSES NOWDT                    //No Watch Dog Timer
#FUSES NOBROWNOUT               //No brownout reset
#FUSES NOLVP                    //No low voltage prgming, B3(PIC16) or B5(PIC18) used for I/O

#use delay(crystal=8MHz)
#use rs232(baud=9600,parity=N,xmit=PIN_C6,rcv=PIN_C7,bits=8,stream=PORT1)
#use i2c(Master,slow,sda=PIN_C3,scl=PIN_C4,FORCE_SW)

#define LED PIN_A0
#define DELAY 1000
Gabriel



Joined: 03 Aug 2009
Posts: 1067
Location: Panama

View user's profile Send private message

PostPosted: Thu Oct 26, 2017 5:53 am     Reply with quote

Hi,

The most obvious problem I see is that your serial STREAM declaration does not match the stream on the code's print statements.

Other possible reasons:
Check your pullups.
Check your I2C declaration.

G.
_________________
CCS PCM 5.078 & CCS PCH 5.093
patan_mustafa



Joined: 10 Dec 2006
Posts: 2

View user's profile Send private message Send e-mail Visit poster's website

PostPosted: Sat Dec 23, 2017 2:08 am     Reply with quote

If you add following lines before read sensor, code works well.
Code:

output_low(PIN_C4);
output_low(PIN_C3);
delay_ms(500);
Display posts from previous:   
Post new topic   Reply to topic    CCS Forum Index -> Code Library All times are GMT - 6 Hours
Page 1 of 1

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum


Powered by phpBB © 2001, 2005 phpBB Group