Tuesday, April 30, 2013

16. Infrared Thermometer - MLX90614

The Melexis MLX90614 is a factory pre-calibrated infrared thermopile with integrated signal conditioning and temperature calculation.  It incorporates a low noise amplifier, 17 bit ADC and a powerful digital signal processing unit, leading to high accuracy (0.5C) and precision (0.01C).  Smart - eh?

That's a formal way of describing this very clever, tiny digital non-contact thermometer.  It has a diameter of about 8mm, and a field of view of about  ±20°.  So it can give a true reading as long as the object is within, and fully occupies, that field.

The one I have operates at 3.3V, which is available from my BreadboArduino.  This is what it looks like:

  

Here is mine mounted at the centre of a breadboard to the left of my BreadboArduino:  The BreadboArduino has a red LED indicating power on, and a flashing green LED to indicate that the sketch (see below) is running.


This video gives some idea of what the finished project is capable of:  First I bring a bag of very cold ice down close to the thermopile.  Notice the colour of the RGB LED changing into the blues and greens.  The LED is so bright that it is whiting out its image.  However, you can get an idea of its colour from its light reflected off the surrounding surfaces.  Then I introduce a hot cup of tea, and the LED goes into the reds and whites.


The serial port gives a running list (about every second) of the current measured temperature in Celsius and Fahrenheit:


Note the changing temperature as the bag of very cold ice is placed in front of the thermopile, followed by a hot cup of tea.  (No milk - one sugar).  The code is a little tricky to get going, but there are excellent instructions at: http://bildr.org/2011/02/mlx90614-arduino/

1:  // MLX90614 Program April 2013  
2:    
3:  #include <i2cmaster.h>  
4:    
5:  int led = 13;  
6:  int mappedSensorValue = 0; // maps range of rawSensorVale and constrains it between 0 and 255  
7:  int mSV = 0;  
8:    
9:  int minF = -40; // min range of sensor is -40C = -40F  
10:  int maxF = 257; // max range of sensor is 125C = 257F  
11:    
12:  int REDPin = 6;  // RED pin of the LED to PWM pin 6  
13:  int GREENPin = 5; // GREEN pin of the LED to PWM pin 5  
14:  int BLUEPin = 3;  // BLUE pin of the LED to PWM pin 3  
15:  //int brightness = 0; // LED brightness  
16:    
17:  void setup(){  
18:       Serial.begin(9600);  
19:       Serial.println("Setup...");  
20:         
21:       i2c_init(); //Initialise the i2c bus  
22:       PORTC = (1 << PORTC4) | (1 << PORTC5);//enable pullups  
23:     pinMode(led, OUTPUT);  
24:     pinMode(REDPin, OUTPUT);  
25:     pinMode(GREENPin, OUTPUT);  
26:     pinMode(BLUEPin, OUTPUT);   
27:  }  
28:    
29:  void loop(){  
30:    digitalWrite(led, HIGH);  // turn the LED on (HIGH is the voltage level)  
31:    delay(100);        // wait   
32:    digitalWrite(led, LOW);  // turn the LED off by making the voltage LOW  
33:    delay(100);        // wait   
34:    digitalWrite(led, HIGH);  // turn the LED on (HIGH is the voltage level)  
35:    delay(100);        // wait   
36:    digitalWrite(led, LOW);  // turn the LED off by making the voltage LOW  
37:    delay(1000);        // wait for a second  
38:      
39:    int dev = 0x5A<<1;  
40:    int data_low = 0;  
41:    int data_high = 0;  
42:    int pec = 0;  
43:      
44:    i2c_start_wait(dev+I2C_WRITE);  
45:    i2c_write(0x07);  
46:      
47:    // read  
48:    i2c_rep_start(dev+I2C_READ);  
49:    data_low = i2c_readAck(); //Read 1 byte and then send ack  
50:    data_high = i2c_readAck(); //Read 1 byte and then send ack  
51:    pec = i2c_readNak();  
52:    i2c_stop();  
53:      
54:    //This converts high and low bytes together and processes temperature, MSB is a error bit and is ignored for temps  
55:    double tempFactor = 0.02; // 0.02 degrees per LSB (measurement resolution of the MLX90614)  
56:    double tempData = 0x0000; // zero out the data  
57:    int frac; // data past the decimal point  
58:      
59:    // This masks off the error bit of the high byte, then moves it left 8 bits and adds the low byte.  
60:    tempData = (double)(((data_high & 0x007F) << 8) + data_low);  
61:    tempData = (tempData * tempFactor)-0.01;  
62:      
63:    float celsius = tempData - 273.15;  
64:    float fahrenheit = (celsius*1.8) + 32;  
65:    
66:    Serial.print(celsius);  
67:    Serial.print(" C ... ");  
68:    
69:    Serial.print(fahrenheit);  
70:    Serial.print(" deg F");  
71:      
72:    Serial.println();  
73:      
74:   // maps range of sensor values to target range between 0 and 255  
75:    mappedSensorValue = map( celsius, 10, 40, 0, 255);  
76:    mSV = mappedSensorValue;  
77:        
78:     if (celsius<10)  
79:    {  
80:     analogWrite(REDPin,  0);  
81:     analogWrite(GREENPin, mSV);  
82:     analogWrite(BLUEPin, (255-mSV));  
83:    }    
84:     else if (celsius>40)  
85:    {  
86:     analogWrite(REDPin,  255);  
87:     analogWrite(GREENPin, mSV);  
88:     analogWrite(BLUEPin, mSV);  
89:    }  
90:     else  
91:   {  
92:    analogWrite(REDPin,  mSV);      
93:    analogWrite(GREENPin, 0);  
94:    analogWrite(BLUEPin,  (255-mSV));   
95:   }   
96:      
97:  }  

In the code, REDPin, GREENPin and BLUEPin refer to the anodes of the RGB LED corresponding to the three colours.

The main part of this code has been taken from http://bildr.org/2011/02/mlx90614-arduino/






No comments:

Post a Comment