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]; } }