Interface with the PICAXE-20X2
Measuring Temperature - MLX90614_1.Bas.
This program continually measures the temperature of the TO5 can package and the temperature of the object emmitting the infrared energy. This is a matter of reading RAM locations $06 and $07. Note that RAM locations are 16 bits wide.
The temperature in degrees Kelvin is then calculated as 0.02 * Val. Or TC_100 = 2 * Val - 27315.
Note that in subroutine ReadRAM, an 8-bit CRC consisting of all bytes sent and all byte received is calculated. The result of the final step involving the received packet error correction (PEC) byte should result in zero. If this is true, variable Status is set to a 1 to indicate the read was successful.
Timing is important with the SMBus and thus all CRC calculations are performed outside of the communication sequences.
Note that the ReadRAM involves an I2C read which is of the form;
Start, SlaveAdr*2, RAMLocation, Start, SlaveAdr*2 + 1, Read, Read, Read, Stop
(Note that Slave*2, RAMLocation, SlaveAdr * 2 + 1, Lo, Hi and PEC are used in calculating the CRC).
The PICAXE abbreviates the above sequence as;
Hi2cin [SlaveAdr_2], RamLocation, (Lo, Hi, PEC)
Note that a general slave address may be used in addressing a device if it is the only device on the I2C bus.
' MLX90614_1.Bas
'
' Continually measures and displays T_ambient and T_object.
'
' PICAXE-20X2 MLX90614ESF-AAA
'
' Term 11 SCL --------------- SCL
' Term 13 SDA --------------- SDA
'
' 4.7K resistors to +5 VDC on SDA and SCL
'
' Note that this is a direct interface with the PICAXE. The Parallax and
' Sparkfun boards are not required.
'
' copyright, Peter H Anderson, Baltimore, MD, Mar 12, 11
#picaxe 20x2
#Terminal 9600
#No_Table
#No_Data
#freq m4
Symbol Lo = B0
Symbol Hi = B1
Symbol PEC = B2
Symbol Status = B3
Symbol Whole = B4
Symbol Fract = B5
Symbol Val = W3
Symbol TC_100 = W4
Symbol SlaveAdr_2 = B10
Symbol RamLocation = B11
Symbol X = B12
Symbol N = B13
Symbol CRC8 = B14
Top:
Hi2cSetup I2CMaster, 45, I2CSlow, I2CByte
SlaveAdr_2 = $00 * 2 ' use general slave adr
Again:
RamLocation = $06 ' ambient temperature
GoSub ReadRAM
If Status = 1 Then
TC_100 = Val * 2 - 27315
SerTxD ("T_ambient = ")
GoSub DisplayTc
Else
SerTxD ("T_ambient - Error")
End If
SerTxD (", ")
RamLocation = $07 ' ambient temperature
GoSub ReadRAM
If Status = 1 Then
TC_100 = Val * 2 - 27315
SerTxD ("T_object = ")
GoSub DisplayTc
Else
SerTxD ("T_object - Error")
End If
SerTxD (CR, LF)
Pause 1000
GoTo Again
ReadRAM:
Hi2cin [SlaveAdr_2], RamLocation, (Lo, Hi, PEC)
Val = Hi
Val = Val * 256 + Lo
'SerTxD ("Hello ", #TC_100, " ", #PEC, CR, LF)
CRC8 = $00
X = SlaveAdr_2
GoSub CalcCRC8
X = RamLocation
GoSub CalcCRC8
X = SlaveAdr_2 + 1
GoSub CalcCRC8
X = Lo
GoSub CalcCRC8
X = Hi
GoSub CalcCRC8
X = PEC
GoSub CalcCRC8
'SerTxD ("CRC = ", #CRC8, CR, LF)
If CRC8 = 0 Then
Status = 1 ' success
Else
Status = 0
Endif
Return
DisplayTc:
Whole = TC_100 / 100
Fract = TC_100 // 100
SerTxD (#Whole, ".")
If Fract < 10 Then
SerTxD ("0")
Endif
SerTxD (#Fract)
Return
CalcCRC8:
X = X ^ CRC8
For N = 0 to 7
If X > 127 Then
X = X * 2
X = X ^ $07
Else
X = X * 2
Endif
Next
CRC8 = X
Return
Reading EEPROM - MLX90614_2.Bas
This routine illustrates how to read from the 32 EEPROM locations. Of particular interest is EEPROM location $04 (emissity) and $0e (assigned I2C slave address). Note that all EEPROM locations are 16 bits and the emissivity does use all 16 (values 0 - 65535). However, the slave address, in the range of 0 - 127 uses only the lower byte.
Note that RAM occupies addresses 0 - 31 (or $00 - $1F) and EEPROM occupies addresses $20 - $3F
Hi2cin [SlaveAdr_2], EEPROMLocation, (Lo, Hi, PEC)
' MLX90614_2.Bas
'
' Reads and display 32 words of EEPROM. Note that EEPROM is 16 bits wide.
'
' Note that location $04 is the emissivity and $0e (14) is the slave address.
'
' PICAXE-20X2 MLX90614ESF-AAA
'
' Term 11 SCL --------------- SCL
' Term 13 SDA --------------- SDA
'
' 4.7K resistors to +5 VDC on SDA and SCL
'
' Note that this is a direct interface with the PICAXE. The Parallax and
' Sparkfun boards are not required.
'
'
' copyright, Peter H Anderson, Baltimore, MD, Mar 13, 11
#picaxe 20x2
#Terminal 9600
#No_Table
#No_Data
#freq m4
Symbol Lo = B0
Symbol Hi = B1
Symbol PEC = B2
Symbol Status = B3
Symbol Digit = B4
Symbol Ch = B5
Symbol Val = W3
Symbol I = B8
Symbol J = B9
Symbol K = B10
Symbol SlaveAdr_2 = B11
Symbol EEPROMLocation = B12
Symbol CRC8 = B13
Symbol X = B14
Top:
Hi2cSetup I2CMaster, 45, I2CSlow, I2CByte
SlaveAdr_2 = $00 * 2 ' use the general slave address
Again:
For I = 0 to 31
EEPROMLocation = $20 + I
GoSub ReadEEPROM
If Status = 1 Then
GoSub DisplayEEPROM
Else
SerTxD (#I, " ", "Invalid", CR, LF)
EndIf
Pause 1000
Next
Pause 10000
GoTo Again
ReadEEPROM:
Hi2cin [SlaveAdr_2], EEPROMLocation, (Lo, Hi, PEC)
Val = Hi
Val = Val * 256 + Lo
CRC8 = $00
X = SlaveAdr_2
GoSub CalcCRC8
X = EEPROMLocation
GoSub CalcCRC8
X = SlaveAdr_2 + 1
GoSub CalcCRC8
X = Lo
GoSub CalcCRC8
X = Hi
GoSub CalcCRC8
X = PEC
GoSub CalcCRC8
'SerTxD ("CRC = ", #CRC8, CR, LF)
If CRC8 = 0 Then
Status = 1 ' success
Else
Status = 0
Endif
Return
DisplayEEPROM:
SerTxD (#I, " ")
For J = 0 to 3
Digit = Val / 4096
If Digit >= 10 Then
Ch = "A" + Digit - 10
Else
Ch = "0" + Digit
EndIf
SerTxD (Ch)
Val = Val * 16
Next
SerTxD (CR, LF)
Return
CalcCRC8:
X = X ^ CRC8
For K = 0 to 7
If X > 127 Then
X = X * 2
X = X ^ $07
Else
X = X * 2
Endif
Next
CRC8 = X
Return
' MLX90614_3.Bas
'
' Prompts user for SlaveAddress and writes this to EEPROM address $0e. Note that
' $00 is used as the SlaveAddress up to this point. But the new slave address is
' used to read and display the content of location $0e.
'
' The intent is a framework for a program to modify the slave address to something
' other than $5a to allow for more than one device on the same bus.
'
' Note that after a lot of frustration, I discovered that after programming a new
' slave address, I had to recycle power to the MLX90614 for the new slave address to
' be recognized.
'
'
' PICAXE-20X2 MLX90614ESF-AAA
'
' Term 11 SCL --------------- SCL
' Term 13 SDA --------------- SDA
'
' 4.7K resistors to +5 VDC on SDA and SCL
'
' Note that this is a direct interface with the PICAXE. The Parallax and
' Sparkfun boards are not required.
'
'
' copyright, Peter H Anderson, Baltimore, MD, Mar 15, 11
#picaxe 20x2
#Terminal 9600
#No_Table
#No_Data
#freq m4
Symbol Lo = B0
Symbol Hi = B1
Symbol PEC = B2
Symbol Status = B3
Symbol Ch = B5
Symbol Val = W3
Symbol I = B8
Symbol J = B9
Symbol K = B10
Symbol SlaveAdr_2 = B11
Symbol EEPROMLocation = B12
Symbol CRC8 = B13
Symbol X = B14
Symbol NewSlaveAdr = B15
Top:
Pause 1000
Hi2cSetup I2CMaster, 45, I2CSlow, I2CByte
TryAgn:
SerTxD ("Enter New Slave Address: ")
SerRxD [15000, TryAgn], #NewSlaveAdr
SerTxD (#NewSlaveAdr, CR, LF);
Pause 5000 ' pause to admire
SlaveAdr_2 = $00 * 2 ' Use the general address for now
Again:
EEPROMLocation = $20 + $0e
GoSub ReadEEPROM
If Status = 1 Then
Val = Val & $00ff ' take the low byte
SerTxD ("Current Slave Adr: ", #Val, CR, LF)
Else
SerTxD ("Current Slave Adr", "Invalid", CR, LF)
EndIf
Pause 5000
SlaveAdr_2 = $00 * 2
Val = $00
GoSub WriteEEPROM ' erase location $0e
Val = NewSlaveAdr ' now program in the new slave address
GoSub WriteEEPROM
' recycle power to the MLX90614 before trying to use the new slave address
SerTxD ("Recycle power to the MLX90614. Key in a number when done", CR, LF)
SerRxD [45000], Ch
SlaveAdr_2 = NewSlaveAdr * 2
GoSub ReadEEPROM
If Status = 1 Then
Val = Val & $00ff ' take the low byte
SerTxD ("Current Slave Adr: ", #Val, CR, LF)
Else
SerTxD ("Current Slave Adr", "Invalid", #Val, CR, LF)
EndIf
Pause 10000
GoTo Again
ReadEEPROM:
Hi2cin [SlaveAdr_2], EEPROMLocation, (Lo, Hi, PEC)
Val = Hi
Val = Val * 256 + Lo
CRC8 = $00
X = SlaveAdr_2
GoSub CalcCRC8
X = EEPROMLocation
GoSub CalcCRC8
X = SlaveAdr_2 + 1
GoSub CalcCRC8
X = Lo
GoSub CalcCRC8
X = Hi
GoSub CalcCRC8
X = PEC
GoSub CalcCRC8
' SerTxD ("CRC = ", #CRC8, CR, LF)
If CRC8 = 0 Then
Status = 1 ' success
Else
Status = 0
Endif
SerTxD (#SlaveAdr_2, " ", #EEPROMLocation, CR, LF)
Return
WriteEEPROM:
Lo = Val
Hi = $00
CRC8 = $00
X = SlaveAdr_2
GoSub CalcCRC8
X = EEPROMLocation
GoSub CalcCRC8
X = Lo
GoSub CalcCRC8
X = Hi
GoSub CalcCRC8
PEC = CRC8
Hi2cOut [SlaveAdr_2], EEPROMLocation, (Lo, Hi, PEC)
Pause 20
Return
CalcCRC8:
X = X ^ CRC8
For K = 0 to 7
If X > 127 Then
X = X * 2
X = X ^ $07
Else
X = X * 2
Endif
Next
CRC8 = X
Return
' MLX90614_4.Bas
'
' Continually measures and displays T_ambient and T_object for three devices
' on a single bus.
'
' Note that MLX90614_3 was used to program the slave addresses for the three
' sensors 90, 91 and 92.
'
' PICAXE-20X2 MLX90614ESF-AAA
'
' Term 11 SCL --------------- SCL -------------------- To two additional
' Term 13 SDA --------------- SDA -------------------- devices
'
' 4.7K resistors to +5 VDC on SDA and SCL
'
' Note that this is a direct interface with the PICAXE. The Parallax and
' Sparkfun boards are not required.
'
'
' copyright, Peter H Anderson, Baltimore, MD, Mar 12, 11
#picaxe 20x2
#Terminal 9600
#No_Table
#No_Data
#freq m4
Symbol Lo = B0
Symbol Hi = B1
Symbol PEC = B2
Symbol Status = B3
Symbol Whole = B4
Symbol Fract = B5
Symbol Val = W3
Symbol TC_100 = W4
Symbol SlaveAdr_2 = B10
Symbol RamLocation = B11
Symbol X = B12
Symbol N = B13
Symbol CRC8 = B14
Symbol J = B15
Top:
Hi2cSetup I2CMaster, 45, I2CSlow, I2CByte
Again:
For J = 0 to 2
Lookup J, (180, 182, 184), SlaveAdr_2
RamLocation = $06 ' ambient temperature
GoSub ReadRAM
SerTxD (#J, " ")
If Status = 1 Then
TC_100 = Val * 2 - 27315
SerTxD ("T_ambient = ")
GoSub DisplayTc
Else
SerTxD ("T_ambient - Error")
End If
SerTxD (", ")
RamLocation = $07 ' ambient temperature
GoSub ReadRAM
If Status = 1 Then
TC_100 = Val * 2 - 27315
SerTxD ("T_object = ")
GoSub DisplayTc
Else
SerTxD ("T_object - Error")
End If
SerTxD (CR, LF)
Next
Pause 2000
GoTo Again
ReadRAM:
Hi2cin [SlaveAdr_2], RamLocation, (Lo, Hi, PEC)
Val = Hi
Val = Val * 256 + Lo
'SerTxD ("Hello ", #TC_100, " ", #PEC, CR, LF)
CRC8 = $00
X = SlaveAdr_2
GoSub CalcCRC8
X = RamLocation
GoSub CalcCRC8
X = SlaveAdr_2 + 1
GoSub CalcCRC8
X = Lo
GoSub CalcCRC8
X = Hi
GoSub CalcCRC8
X = PEC
GoSub CalcCRC8
'SerTxD ("CRC = ", #CRC8, CR, LF)
If CRC8 = 0 Then
Status = 1 ' success
Else
Status = 0
Endif
Return
DisplayTc:
Whole = TC_100 / 100
Fract = TC_100 // 100
SerTxD (#Whole, ".")
If Fract < 10 Then
SerTxD ("0")
Endif
SerTxD (#Fract)
Return
CalcCRC8:
X = X ^ CRC8
For N = 0 to 7
If X > 127 Then
X = X * 2
X = X ^ $07
Else
X = X * 2
Endif
Next
CRC8 = X
Return
' MLX90614_5.Bas
'
' Sets the emissivity to 1.0 (65535) and performs ten temperature
' measurements. Then prompts the user for an emmisivity in the range
' of 0 to 65535 (corresponding to 0.0 to 1.0). Then performs 10
' measurements using this emmisivity.
'
' Terminates in a loop.
'
' PICAXE-20X2 MLX90614ESF-AAA
'
' Term 11 SCL --------------- SCL
' Term 13 SDA --------------- SDA
'
' 4.7K resistors to +5 VDC on SDA and SCL
'
' Note that this is a direct interface with the PICAXE. The Parallax and
' Sparkfun boards are not required.
'
'
' copyright, Peter H Anderson, Baltimore, MD, Mar 20, 11
#picaxe 20x2
#Terminal 9600
#No_Table
#No_Data
#freq m4
Symbol Lo = B0
Symbol Ch = B0
Symbol Hi = B1
Symbol PEC = B2
Symbol Status = B3
Symbol Whole = B4
Symbol Fract = B5
Symbol Val = W3
Symbol TC_100 = W4
Symbol SlaveAdr_2 = B10
Symbol RamLocation = B11
Symbol EEPROMLocation = B12
Symbol X = B13
Symbol N = B14
Symbol CRC8 = B15
Symbol J = B16
Top:
Hi2cSetup I2CMaster, 45, I2CSlow, I2CByte
SlaveAdr_2 = $00 * 2
EEPROMLocation = $20 + $04
Val = $0000 ' erase the eeprom
GoSub WriteEEPROM
Val = $FFFF ' emissivity set to 1.0
GoSub WriteEEPROM
#REM ' this was used in debugging to verify the EEPROM was being written
GoSub ReadEEPROM
SerTxD ("Emis = ", #Val, CR, LF)
' recycle power to the MLX90614 before trying to use the new emmisivity
' SerTxD ("Recycle power to the MLX90614. Key in a number when done", CR, LF)
' SerRxD [45000], Ch
#ENDREM
For J = 0 to 9 ' ten measurements
RamLocation = $06 ' ambient temperature
GoSub ReadRAM
SerTxD (#J, " ")
If Status = 1 Then
TC_100 = Val * 2 - 27315
SerTxD ("T_ambient = ")
GoSub DisplayTc
Else
SerTxD ("T_ambient - Error")
End If
SerTxD (", ")
RamLocation = $07 ' ambient temperature
GoSub ReadRAM
If Status = 1 Then
TC_100 = Val * 2 - 27315
SerTxD ("T_object = ")
GoSub DisplayTc
Else
SerTxD ("T_object - Error")
End If
SerTxD (CR, LF)
Next
Pause 10000
' now cahnge to emmisivity
EEPROMLocation = $20 + $04
Val = $0000 ' erase the location
GoSub WriteEEPROM
TryAgn:
SerTxD ("Enter emmisivity: ")
SerRxD [15000, TryAgn], #Val
SerTxD (#Val, CR, LF);
GoSub WriteEEPROM
#REM ' for debugging as noted above
GoSub ReadEEPROM
SerTxD ("Emis = ", #Val, CR, LF)
' recycle power to the MLX90614 before trying to use the new slave address
' SerTxD ("Recycle power to the MLX90614. Key in a number when done", CR, LF)
' SerRxD [45000], Ch
#ENDREM
For J = 0 to 9 ' ten measurements with the new emmisivity
RamLocation = $06 ' ambient temperature
GoSub ReadRAM
SerTxD (#J, " ")
If Status = 1 Then
TC_100 = Val * 2 - 27315
SerTxD ("T_ambient = ")
GoSub DisplayTc
Else
SerTxD ("T_ambient - Error")
End If
SerTxD (", ")
RamLocation = $07 ' ambient temperature
GoSub ReadRAM
If Status = 1 Then
TC_100 = Val * 2 - 27315
SerTxD ("T_object = ")
GoSub DisplayTc
Else
SerTxD ("T_object - Error")
End If
SerTxD (CR, LF)
Next
Agn: ' loop forever
SerTxD (".");
Pause 10000
Goto Agn
ReadRAM:
Hi2cin [SlaveAdr_2], RamLocation, (Lo, Hi, PEC)
Val = Hi
Val = Val * 256 + Lo
'SerTxD ("Hello ", #TC_100, " ", #PEC, CR, LF)
CRC8 = $00
X = SlaveAdr_2
GoSub CalcCRC8
X = RamLocation
GoSub CalcCRC8
X = SlaveAdr_2 + 1
GoSub CalcCRC8
X = Lo
GoSub CalcCRC8
X = Hi
GoSub CalcCRC8
X = PEC
GoSub CalcCRC8
'SerTxD ("CRC = ", #CRC8, CR, LF)
If CRC8 = 0 Then
Status = 1 ' success
Else
Status = 0
Endif
Return
ReadEEPROM:
Hi2cin [SlaveAdr_2], EEPROMLocation, (Lo, Hi, PEC)
Val = Hi
Val = Val * 256 + Lo
CRC8 = $00
X = SlaveAdr_2
GoSub CalcCRC8
X = EEPROMLocation
GoSub CalcCRC8
X = SlaveAdr_2 + 1
GoSub CalcCRC8
X = Lo
GoSub CalcCRC8
X = Hi
GoSub CalcCRC8
X = PEC
GoSub CalcCRC8
' SerTxD ("CRC = ", #CRC8, CR, LF)
If CRC8 = 0 Then
Status = 1 ' success
Else
Status = 0
Endif
SerTxD (#SlaveAdr_2, " ", #EEPROMLocation, CR, LF)
Return
WriteEEPROM:
Lo = Val
Hi = Val / 256
CRC8 = $00
X = SlaveAdr_2
GoSub CalcCRC8
X = EEPROMLocation
GoSub CalcCRC8
X = Lo
GoSub CalcCRC8
X = Hi
GoSub CalcCRC8
PEC = CRC8
Hi2cOut [SlaveAdr_2], EEPROMLocation, (Lo, Hi, PEC)
Pause 20
Return
DisplayTc:
Whole = TC_100 / 100
Fract = TC_100 // 100
SerTxD (#Whole, ".")
If Fract < 10 Then
SerTxD ("0")
Endif
SerTxD (#Fract)
Return
CalcCRC8:
X = X ^ CRC8
For N = 0 to 7
If X > 127 Then
X = X * 2
X = X ^ $07
Else
X = X * 2
Endif
Next
CRC8 = X
Return
Arduino
// MLX_Temperature (Arduino - ATMega328)
//
// Arduino Melexis MLX90614
//
// 9 (PORTB.1) ----------------- SDA (2)
// 8 (PORTB.0) ----------------- SCL (1)
// +5 ---- VDD (3)
// GRD --- VSS (4)
//
// 1 K pullups to + 5 VDC on SDA and SCL
//
//
// Continually measures ambient Ta and object To and displays values
// in degrees F to terminal.
//
// copyright, Peter H Anderson, Baltimore, MD, Feb 23, '11
//
#include <avr\io.h>
#define cbi(sfr, bit) (sfr &= (~(0x01 << bit)))
#define sbi(sfr, bit) (sfr |= (0x01 << bit))
#define TRUE 1
#define FALSE 0
#define SUCCESS !0
#define FAILURE 0
#define SCL 0
#define SDA 1
byte meas_temperature(float *pT, byte slave_address, byte ram_location);
float celcius_to_fahr(byte Tc);
byte CalcCRC8(byte CRC8, byte v);
void smI2CStart(void);
void smI2CStop(void);
void smI2COutByte(byte X);
byte smI2CInByte(byte Ack);
void smSDA_HIGH(void);
void smSCL_HIGH(void);
void smSDA_LOW(void);
void smSCL_LOW(void);
void print_float(float f, int num_digits);
void setup(void)
{
Serial.begin(9600);
delay(5000);
Serial.println(">>>>>>>>>>>>>>>>>>>>>>>>"); // just to be sure things are working
}
void loop(void)
{
float Ta_f, To_f;
meas_temperature(&Ta_f, 0x00, 0x06);
meas_temperature(&To_f, 0x00, 0x07);
print_float(Ta_f, 2);
Serial.print(" ");
print_float(To_f, 2);
Serial.print("\n");
delay(1000);
}
byte meas_temperature(float *pT, byte slave_address, byte ram_location) // 0x06 for Ta, 0x07 for Tobj
{
byte low, high, PEC, CRC8;
unsigned int v;
float Tc, Tf;
smI2CStart();
smI2COutByte(slave_address * 2);
smI2COutByte(ram_location);
smI2CStart();
smI2COutByte(slave_address * 2 | 0x01);
low = smI2CInByte(1);
high = smI2CInByte(1);
PEC = smI2CInByte(1);
smI2CStop();
CRC8 = 0x00;
CRC8 = CalcCRC8(CRC8, slave_address*2);
CRC8 = CalcCRC8(CRC8, ram_location);
CRC8 = CalcCRC8(CRC8, slave_address*2+1);
CRC8 = CalcCRC8(CRC8, low);
CRC8 = CalcCRC8(CRC8, high);
CRC8 = CalcCRC8(CRC8, PEC);
if (CRC8 != 0)
{
*pT = 99.9; // used as failure indication
return(FAILURE);
}
else
{
v = (unsigned int) high * 256 + low;
Tc = (float)(v) * 0.02 - 273.15;
Tf = 1.8 * Tc + 32.0;
*pT = Tf;
return(SUCCESS);
}
}
byte CalcCRC8(byte CRC8, byte v)
{
byte n;
v = v ^ CRC8;
for (n=0; n<8; n++)
{
if (v & 0x80)
{
v = (v << 1) ^ 0x07;
}
else
{
v = v << 1;
}
}
return(v);
}
void smI2CStart(void)
{
smSDA_HIGH();
smSCL_HIGH();
smSDA_LOW();
smSCL_LOW();
}
void smI2CStop(void)
{
smSCL_LOW();
smSDA_LOW(); ;
smSCL_HIGH();
smSDA_HIGH();
}
void smI2COutByte(byte X)
{
byte n;
for (n=0; n<8; n++)
{
if (X & 0x80)
{
smSDA_HIGH();
}
else
{
smSDA_LOW();
}
smSCL_HIGH();
smSCL_LOW();
X = X << 1;
}
smSDA_HIGH();
smSCL_HIGH();
smSCL_LOW();
smSDA_LOW();
}
byte smI2CInByte(byte Ack)
{
byte n, X;
smSDA_HIGH();
for (n=0; n<8; n++)
{
smSCL_HIGH();
if (digitalRead(9))
{
X = (X << 1) | 0x01;
}
else
{
X = X << 1;
}
smSCL_LOW();
}
if (Ack)
{
smSDA_LOW();
}
else
{
smSDA_HIGH();
}
smSCL_HIGH();
smSCL_LOW();
smSDA_LOW();
return(X);
}
void smSDA_HIGH(void)
{
cbi(DDRB, SDA);
delayMicroseconds(10);
}
void smSCL_HIGH(void)
{
cbi(DDRB, SCL);
delayMicroseconds(10);
}
void smSDA_LOW(void)
{
cbi(PORTB, SDA);
sbi(DDRB, SDA);
delayMicroseconds(10);
}
void smSCL_LOW(void)
{
cbi(PORTB, SCL);
sbi(DDRB, SCL);
delayMicroseconds(10);
}
void print_float(float f, int num_digits)
{
int f_int;
int pows_of_ten[4] = {1, 10, 100, 1000};
int multiplier, whole, fract, d, n;
multiplier = pows_of_ten[num_digits];
if (f < 0.0)
{
f = -f;
Serial.print("-");
}
whole = (int) f;
fract = (int) (multiplier * (f - (float)whole));
Serial.print(whole);
Serial.print(".");
for (n=num_digits-1; n>=0; n--) // print each digit with no leading zero suppression
{
d = fract / pows_of_ten[n];
Serial.print(d);
fract = fract % pows_of_ten[n];
}
}
// Melexis_EEPROM
//
// Arduino Melexis MLX90614
//
// 9 (PORTB.1) ----------------- SDA (2)
// 8 (PORTB.0) ----------------- SCL (1)
// +5 ---- VDD (3)
// GRD --- VSS (4)
//
// 1 K pullups to + 5 VDC on SDA and SCL
//
// Reads 32 EEPROM locations and displays.
//
// EEPROM location 0x0e is changed to 0x5A. The device is then addressed as 0x5a.
//
// copyright, Peter H Anderson, Baltimore, MD, Feb 5, '11
//
#include <avr\io.h>
#define cbi(sfr, bit) (sfr &= (~(0x01<<bit)))
#define sbi(sfr, bit) (sfr |= (0x01 << bit))
#define TRUE 1
#define FALSE 0
#define SUCCESS !0
#define FAILURE 0
#define SCL 0
#define SDA 1
byte MLXReadEEPROM(unsigned int *pdat, byte slave_adr, byte adr);
byte MLXWriteEEPROM(byte slave_adr, byte eeprom_adr, unsigned int v);
void print_eeprom(byte adr, int v);
byte CalcCRC8(byte CRC8, byte v);
void smI2CStart(void);
void smI2CStop(void);
void smI2COutByte(byte X);
byte smI2CInByte(byte Ack);
void smSDA_HIGH(void);
void smSCL_HIGH(void);
void smSDA_LOW(void);
void sbSCL_LOW(void);
void setup(void)
{
Serial.begin(9600);
delay(5000);
Serial.print(">>>>>>>>>>>>>>>>>>>>>>>>\n");
}
void loop(void)
{
byte n;
unsigned int v;
for(n=0; n<32; n++)
{
MLXReadEEPROM(&v, 0x00, n);
print_eeprom(n, v);
}
n = 10;
while(n--)
{
Serial.print(".");
delay(1000);
}
Serial.println();
// erase location 004
MLXWriteEEPROM(0x00, 0x0e, 0x0000); // write zero to erase
delay(10);
MLXReadEEPROM(&v, 0x00, 0x0e); // read to verify
Serial.println(v, HEX);
MLXWriteEEPROM(0x00, 0x0e, 0x005a); // write slave adr
delay(10);
MLXReadEEPROM(&v, 0x5a / 2, 0x0e); // use the new slave adr to read
Serial.println(v, HEX);
while(1)
{
Serial.print("!");
delay(1000);
}
}
byte MLXWriteEEPROM(byte slave_address, byte eeprom_adr, unsigned int v)
{
byte high, low, CRC8, PEC;
low = v & 0xff; high = (v>>8) & 0xff;
// compute packet error
CRC8 = 0x00;
CRC8 = CalcCRC8(CRC8, 2*slave_address);
CRC8 = CalcCRC8(CRC8, 0x20 + eeprom_adr);
CRC8 = CalcCRC8(CRC8, low);
CRC8 = CalcCRC8(CRC8, high);
PEC = CRC8;
smI2CStart();
smI2COutByte(slave_address*2);
smI2COutByte(0x20 + eeprom_adr); // EEPROM location
smI2COutByte(low);
smI2COutByte(high);
smI2COutByte(PEC);
smI2CStop();
return(SUCCESS);
}
byte MLXReadEEPROM(unsigned int *pdat, byte slave_adr, byte adr)
{
byte low, high, PEC, CRC8;
smI2CStart();
smI2COutByte(slave_adr*2); // assume device adr of 00
smI2COutByte(0x20 + adr); // read EEPROM location
smI2CStart();
smI2COutByte(slave_adr * 2 + 0x01);
low = smI2CInByte(1);
high = smI2CInByte(1);
PEC = smI2CInByte(1);
smI2CStop();
CRC8 = 0;
CRC8 = CalcCRC8(CRC8, 2 * slave_adr);
CRC8 = CalcCRC8(CRC8, 0x20 + adr);
CRC8 = CalcCRC8(CRC8, slave_adr * 2 + 1);
CRC8 = CalcCRC8(CRC8, low);
CRC8 = CalcCRC8(CRC8, high);
if (CRC8 != PEC)
{
*pdat = 0;
return(FAILURE);
}
else
{
*pdat = high * 256 + low;
return(SUCCESS);
}
}
void print_eeprom(byte adr, unsigned int v)
{
v = v & 0x0000ffff;
Serial.print(adr, HEX);
Serial.print(" ");
Serial.println(v, HEX);
}
byte CalcCRC8(byte CRC8, byte v)
{
byte n;
v = v ^ CRC8;
for (n=0; n<8; n++)
{
if (v&0x80)
{
v = (v << 1) ^ 0x07;
}
else
{
v = v << 1;
}
}
return(v);
}
void smI2CStart(void)
{
smSDA_HIGH();
smSCL_HIGH();
smSDA_LOW();
smSCL_LOW();
}
void smI2CStop(void)
{
smSCL_LOW();
smSDA_LOW(); ;
smSCL_HIGH();
smSDA_HIGH();
}
void smI2COutByte(byte X)
{
byte n;
for (n=0; n<8; n++)
{
if (X & 0x80)
{
smSDA_HIGH();
}
else
{
smSDA_LOW();
}
smSCL_HIGH();
smSCL_LOW();
X = X << 1;
}
smSDA_HIGH();
smSCL_HIGH();
smSCL_LOW();
smSDA_LOW();
}
byte smI2CInByte(byte Ack)
{
byte n, X;
smSDA_HIGH();
for (n=0; n<8; n++)
{
smSCL_HIGH();
if (digitalRead(9))
{
X = (X << 1) | 0x01;
}
else
{
X = X << 1;
}
smSCL_LOW();
}
if (Ack)
{
smSDA_LOW();
}
else
{
smSDA_HIGH();
}
smSCL_HIGH();
smSCL_LOW();
smSDA_LOW();
return(X);
}
void smSDA_HIGH(void)
{
cbi(DDRB, SDA);
delayMicroseconds(10);
}
void smSCL_HIGH(void)
{
cbi(DDRB, SCL);
delayMicroseconds(10);
}
void smSDA_LOW(void)
{
cbi(PORTB, SDA);
sbi(DDRB, SDA);
delayMicroseconds(10);
}
void smSCL_LOW(void)
{
cbi(PORTB, SCL);
sbi(DDRB, SCL);
delayMicroseconds(10);
}
// MLX_emis (Arduino - ATMega328)
//
// Arduino Melexis MLX90614
//
// 9 (PORTB.1) ----------------- SDA (2)
// 8 (PORTB.0) ----------------- SCL (1)
// +5 ---- VDD (3)
// GRD --- VSS (4)
//
// 1.0 K pullup resistors to +5 VDC on SDA and SCL
//
// Changes emisivity at EEPROM location 0x04 to 0.8 and performs 10 temperature measurements.
// Change emissivity to 1.0 and performs 10 measurments.
//
// copyright, Peter H Anderson, Baltimore, MD, Feb 23, '10
//
#include <avr\io.h>
#define cbi(sfr, bit) (sfr &= (~(0x01<<bit)))
#define sbi(sfr, bit) (sfr |= (0x01 << bit))
#define TRUE 1
#define FALSE 0
#define SUCCESS !0
#define FAILURE 0
#define SCL 0
#define SDA 1
byte meas_temperature(float *pT, byte slave_address, byte ram_location);
float celcius_to_fahr(byte Tc);
byte MLXReadEEPROM(unsigned int *pdat, byte slave_adr, byte adr);
byte MLXWriteEEPROM(byte slave_adr, byte eeprom_adr, unsigned int v);
byte CalcCRC8(byte CRC8, byte v);
void smI2CStart(void);
void smI2CStop(void);
void smI2COutByte(byte X);
byte smI2CInByte(byte Ack);
void smSDA_HIGH(void);
void smSCL_HIGH(void);
void smSDA_LOW(void);
void smSCL_LOW(void);
void print_float(float f, int num_digits);
void setup(void)
{
Serial.begin(9600);
delay(5000);
Serial.println(">>>>>>>>>>>>>>>>>>>>>>>>"); // just to be sure things are working
}
void loop()
{
unsigned int v, w;
byte slave_address, n;
float Ta_f, To_f, emissivity;
// read emissitvity
MLXReadEEPROM(&v, 0x00, 0x04);
emissivity = ((float) (v-1)) / 65535.0 * 100.0;
Serial.print("0.");
Serial.println((unsigned int)emissivity, DEC);
// change emisivity to 0.8
emissivity = 0.8;
w = (unsigned int) (emissivity * 65535.0);
MLXWriteEEPROM(0x00, 0x04, 0x0000); // write zero to erase
delay(25);
MLXReadEEPROM(&v, 0x00, 0x04); // verify
Serial.println(v, HEX); // should be 0
MLXWriteEEPROM(0x00, 0x04, w);
delay(25);
MLXReadEEPROM(&v, 0x00, 0x04);
emissivity = ((float) (v-1)) / 65535.0 * 100.0;
Serial.print("0.");
Serial.println((unsigned int)emissivity, DEC);
// now measure temperatures
for (n=0; n<10; n++)
{
meas_temperature(&Ta_f, 0x00, 0x06);
meas_temperature(&To_f, 0x00, 0x07);
print_float(Ta_f, 2);
Serial.print(" ");
print_float(To_f, 2);
Serial.print("\n");
delay(1000);
}
// now write emissivity of 1.0
emissivity = 1.0;
w = (unsigned int) (emissivity * 65535.0);
MLXWriteEEPROM(0x00, 0x04, 0x0000); // write zero to erase
delay(25);
MLXReadEEPROM(&v, 0x00, 0x04);
Serial.println(v, HEX); // should be 0
MLXWriteEEPROM(0x00, 0x04, w);
delay(25);
MLXReadEEPROM(&v, 0x00, 0x04);
emissivity = ((float) (v-1)) / 65535.0 * 100.0;
Serial.print("0.");
Serial.println((unsigned int)emissivity, DEC);
// now measure temperatures
for (n=0; n<10; n++)
{
meas_temperature(&Ta_f, 0x00, 0x06);
meas_temperature(&To_f, 0x00, 0x07);
print_float(Ta_f, 2);
Serial.print(" ");
print_float(To_f, 2);
Serial.print("\n");
delay(1000);
}
while(1)
{
//Serial.print(".");
delay(1000);
}
}
byte meas_temperature(float *pT, byte slave_address, byte ram_location) // 0x06 for Ta, 0x07 for Tobj
{
byte low, high, PEC, CRC8;
unsigned int v;
float Tc, Tf;
smI2CStart();
smI2COutByte(slave_address * 2);
smI2COutByte(ram_location);
smI2CStart();
smI2COutByte(slave_address * 2 | 0x01);
low = smI2CInByte(1);
high = smI2CInByte(1);
PEC = smI2CInByte(1);
smI2CStop();
CRC8 = 0x00;
CRC8 = CalcCRC8(CRC8, slave_address*2);
CRC8 = CalcCRC8(CRC8, ram_location);
CRC8 = CalcCRC8(CRC8, slave_address*2+1);
CRC8 = CalcCRC8(CRC8, low);
CRC8 = CalcCRC8(CRC8, high);
CRC8 = CalcCRC8(CRC8, PEC);
if (CRC8 != 0)
{
*pT = 99.9; // used as failure indication
return(FAILURE);
}
else
{
v = (unsigned int) high * 256 + low;
Tc = (float)(v) * 0.02 - 273.15;
Tf = 1.8 * Tc + 32.0;
*pT = Tf;
return(SUCCESS);
}
}
byte MLXWriteEEPROM(byte slave_address, byte eeprom_adr, unsigned int v)
{
byte high, low, CRC8, PEC;
low = v & 0xff; high = (v>>8) & 0xff;
// compute packet error
CRC8 = 0x00;
CRC8 = CalcCRC8(CRC8, 2*slave_address);
CRC8 = CalcCRC8(CRC8, 0x20 + eeprom_adr);
CRC8 = CalcCRC8(CRC8, low);
CRC8 = CalcCRC8(CRC8, high);
PEC = CRC8;
smI2CStart();
smI2COutByte(slave_address*2);
smI2COutByte(0x20 + eeprom_adr); // EEPROM location
smI2COutByte(low);
smI2COutByte(high);
smI2COutByte(PEC);
smI2CStop();
return(SUCCESS);
}
byte MLXReadEEPROM(unsigned int *pdat, byte slave_adr, byte adr)
{
byte low, high, PEC, CRC8;
smI2CStart();
smI2COutByte(slave_adr*2);
smI2COutByte(0x20 + adr); // read EEPROM location
smI2CStart();
smI2COutByte(slave_adr * 2 + 0x01);
low = smI2CInByte(1);
high = smI2CInByte(1);
PEC = smI2CInByte(1);
smI2CStop();
CRC8 = 0;
CRC8 = CalcCRC8(CRC8, 2 * slave_adr);
CRC8 = CalcCRC8(CRC8, 0x20 + adr);
CRC8 = CalcCRC8(CRC8, slave_adr * 2 + 1);
CRC8 = CalcCRC8(CRC8, low);
CRC8 = CalcCRC8(CRC8, high);
//Serial.print(CRC8, HEX);
//Serial.print("... ");
//Serial.println(PEC, HEX);
if (CRC8 != PEC)
{
Serial.print(CRC8, HEX);
Serial.print("..");
Serial.println(PEC, HEX);
*pdat = high * 256 + low;
return(FAILURE);
}
else
{
*pdat = high * 256 + low;
return(SUCCESS);
}
}
void print_eeprom(byte adr, unsigned int v)
{
v = v & 0x0000ffff;
Serial.print(adr, HEX);
Serial.print(" ");
Serial.println(v, HEX);
}
byte CalcCRC8(byte CRC8, byte v)
{
byte n;
v = v ^ CRC8;
for (n=0; n<8; n++)
{
if (v&0x80)
{
v = (v << 1) ^ 0x07;
}
else
{
v = v << 1;
}
}
return(v);
}
void smI2CStart(void)
{
smSDA_HIGH();
smSCL_HIGH();
smSDA_LOW();
smSCL_LOW();
}
void smI2CStop(void)
{
smSCL_LOW();
smSDA_LOW(); ;
smSCL_HIGH();
smSDA_HIGH();
}
void smI2COutByte(byte X)
{
byte n;
for (n=0; n<8; n++)
{
if (X & 0x80)
{
smSDA_HIGH();
}
else
{
smSDA_LOW();
}
smSCL_HIGH();
smSCL_LOW();
X = X << 1;
}
smSDA_HIGH();
smSCL_HIGH();
smSCL_LOW();
smSDA_LOW();
}
byte smI2CInByte(byte Ack)
{
byte n, X;
smSDA_HIGH();
for (n=0; n<8; n++)
{
smSCL_HIGH();
if (digitalRead(9))
{
X = (X << 1) | 0x01;
}
else
{
X = X << 1;
}
smSCL_LOW();
}
if (Ack)
{
smSDA_LOW();
}
else
{
smSDA_HIGH();
}
smSCL_HIGH();
smSCL_LOW();
smSDA_LOW();
return(X);
}
void smSDA_HIGH(void)
{
cbi(DDRB, SDA);
delayMicroseconds(10);
}
void smSCL_HIGH(void)
{
cbi(DDRB, SCL);
delayMicroseconds(10);
}
void smSDA_LOW(void)
{
cbi(PORTB, SDA);
sbi(DDRB, SDA);
delayMicroseconds(10);
}
void smSCL_LOW(void)
{
cbi(PORTB, SCL);
sbi(DDRB, SCL);
delayMicroseconds(10);
}
void print_float(float f, int num_digits)
{
int f_int;
int pows_of_ten[4] = {1, 10, 100, 1000};
int multiplier, whole, fract, d, n;
multiplier = pows_of_ten[num_digits];
if (f < 0.0)
{
f = -f;
Serial.print("-");
}
whole = (int) f;
fract = (int) (multiplier * (f - (float)whole));
Serial.print(whole);
Serial.print(".");
for (n=num_digits-1; n>=0; n--) // print each digit with no leading zero suppression
{
d = fract / pows_of_ten[n];
Serial.print(d);
fract = fract % pows_of_ten[n];
}
}