0

I have one IR Thermal Sensor (mlx90614 with this datasheet) based on datasheet communication with sensor is in this way: datasheet communication

Some of example is in the here: mlx90614 example arduino

The code for working with arduino Base is here:

#include <i2cmaster.h>
void setup(){
Serial.begin(9600);
Serial.println("Setup...");

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

}
void loop(){
int dev = 0x5A<<1;
int data_low = 0;
int data_high = 0;
int pec = 0;

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;
float fahrenheit = (celcius*1.8) + 32;

Serial.print("Celcius: ");
Serial.println(celcius);

Serial.print("Fahrenheit: ");
Serial.println(fahrenheit);

delay(1000); // wait a second before printing again



}

SO i need to chnage this code for my mikrobasic programing the avr so i have changed those codes and made this code:

    program mlx60914
symbol LCD_RS_my = PORTc7_bit
  symbol LCD_EN_my =PORTc6_bit
  symbol LCD_D4_my =PORTc2_bit
  symbol LCD_D5_my=PORTc3_bit
  symbol LCD_D6_my =PORTc4_bit
  symbol LCD_D7_my=PORTc5_bit

  symbol LCD_RS_Direction_my = DDc7_bit
  symbol LCD_EN_Direction_my =DDc6_bit
  symbol LCD_D4_Direction_my =DDc2_bit
  symbol LCD_D5_Direction_my=DDc3_bit
  symbol LCD_D6_Direction_my =DDc4_bit
  symbol LCD_D7_Direction_my=DDc5_bit
dim  celcius,fahrenheit as float
txt1 as string[6]

' Lcd module connections
dim LCD_RS as sbit at LCD_RS_my
dim LCD_EN as sbit at LCD_EN_my
dim LCD_D4 as sbit at LCD_D4_my
dim LCD_D5 as sbit at LCD_D5_my
dim LCD_D6 as sbit at LCD_D6_my
dim LCD_D7 as sbit at LCD_D7_my

dim LCD_RS_Direction as sbit at LCD_RS_Direction_my
dim LCD_EN_Direction as sbit at LCD_EN_Direction_my
dim LCD_D4_Direction as sbit at LCD_D4_Direction_my
dim LCD_D5_Direction as sbit at LCD_D5_Direction_my
dim LCD_D6_Direction as sbit at LCD_D6_Direction_my
dim LCD_D7_Direction as sbit at LCD_D7_Direction_my

dim Soft_I2C_Scl_Output    as sbit at PORTC0_bit
    Soft_I2C_Sda_Output    as sbit at PORTC1_bit
    Soft_I2C_Scl_Input     as sbit at PINC0_bit
    Soft_I2C_Sda_Input     as sbit at PINC1_bit
    Soft_I2C_Scl_Direction as sbit at DDC0_bit
    Soft_I2C_Sda_Direction as sbit at DDC1_bit


sub procedure Work_MLX90614()''dim celcius as ^double, dim fahrenheit as ^double)

dim  dev1,data_low1,data_high1, pec1,frac   as integer
dim  tempFactor,tempData as double
'dim  celcius,fahrenheit as float

dev1 = 0x5A<<1
data_low1 = 0
data_high1 = 0
pec1 = 0

'' Write
    Soft_I2C_Start()                         ' issue start signal
    Soft_I2C_Write(dev1)                 ' address dev
    Soft_I2C_Write(0x07)                   ' write 01 to year word (REG6)
'    Soft_I2C_Stop()                          ' issue stop signal
'
'' Read
'    Soft_I2C_Start()                         ' issue start signal
'    Soft_I2C_Write(dev1)                 ' address dev
    data_low1=Soft_I2C_Read(1)
    data_high1=Soft_I2C_Read(1)
    pec1=Soft_I2C_Read(0)
    Soft_I2C_Stop()   ' Issue stop signal

     tempFactor= 0.02 '' 0.02 degrees per LSB (measurement resolution of the MLX90614)
     tempData = 0x0000'' zero out the data


'   tempData=data_high and 0x007F
    tempData = ((data_high1 and 0x007F) << 8) + data_low1
    tempData = (tempData * tempFactor)-0.01

    celcius = tempData - 273.15
    fahrenheit = (celcius*1.8) + 32
    Lcd_Cmd(_LCD_CLEAR) FloatToStr(celcius,txt1) lcd_out(1,1,"Celcius: ")   lcd_out(2,1,txt1)


end sub


main:

 celcius=0
 Soft_I2C_Init()
 Lcd_Init()
 Lcd_Cmd(_LCD_CLEAR)               ' Clear display
 Lcd_Cmd(_LCD_CURSOR_OFF)          ' Cursor off
  while 1

