diff --git a/arduino/Arduino_ESP32_MLX90640/Arduino_ESP32_MLX90640.ino b/arduino/Arduino_ESP32_MLX90640_alt/Arduino_ESP32_MLX90640.ino similarity index 99% rename from arduino/Arduino_ESP32_MLX90640/Arduino_ESP32_MLX90640.ino rename to arduino/Arduino_ESP32_MLX90640_alt/Arduino_ESP32_MLX90640.ino index 9fd2210..e5d7775 100644 --- a/arduino/Arduino_ESP32_MLX90640/Arduino_ESP32_MLX90640.ino +++ b/arduino/Arduino_ESP32_MLX90640_alt/Arduino_ESP32_MLX90640.ino @@ -30,7 +30,7 @@ float T_max, T_min; // maximale bzw. minimale gemesse float T_center; // Temperatur in der Bildschirmmitte - +boolean isConnected(); // *************************************** // **************** SETUP **************** diff --git a/arduino/wärmebildkamera/Arduino_ESP32_MLX90640/MLX90640_I2C_Driver.zip b/arduino/wärmebildkamera/Arduino_ESP32_MLX90640/MLX90640_I2C_Driver.zip deleted file mode 100644 index d5c281a..0000000 Binary files a/arduino/wärmebildkamera/Arduino_ESP32_MLX90640/MLX90640_I2C_Driver.zip and /dev/null differ diff --git a/arduino/wärmebildkamera/Arduino_ESP32_MLX90640_aktuell/Arduino_ESP32_MLX90640_aktuell.ino b/arduino/wärmebildkamera/Arduino_ESP32_MLX90640_aktuell/Arduino_ESP32_MLX90640_aktuell.ino new file mode 100644 index 0000000..37f6a1a --- /dev/null +++ b/arduino/wärmebildkamera/Arduino_ESP32_MLX90640_aktuell/Arduino_ESP32_MLX90640_aktuell.ino @@ -0,0 +1,313 @@ +#include +#include "MLX90640_API.h" +#include "MLX90640_I2C_Driver1.h" +#include "SPI.h" +//#include "Adafruit_GFX.h" +//#include "Adafruit_ILI9341.h" + +// For the ESP-WROVER_KIT, these are the default. +/*#define TFT_CS 15 +#define TFT_DC 2 +#define TFT_MOSI 13 +#define TFT_CLK 14 +#define TFT_RST 26 +#define TFT_MISO 12 +#define TFT_LED 27*/ + +/*Adafruit_ILI9341 tft = Adafruit_ILI9341(TFT_CS, TFT_DC, TFT_MOSI, TFT_CLK, TFT_RST, TFT_MISO);*/ + +const byte MLX90640_address = 0x33; //Default 7-bit unshifted address of the MLX90640 + +#define TA_SHIFT 8 //Default shift for MLX90640 in open air + +static float mlx90640To[768]; +paramsMLX90640 mlx90640; + +int xPos, yPos; // Abtastposition +int R_colour, G_colour, B_colour; // RGB-Farbwert +int i, j; // Zählvariable +float T_max, T_min; // maximale bzw. minimale gemessene Temperatur +float T_center; // Temperatur in der Bildschirmmitte + + + + +// *************************************** +// **************** SETUP **************** +// *************************************** + +void setup() + { + Serial.begin(115200); + + Wire.begin(); + Wire.setClock(400000); //Increase I2C clock speed to 400kHz + + while (!Serial); //Wait for user to open terminal + + Serial.println("MLX90640 IR Array Example"); + + if (isConnected() == false) + { + Serial.println("MLX90640 not detected at default I2C address. Please check wiring. Freezing."); + while (1); + } + + Serial.println("MLX90640 online!"); + + //Get device parameters - We only have to do this once + int status; + uint16_t eeMLX90640[832]; + + status = MLX90640_DumpEE(MLX90640_address, eeMLX90640); + + if (status != 0) + Serial.println("Failed to load system parameters"); + if (status == 0) + Serial.println("dumpee_okay"); + + status = MLX90640_ExtractParameters(eeMLX90640, &mlx90640); + + if (status != 0) + { + Serial.println("Parameter extraction failed"); + Serial.print(" status = "); + Serial.println(status); + } + + //Once params are extracted, we can release eeMLX90640 array + + MLX90640_I2CWrite(0x33, 0x800D, 6401); // writes the value 1901 (HEX) = 6401 (DEC) in the register at position 0x800D to enable reading out the temperatures!!! + // =============================================================================================================================================================== + + //MLX90640_SetRefreshRate(MLX90640_address, 0x00); //Set rate to 0.25Hz effective - Works + //MLX90640_SetRefreshRate(MLX90640_address, 0x01); //Set rate to 0.5Hz effective - Works + //MLX90640_SetRefreshRate(MLX90640_address, 0x02); //Set rate to 1Hz effective - Works + //MLX90640_SetRefreshRate(MLX90640_address, 0x03); //Set rate to 2Hz effective - Works + MLX90640_SetRefreshRate(MLX90640_address, 0x04); //Set rate to 4Hz effective - Works + //MLX90640_SetRefreshRate(MLX90640_address, 0x05); //Set rate to 8Hz effective - Works at 800kHz + //MLX90640_SetRefreshRate(MLX90640_address, 0x06); //Set rate to 16Hz effective - Works at 800kHz + //MLX90640_SetRefreshRate(MLX90640_address, 0x07); //Set rate to 32Hz effective - fails + + + //pinMode(TFT_LED, OUTPUT); + //digitalWrite(TFT_LED, HIGH); + + /*tft.begin(); + + tft.setRotation(1); + + tft.fillScreen(ILI9341_BLACK); + tft.fillRect(0, 0, 319, 13, tft.color565(255, 0, 10)); + tft.setCursor(100, 3); + tft.setTextSize(1); + tft.setTextColor(ILI9341_YELLOW, tft.color565(255, 0, 10)); + tft.print("Thermographie - stoppi"); + + tft.drawLine(250, 210 - 0, 258, 210 - 0, tft.color565(255, 255, 255)); + tft.drawLine(250, 210 - 30, 258, 210 - 30, tft.color565(255, 255, 255)); + tft.drawLine(250, 210 - 60, 258, 210 - 60, tft.color565(255, 255, 255)); + tft.drawLine(250, 210 - 90, 258, 210 - 90, tft.color565(255, 255, 255)); + tft.drawLine(250, 210 - 120, 258, 210 - 120, tft.color565(255, 255, 255)); + tft.drawLine(250, 210 - 150, 258, 210 - 150, tft.color565(255, 255, 255)); + tft.drawLine(250, 210 - 180, 258, 210 - 180, tft.color565(255, 255, 255)); + + tft.setCursor(80, 220); + tft.setTextColor(ILI9341_WHITE, tft.color565(0, 0, 0)); + tft.print("T+ = "); + + + // drawing the colour-scale + // ======================== + + for (i = 0; i < 181; i++) + { + //value = random(180); + + getColour(i); + tft.drawLine(240, 210 - i, 250, 210 - i, tft.color565(R_colour, G_colour, B_colour)); + } + + + +*/ + } +// ********************************** +// ************** LOOP ************** +// ********************************** + +void loop(){ + for (byte x = 0 ; x < 2 ; x++) //Read both subpages + { + uint16_t mlx90640Frame[834]; + int status = MLX90640_GetFrameData(MLX90640_address, mlx90640Frame); + + if (status < 0) + { + Serial.print("GetFrame Error: "); + Serial.println(status); + } + + float vdd = MLX90640_GetVdd(mlx90640Frame, &mlx90640); + float Ta = MLX90640_GetTa(mlx90640Frame, &mlx90640); + + float tr = Ta - TA_SHIFT; //Reflected temperature based on the sensor ambient temperature + float emissivity = 0.95; + + MLX90640_CalculateTo(mlx90640Frame, &mlx90640, emissivity, tr, mlx90640To); + } + + + // determine T_min and T_max and eliminate error pixels + // ==================================================== + + mlx90640To[1*32 + 21] = 0.5 * (mlx90640To[1*32 + 20] + mlx90640To[1*32 + 22]); // eliminate the error-pixels + mlx90640To[4*32 + 30] = 0.5 * (mlx90640To[4*32 + 29] + mlx90640To[4*32 + 31]); // eliminate the error-pixels + + T_min = mlx90640To[0]; + T_max = mlx90640To[0]; + + for (i = 1; i < 768; i++) + { + if((mlx90640To[i] > -41) && (mlx90640To[i] < 301)) + { + if(mlx90640To[i] < T_min) + { + T_min = mlx90640To[i]; + } + + if(mlx90640To[i] > T_max) + { + T_max = mlx90640To[i]; + } + } + else if(i > 0) // temperature out of range + { + mlx90640To[i] = mlx90640To[i-1]; + } + else + { + mlx90640To[i] = mlx90640To[i+1]; + } + } + + + // determine T_center + // ================== + + T_center = mlx90640To[11* 32 + 15]; + + // drawing the picture + // =================== + + for (i = 0 ; i < 24 ; i++) + { + for (j = 0; j < 32; j++) + { + mlx90640To[i*32 + j] = 180.0 * (mlx90640To[i*32 + j] - T_min) / (T_max - T_min); + + getColour(mlx90640To[i*32 + j]); + + // tft.fillRect(217 - j * 7, 35 + i * 7, 7, 7, tft.color565(R_colour, G_colour, B_colour)); + } + } + /* + tft.drawLine(217 - 15*7 + 3.5 - 5, 11*7 + 35 + 3.5, 217 - 15*7 + 3.5 + 5, 11*7 + 35 + 3.5, tft.color565(255, 255, 255)); + tft.drawLine(217 - 15*7 + 3.5, 11*7 + 35 + 3.5 - 5, 217 - 15*7 + 3.5, 11*7 + 35 + 3.5 + 5, tft.color565(255, 255, 255)); + + tft.fillRect(260, 25, 37, 10, tft.color565(0, 0, 0)); + tft.fillRect(260, 205, 37, 10, tft.color565(0, 0, 0)); + tft.fillRect(115, 220, 37, 10, tft.color565(0, 0, 0)); + + tft.setTextColor(ILI9341_WHITE, tft.color565(0, 0, 0)); + tft.setCursor(265, 25); + tft.print(T_max, 1); + tft.setCursor(265, 205); + tft.print(T_min, 1); + tft.setCursor(120, 220); + tft.print(T_center, 1); + + tft.setCursor(300, 25); + tft.print("C"); + tft.setCursor(300, 205); + tft.print("C"); + tft.setCursor(155, 220); + tft.print("C"); + */ + delay(20); + } + + + +// =============================== +// ===== determine the colour ==== +// =============================== + +void getColour(int j) + { + if (j >= 0 && j < 30) + { + R_colour = 0; + G_colour = 0; + B_colour = 20 + (120.0/30.0) * j; + } + + if (j >= 30 && j < 60) + { + R_colour = (120.0 / 30) * (j - 30.0); + G_colour = 0; + B_colour = 140 - (60.0/30.0) * (j - 30.0); + } + + if (j >= 60 && j < 90) + { + R_colour = 120 + (135.0/30.0) * (j - 60.0); + G_colour = 0; + B_colour = 80 - (70.0/30.0) * (j - 60.0); + } + + if (j >= 90 && j < 120) + { + R_colour = 255; + G_colour = 0 + (60.0/30.0) * (j - 90.0); + B_colour = 10 - (10.0/30.0) * (j - 90.0); + } + + if (j >= 120 && j < 150) + { + R_colour = 255; + G_colour = 60 + (175.0/30.0) * (j - 120.0); + B_colour = 0; + } + + if (j >= 150 && j <= 180) + { + R_colour = 255; + G_colour = 235 + (20.0/30.0) * (j - 150.0); + B_colour = 0 + 255.0/30.0 * (j - 150.0); + } + + } + + +//Returns true if the MLX90640 is detected on the I2C bus +boolean isConnected() + { + Wire.beginTransmission((uint8_t)MLX90640_address); + + if (Wire.endTransmission() != 0) + return (false); //Sensor did not ACK + + return (true); + } + + + + + + + + + + + diff --git a/arduino/wärmebildkamera/Arduino_ESP32_MLX90640/MLX90640_API.zip b/arduino/wärmebildkamera/Arduino_ESP32_MLX90640_aktuell/MLX90640_API.zip similarity index 100% rename from arduino/wärmebildkamera/Arduino_ESP32_MLX90640/MLX90640_API.zip rename to arduino/wärmebildkamera/Arduino_ESP32_MLX90640_aktuell/MLX90640_API.zip diff --git a/arduino/wärmebildkamera/Arduino_ESP32_MLX90640_aktuell/MLX90640_I2C_Driver1.cpp b/arduino/wärmebildkamera/Arduino_ESP32_MLX90640_aktuell/MLX90640_I2C_Driver1.cpp new file mode 100644 index 0000000..2dcf231 --- /dev/null +++ b/arduino/wärmebildkamera/Arduino_ESP32_MLX90640_aktuell/MLX90640_I2C_Driver1.cpp @@ -0,0 +1,125 @@ +/** + @copyright (C) 2017 Melexis N.V. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +*/ + +#include +#include +#include "MLX90640_I2C_Driver.h" + +void MLX90640_I2CInit() +{ + +} +int MLX90640_I2CRead(uint8_t _deviceAddress, unsigned int startAddress, unsigned int nWordsRead, uint16_t *data) +{ + // nWordsRead must be <= 32767 + Wire.beginTransmission(_deviceAddress); + Wire.write(startAddress >> 8); //MSB + Wire.write(startAddress & 0xFF); //LSB + Wire.endTransmission(false); + i2c_err_t error = Wire.readTransmission(_deviceAddress, (uint8_t*) data, nWordsRead*2); + if(error != 0){//problems + Serial.printf("Block read from sensor(0x%02X) at address=%d of %d uint16_t's failed=%d(%s)\n", + _deviceAddress,startAddress,nWordsRead,error,Wire.getErrorText(error)); + } + else { // reverse byte order, sensor Big Endian, ESP32 Little Endian + for(auto a = 0; a>8)&0xff); + } + } + return 0; +} +/* +//Read a number of words from startAddress. Store into Data array. +//Returns 0 if successful, -1 if error +int MLX90640_I2CRead(uint8_t _deviceAddress, unsigned int startAddress, unsigned int nWordsRead, uint16_t *data) +{ + + //Caller passes number of 'unsigned ints to read', increase this to 'bytes to read' + uint16_t bytesRemaining = nWordsRead * 2; + + //It doesn't look like sequential read works. Do we need to re-issue the address command each time? + + uint16_t dataSpot = 0; //Start at beginning of array + + //Setup a series of chunked I2C_BUFFER_LENGTH byte reads + while (bytesRemaining > 0) + { + Wire.beginTransmission(_deviceAddress); + Wire.write(startAddress >> 8); //MSB + Wire.write(startAddress & 0xFF); //LSB + if(Wire.endTransmission(false) != 7){ + Serial.println("Error: Sensor did not ack"); + return (0);//Sensor did not ACK + + } + uint16_t numberOfBytesToRead = bytesRemaining; + if (numberOfBytesToRead > I2C_BUFFER_LENGTH) numberOfBytesToRead = I2C_BUFFER_LENGTH; + + Wire.requestFrom((uint8_t)_deviceAddress, numberOfBytesToRead); + if (Wire.available()) + { + for (uint16_t x = 0 ; x < numberOfBytesToRead / 2; x++) + { + //Store data into array + data[dataSpot] = Wire.read() << 8; //MSB + data[dataSpot] |= Wire.read(); //LSB + + dataSpot++; + } + } + + bytesRemaining -= numberOfBytesToRead; + + startAddress += numberOfBytesToRead / 2; + } + + return (0); //Success +} +*/ +//Set I2C Freq, in kHz +//MLX90640_I2CFreqSet(1000) sets frequency to 1MHz +void MLX90640_I2CFreqSet(int freq) +{ + //i2c.frequency(1000 * freq); + Wire.setClock((long)1000 * freq); +} + +//Write two bytes to a two byte address +int MLX90640_I2CWrite(uint8_t _deviceAddress, unsigned int writeAddress, uint16_t data) +{ + Wire.beginTransmission((uint8_t)_deviceAddress); + Wire.write(writeAddress >> 8); //MSB + Wire.write(writeAddress & 0xFF); //LSB + Wire.write(data >> 8); //MSB + Wire.write(data & 0xFF); //LSB + if (Wire.endTransmission() != 0) + { + //Sensor did not ACK + Serial.println("Error: Sensor did not ack"); + return (0);//Sensor did not ACK + } + + uint16_t dataCheck; + MLX90640_I2CRead(_deviceAddress, writeAddress, 1, &dataCheck); + if (dataCheck != data) + { + //Serial.println("The write request didn't stick"); + return -2; + } + + return (0); //Success +} diff --git a/arduino/wärmebildkamera/Arduino_ESP32_MLX90640_aktuell/MLX90640_I2C_Driver1.h b/arduino/wärmebildkamera/Arduino_ESP32_MLX90640_aktuell/MLX90640_I2C_Driver1.h new file mode 100644 index 0000000..4de44d0 --- /dev/null +++ b/arduino/wärmebildkamera/Arduino_ESP32_MLX90640_aktuell/MLX90640_I2C_Driver1.h @@ -0,0 +1,51 @@ +/** + @copyright (C) 2017 Melexis N.V. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +*/ +#ifndef _MLX90640_I2C_Driver_H_ +#define _MLX90640_I2C_Driver_H_ + +#include + +//Define the size of the I2C buffer based on the platform the user has +//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= +#if defined(__AVR_ATmega328P__) || defined(__AVR_ATmega168__) + +//I2C_BUFFER_LENGTH is defined in Wire.H +#define I2C_BUFFER_LENGTH BUFFER_LENGTH + +#elif defined(__SAMD21G18A__) + +//SAMD21 uses RingBuffer.h +#define I2C_BUFFER_LENGTH SERIAL_BUFFER_SIZE + +#elif __MK20DX256__ +//Teensy 3.2 +#define I2C_BUFFER_LENGTH 32 + +#else + +//The catch-all default is 32 +#define I2C_BUFFER_LENGTH 32 + +#endif +//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= + + +void MLX90640_I2CInit(void); +int MLX90640_I2CRead(uint8_t slaveAddr, unsigned int startAddress, unsigned int nWordsRead, uint16_t *data); +int MLX90640_I2CWrite(uint8_t slaveAddr, unsigned int writeAddress, uint16_t data); +void MLX90640_I2CFreqSet(int freq); +#endif diff --git a/arduino/wärmebildkamera/Example1_BasicReadings/Example1_BasicReadings.ino b/arduino/wärmebildkamera/Example1_BasicReadings/Example1_BasicReadings.ino index f1ce9f2..b211b94 100644 --- a/arduino/wärmebildkamera/Example1_BasicReadings/Example1_BasicReadings.ino +++ b/arduino/wärmebildkamera/Example1_BasicReadings/Example1_BasicReadings.ino @@ -28,7 +28,6 @@ */ #include - #include "MLX90640_API.h" #include "MLX90640_I2C_Driver.h" @@ -86,10 +85,10 @@ void loop() float tr = Ta - TA_SHIFT; //Reflected temperature based on the sensor ambient temperature float emissivity = 0.95; - + Serial.print("loop-schleife"); MLX90640_CalculateTo(mlx90640Frame, &mlx90640, emissivity, tr, mlx90640To); } - + Serial.print("loop-schleife2"); for (int x = 0 ; x < 10 ; x++) { Serial.print("Pixel "); @@ -110,4 +109,5 @@ boolean isConnected() if (Wire.endTransmission() != 0) return (false); //Sensor did not ACK return (true); -} + Serial.print("verbunden"); + } diff --git a/arduino/wärmebildkamera/MLX90640_I2C_Driver.cpp b/arduino/wärmebildkamera/MLX90640_I2C_Driver.cpp index 0689a49..2dcf231 100644 --- a/arduino/wärmebildkamera/MLX90640_I2C_Driver.cpp +++ b/arduino/wärmebildkamera/MLX90640_I2C_Driver.cpp @@ -23,7 +23,26 @@ void MLX90640_I2CInit() { } - +int MLX90640_I2CRead(uint8_t _deviceAddress, unsigned int startAddress, unsigned int nWordsRead, uint16_t *data) +{ + // nWordsRead must be <= 32767 + Wire.beginTransmission(_deviceAddress); + Wire.write(startAddress >> 8); //MSB + Wire.write(startAddress & 0xFF); //LSB + Wire.endTransmission(false); + i2c_err_t error = Wire.readTransmission(_deviceAddress, (uint8_t*) data, nWordsRead*2); + if(error != 0){//problems + Serial.printf("Block read from sensor(0x%02X) at address=%d of %d uint16_t's failed=%d(%s)\n", + _deviceAddress,startAddress,nWordsRead,error,Wire.getErrorText(error)); + } + else { // reverse byte order, sensor Big Endian, ESP32 Little Endian + for(auto a = 0; a>8)&0xff); + } + } + return 0; +} +/* //Read a number of words from startAddress. Store into Data array. //Returns 0 if successful, -1 if error int MLX90640_I2CRead(uint8_t _deviceAddress, unsigned int startAddress, unsigned int nWordsRead, uint16_t *data) @@ -42,7 +61,11 @@ int MLX90640_I2CRead(uint8_t _deviceAddress, unsigned int startAddress, unsigned Wire.beginTransmission(_deviceAddress); Wire.write(startAddress >> 8); //MSB Wire.write(startAddress & 0xFF); //LSB - Wire.endTransmission(false) + if(Wire.endTransmission(false) != 7){ + Serial.println("Error: Sensor did not ack"); + return (0);//Sensor did not ACK + + } uint16_t numberOfBytesToRead = bytesRemaining; if (numberOfBytesToRead > I2C_BUFFER_LENGTH) numberOfBytesToRead = I2C_BUFFER_LENGTH; @@ -66,7 +89,7 @@ int MLX90640_I2CRead(uint8_t _deviceAddress, unsigned int startAddress, unsigned return (0); //Success } - +*/ //Set I2C Freq, in kHz //MLX90640_I2CFreqSet(1000) sets frequency to 1MHz void MLX90640_I2CFreqSet(int freq) @@ -87,7 +110,7 @@ int MLX90640_I2CWrite(uint8_t _deviceAddress, unsigned int writeAddress, uint16_ { //Sensor did not ACK Serial.println("Error: Sensor did not ack"); - return (-1); + return (0);//Sensor did not ACK } uint16_t dataCheck;