3. Software

This sample program reads the temperature from the MLX90614ESF’s RAM using SMBus. The program works with our Orangutan robot controllers (except for the Orangutan X2) and uses the Pololu AVR C/C++ Library to print the measured temperature to the LCD. For specific information on how to program your Orangutan, read its User’s Guide, which can be found on the resources tab of the product’s website.

#include <avr/io.h>
#include <pololu/orangutan.h>

void i2c_start() {
	TWCR = (1 << TWINT) | (1 << TWSTA) | (1 << TWEN);	// send start condition
	while (!(TWCR & (1 << TWINT)));
}

void i2c_write_byte(char byte) {
	TWDR = byte;			
	TWCR = (1 << TWINT) | (1 << TWEN); // start address transmission
	while (!(TWCR & (1 << TWINT)));
}

char i2c_read_byte() {
	TWCR = (1 << TWINT) | (1 << TWEA) | (1 << TWEN);	// start data reception, transmit ACK
	while (!(TWCR & (1 << TWINT)));
	return TWDR;
}

void i2c_receive_pec() {
	TWCR = (1 << TWINT) | (1 << TWEN);	// start PEC reception, transmit NACK
	while (!(TWCR & (1 << TWINT)));
}

void i2c_stop() {
	TWCR = (1 << TWINT) | (1 << TWSTO) | (1 << TWEN); // send stop condition
}

//Returns 100 times the temperature read by the sensor giving a 0.01 degree resolution.
long i2c_read_temperature_f() {
	long low_byte, high_byte;

	DDRC = 0;							// all inputs
	PORTC = (1 << PORTC4) | (1 << PORTC5);	// enable pull-ups on SDA and SCL, respectively

	TWSR = 0;		// clear bit-rate prescale bits
	TWBR = 192;		// produces an SCL frequency of 50 kHz with a 20 MHz CPU clock speed.

	i2c_start();
	// The expected value of TWSR & 0xF8 is now 0x08 (Start condition transmitted).

	i2c_write_byte(0);// 0 is the universal write address for slaves.
	// The expected value of TWSR & 0xF8 is now 0x18 (SLA+W transmitted ACK received).

	i2c_write_byte(0x07); // read TObj1 (0x07) from RAM
	// The expected value of TWSR & 0xF8 is now 0x28 (Data transmitted ACK received).

	i2c_start();
	// The expected value of TWSR & 0xF8 is now 0x10 (Repeated start has been transmitted).

	i2c_write_byte(1); // 1 is the universal read address for slaves.
	// The expected value of TWSR & 0xF8 is now 0x40 (SLA+R transmitted ACK received).

	low_byte = i2c_read_byte();
	// The expected value of TWSR & 0xF8 is now 0x50 (Data received ACK received).

	high_byte = i2c_read_byte();
	// The expected value of TWSR & 0xF8 is now 0x50 (Data received ACK received).

	i2c_receive_pec();  // read packet error code (PEC)
	// The expected value of TWSR & 0xF8 is now 0x58 (Data received NOT ACK received).

	i2c_stop();

	// Tk is temperature in Kelvin, Tf is temperature in degrees Fahrenheit, To is the raw
	// value of the object temperature as returned by the sensor
	// 100 Tk = To × 2 (from the datasheet section 8.7.2--To has the units 0.02K)
	// Tf = Tk × 9/5 - 459.67 (conversion from Kelvin to Farenheit)

	// 100 × Tf = 100 × Tk ×  9/5 - 45967
	// 100 × Tf = To  × 2  × 9/5  - 45967
	// 100 × Tf = To  × 18/5      - 45967
	return (256*high_byte+low_byte) * 18/5 - 45967;  // return temperature in units of 0.01°F
}


int main()
{
	long object_temperature_f;
	clear();
	print("press");
	lcd_goto_xy(0, 1);
	print("button");

	wait_for_button(ALL_BUTTONS);
	clear();
	while (1)   // loop forever
	{
		object_temperature_f = i2c_read_temperature_f();
          
		lcd_goto_xy(0, 0);
		// print the temperature in degrees Fahrenheit on the LCD (this code formats it nicely)
		if (object_temperature_f < 0)
		{
			print("-");
			object_temperature_f = -object_temperature_f;
		}
		long integer_temperature = object_temperature_f / 100;
		print_long(integer_temperature);
		print(".");
		long decimal = object_temperature_f - integer_temperature * 100;
		if (decimal < 10)
			print("0");
		print_long(decimal);
		print_character(223);		// degree symbol
		print("F   ");
		delay_ms(75);
	}

	return 0;
}