Benutzer-Werkzeuge

Webseiten-Werkzeuge


Seitenleiste

bauteile:thermokamera

Thermokamera Melexis MLX90620

Um die Temperatur zu messen, ohne dabei in Kontakt mit dem Objekt zu treten, funktioniert mit eine Wärmebildkamera. Im Labor haben wir die Melexis MLX90620 Thermo Cam (Abb. unten) zur Verfügung. Melexis MLX90620 Thermo Cam

Sie hat 16×4 nach dem Bolometer-Prinzip aufgebaute Pixel, die langwellige Infrarotstrahlung messen können. Sie kann damit Temperaturen zwischen $-20^\circ C$ und $300^\circ C$ mit einer Framerate von $0,5Hz - 64Hz$ messen. Im Temperaturbereich von $0^\circ C - 50^\circ C$ ist die Genauigkeit angeblich besser als $\pm 1,5^\circ C$.

Hier findet ihr das Datenblatt: http://www.melexis.com/Infrared-Thermometer-Sensors/Infrared-Thermometer-Sensors/MLX90620-776.aspx.

Installation

Die Kamera läuft auf einer recht niedrigen Spannung von 2.6V und ist deshalb nur mit etwas Aufwand mit einem 5V Arduino zusammen zu betreiben. Einfacher funktioniert es mit einem der Teensy3.0++, die wir im Labor haben. Die sind auch gleich schnell genug, um die Temperaturen mit einer akzetablen Geschwindigkeit und Präzision zu berechnen.

Ein Teensy liefert 3.3V. D.h. um die Kamera nicht zu beschädigen, müsst ihr die Spanung begrenzen.Hier gibt es eine Beispielschaltung zu sehen.

Code-Beispiel

Dieses Beispiel ist eine Modifikation von http://forum.arduino.cc/index.php?topic=122306.0

/*****************************************************************
   This code is design to interface with the MLX90621 sensor.
   This sensor is a Low noise High Speed 16x4 Far Infrared array.
   Here is used to obtain data for making a thermal sensor.
   More information is available here: http://www.melexis.com/Infrared-Thermometer-Sensors/Infrared-Thermometer-Sensors/Low-noise-high-speed-16x4-Far-Infrared-array-823.aspx
 
   Pixel position:
   The array consists of 64 IR sensors (also called pixels). Each pixel is identified with its row and
   column position as Pix(i,j) where i is its row number (from 0 to 3) and j is its column number (from 0 to 15)
 
   RAM:
   The on chip 146x16 RAM is accessible for reading via I2C. The RAM is used for storing the results of
   measurements of pixels and Ta sensor and is distributes as follows:
   64 words for IR sensors. The data is in 2’s complement format
   1 word for measurement result of PTAT sensor. The data is 16 bit without sign.
   The memory map of the RAM is shown below:
   0x00=IR Sensor(0,0) result
   0x01=IR Sensor(1,0) result
   0x02=IR Sensor(2,0) result
   0x03=IR Sensor(3,0) result
   0x04=IR Sensor(0,1) result
   0x05=IR Sensor(1,1) result
   ...
   0x3B=IR Sensor(3,14) result
   0x3C=IR Sensor(0,15) result
   0x3D=IR Sensor(1,15) result
   0x3E=IR Sensor(2,15) result
   0x3F=IR Sensor(3,15) result
 
   Device Addressing:
   For accessing to internal EEPROM: 0x50
   For accessing to IR array data:   0x60
*/
 
//Libraries to be included
#include <Arduino.h>
#include <Wire.h>
 
//Begin registers
#define CAL_ACOMMON_L 0xD0
#define CAL_ACOMMON_H 0xD1
#define CAL_ACP_L 0xD3
#define CAL_ACP_H 0xD4
#define CAL_BCP 0xD5
#define CAL_alphaCP_L 0xD6
#define CAL_alphaCP_H 0xD7
#define CAL_TGC 0xD8
#define CAL_AI_SCALE 0xD9
#define CAL_BI_SCALE 0xD9
 
