0

i have connected mlx90615 Thermometer module to my raspberry i2c pins
but i was not able to find any code or guidance on how to receive measured temperatures from the sensor (i2c bus)
but there are some libraries and code snippets for arduino
i tried a lot to port arduino library to raspberry but every time i run the code the result is the same
this is arduino library
and this is the code that i wrote for raspberry according to the mentioned library :

#include <stdio.h>
#include <stdint.h>
#include <wiringPi.h>
#include <wiringPiI2C.h>

#define SDA_PIN 8   //define the SDA pin (8 is wiringPi pin for raspberry pin 3)
#define SCL_PIN 9   //define the SCL pin (9 is wiringPi pin for raspberry pin 5)

#define i2c_addr 0x5b

#define MLX90615_OBJECT_TEMPERATURE     0x27
#define MLX90615_AMBIENT_TEMPERATURE    0x26

uint8_t const I2C_DELAY_USEC = 4;
uint8_t const I2C_READ = 1;
uint8_t const I2C_WRITE = 0;

typedef unsigned char byte;

uint8_t read(uint8_t);
bool restart(uint8_t);
bool start(uint8_t);
void stop(void);
bool write(uint8_t);
float getTemperature(int);


int main()
{

    printf("RESULT : %f\n",getTemperature(MLX90615_AMBIENT_TEMPERATURE));

    return 0;
}

float getTemperature(int Temperature_kind) {

    wiringPiSetup();

    pinMode(SDA_PIN, OUTPUT);
    digitalWrite(SDA_PIN, HIGH);
    pinMode(SCL_PIN, OUTPUT);
    digitalWrite(SCL_PIN, HIGH);

    //wiringPiI2CSetup(0x5b);
    byte dev = (i2c_addr << 1);  // remain to be seen!
    byte dataLow = 0;
    byte dataHigh = 0;
    float celcius = 0.0;

    start(dev | I2C_WRITE);
    write(Temperature_kind);

    // read
    restart(dev | I2C_READ);
    dataLow = read(false);
    dataHigh = read(false);
    read(true);
    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

    // This masks off the error bit of the high byte, then moves it left 8 bits and adds the low byte.
    tempData = (double)(((dataHigh & 0x007F) << 8) | dataLow);
    tempData = (tempData * tempFactor) - 0.01;

    celcius = (float)(tempData - 273.15);

    return celcius;
    //float fahrenheit = (celcius*1.8) + 32;
 }

uint8_t read(uint8_t last) {
    uint8_t b = 0;
    // make sure pull-up enabled
    digitalWrite(SDA_PIN, HIGH);
    pinMode(SDA_PIN, INPUT);
    // read byte
    for (uint8_t i = 0; i < 8; i++) {
        // don't change this loop unless you verify the change with a scope
        b <<= 1;
        delayMicroseconds(I2C_DELAY_USEC);
        digitalWrite(SCL_PIN, HIGH);
        if (digitalRead(SDA_PIN)) b |= 1;
        digitalWrite(SCL_PIN, LOW);
    }
    // send Ack or Nak
    pinMode(SDA_PIN, OUTPUT);
    digitalWrite(SDA_PIN, last);
    digitalWrite(SCL_PIN, HIGH);
    delayMicroseconds(I2C_DELAY_USEC);
    digitalWrite(SCL_PIN, LOW);
    digitalWrite(SDA_PIN, LOW);

    return b;
}
//--------------------------------------------------------------------------    ----
/** Issue a restart condition.
*
* \param[in] addressRW I2C address with read/write bit.
*
* \return The value true, 1, for success or false, 0, for failure.
*/
bool restart(uint8_t address) {
    digitalWrite(SDA_PIN, HIGH);
    digitalWrite(SCL_PIN, HIGH);
    delayMicroseconds(I2C_DELAY_USEC);
    return start(address);
}
//------------------------------------------------------------------------------
/** Issue a start condition.
*
* \param[in] addressRW I2C address with read/write bit.
*
* \return The value true, 1, for success or false, 0, for failure.
*/
bool start(uint8_t address) {
    digitalWrite(SDA_PIN, LOW);
    delayMicroseconds(I2C_DELAY_USEC);
    digitalWrite(SCL_PIN, LOW);
    return write(address);
}
//------------------------------------------------------------------------------
/**  Issue a stop condition. */
void stop(void) {
    digitalWrite(SDA_PIN, LOW);
    delayMicroseconds(I2C_DELAY_USEC);
    digitalWrite(SCL_PIN, HIGH);
    delayMicroseconds(I2C_DELAY_USEC);
    digitalWrite(SDA_PIN, HIGH);
    delayMicroseconds(I2C_DELAY_USEC);
}
//------------------------------------------------------------------------------
/**
* Write a byte.
*
* \param[in] data The byte to send.
*
* \return The value true, 1, if the slave returned an Ack or false for Nak.
*/
bool write(uint8_t data) {
    // write byte
    for (uint8_t m = 0X80; m != 0; m >>= 1) {
        // don't change this loop unless you verify the change with a scope
        digitalWrite(SDA_PIN, m & data);
        digitalWrite(SCL_PIN, HIGH);
        delayMicroseconds(I2C_DELAY_USEC);
        digitalWrite(SCL_PIN, LOW);
    }
    // get Ack or Nak
    pinMode(SDA_PIN, INPUT);
    // enable pullup
    digitalWrite(SDA_PIN, HIGH);
    digitalWrite(SCL_PIN, HIGH);
    uint8_t rtn = digitalRead(SDA_PIN);
    digitalWrite(SCL_PIN, LOW);
    pinMode(SDA_PIN, OUTPUT);
    digitalWrite(SDA_PIN, LOW);
    return rtn == 0;
}

as i mentioned before the problem with the above code is that the result is always "382.179993"
i have also checked my i2c connection and device address with i2cdetect -y 1 and everything is good but i have been stuck about receiving the correct temperature value!
note that for converting arduino code to be used in raspberry i used wiringPi Library
any help will be highly appreciated...(i have been stuck here for more than one week!!)

  • i hope somebody may help me... – hossein nakhaeipoor Jul 23 '16 at 14:56
  • I'm having a similar problem trying to do this in Python. In hex, I return FFFF for both ambient and object temperatures. This happens regardless of whether or not I use pull-up resistors. @Hossein - did you ever solve this? – Larry Garber Aug 13 '16 at 22:19
  • Take a look at the BCM2835 GPIO library. It's for a RPi2B but I found it works with a RPi3B too since the GPIO is similiar. I2C, SPI, & GPIO all work. – Farad'n Oct 28 '18 at 14:21
0

I may have your solution. It appears that the MLX90615 requires 2 start bits (the second being classified as the "Repeated Start Condition" in the MLX90615 spec sheet). By default, I believe the RPi only sends the first. So you have to configure it to send the second. This is the command line code I found elsewhere on the net:

sudo su -

echo -n 1 > /sys/module/i2c_bcm2708/parameters/combined

exit

Good luck!

  • hi larry and thanks for your feedback i was not able to solve the problem but i found an oddly solution. i convert the interface from i2c to uart and send start bits with serial port and it worked! – hossein nakhaeipoor Aug 16 '16 at 0:20
  • Would you please write a detailed answer and then accept it. I've heard it can take four days before you're allowed to accept your own answer, but it will help anybody who is searching on your thermometer module. – NomadMaker Jul 19 '18 at 17:39

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.