'lcd_out(1,1,"Celcius: ")  FloatToStr(celcius,txt1) lcd_out(2,1,txt1)
   Work_MLX90614()  '' FloatToStr(celcius,txt1) lcd_out(1,1,"Celcius: ")   lcd_out(2,1,txt1)
   delay_ms(300)
  wend
end.

So it don't Show, but the LCD don't show the correct number, it's show -273.00 or 378.00 or 59.00 number or ... so it's don's Show correct temperature only some times show near correct temperature degree !!!

Dose these number's Showing the I2C communication is done correctly or this is one signal of mismatching in I2C configuration?

It must be recommended that the IR sensor communication (SPI Connection) don't Show sometimes the correct number with Arduino don't Show correct too.

my guess is the conversion from Arduino code to Mikrobasic from this codes are too important and may be have some mistake in my conversion.

// read

i2c_rep_start(dev+I2C_READ);

So the code's and simulation in Proteus (without mlx90614 library) is here: simulation in Proteus Thanks a lot .

SamGibson
  • 17,231
  • 5
  • 37
  • 58
Soheil Paper
  • 1
  • 1
  • 3
  • 25

1 Answers1

1

I don't use mikroBasic, and some parts of your question are unclear in English, but I can see some mistakes in your mikroBasic code, which I have attempted to fix below.

Background

With I²C (and SMBus) devices, after a Start (or Repeated Start) condition, the direction of data transfer is fixed until the next Start (or Repeated Start). Therefore to switch between using Write to specify a device register (in your case, 0x07) and using Read to read the values from that register (in your case, the temperature value) either a Stop+Start or a Repeated Start is required. A Repeated Start is typically used.

Also note that due to the \$\small{R/\overline{W}}\$ bit being part of the 8-bit byte which also contains the 7-bit I²C address, then the full 8-bit byte following a Start (or Repeated Start) condition has a different value, depending on whether the Master is going to Write to the Slave (Master Transmitter) or Read from the Slave (Master Receiver).

In the Arduino code, we see that it does contain a call to i2c_rep_start() to perform that Repeated Start with the \$\small{R/\overline{W}}\$ bit set to 1 (since the constant I2C_READ = 1):

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();

But in your original mikroBasic code, after removing the lines which are only comments, we see there is no call to anything which could be a Repeated Start and which sets the \$\small{R/\overline{W}}\$ bit to 1:

dev1 = 0x5A<<1

    Soft_I2C_Start()                         ' issue start signal
    Soft_I2C_Write(dev1)                 ' address dev
    Soft_I2C_Write(0x07)                   ' write 01 to year word (REG6)

    data_low1=Soft_I2C_Read(1)
    data_high1=Soft_I2C_Read(1)
    pec1=Soft_I2C_Read(0)
    Soft_I2C_Stop()   ' Issue stop signal

So a Repeated Start is missing between the last call to Soft_I2C_Write() and the first call to Soft_I2C_Read(). I guess this might be what you are trying to say near the end of your question.

Suggested approach

The good news is that the mikroBasic documentation for their "Software I2C Library" includes an example of how you should handle this situation. Using the example on that webpage, I have written this modified version below and I suggest that your mikroBasic code should be similar to this (but note that I have not, and cannot, test this - you must debug it yourself):

' 7-bit I2C slave address = 0x5A
dev1write = 0x5A<<1
dev1read = (0x5A<<1)+1

Soft_I2C_Start()
Soft_I2C_Write(dev1write)     ' Send I2C Address with R/-W bit = 0
Soft_I2C_Write(0x07)
Soft_I2C_Start()              ' Send I2C Repeated Start
Soft_I2C_Write(dev1read)      ' Send I2C Address with R/-W bit = 1
data_low = Soft_I2C_Read(1)
data_high = Soft_I2C_Read(1)
pec = Soft_I2C_Read(0)
Soft_I2C_Stop()               ' Send I2C Stop

I hope that will be a good starting point for you. Refer to the linked mikroBasic documentation above for more information.


You will also find it easier to troubleshoot similar problems if you get a logic analyser. Either buy a cheap one from the usual sources and use the open source Sikrok software (initial costs are low, but there is no manufacturer support and I have seen limitations with some of the hardware) or buy a brand-name one with its own software (initial costs are higher, but there is support from the manufacturer).

With one of those, you would be able to see what is happening on the I²C bus (and, if you have an Arduino, you could run the Arduino code, then run the mikroBasic code, and compare those two I²C bus traces from the logic analyser).

If you continue to have problems, and if you decide not to use a logic analyser, then at least eliminate the temperature calculation part of your code, and examine the raw bytes received from the sensor - in case your temperature calculation code also contains a bug. I have not reviewed that part of your code.

SamGibson
  • 17,231
  • 5
  • 37
  • 58