#define VTH_L 0xDA
#define VTH_H 0xDB
#define KT1_L 0xDC
#define KT1_H 0xDD
#define KT2_L 0xDE
#define KT2_H 0xDF
#define KT_SCALE 0xD2
 
//Common sensitivity coefficients
#define CAL_A0_L 0xE0
#define CAL_A0_H 0xE1
#define CAL_A0_SCALE 0xE2
#define CAL_DELTA_A_SCALE 0xE3
#define CAL_EMIS_L 0xE4
#define CAL_EMIS_H 0xE5
 
//Config register = 0xF5-F6
#define OSC_TRIM_VALUE 0xF7
 
/* Variables */
const byte refreshRate = 1; //Set this value to your desired refresh frequency. Possible values: 0=0.5Hz, 1=1Hz, 2=2Hz, 4=4Hz, 8=8Hz, 16=16Hz, 32=32Hz.
int16_t irData[64]; //Contains the raw IR data from the sensor
float temperatures[64]; //Contains the calculated temperatures of each pixel in the array
 
byte eepromData[256]; //Contains the full EEPROM reading from the MLX90621
int16_t k_t1_scale = 0, k_t2_scale = 0, resolution = 0, configuration = 0, cpix = 0;
uint16_t  ptat = 0;
 
// modified:
int16_t irDataAtStart[64];
 
void setup()
{
  Serial.begin(115200);
  Wire.begin();
  delay(5);
  readEEPROM();
  writeTrimmingValue();
  setConfiguration();
 
  // the initial values obtained by the camera are read. They are then substracted from the measured values. 
  // This way, if there is no temperature change compared to the observation start, the Serial Monitor 
  // will display an array of 0. 
  readIR();
  for (int i = 0; i<64; i++) {
    irDataAtStart[i] = irData[i];
  }
 
}
 
void loop()
{
  if (checkConfig())
  {
    readEEPROM();
    writeTrimmingValue();
    setConfiguration();
  }
  for (int i = 0; i < 16; i++) //Every 16 readings check that the POR flag is not set
  {
    readIR();
    Serial.println();
    Serial.println();
    delay(1000);
  }
}
 
void readEEPROM()
{
  int i = 0;
  Serial.print("\nReading EEPPROM...");
  for (int j = 0; j < 256; j = j + 32)
  {
    Wire.beginTransmission(0x50);
    Wire.write((byte)j);
    //Wire.endTransmission(false); // use repeated start to get answer
    Wire.requestFrom(0x50, 32);
    i = j;
    Serial.print("\n["); Serial.print(j); Serial.print("] ");
    while ( Wire.available() )
    { // slave may send less than requested
      eepromData[i] = (byte)Wire.read();
      Serial.print(eepromData[i]); Serial.print(" ");
      i++;
    }
    Wire.endTransmission();
  }
  Serial.println(" ");
}
 
void writeTrimmingValue()
{
  Serial.print("\nWriting Trimming Value...");
  Wire.beginTransmission(0x60);
  Wire.write(0x04);
  Wire.write((byte)eepromData[OSC_TRIM_VALUE] - 0xAA);
  Wire.write(eepromData[OSC_TRIM_VALUE]);//eepromData[0xF7]
  Wire.write(0x100 - 0xAA); //0x56
  Wire.write(0x00);
  I2Canswer(Wire.endTransmission());
}
 
