mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik Wärmebildkamera mit dem MLX90640 und Arduino Due


Autor: Christoph E. (stoppi)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
Hallo!

Frohe Weihnachten euch allen...

Hier (https://forum.mosfetkiller.de/viewtopic.php?f=6&t=20202) habe ich 
bereits meine erste Wärmebildkamera mit dem MLX90614 DCI vorgestellt. 
Das große Manko dieser Anordnung war die lange Belichtungszeit von rund 
5 Minuten. Nun gibt es von Melexis einen neuen Sensor, den MLX90640. 
Dieser besitzt immerhin eine Auflösung von 32x24, also insgesamt 768 
Pixel.

Habe heute einen aus Fernost bestellt und zwar jenen mit dem 55°x35° 
Gesichtsfeld: 
https://de.aliexpress.com/item/MLX90640-Kamera-Modul-IR-32-24-GY-MCU90640-Infrarot-Thermometrische-Dot-Matrix-Sensor-32x24-Sensor-Modul/32962087015.html?ws_ab_test=searchweb0_0%2Csearchweb201602_5_10065_10068_10547_319_317_10548_10696_10084_453_454_10083_10618_10304_10307_10820_10821_538_537_10302_536_10059_10884_10887_100031_321_322_10103%2Csearchweb201603_51%2CppcSwitch_0&algo_pvid=1d6caa67-fdeb-4212-90aa-f50add383914&algo_expid=1d6caa67-fdeb-4212-90aa-f50add383914-0

Da ich ja bekanntlich möglichst wenig auf fertige Produkte zurückgreifen 
möchte, habe ich mich bereits um die Software gekümmert.

github-Link für das Auslesen des Sensors: 
https://github.com/sparkfun/SparkFun_MLX90640_Arduino_Example

Als Prozessor kommt ein Arduino Due zum Einsatz, da dieser einen 
ausreichenden Speicher für die doch komplexen Berechungen besitzt. Im 
Internet findet man immer wieder einzelne Berichte, dass es Probleme mit 
dem Arduino Due geben soll. Ich hoffe, dass sich dann alles in Luft 
auflöst. Display ist das von mir schon bei mehreren Projekten zum 
Einsatz gekommene mit 480x320 Pixel 
(Ebay-Artikel Nr. 163228939051).

Als Farbskala für das Wärmebild kommt ein "Nachbau" der abgebildeten zum 
Einsatz. War gar nicht so einfach, einen möglichst simplen, nur aus 
linesaren Verläufen bestehenden Klon zu erstellen. Habe das Farbspekrum 
nun in 180 Pixel unterteilt und übergebe an das Unterprogramm eben auch 
einen Wert im Intervall [0,180]. Die Abstimmung auf die gemessene 
Temperatur ist dann einfach. Sie lautet: Pixel i = 180 * (T_gemessen - 
T_min) / (T_max - T_min). So bilde ich den gesamten Temperaturbereich 
[T_min,T_max] auf den Zahlenbereich [0, 180] ab.

Auf dem Display wird neben dem Falschfarbenwärmebild noch seitlich die 
färbige Temperaturskala mit T_min und T_max angezeigt. So schöpfe ich 
immer den gesamten Farbraum von dunkelblau bis weiß aus. Zudem wird noch 
die Temperatur des Pixels in der Mitte angezeigt (siehe Kreuz).

Leider entsprechen die Farben auf dem Photo vom Display bei weitem nicht 
dem tatsächlichen Erscheinungsbild (violett wird z.B. nahezu gar nicht 
dargestellt). Dieses stimmt bei weitem mehr mit den Vorgaben überein, 
als es den Anschein hat...

Wenn der Sensor eingetroffen ist, geht es hier weiter.

: Bearbeitet durch User
Autor: Christoph E. (stoppi)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
Habe den Farbverlauf nochmals geändert, passt jetzt besser (Farben 
werden aber durch die Kamera nach wie vor nicht 1:1 wiedergegeben...)

Autor: Johannes S. (jojos)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
soll der Pixelmatsch schon das Wärmebild sein? Da scheint eher etwas mit 
dem einlesen nicht zu klappen als mit der Farbpalette.
Für einen Omron Sensor habe ich mir eine C++ Klasse für eine Farbpalette 
gebaut. Es können Farben als Stützpunkte eingefügt werden und dazwischen 
wird interpoliert, so können verschiedene Farbverläufe realisiert 
werden. Der RGB565 Werte wird berechnet, als Optimierung könnte man noch 
eine Tabelle vorberechnen lassen. Ich habe das auf einem STM32F407 
laufen, der ist so schnell das eine Tabelle nicht nötig war. Das TFT für 
Board ist allerdings nicht besonders gut, die Farben sind extrem 
blickwinkelabhängig.
Im Anhang ist meine C++ Klasse und wird so benutzt:
    // create palette
    ColorPalette cpRainbow;
    cpRainbow.addItem(   0.0f,   0,   0, 255);      //   0 % blue
    cpRainbow.addItem(  33.0f,   0, 255,   0);      //  33 % green
    cpRainbow.addItem(  66.0f, 255, 255,   0);      //  66 % yellow
    cpRainbow.addItem( 100.0f, 255,   0,   0);      // 100 % red

    cpRainbow.setMinMax(20.0f, 35.0f);

    // create palette
    ColorPalette cpBlueRed;
    cpBlueRed.addItem(   0.0f,   0,   0, 255);      //   0 % blue
    cpBlueRed.addItem(  50.0f, 255, 255, 255);      //  50 % white
    cpBlueRed.addItem( 100.0f, 255,   0,   0);      // 100 % red

    cpBlueRed.setMinMax(20.0f, 35.0f);

    // get color from palette
    uint16_t color = cpBlueRed.getColor(temperature);

Autor: Christoph E. (stoppi)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Danke für den Beitrag...
Das Wärmebild besteht noch aus reinen Zufallstemperaturen [random(180)], 
da ich ja den Sensor noch nicht habe.

Autor: Johannes S. (jojos)
Datum:
Angehängte Dateien:

Bewertung
1 lesenswert
nicht lesenswert
Christoph E. schrieb:
> Das Wärmebild besteht noch aus reinen Zufallstemperaturen [random(180)],
> da ich ja den Sensor noch nicht habe.

ok, das war durch 'Farben werden aber durch die Kamera nach wie vor 
nicht 1:1 wiedergegeben...' etwas missverständlich.

Im Anhang ein Bild wie das auf minem Display aussieht. Der Balken gibt 
den Farbverlauf von 0..max wieder.

Autor: Christoph E. (stoppi)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
So, der Sensor ist gestern angekommen. Leider bringe ich ihn am Arduino 
Due nicht zum Laufen. Ich erhalte anstelle der Temperaturen nur den 
"Wert" nan

Habe mich im Internet nach einer Lösung umgesehen, aber mit einem Due 
hat scheinbar noch keiner den MLX90640 erfolgreich betrieben...

Habe schon so einiges versucht. Den PS-pin an/nicht an GND usw.

Betreiben tue ich das Board an 5V, da es einen 3.3V-Spannungswandler 
integriert hat. Die SDA/SCL-Leitungen verfügen über je einen 2.2kOhm 
pull-up Widerstand.

Eine Frage an die Spezialisten: Mein Board verfügt neben der SDA/SCL 
Schnittstelle auch noch über RX/TX-pins. Das Board verfügt bereits über 
einen eigenen microcontroller, der dann die 768 Temperaturen ausgibt. Im 
Netz findet man ein Programm, welches die Daten dann gleich graphisch 
ausgibt. Hat jemand vielleicht eine Idee, wie ich diese Daten mit dem 
Arduino Due an den RX/TX pins abgreifen und auslesen kann?

Wenn das alles nicht weiterführt, werde ich mir wohl einen empfohlenen 
Teensy besorgen müssen. Nur kann ich mit einem Teensy auch so einfach 
wie mit dem Arduino Due ein 320x480 display anschließen?

Link zum Sensor: 
https://www.aliexpress.com/snapshot/0.html?spm=a2g0s.9042647.6.2.77b74c4dxkdXfJ&orderId=97282295260631&productId=32958277975

sparkfun-Seite mit einem anderen board nur mit SDA/SCL: 
https://learn.sparkfun.com/tutorials/qwiic-ir-array-mlx90640-hookup-guide/all

Verwendete Software: 
https://github.com/sparkfun/SparkFun_MLX90640_Arduino_Example/tree/master/Firmware/Example1_BasicReadings

Danke im voraus für eure Hilfe...

: Bearbeitet durch User
Autor: Christoph E. (stoppi)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
So, ich habe inzwischen aus China Software für PC und Arduino erhalten 
(siehe code). Verwende wie gesagt einen Arduino Due. RX/TX vom Sensor 
habe ich mit TX1/RX1 vom Due verbunden. Problem ist, es tut sich im 
seriellen Monitor überhaupt nichts. TX vom MLX90640 sendet aber Signale 
(siehe Abbildung).

Da ich mit Kommunikationscode alles andere als fit bin, vielleicht hätte 
einer von den Profis für mich einen Tipp was ich noch versuchen könnte. 
Danke im voraus...

P.S.: Die Zeilen mit Serial1 und Serial2 sind nicht original aus China, 
da hat sich der Compiler aber immer aufgeregt...

P.P.S: Bei GYSerial.available()> 0 kommt scheinbar gar nichts an...


//GY_mlx90640 ARDUINO

//   GY_mlx90640                 arduino pro mini
/*
1.GY_mlx90640_uart arduino
2.GY_mlx90640 VCC  GND
3.arduino_TX---GY_mlx90640_RX   Rest arduino
4.arduino__RX---GY_mlx90640_TX
5.GYSerial,baud=9600
6.arduino_pin_11---FT232_RX
7.arduino_pin_10---FT232_TX
8.PCSerial ,baud=115200
*/

//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
// Ändere hier, welcher Hardware Serial für was verwendet wird.
#define PCSerial   Serial2
#define GYSerial   Serial1

uint16_t temp1=0;
int16_t temp2=0;

uint8_t Re_buf[10];
uint16_t re_count=0,rest_count=0;
uint16_t counter=0;

unsigned char sign=0;
int led = 13;
float myMap(float x, float in_min, float in_max, float out_min, float out_max);
float max_temp=0;
float min_temp=500;


//-----------------------------------------------------------
void setup()
   {
    GYSerial.begin(9600);  
    PCSerial.begin(115200);
   
    delay(1000);    
   }


//-------------------------------------------------------------
void loop()
   {
    if (GYSerial.available()>0) 
       {   
        Re_buf[counter]=(unsigned char)GYSerial.read();
  
        if(counter==0&&Re_buf[0]!=0x5A) return;    
        else  if(counter==1&&Re_buf[1]!=0x5A)
           {
            counter=0;
            return;
           };       
        
        if(counter<6)    
           counter++;       
        if(counter==4)               
           {    
            if(Re_buf[2]==0x02&&Re_buf[3]==0x06)
               sign=1;
            else
               counter=0;
           }     
        if(counter>5)
           {
            float temp=(float)(Re_buf[4]+Re_buf[5]*256)/100;
            
            if(temp>max_temp)
               max_temp=temp;
            
            if(temp<min_temp)
               min_temp=temp;
        
            counter=4;
            re_count++;
      
        if(rest_count>20)
           {
            min_temp=500;
            max_temp=0;
            rest_count=0;
           }
       
        //PCSerial.print(temp); 
        // PCSerial.print(","); 
        
        float inv= myMap(temp,min_temp,max_temp,0.5,1);
      
        if(inv>0.75)
           PCSerial.print("**"); 
        else
           PCSerial.print("--"); 
        
        if((re_count%32)==0)
           PCSerial.println(); 
        
        if(re_count%768==0)
           PCSerial.print("TA:"); 
        
        if(re_count==769)
           { 
            rest_count++;
            counter=0;
            PCSerial.print(temp); 
            PCSerial.println(); 
            re_count=0;
           }
       }
     }
   } 


//---------------------------------------------------------------
float myMap(float x, float in_min, float in_max, float out_min, float out_max)
   {
    return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;
   }

: Bearbeitet durch User
Autor: Cornelius (Gast)
Datum:

Bewertung
1 lesenswert
nicht lesenswert
Hallo Christoph,

vor einiger Zeit habe ich auch mit dem Sensor und einem ESP32 herum 
probiert.
Es ging ewig lange nichts und ich habe schon geglaubt, es liegt am 
Sensor.
Dann habe ich einen zweiten bekommen, da ging auch nichts.

Irgendwann hatte ich aber ein Lösung gefunden: Der Sensor hat ein EEPROM 
eingebaut und es ist vermutlich so, dass die meiste Open-Source-Software 
nur mit den vor eingestellten Werten funktioniert ( ich weiß nicht mehr, 
ob es Adafruit war, die den Sensor mit vor eingestellten Werten 
ausliefern ). Die anderen gehen dann nicht mit der Software.
Ich habe die dann rein geschrieben, und siehe da, beide Sensoren gingen.
Leider weiß ich schon nicht mehr, welche es waren.

Autor: Christoph E. (stoppi)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo Cornelius!

Vielen Dank für deinen interessanten Hinweis. Ich habe meinen Sensor 
über aliexpress gekauft und er hat bereits einen microcontroller an 
Bord, der per serieller Schnittstelle (Tx/Rx) eben die 768 Temperaturen 
ausgibt. Die reinen Sensoren von Sparkfun etc. haben den nicht und daher 
kommunizieren diese direkt mit dem Sensor über den I2C-Bus (SCL,SDA)...

Oben im Programm habe ich nun PCSerial mit Serial definiert. So kann ich 
zumindest das array Re_buf[Counter] auslesen. Die Werte sind aber auch 
nicht nachvollziehbar...

: Bearbeitet durch User
Autor: Cornelius (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Das hier sind die Werte ab Adresse 0x8000, mit dem der Sensor geht.
Vielleicht hilft Dir das weiter:

// Sparkfun sensor
Device found @ 0x33
0: 9
1: AB
2: 499B
3: 0
4: 2061
5: 5
6: 320
7: 3E0
8: 1A26
9: A228
10: 185
11: 499
12: 0
13: 1901
14: 0
15: 0

Autor: Christoph E. (stoppi)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
Vielen Dank Cornelius für deine Hilfe!

Habe nun das Programm so weit wie möglich entschlackt. Ich erhalte jetzt 
mit Baud = 115200 im 32x24-Raster auch zum Teil recht plausible Werte 
(Zimmertemperaturen um die 21°C bzw. Handtemperatur um die 35°C), aber 
auch etliche nicht nachvollziehbare Temperaturen über 100-400°C.

Vielleicht hat ja jemand von euch noch einen Tipp für mich...

//GY_mlx90640 ARDUINO

//   GY_mlx90640                 arduino pro mini
/*
1.GY_mlx90640_uart arduino
2.GY_mlx90640 VCC  GND
3.arduino_TX---GY_mlx90640_RX   Rest arduino
4.arduino__RX---GY_mlx90640_TX
5.GYSerial,baud=9600
6.arduino_pin_11---FT232_RX
7.arduino_pin_10---FT232_TX
8.PCSerial ,baud=115200
*/

#define PCSerial Serial
#define GYSerial Serial1

uint8_t Re_buf[10];
uint16_t re_count = 0;
uint16_t counter = 0;

unsigned char sign = 0;
int led = 13;


//-----------------------------------------------------------
void setup()
   {
    GYSerial.begin(115200);  
    PCSerial.begin(115200);
   
    delay(1000);    
   }


//-------------------------------------------------------------
void loop()
   {
    if (GYSerial.available() > 0) 
       {   
        Re_buf[counter]=(unsigned char)GYSerial.read();

        if(counter == 0 && Re_buf[0] != 0x5A) return;
        else if(counter == 1 && Re_buf[1]!= 0x5A)
           {
            counter = 0;
            return;
           };      
    
        if(counter < 6)    
           counter++;       
    
        if(counter == 4)             
           {    
            if(Re_buf[2] == 0x02 && Re_buf[3] == 0x06)
               sign = 1;
            else
               counter = 0;
           }     
      
        if(counter > 5)
           {
            float temp = (float)(Re_buf[4] + Re_buf[5] * 256) / 100;
      
            counter = 4;
        
            re_count++;
       
            PCSerial.print(temp); 
            PCSerial.print(","); 
       
            if((re_count%32) == 0)
               PCSerial.println(); 
            
            if(re_count == 769)
               { 
                counter = 0;
                PCSerial.println(); 
                re_count=0;
               }
           }
      }
   } 


Autor: Elias K. (elik)
Datum:

Bewertung
1 lesenswert
nicht lesenswert
Auf dem Oszibild oben sehe ich eine UART-Datenstrom mit 115.200 kBaud, 
8N1. Ich tippe auf ein Problem mit dem Stoppbit. Da es nur eines ist, 
könnte das Probleme mit der Synchronisation über einen so langen 
Datenstrom geben.

Schau dir mal den Wikieintrag zu Baudratenquarz an.

Autor: Christoph E. (stoppi)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Danke Elias für deinen Hinweis. Das klingt dann aber nach unlösbaren 
Problem oder? Denn die Länge bzw. Aufteilung des Datenstroms kann ich ja 
so nicht beeinflussen.

Deine Vermutung mit timing-Problemen würde sich mit der Beobachtung 
decken, dass zumindest zu Beginn der Übertragung die Temperaturen 
stimmen und erst nach einer Zeit durch einen Zeitdrift falsche Werte 
eingelesen werden...

: Bearbeitet durch User
Autor: Christoph E. (stoppi)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
Würde es ggf. Sinn machen die baudrate z.B. auf 9600 zu senken um mehr 
Genauigkeit beim Einlesen der Temperaturen zu bekommen?

Autor: Elias K. (elik)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Christoph E. schrieb:
> Würde es ggf. Sinn machen die baudrate z.B. auf 9600 zu senken um mehr
> Genauigkeit beim Einlesen der Temperaturen zu bekommen?

Probieren geht über studieren. Könnte klappen Die Übertragung eines 
Frames dauert dann aber schon ganz schön lang.

Eine schöne Möglichkeit wäre, wenn du den Controller bei der Camera auf 
8N2 (2 Stoppbits) setzen könntest, und den Arduino auf 8N1 Empfang. Das 
gibt eine kleine Lücke zur Re-Synchronisation.

Auch gut wäre, wenn beide Seiten passende Quarze haben. Der Controller 
an der Kamera nutzt aber wahrscheinlich den internen Taktgenerator, der 
idR alles andere als genaue Takte generiert. Also eher nicht 
praktikabel...
Lesestoff: 
https://www.allaboutcircuits.com/technical-articles/the-uart-baud-rate-clock-how-accurate-does-it-need-to-be/

Evtl. lohnt es auch, den UART auf dem Arduino per Hand zu tunen. Also 
die Register im Atmega selbst zu setzen. Dazu findet sich im Atmega 
Datenblatt unter Kapitel USART jede Menge Lesestoff.

Vielleicht reicht es auch, wenn du den Takt auf dem Arduino etwas 
schneller/langsamer machst. Das könnte durch einen Austausch der 
Kondensatoren am Quarz klappen.
Lesestoff: 
https://www.all-electronics.de/wp-content/uploads/migrated/article-pdf/113375/174ag0206.pdf

Autor: Christoph E. (stoppi)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
Vielen Dank Elias für die Tipps...

Es geht voran. Habe nun mittels TTL-USB-Adapter die China-PC-Software 
ausprobiert und siehe da, ich erhalte ein Bild.

Problem ist nur, dass ich im Programm trotz vorhandener Buttons 
scheinbar die baud-rate nicht ändern kann. Deshalb schnell in teraterm 
die baud-rate von 115200 auf 9600 gesenkt. Und siehe da, ich habe nun 
mit dem Arduino-Programm keine falschen Temperaturen mehr.

Schönheitsfehler: Ich erhalte so nur etwa 1 Bild pro Sekunde...

Das eigenartige ist aber nun, dass ich mit teraterm (siehe Abbildung) 
die baud-rate nicht mehr z.B. auf 115200 zurücksetzen kann. Mache ich da 
irgendetwas falsch?

Gebe die Kommandos laut Abbildung (danke count-doku für den link) ein. 
Wie gesagt, bei der ersten Umstellung von 115200 auf 9600 hat es so 
geklappt, nur jetzt nicht mehr...

Als nächstes werde ich die 768 Temperaturen in einem array abspeichern 
und dann mit dem bereits geschriebenen Programm graphisch ausgeben.

Autor: Seine LED leuchtet nicht (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo Christoph,

ein interessantes Thema. Danke dass du uns teilnehmen lässt.

Frage
Es gibt von den MLX90640 zwei Typen, mit BAA und BAB am Ende.
Welchen hast du im Einsatz?

Autor: Christoph E. (stoppi)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
Habe den MLX90640BAB mit 55°x35° Gesichtsfeld...

Schlechte Nachrichten: Der Sensor scheint tot zu sein. Es kommen über TX 
keine Signale mehr. Warum dies so ist, weiß ich leider nicht. Sprich ein 
Fehler (Überspannung o.ä.) ist mir nicht bewusst.

Werde jetzt versuchen, einen zweiten günstig zu bekommen. Anbei noch das 
letzte Bild von mir und Halogenlampe an der Wohnungsdecke...

Autor: Christoph M. (mchris)
Datum:

Bewertung
1 lesenswert
nicht lesenswert
>Schlechte Nachrichten: Der Sensor scheint tot zu sein. Es kommen über TX
>keine Signale mehr.

Gib nicht so schnell auf. Mit dem Arduino-Due kannst Du einen 
I2C-Scanner programmieren und dann mal sehen, ob der Sensor noch auf die 
Adresse antwortet.
https://playground.arduino.cc/Main/I2cScanner
Vielleicht ist ja nur die Konfiguration des Sensors zerschossen.

Autor: Christoph E. (stoppi)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
Zu früh möchte ich die Flinte eh nicht ins Korn werfen...

Habe mir die Signale nochmals angesehen. Also wie gesagt TX ist tot. 
Über I2C kommen aber noch Signale und der I2C-Scanner erkennt den Sensor 
an 0x33, was ja auch passen würde.

Das Sparkfun-Programm für den MLX90640, welches auf den I2C zurückgreift 
funktioniert zwar nicht, liefert aber diesselben Ergebnisse wie noch vor 
wenigen Tagen (siehe Abbildung MLX90640_Arduino_44)

Ich tippe daher auf einen defekten Microcontroller (STM32F103). Was sagt 
ihr?

: Bearbeitet durch User
Autor: Jedi Knight (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Christoph E. schrieb:

> Ich tippe daher auf einen defekten Microcontroller (STM32F103). Was sagt
> ihr?

Na also, halb so wild. Ein Microcontroller Ersatz lässt sich doch 
schnell und billig beschaffen. Sollte man m.E. sowieso immer i.d. 
Schublade liegen haben.

Allerdings sollte auch ein mutmaßlicher Grund da sein, WARUM etwas 
kaputt gegangen sein könnte. Von selbst gehen ICs i.d.R. nicht kaput.

Bleib dran. Ich beobachte, es interessiert mich.
und viel Erfolg :-)

Autor: Christoph M. (mchris)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
>Ich tippe daher auf einen defekten Microcontroller (STM32F103). Was sagt
>ihr?

Schwierig zu sagen. Ich könnte mir vorstellen, dass Du die EEPROM 
Konfiguration im MLX zerschossen hast und das Sparkfun Programm nur mit 
voreingestellten Werten funktioniert.

Was dann hilft: Werte einfach neu rein schreiben. Zur Not kann man sie 
auch einfach jedesmal beim Start ins RAM schreiben. So kannst Du 
übrigens auch Deinen MC testen: Einfach Werte ins RAM schreiben und 
zurück lesen.

Autor: Christoph E. (stoppi)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
So, habe mich nun auf die Suche gemacht, wie ich das EEPROM des Sensors 
auslesen und verändern kann.

Bin hier bei einem Programm für den Arduino fündig geworden: 
http://forum.arduino.cc/index.php?topic=351494.msg3004267#msg3004267

Ich muss ja laut Cornelius (siehe Beitrag weiter oben) folgende Werte 
ins EEPROM ab Adresse 0x8000 schreiben:

// Sparkfun sensor
Device found @ 0x33
0: 9
1: AB
2: 499B
3: 0
4: 2061
5: 5
6: 320
7: 3E0
8: 1A26
9: A228
10: 185
11: 499
12: 0
13: 1901
14: 0
15: 0

Ausgelesen habe ich bei meinem MLX90640 Sensor einmal folgende Werte 
(siehe auch Abbildung):

9  172  27039  0  8289  5  800  992  2571  24488  390  1177  0  6657  0 
0

Jetzt regt sich das Programm aber beim "Wert" AB usw. auf. Muss ich nun 
AB etwa vom hexadezimalen ins dezimale Zahlensystem umwandeln und statt 
AB = 10 * 16 + 11 * 1 = 171 ins EEPROM schreiben?



#include <Wire.h>
#define I2C_EEPROM_ADRESSE 0x33
#define EEPROM_SPEICHER_ADR 0x8000

const uint16_t Anzahl_Rezepte = 16;  // anzahl Rezepte
uint16_t Zaehler[Anzahl_Rezepte] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
bool oneshot = true;

void setup()
   {
    Wire.begin();
    Serial.begin(9600);
    Serial.println("Programmanfang");
    Serial.print("Zaehlerfeld vor dem Lesen: \t");
    
    for (uint16_t j = 0; j < (sizeof(Zaehler) / sizeof(Zaehler[0])); j++)
       {
        Serial.print(Zaehler[j]);
        Serial.print(" ");
       }
       
    Serial.println();
    
    bool zaehlerzuruecksetzen = false;  // auf true zum Loeschen, auch zur Speicherinitialisierung auf 0
    
    if (zaehlerzuruecksetzen)
       {
        i2c_eeprom_updateUIntArray(I2C_EEPROM_ADRESSE, EEPROM_SPEICHER_ADR, Zaehler, sizeof(Zaehler) / sizeof(Zaehler[0]));  // Zaehler zuruecksetzen
       }
    else
       {
        i2c_eeprom_readUIntArray(I2C_EEPROM_ADRESSE, EEPROM_SPEICHER_ADR, Zaehler, sizeof(Zaehler) / sizeof(Zaehler[0]));
       }
  
    Serial.print("Zaehlerfeld nach dem Lesen: \t");
    
    for (uint16_t j = 0; j < (sizeof(Zaehler) / sizeof(Zaehler[0])); j++)
       {
        Serial.print(Zaehler[j]);
        Serial.print(" ");
       }
    
    Serial.println();
   }

void loop()
   {
    if (oneshot)
       {
        Zaehler[0] = 9;
        Zaehler[1] = AB;
        Zaehler[2] = 499B;
        Zaehler[3] = 0;
        Zaehler[4] = 2061;
        Zaehler[5] = 5;
        Zaehler[6] = 320;
        Zaehler[7] = 3E0;
        Zaehler[8] = 1A26;
        Zaehler[9] = A228;
        Zaehler[10] = 185;
        Zaehler[11] = 499;
        Zaehler[12] = 0;
        Zaehler[13] = 1901;
        Zaehler[14] = 0;
        Zaehler[15] = 0;
            
        i2c_eeprom_updateUIntArray(I2C_EEPROM_ADRESSE, EEPROM_SPEICHER_ADR, Zaehler, sizeof(Zaehler) / sizeof(Zaehler[0]));

        Serial.print("Zaehlerfeld nach dem Schreiben: \t");
        
        for (uint16_t j = 0; j < (sizeof(Zaehler) / sizeof(Zaehler[0])); j++)
           {
            Serial.print(Zaehler[j]);
            Serial.print(" ");
           }
        
        Serial.println();
        
        oneshot = false;
       }
   }



void i2c_eeprom_updateUIntArray(int16_t deviceaddress, uint16_t eeaddress, uint16_t *ptr, uint16_t anzahlElemente)
   {
    uint16_t buf[anzahlElemente];
    i2c_eeprom_readUIntArray(deviceaddress, eeaddress, buf, sizeof(buf) / sizeof(buf[0]));
    uint16_t eadr=eeaddress;
    
    for (uint16_t j = 0; j < anzahlElemente; j++)
       {
        if ((ptr[j] >> 8) != (buf[j] >> 8))
           {
            Wire.beginTransmission(deviceaddress);
            Wire.write((int)(eadr >> 8)); // MSB
            Wire.write((int)(eadr & 0xFF)); // LSB
            Wire.write(ptr[j] >> 8);
            Wire.endTransmission();
            delay(10);
           }
       
        eadr++;
    
        if ((ptr[j] & 0xFF) != (buf[j] & 0xFF))
           {
            Wire.beginTransmission(deviceaddress);
            Wire.write((int)(eadr >> 8)); // MSB
            Wire.write((int)(eadr & 0xFF)); // LSB
            Wire.write(ptr[j] & 0xFF);
            Wire.endTransmission();
            delay(10);
           }
        eadr++;
       }
   }



void i2c_eeprom_readUIntArray(int16_t deviceaddress, uint16_t eeaddress, uint16_t *ptr, uint16_t anzahlElemente)
   {
    uint16_t data = 0xFF;
    delay(2);
    
    Wire.beginTransmission(deviceaddress);
    Wire.write((int)(eeaddress >> 8)); // MSB
    Wire.write((int)(eeaddress & 0xFF)); // LSB
    Wire.endTransmission();
    Wire.requestFrom(deviceaddress, anzahlElemente << 1);
    
    for (uint16_t j = 0; j < anzahlElemente; j++)
       {
        delay(5);
        data = Wire.read() << 8;
        delay(5);
        data = data | Wire.read();
        ptr[j] = data;
       }
   }

Autor: Christoph M. (mchris)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
Eigentlich reicht es, wenn Du erst mal die Konfigurationsregister ( RAM 
) richtig beschriebst ( Datenblatt S.16 ).

Beitrag #5715981 wurde vom Autor gelöscht.
Beitrag #5715984 wurde vom Autor gelöscht.
Autor: Christoph E. (stoppi)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
So, habe nun die HEX-Werte in DEZ-Werte umgewandelt und versucht, den
EEPROM-Speicher abzuändern. Er behält aber scheinbar nicht die
geänderten Werte, da noch die alten Werte gelesen werden....

Kann mir da jemand vielleicht helfen? Danke im voraus...


#include <Wire.h>
#define I2C_EEPROM_ADRESSE 0x33
#define EEPROM_SPEICHER_ADR 0x8000

const uint16_t Anzahl_Rezepte = 16;  // anzahl Rezepte
uint16_t Zaehler[Anzahl_Rezepte] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
bool oneshot = true;

void setup()
   {
    Wire.begin();
    Serial.begin(9600);
    Serial.println("Programmanfang");

    i2c_eeprom_readUIntArray(I2C_EEPROM_ADRESSE, EEPROM_SPEICHER_ADR, Zaehler, sizeof(Zaehler) / sizeof(Zaehler[0]));
  
    Serial.print("Zaehlerfeld vor dem Schreiben: \t");
    
    for (uint16_t j = 0; j < (sizeof(Zaehler) / sizeof(Zaehler[0])); j++)
       {
        Serial.print(Zaehler[j]);
        Serial.print(" ");
       }
    
    Serial.println();
   }

void loop()
   {
    //oneshot = false;
    
    if (oneshot)
       {
        Zaehler[0] = 9;
        Zaehler[1] = 171;      // = HEX AB
        Zaehler[2] = 18843;    // = HEX 499B
        Zaehler[3] = 0;
        Zaehler[4] = 8289;     // = HEX 2061
        Zaehler[5] = 5;
        Zaehler[6] = 800;      // = HEX 320
        Zaehler[7] = 992;      // = HEX 3E0
        Zaehler[8] = 6694;     // = HEX 1A26
        Zaehler[9] = 41512;    // = HEX A228
        Zaehler[10] = 389;     // = HEX 185
        Zaehler[11] = 1177;    // = HEX 499
        Zaehler[12] = 0;
        Zaehler[13] = 6401;    // = HEX 1901
        Zaehler[14] = 0;
        Zaehler[15] = 0;

        Serial.print("neu zu schreibende Werte: \t");

        for (uint16_t j = 0; j < (sizeof(Zaehler) / sizeof(Zaehler[0])); j++)
           {
            Serial.print(Zaehler[j]);
            Serial.print(" ");
           }
        
        i2c_eeprom_updateUIntArray(I2C_EEPROM_ADRESSE, EEPROM_SPEICHER_ADR, Zaehler, sizeof(Zaehler) / sizeof(Zaehler[0]));


        i2c_eeprom_readUIntArray(I2C_EEPROM_ADRESSE, EEPROM_SPEICHER_ADR, Zaehler, sizeof(Zaehler) / sizeof(Zaehler[0]));
        
        Serial.println();
        Serial.print("Zaehlerfeld nach dem Schreiben: \t");
        
        for (uint16_t j = 0; j < (sizeof(Zaehler) / sizeof(Zaehler[0])); j++)
           {
            Serial.print(Zaehler[j]);
            Serial.print(" ");
           }
        
        Serial.println();
        
        oneshot = false;
       }
   }



void i2c_eeprom_updateUIntArray(int16_t deviceaddress, uint16_t eeaddress, uint16_t *ptr, uint16_t anzahlElemente)
   {
    uint16_t buf[anzahlElemente];
    i2c_eeprom_readUIntArray(deviceaddress, eeaddress, buf, sizeof(buf) / sizeof(buf[0]));
    uint16_t eadr=eeaddress;
    
    for (uint16_t j = 0; j < anzahlElemente; j++)
       {
        if ((ptr[j] >> 8) != (buf[j] >> 8))
           {
            Wire.beginTransmission(deviceaddress);
            Wire.write((int)(eadr >> 8)); // MSB
            Wire.write((int)(eadr & 0xFF)); // LSB
            Wire.write(ptr[j] >> 8);
            Wire.endTransmission();
            delay(10);
           }
       
        eadr++;
    
        if ((ptr[j] & 0xFF) != (buf[j] & 0xFF))
           {
            Wire.beginTransmission(deviceaddress);
            Wire.write((int)(eadr >> 8)); // MSB
            Wire.write((int)(eadr & 0xFF)); // LSB
            Wire.write(ptr[j] & 0xFF);
            Wire.endTransmission();
            delay(10);
           }
        eadr++;
       }
   }



void i2c_eeprom_readUIntArray(int16_t deviceaddress, uint16_t eeaddress, uint16_t *ptr, uint16_t anzahlElemente)
   {
    uint16_t data = 0xFF;
    delay(2);
    
    Wire.beginTransmission(deviceaddress);
    Wire.write((int)(eeaddress >> 8)); // MSB
    Wire.write((int)(eeaddress & 0xFF)); // LSB
    Wire.endTransmission();
    Wire.requestFrom(deviceaddress, anzahlElemente << 1);
    
    for (uint16_t j = 0; j < anzahlElemente; j++)
       {
        delay(5);
        data = Wire.read() << 8;
        delay(5);
        data = data | Wire.read();
        ptr[j] = data;
       }
   }


Autor: Elias K. (elik)
Datum:
Angehängte Dateien:

Bewertung
1 lesenswert
nicht lesenswert
Christoph E. schrieb:
> Ich tippe daher auf einen defekten Microcontroller (STM32F103). Was sagt
> ihr?
Der STM32 ist der zusätzliche Controller auf der Kameraplatine? Gut 
möglich, dass der die Hufe gehoben hat. Vielleicht auch nur irgendein 
Problem in der Ansteuerung. Alles in allem aber eine Blackbox, wo man 
nicht weiß, was Sache ist. (Oder hast du das Programm, was da drauf 
ist?) Deswegen würde ich mich (wie du ja bereits machst) auf I2C 
konzentrieren.

Wieso die neuen Werte im Speicher nicht ankommen, kann ich aus dem Code 
nicht erkennen. Hast du die Möglichkeit, mit dem Oszi die Übertragung 
aufzunehmen? Wenn ja, dann schau dir die Telegramme doch mal an, ob die 
passen. Z.B. den ersten Schreibbefehl und das erste gelesene Telegramm.

Hast du im Datenblatt auf Seite 13 gesehen, dass du eine ca. 4s Pause 
nach Power On Reset einhalten solltest?

Hast du probiert, die vom I2C zurückgelesenen Werte direkt nach "data = 
Wire.read()" auszugeben, um Fehler im Programm auszuschließen?

Was soll die folgende Zeile erreichen? "if ((ptr[j] >> 8) != (buf[j] >> 
8))" Wieso schreibst du nicht pauschal alle Werte?

Hast du im Datenblatt gesehen, dass das LSB der Deviceadresse angibt, ob 
die folgenden Daten geschrieben oder gelesen werden? (Siehe Bild) Ich 
kann in dem Programm nicht erkennen, dass du die Deviceadresse 
entsprechend ändern würdest.

Autor: Christoph M. (mchris)
Datum:

Bewertung
1 lesenswert
nicht lesenswert
>So, habe nun die HEX-Werte in DEZ-Werte umgewandelt und versucht, den
>EEPROM-Speicher abzuändern.

Versuche erst mal, nur die Ram-Registerwerte direkt am Anfang des 
Programms zu schreiben und zu lesen. Mehr brauchst Du nicht.

Autor: Christoph E. (stoppi)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo!

Vielen Dank für die Rückmeldung.

@Elias: Programm des MC habe ich leider nicht...
Ist das Ansprechen/Abändern von Speicherzuständen über I²C nicht 
softwareseitig standardisiert? Falls nein, und dieser MLX90640-sensor 
z.B. ein spezielles/das oben angehängte Ansprechen verlangt, wie müsste 
ich dann die Programmzeilen abändern?

@Christoph: RAM ist ja wieder ein ganz eigener Speicherbereich (0x0400 
bis 0x07FF). Was fange ich dann mit den Speicherwerten von Cornelius an?

Bin wie gesagt alles andere als der Fachmann auf diesen Gebiet...

: Bearbeitet durch User
Autor: Elias K. (elik)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Christoph E. schrieb:
> Ist das Ansprechen/Abändern von Speicherzuständen über I²C nicht
> softwareseitig standardisiert?

Habe nochmal kurz recherchiert. Wahrscheinlich kümmern sich die beiden 
Funktionen Wire.beginTransmission() und Wire.requestFrom() um das 
besagte Lesen-/Schreiben-Bit. Trotzdem schadet es sicher nicht, sich am 
Oszi anzuschauen, ob exakt die Daten übermittelt werden, die du 
erwartest.

RAM/ROM: Ich kann nicht ohne weiteres im Datenblatt finden, welche 
Speicherbereiche du überhaupt ändern kannst. Also nimm etwas, was du 
sicher ändern darfst. Zum Beispiel das Datenwort bei Adresse 0x800D, Bit 
7, 8 und 9. Am Anfang reicht es auch, wenn du nur ein Bit ändern kannst. 
Das eliminiert viele versteckte Fehlerquellen in Schleifen, Pointern, 
... Wenn dir das gelingt, dann kannst du weiterschauen.

Autor: Christoph M. (mchris)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
>@Christoph: RAM ist ja wieder ein ganz eigener Speicherbereich (0x0400
>bis 0x07FF). Was fange ich dann mit den Speicherwerten von Cornelius an?

Die Konfigurationsregister liegen ab 0x8000.
Schau Dir im Datenblatt deren Bedeutung an, und versuche sie zu 
verstehen.

Autor: Christoph E. (stoppi)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
So, habe das Datenblatt studiert aber es ergeben sich viele Fragen für 
mich. Diese habe ich versucht in den angehängten Abbildungen klar zu 
machen...

Autor: Thomas Malwinter (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hier wollte ich ursprünglich posten:

Hier gibt es auch ein Problem mit dem Auslesen:

Beitrag "Wer nutzt das Nucleo-64 und kann mir"

Allerding liegt das wohl an einer I2C-Lib. Der wo helfen könnte, wollte
anscheinend nicht...

Autor: Christoph E. (stoppi)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
Hallo!

Danke Thomas für den link...

Habe nun diese Zeilen zum Abändern des EEPROMS unter Verwendung der 
melexis-library geschrieben:

const uint16_t len = 16;
uint16_t adr = 0x8000;
uint16_t Buffer[len];

#include <Wire.h>
#include "MLX90640_API.h"
#include "MLX90640_I2C_Driver.h"


void setup() {
  // put your setup code here, to run once:
    Wire.begin();
    Wire.setClock(400000); //Increase I2C clock speed to 400kHz
   
    Serial.begin(9600);
   
   
    MLX90640_I2CRead(0x33, adr, len, Buffer);
    for (int n = 0; n < len; n++)
    {
      Serial.print(n); Serial.print(": "); Serial.println(Buffer[n], HEX);
    }

    MLX90640_I2CWrite(0x33, 0x800D, 6401);    // HEX 1901
    //MLX90640_I2CWrite(0x33, 0x800D, 6657);    // HEX 1A01
   
    delay(4000);

    MLX90640_I2CRead(0x33, adr, len, Buffer);
    for (int n = 0; n < len; n++)
    {
      Serial.print(n); Serial.print(": "); Serial.println(Buffer[n], HEX);
    }
   
}

void loop() {
  // put your main code here, to run repeatedly:

}



Damit kann ich z.B. den Speicherwert 1A01 (HEX) an der Stelle 0x800D in 
1901 (HEX) umwandeln und wieder retour.

Mit anderen Stellen, z.B. 0x8000, funktioniert das nicht. Die sind ja 
auch scheinbar für Melexis reserviert...

Warum muss/kann ich aber die Stelle 0x800D direkt mittels 
MLX90640_I2CWrite(0x33, 0x800D, 6401);  ansprechen und verändern? Die 
Speicheradresse 0x800D ist ja mit 0x240C verknüpft und nur diese lässt 
sich doch verändern und dann auf 0x800D übertragen?

Was ist mit den anderen Speicherwerten von Cornelius ab 0x8000? Die kann 
ich wohl nicht ändern oder?

Die Veränderung in 1901 der Stelle 0x800D hat übrigens leider keine 
Auswirkungen auf das Auslesen der Temperaturen. Erhalte nach wie vor 
"nan"

Danke im voraus für eure Hilfe...

: Bearbeitet durch User
Autor: Christoph E. (stoppi)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
Es gibt Neuigkeiten: Heute ist ein ESP32 angekommen und ich habe 
natürlich sofort den Arduino-Code ausprobiert und....

... heureka, der Sensor lebt noch und übermittelt passende Temperaturen. 
Damit dies so ist, muss jedoch in der Datei MLX90640_I2C_Driver.cpp zu 
Beginn die Zeile #include <Arduino.h> hinzugefügt werden.

Von den 768 Pixel scheint nur ein einziges defekt zu sein, da es die 
Temperatur "nan" liefert. Da übernehme ich nach Abfrage aber den 
Temperaturwert des Nachbarn.

Jetzt warte ich noch auf das ILI9341 320x240 display, dann biegt dieses 
Projekt in die Zielgerade ein.

Autor: Marc (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
>Es gibt Neuigkeiten: Heute ist ein ESP32 angekommen und ich habe
>natürlich sofort den Arduino-Code ausprobiert und....

Welchen? Den gleichen wie auf dem Due?
Falls nicht, musst Du einfach nur die Stelle im Code finden, in der das 
Register richtig beschrieben wird und in den Due-Code kopieren ....

Autor: Christoph E. (stoppi)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Nein, ist derselbe Code wie jener, der eben mit dem Arduino Due nicht 
funktioniert hat...

Autor: Marc (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
>Nein, ist derselbe Code wie jener, der eben mit dem Arduino Due nicht
>funktioniert hat...

Erstaunlich ... an was könnte es liegen: timing, I2C Widerstände?

Autor: Christoph E. (stoppi)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
So, habe nun auch die Software auf die geringere Auflösung von 320x240 
Pixel abgeändert...

Autor: Christoph E. (stoppi)
Datum:
Angehängte Dateien:

Bewertung
1 lesenswert
nicht lesenswert
Heute ist das ILI9341 display angekommen und ich habe die 
Wärmebildkamera fertig stellen können. Anbei noch die Verkabelung, die 
display-pins, einige Testbilder, der code und das youtube-video:

Youtube-Video "DIY infrared thermal imaging camera with MLX90640 and ESP32 - Wärmebildkamera mit MLX90640"
#include <Wire.h>
#include "MLX90640_API.h"
#include "MLX90640_I2C_Driver.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");

    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);    // Schreibt den Wert 1901 (HEX) = 6401 (DEC) ins Register an die Stelle 0x800D, damit der Sensor ausgelesen werden kann!!!
                                              // =======================================================================================================================

    //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+ = ");    


    // Zeichnen der seitlichen Farbskala
    // =================================
 
    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));
       } 

   } 



// *******************************************
// ************** HAUPTSCHLEIFE **************
// *******************************************

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 of T_min and T_max and find out error pixel
    // =====================================================

    mlx90640To[1*32 + 21] = 0.5 * (mlx90640To[1*32 + 20] + mlx90640To[1*32 + 22]);    // elininate the error-pixels
    mlx90640To[4*32 + 30] = 0.5 * (mlx90640To[4*32 + 29] + mlx90640To[4*32 + 31]);    // elininate 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)
           {
            mlx90640To[i] = mlx90640To[i-1];
           }
        else
           {
            mlx90640To[i] = mlx90640To[i+1];
           }
       }


    // determine of 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.fillRect(260, 25, 47, 10, tft.color565(0, 0, 0));
    tft.fillRect(260, 205, 47, 10, tft.color565(0, 0, 0));    
    tft.fillRect(115, 220, 47, 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(310, 25);
    tft.print("C");
    tft.setCursor(310, 205);
    tft.print("C");
    tft.setCursor(165, 220);
    tft.print("C");

    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));
 
    delay(20);
   }
   


// =========================
// ===== Farbbestimmung ====
// =========================

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

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.