void setConfiguration()
{
  Serial.print("\nSetting configuration...");
  byte Hz_LSB;
  switch (refreshRate)
  {
    case 0:
      Hz_LSB = 0b00111111;
      break;
    case 1:
      Hz_LSB = 0b00111110;
      break;
    case 2:
      Hz_LSB = 0b00111101;
      break;
    case 4:
      Hz_LSB = 0b00111100;
      break;
    case 8:
      Hz_LSB = 0b00111011;
      break;
    case 16:
      Hz_LSB = 0b00111010;
      break;
    case 32:
      Hz_LSB = 0b00111001;
      break;
    default:
      Hz_LSB = 0b00111110;
  }
  //byte defaultConfig_H =0b00000100; //0x04;//0b00000100;
  byte defaultConfig_H = 0b00000110;
  Wire.beginTransmission(0x60);
  Wire.write(0x03);
  Wire.write((byte)Hz_LSB - 0x55);
  Wire.write(Hz_LSB);
  Wire.write(defaultConfig_H - 0x55);//0x14-0x55
  Wire.write(defaultConfig_H);
  I2Canswer(Wire.endTransmission());
 
  //Read the resolution from the config register
  resolution = (readConfig() & 0x30) >> 4;
  Serial.print("Resolution: "); Serial.println(resolution); delay(100);
}
 
/*****************************************************
  IR  data of the device that it is read by lines
  by using the following function.
 *****************************************************/
void readIR()
{
  int i = 0;
  Serial.print("Reading IRsensor:");
  // Due to wire library buffer limitations, we can only read up to 32 bytes at a time
  // Thus, the request has been split into multiple different requests to get the full 128 values
  // Each pixel value takes up two bytes (???) thus NUM_PIXELS * 2
  for (int line = 0; line < 4; line++) //4 pixels lines
  {
    Serial.print("\n["); Serial.print(line); Serial.print("] ");
    Wire.beginTransmission(0x60);//Sensor Address
    Wire.write(0x02);//CMD_Sensor_Read
    Wire.write(line);//lines:0x00,0x01,0x02,0x03
    Wire.write(0x04);//0x04
    Wire.write(0x10);//0x10
    Wire.endTransmission(false);
    Wire.requestFrom(0x60, 32);//16 pixels per column x 2 bytes per pixel
    for (int j = 0; j < 16; j++)
    {
      // We read two bytes
      byte pixelDataLow = Wire.read();
      byte pixelDataHigh = Wire.read();
      irData[i] = (int16_t) ((pixelDataHigh << 8) | pixelDataLow);
      Serial.print(irData[i] - irDataAtStart[i]); Serial.print(" "); // modified
      i++;
    }
  }
  I2Canswer(Wire.endTransmission());
}
 
void I2Canswer(int opcion)
{
  switch (opcion)
  {
    case 0:
      Serial.print(" Success. ");
      break;
    case 1:
      Serial.print(" Data too long to fit in transmit buffer. ");
      break;
    case 2:
      Serial.print(" Received NACK on transmit of address. ");
      break;
    case 3:
      Serial.print(" Received NACK on transmit of data. ");
      break;
    default:
      Serial.print(" Other error. ");
  }
}
 
float getTemperature(int num)
{
  if ((num >= 0) && (num < 64)) return temperatures[num];
  else                    return NULL;
}
 
 
//Poll the MLX90621 for its current status
//Returns true if the POR/Brown out bit is set
boolean checkConfig() //Every 16 readings check that the POR flag is not set
{
  bool check = !((readConfig() & 0x0400) >> 10);
  return check;
}
 
/****************************************************
  Configuration Registers of the device can be read
  by using the following function.
 ****************************************************/
int16_t readConfig()
{
  int i = 0;
  byte configLow = 0, configHigh = 0;
  Serial.print("\nReading Configuration...");
  Wire.beginTransmission(0x60);
  Wire.write(0x02);
  Wire.write(0x92);
  Wire.write(0x00);
  Wire.write(0x01);
  I2Canswer(Wire.endTransmission(false)); // use repeated start to get answer   )
  Wire.requestFrom(0x60, 2);
  while ( Wire.available() )
  {
    i++;
    byte configLow = Wire.read();
    byte configHigh = Wire.read();
    if (i > 2) Serial.print("Error reading Config");
  }
  I2Canswer(Wire.endTransmission()); // use repeated start to get answer   )
  configuration = ((int16_t) (configHigh << 8) | configLow);
  Serial.print("Configuration:"); Serial.print(configHigh); Serial.println(configLow);
  return configuration;
}
bauteile/thermokamera.txt · Zuletzt geändert: 2018/02/07 16:25 von d.golovko