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 (https://www.ebay.com/itm/3-5inch-TFT-LCD-Color-Display-Module-320x480-Support-for-Ar-Mega2560-16-Bit/163228939051?epid=20023227698&hash=item260133f32b:g:2xgAAOSwvoNbh4~D:rk:19:pf:0). 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
Habe den Farbverlauf nochmals geändert, passt jetzt besser (Farben werden aber durch die Kamera nach wie vor nicht 1:1 wiedergegeben...)
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:
1 | // create palette |
2 | ColorPalette cpRainbow; |
3 | cpRainbow.addItem( 0.0f, 0, 0, 255); // 0 % blue |
4 | cpRainbow.addItem( 33.0f, 0, 255, 0); // 33 % green |
5 | cpRainbow.addItem( 66.0f, 255, 255, 0); // 66 % yellow |
6 | cpRainbow.addItem( 100.0f, 255, 0, 0); // 100 % red |
7 | |
8 | cpRainbow.setMinMax(20.0f, 35.0f); |
9 | |
10 | // create palette |
11 | ColorPalette cpBlueRed; |
12 | cpBlueRed.addItem( 0.0f, 0, 0, 255); // 0 % blue |
13 | cpBlueRed.addItem( 50.0f, 255, 255, 255); // 50 % white |
14 | cpBlueRed.addItem( 100.0f, 255, 0, 0); // 100 % red |
15 | |
16 | cpBlueRed.setMinMax(20.0f, 35.0f); |
17 | |
18 | // get color from palette |
19 | uint16_t color = cpBlueRed.getColor(temperature); |
Danke für den Beitrag... Das Wärmebild besteht noch aus reinen Zufallstemperaturen [random(180)], da ich ja den Sensor noch nicht habe.
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.
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
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...
1 | //GY_mlx90640 ARDUINO |
2 | |
3 | // GY_mlx90640 arduino pro mini |
4 | /* |
5 | 1.GY_mlx90640_uart arduino |
6 | 2.GY_mlx90640 VCC GND |
7 | 3.arduino_TX---GY_mlx90640_RX Rest arduino |
8 | 4.arduino__RX---GY_mlx90640_TX |
9 | 5.GYSerial,baud=9600 |
10 | 6.arduino_pin_11---FT232_RX |
11 | 7.arduino_pin_10---FT232_TX |
12 | 8.PCSerial ,baud=115200 |
13 | */ |
14 | |
15 | //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! |
16 | // Ändere hier, welcher Hardware Serial für was verwendet wird. |
17 | #define PCSerial Serial2 |
18 | #define GYSerial Serial1 |
19 | |
20 | uint16_t temp1=0; |
21 | int16_t temp2=0; |
22 | |
23 | uint8_t Re_buf[10]; |
24 | uint16_t re_count=0,rest_count=0; |
25 | uint16_t counter=0; |
26 | |
27 | unsigned char sign=0; |
28 | int led = 13; |
29 | float myMap(float x, float in_min, float in_max, float out_min, float out_max); |
30 | float max_temp=0; |
31 | float min_temp=500; |
32 | |
33 | |
34 | //----------------------------------------------------------- |
35 | void setup() |
36 | { |
37 | GYSerial.begin(9600); |
38 | PCSerial.begin(115200); |
39 | |
40 | delay(1000); |
41 | } |
42 | |
43 | |
44 | //------------------------------------------------------------- |
45 | void loop() |
46 | { |
47 | if (GYSerial.available()>0) |
48 | { |
49 | Re_buf[counter]=(unsigned char)GYSerial.read(); |
50 | |
51 | if(counter==0&&Re_buf[0]!=0x5A) return; |
52 | else if(counter==1&&Re_buf[1]!=0x5A) |
53 | { |
54 | counter=0; |
55 | return; |
56 | }; |
57 | |
58 | if(counter<6) |
59 | counter++; |
60 | if(counter==4) |
61 | { |
62 | if(Re_buf[2]==0x02&&Re_buf[3]==0x06) |
63 | sign=1; |
64 | else |
65 | counter=0; |
66 | } |
67 | if(counter>5) |
68 | { |
69 | float temp=(float)(Re_buf[4]+Re_buf[5]*256)/100; |
70 | |
71 | if(temp>max_temp) |
72 | max_temp=temp; |
73 | |
74 | if(temp<min_temp) |
75 | min_temp=temp; |
76 | |
77 | counter=4; |
78 | re_count++; |
79 | |
80 | if(rest_count>20) |
81 | { |
82 | min_temp=500; |
83 | max_temp=0; |
84 | rest_count=0; |
85 | } |
86 | |
87 | //PCSerial.print(temp); |
88 | // PCSerial.print(","); |
89 | |
90 | float inv= myMap(temp,min_temp,max_temp,0.5,1); |
91 | |
92 | if(inv>0.75) |
93 | PCSerial.print("**"); |
94 | else |
95 | PCSerial.print("--"); |
96 | |
97 | if((re_count%32)==0) |
98 | PCSerial.println(); |
99 | |
100 | if(re_count%768==0) |
101 | PCSerial.print("TA:"); |
102 | |
103 | if(re_count==769) |
104 | { |
105 | rest_count++; |
106 | counter=0; |
107 | PCSerial.print(temp); |
108 | PCSerial.println(); |
109 | re_count=0; |
110 | } |
111 | } |
112 | } |
113 | } |
114 | |
115 | |
116 | //--------------------------------------------------------------- |
117 | float myMap(float x, float in_min, float in_max, float out_min, float out_max) |
118 | { |
119 | return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min; |
120 | } |
:
Bearbeitet durch User
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.
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
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
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...
1 | //GY_mlx90640 ARDUINO |
2 | |
3 | // GY_mlx90640 arduino pro mini |
4 | /* |
5 | 1.GY_mlx90640_uart arduino |
6 | 2.GY_mlx90640 VCC GND |
7 | 3.arduino_TX---GY_mlx90640_RX Rest arduino |
8 | 4.arduino__RX---GY_mlx90640_TX |
9 | 5.GYSerial,baud=9600 |
10 | 6.arduino_pin_11---FT232_RX |
11 | 7.arduino_pin_10---FT232_TX |
12 | 8.PCSerial ,baud=115200 |
13 | */ |
14 | |
15 | #define PCSerial Serial |
16 | #define GYSerial Serial1 |
17 | |
18 | uint8_t Re_buf[10]; |
19 | uint16_t re_count = 0; |
20 | uint16_t counter = 0; |
21 | |
22 | unsigned char sign = 0; |
23 | int led = 13; |
24 | |
25 | |
26 | //----------------------------------------------------------- |
27 | void setup() |
28 | { |
29 | GYSerial.begin(115200); |
30 | PCSerial.begin(115200); |
31 | |
32 | delay(1000); |
33 | } |
34 | |
35 | |
36 | //------------------------------------------------------------- |
37 | void loop() |
38 | { |
39 | if (GYSerial.available() > 0) |
40 | { |
41 | Re_buf[counter]=(unsigned char)GYSerial.read(); |
42 | |
43 | if(counter == 0 && Re_buf[0] != 0x5A) return; |
44 | else if(counter == 1 && Re_buf[1]!= 0x5A) |
45 | { |
46 | counter = 0; |
47 | return; |
48 | }; |
49 | |
50 | if(counter < 6) |
51 | counter++; |
52 | |
53 | if(counter == 4) |
54 | { |
55 | if(Re_buf[2] == 0x02 && Re_buf[3] == 0x06) |
56 | sign = 1; |
57 | else |
58 | counter = 0; |
59 | } |
60 | |
61 | if(counter > 5) |
62 | { |
63 | float temp = (float)(Re_buf[4] + Re_buf[5] * 256) / 100; |
64 | |
65 | counter = 4; |
66 | |
67 | re_count++; |
68 | |
69 | PCSerial.print(temp); |
70 | PCSerial.print(","); |
71 | |
72 | if((re_count%32) == 0) |
73 | PCSerial.println(); |
74 | |
75 | if(re_count == 769) |
76 | { |
77 | counter = 0; |
78 | PCSerial.println(); |
79 | re_count=0; |
80 | } |
81 | } |
82 | } |
83 | } |
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.
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
Würde es ggf. Sinn machen die baudrate z.B. auf 9600 zu senken um mehr Genauigkeit beim Einlesen der Temperaturen zu bekommen?
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
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.
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?
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...
>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.
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
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 :-)
>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.
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?
1 | #include <Wire.h> |
2 | #define I2C_EEPROM_ADRESSE 0x33 |
3 | #define EEPROM_SPEICHER_ADR 0x8000 |
4 | |
5 | const uint16_t Anzahl_Rezepte = 16; // anzahl Rezepte |
6 | uint16_t Zaehler[Anzahl_Rezepte] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; |
7 | bool oneshot = true; |
8 | |
9 | void setup() |
10 | { |
11 | Wire.begin(); |
12 | Serial.begin(9600); |
13 | Serial.println("Programmanfang"); |
14 | Serial.print("Zaehlerfeld vor dem Lesen: \t"); |
15 | |
16 | for (uint16_t j = 0; j < (sizeof(Zaehler) / sizeof(Zaehler[0])); j++) |
17 | { |
18 | Serial.print(Zaehler[j]); |
19 | Serial.print(" "); |
20 | } |
21 | |
22 | Serial.println(); |
23 | |
24 | bool zaehlerzuruecksetzen = false; // auf true zum Loeschen, auch zur Speicherinitialisierung auf 0 |
25 | |
26 | if (zaehlerzuruecksetzen) |
27 | { |
28 | i2c_eeprom_updateUIntArray(I2C_EEPROM_ADRESSE, EEPROM_SPEICHER_ADR, Zaehler, sizeof(Zaehler) / sizeof(Zaehler[0])); // Zaehler zuruecksetzen |
29 | } |
30 | else |
31 | { |
32 | i2c_eeprom_readUIntArray(I2C_EEPROM_ADRESSE, EEPROM_SPEICHER_ADR, Zaehler, sizeof(Zaehler) / sizeof(Zaehler[0])); |
33 | } |
34 | |
35 | Serial.print("Zaehlerfeld nach dem Lesen: \t"); |
36 | |
37 | for (uint16_t j = 0; j < (sizeof(Zaehler) / sizeof(Zaehler[0])); j++) |
38 | { |
39 | Serial.print(Zaehler[j]); |
40 | Serial.print(" "); |
41 | } |
42 | |
43 | Serial.println(); |
44 | } |
45 | |
46 | void loop() |
47 | { |
48 | if (oneshot) |
49 | { |
50 | Zaehler[0] = 9; |
51 | Zaehler[1] = AB; |
52 | Zaehler[2] = 499B; |
53 | Zaehler[3] = 0; |
54 | Zaehler[4] = 2061; |
55 | Zaehler[5] = 5; |
56 | Zaehler[6] = 320; |
57 | Zaehler[7] = 3E0; |
58 | Zaehler[8] = 1A26; |
59 | Zaehler[9] = A228; |
60 | Zaehler[10] = 185; |
61 | Zaehler[11] = 499; |
62 | Zaehler[12] = 0; |
63 | Zaehler[13] = 1901; |
64 | Zaehler[14] = 0; |
65 | Zaehler[15] = 0; |
66 | |
67 | i2c_eeprom_updateUIntArray(I2C_EEPROM_ADRESSE, EEPROM_SPEICHER_ADR, Zaehler, sizeof(Zaehler) / sizeof(Zaehler[0])); |
68 | |
69 | Serial.print("Zaehlerfeld nach dem Schreiben: \t"); |
70 | |
71 | for (uint16_t j = 0; j < (sizeof(Zaehler) / sizeof(Zaehler[0])); j++) |
72 | { |
73 | Serial.print(Zaehler[j]); |
74 | Serial.print(" "); |
75 | } |
76 | |
77 | Serial.println(); |
78 | |
79 | oneshot = false; |
80 | } |
81 | } |
82 | |
83 | |
84 | |
85 | void i2c_eeprom_updateUIntArray(int16_t deviceaddress, uint16_t eeaddress, uint16_t *ptr, uint16_t anzahlElemente) |
86 | { |
87 | uint16_t buf[anzahlElemente]; |
88 | i2c_eeprom_readUIntArray(deviceaddress, eeaddress, buf, sizeof(buf) / sizeof(buf[0])); |
89 | uint16_t eadr=eeaddress; |
90 | |
91 | for (uint16_t j = 0; j < anzahlElemente; j++) |
92 | { |
93 | if ((ptr[j] >> 8) != (buf[j] >> 8)) |
94 | { |
95 | Wire.beginTransmission(deviceaddress); |
96 | Wire.write((int)(eadr >> 8)); // MSB |
97 | Wire.write((int)(eadr & 0xFF)); // LSB |
98 | Wire.write(ptr[j] >> 8); |
99 | Wire.endTransmission(); |
100 | delay(10); |
101 | } |
102 | |
103 | eadr++; |
104 | |
105 | if ((ptr[j] & 0xFF) != (buf[j] & 0xFF)) |
106 | { |
107 | Wire.beginTransmission(deviceaddress); |
108 | Wire.write((int)(eadr >> 8)); // MSB |
109 | Wire.write((int)(eadr & 0xFF)); // LSB |
110 | Wire.write(ptr[j] & 0xFF); |
111 | Wire.endTransmission(); |
112 | delay(10); |
113 | } |
114 | eadr++; |
115 | } |
116 | } |
117 | |
118 | |
119 | |
120 | void i2c_eeprom_readUIntArray(int16_t deviceaddress, uint16_t eeaddress, uint16_t *ptr, uint16_t anzahlElemente) |
121 | { |
122 | uint16_t data = 0xFF; |
123 | delay(2); |
124 | |
125 | Wire.beginTransmission(deviceaddress); |
126 | Wire.write((int)(eeaddress >> 8)); // MSB |
127 | Wire.write((int)(eeaddress & 0xFF)); // LSB |
128 | Wire.endTransmission(); |
129 | Wire.requestFrom(deviceaddress, anzahlElemente << 1); |
130 | |
131 | for (uint16_t j = 0; j < anzahlElemente; j++) |
132 | { |
133 | delay(5); |
134 | data = Wire.read() << 8; |
135 | delay(5); |
136 | data = data | Wire.read(); |
137 | ptr[j] = data; |
138 | } |
139 | } |
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.
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...
1 | #include <Wire.h> |
2 | #define I2C_EEPROM_ADRESSE 0x33 |
3 | #define EEPROM_SPEICHER_ADR 0x8000 |
4 | |
5 | const uint16_t Anzahl_Rezepte = 16; // anzahl Rezepte |
6 | uint16_t Zaehler[Anzahl_Rezepte] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; |
7 | bool oneshot = true; |
8 | |
9 | void setup() |
10 | { |
11 | Wire.begin(); |
12 | Serial.begin(9600); |
13 | Serial.println("Programmanfang"); |
14 | |
15 | i2c_eeprom_readUIntArray(I2C_EEPROM_ADRESSE, EEPROM_SPEICHER_ADR, Zaehler, sizeof(Zaehler) / sizeof(Zaehler[0])); |
16 | |
17 | Serial.print("Zaehlerfeld vor dem Schreiben: \t"); |
18 | |
19 | for (uint16_t j = 0; j < (sizeof(Zaehler) / sizeof(Zaehler[0])); j++) |
20 | { |
21 | Serial.print(Zaehler[j]); |
22 | Serial.print(" "); |
23 | } |
24 | |
25 | Serial.println(); |
26 | } |
27 | |
28 | void loop() |
29 | { |
30 | //oneshot = false; |
31 | |
32 | if (oneshot) |
33 | { |
34 | Zaehler[0] = 9; |
35 | Zaehler[1] = 171; // = HEX AB |
36 | Zaehler[2] = 18843; // = HEX 499B |
37 | Zaehler[3] = 0; |
38 | Zaehler[4] = 8289; // = HEX 2061 |
39 | Zaehler[5] = 5; |
40 | Zaehler[6] = 800; // = HEX 320 |
41 | Zaehler[7] = 992; // = HEX 3E0 |
42 | Zaehler[8] = 6694; // = HEX 1A26 |
43 | Zaehler[9] = 41512; // = HEX A228 |
44 | Zaehler[10] = 389; // = HEX 185 |
45 | Zaehler[11] = 1177; // = HEX 499 |
46 | Zaehler[12] = 0; |
47 | Zaehler[13] = 6401; // = HEX 1901 |
48 | Zaehler[14] = 0; |
49 | Zaehler[15] = 0; |
50 | |
51 | Serial.print("neu zu schreibende Werte: \t"); |
52 | |
53 | for (uint16_t j = 0; j < (sizeof(Zaehler) / sizeof(Zaehler[0])); j++) |
54 | { |
55 | Serial.print(Zaehler[j]); |
56 | Serial.print(" "); |
57 | } |
58 | |
59 | i2c_eeprom_updateUIntArray(I2C_EEPROM_ADRESSE, EEPROM_SPEICHER_ADR, Zaehler, sizeof(Zaehler) / sizeof(Zaehler[0])); |
60 | |
61 | |
62 | i2c_eeprom_readUIntArray(I2C_EEPROM_ADRESSE, EEPROM_SPEICHER_ADR, Zaehler, sizeof(Zaehler) / sizeof(Zaehler[0])); |
63 | |
64 | Serial.println(); |
65 | Serial.print("Zaehlerfeld nach dem Schreiben: \t"); |
66 | |
67 | for (uint16_t j = 0; j < (sizeof(Zaehler) / sizeof(Zaehler[0])); j++) |
68 | { |
69 | Serial.print(Zaehler[j]); |
70 | Serial.print(" "); |
71 | } |
72 | |
73 | Serial.println(); |
74 | |
75 | oneshot = false; |
76 | } |
77 | } |
78 | |
79 | |
80 | |
81 | void i2c_eeprom_updateUIntArray(int16_t deviceaddress, uint16_t eeaddress, uint16_t *ptr, uint16_t anzahlElemente) |
82 | { |
83 | uint16_t buf[anzahlElemente]; |
84 | i2c_eeprom_readUIntArray(deviceaddress, eeaddress, buf, sizeof(buf) / sizeof(buf[0])); |
85 | uint16_t eadr=eeaddress; |
86 | |
87 | for (uint16_t j = 0; j < anzahlElemente; j++) |
88 | { |
89 | if ((ptr[j] >> 8) != (buf[j] >> 8)) |
90 | { |
91 | Wire.beginTransmission(deviceaddress); |
92 | Wire.write((int)(eadr >> 8)); // MSB |
93 | Wire.write((int)(eadr & 0xFF)); // LSB |
94 | Wire.write(ptr[j] >> 8); |
95 | Wire.endTransmission(); |
96 | delay(10); |
97 | } |
98 | |
99 | eadr++; |
100 | |
101 | if ((ptr[j] & 0xFF) != (buf[j] & 0xFF)) |
102 | { |
103 | Wire.beginTransmission(deviceaddress); |
104 | Wire.write((int)(eadr >> 8)); // MSB |
105 | Wire.write((int)(eadr & 0xFF)); // LSB |
106 | Wire.write(ptr[j] & 0xFF); |
107 | Wire.endTransmission(); |
108 | delay(10); |
109 | } |
110 | eadr++; |
111 | } |
112 | } |
113 | |
114 | |
115 | |
116 | void i2c_eeprom_readUIntArray(int16_t deviceaddress, uint16_t eeaddress, uint16_t *ptr, uint16_t anzahlElemente) |
117 | { |
118 | uint16_t data = 0xFF; |
119 | delay(2); |
120 | |
121 | Wire.beginTransmission(deviceaddress); |
122 | Wire.write((int)(eeaddress >> 8)); // MSB |
123 | Wire.write((int)(eeaddress & 0xFF)); // LSB |
124 | Wire.endTransmission(); |
125 | Wire.requestFrom(deviceaddress, anzahlElemente << 1); |
126 | |
127 | for (uint16_t j = 0; j < anzahlElemente; j++) |
128 | { |
129 | delay(5); |
130 | data = Wire.read() << 8; |
131 | delay(5); |
132 | data = data | Wire.read(); |
133 | ptr[j] = data; |
134 | } |
135 | } |
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.
>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.
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
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.
>@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.
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...
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...
Hallo! Danke Thomas für den link... Habe nun diese Zeilen zum Abändern des EEPROMS unter Verwendung der melexis-library geschrieben:
1 | const uint16_t len = 16; |
2 | uint16_t adr = 0x8000; |
3 | uint16_t Buffer[len]; |
4 | |
5 | #include <Wire.h> |
6 | #include "MLX90640_API.h" |
7 | #include "MLX90640_I2C_Driver.h" |
8 | |
9 | |
10 | void setup() { |
11 | // put your setup code here, to run once: |
12 | Wire.begin(); |
13 | Wire.setClock(400000); //Increase I2C clock speed to 400kHz |
14 | |
15 | Serial.begin(9600); |
16 | |
17 | |
18 | MLX90640_I2CRead(0x33, adr, len, Buffer); |
19 | for (int n = 0; n < len; n++) |
20 | { |
21 | Serial.print(n); Serial.print(": "); Serial.println(Buffer[n], HEX); |
22 | } |
23 | |
24 | MLX90640_I2CWrite(0x33, 0x800D, 6401); // HEX 1901 |
25 | //MLX90640_I2CWrite(0x33, 0x800D, 6657); // HEX 1A01 |
26 | |
27 | delay(4000); |
28 | |
29 | MLX90640_I2CRead(0x33, adr, len, Buffer); |
30 | for (int n = 0; n < len; n++) |
31 | { |
32 | Serial.print(n); Serial.print(": "); Serial.println(Buffer[n], HEX); |
33 | } |
34 | |
35 | } |
36 | |
37 | void loop() { |
38 | // put your main code here, to run repeatedly: |
39 | |
40 | } |
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
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.
>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 ....
Nein, ist derselbe Code wie jener, der eben mit dem Arduino Due nicht funktioniert hat...
>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?
So, habe nun auch die Software auf die geringere Auflösung von 320x240 Pixel abgeändert...
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: https://www.youtube.com/watch?v=k6qim96wB4k
1 | #include <Wire.h> |
2 | #include "MLX90640_API.h" |
3 | #include "MLX90640_I2C_Driver.h" |
4 | #include "SPI.h" |
5 | #include "Adafruit_GFX.h" |
6 | #include "Adafruit_ILI9341.h" |
7 | |
8 | // For the ESP-WROVER_KIT, these are the default. |
9 | #define TFT_CS 15 |
10 | #define TFT_DC 2 |
11 | #define TFT_MOSI 13 |
12 | #define TFT_CLK 14 |
13 | #define TFT_RST 26 |
14 | #define TFT_MISO 12 |
15 | #define TFT_LED 27 |
16 | |
17 | Adafruit_ILI9341 tft = Adafruit_ILI9341(TFT_CS, TFT_DC, TFT_MOSI, TFT_CLK, TFT_RST, TFT_MISO); |
18 | |
19 | const byte MLX90640_address = 0x33; //Default 7-bit unshifted address of the MLX90640 |
20 | |
21 | #define TA_SHIFT 8 //Default shift for MLX90640 in open air |
22 | |
23 | static float mlx90640To[768]; |
24 | paramsMLX90640 mlx90640; |
25 | |
26 | int xPos, yPos; // Abtastposition |
27 | int R_colour, G_colour, B_colour; // RGB-Farbwert |
28 | int i, j; // Zählvariable |
29 | float T_max, T_min; // maximale bzw. minimale gemessene Temperatur |
30 | float T_center; // Temperatur in der Bildschirmmitte |
31 | |
32 | |
33 | |
34 | |
35 | // *************************************** |
36 | // **************** SETUP **************** |
37 | // *************************************** |
38 | |
39 | void setup() |
40 | { |
41 | Serial.begin(115200); |
42 | |
43 | Wire.begin(); |
44 | Wire.setClock(400000); //Increase I2C clock speed to 400kHz |
45 | |
46 | while (!Serial); //Wait for user to open terminal |
47 | |
48 | Serial.println("MLX90640 IR Array Example"); |
49 | |
50 | if (isConnected() == false) |
51 | { |
52 | Serial.println("MLX90640 not detected at default I2C address. Please check wiring. Freezing."); |
53 | while (1); |
54 | } |
55 | |
56 | Serial.println("MLX90640 online!"); |
57 | |
58 | //Get device parameters - We only have to do this once |
59 | int status; |
60 | uint16_t eeMLX90640[832]; |
61 | |
62 | status = MLX90640_DumpEE(MLX90640_address, eeMLX90640); |
63 | |
64 | if (status != 0) |
65 | Serial.println("Failed to load system parameters"); |
66 | |
67 | status = MLX90640_ExtractParameters(eeMLX90640, &mlx90640); |
68 | |
69 | if (status != 0) |
70 | { |
71 | Serial.println("Parameter extraction failed"); |
72 | Serial.print(" status = "); |
73 | Serial.println(status); |
74 | } |
75 | |
76 | //Once params are extracted, we can release eeMLX90640 array |
77 | |
78 | MLX90640_I2CWrite(0x33, 0x800D, 6401); // Schreibt den Wert 1901 (HEX) = 6401 (DEC) ins Register an die Stelle 0x800D, damit der Sensor ausgelesen werden kann!!! |
79 | // ======================================================================================================================= |
80 | |
81 | //MLX90640_SetRefreshRate(MLX90640_address, 0x00); //Set rate to 0.25Hz effective - Works |
82 | //MLX90640_SetRefreshRate(MLX90640_address, 0x01); //Set rate to 0.5Hz effective - Works |
83 | //MLX90640_SetRefreshRate(MLX90640_address, 0x02); //Set rate to 1Hz effective - Works |
84 | //MLX90640_SetRefreshRate(MLX90640_address, 0x03); //Set rate to 2Hz effective - Works |
85 | MLX90640_SetRefreshRate(MLX90640_address, 0x04); //Set rate to 4Hz effective - Works |
86 | //MLX90640_SetRefreshRate(MLX90640_address, 0x05); //Set rate to 8Hz effective - Works at 800kHz |
87 | //MLX90640_SetRefreshRate(MLX90640_address, 0x06); //Set rate to 16Hz effective - Works at 800kHz |
88 | //MLX90640_SetRefreshRate(MLX90640_address, 0x07); //Set rate to 32Hz effective - fails |
89 | |
90 | |
91 | pinMode(TFT_LED, OUTPUT); |
92 | digitalWrite(TFT_LED, HIGH); |
93 | |
94 | tft.begin(); |
95 | |
96 | tft.setRotation(1); |
97 | |
98 | tft.fillScreen(ILI9341_BLACK); |
99 | tft.fillRect(0, 0, 319, 13, tft.color565(255, 0, 10)); |
100 | tft.setCursor(100, 3); |
101 | tft.setTextSize(1); |
102 | tft.setTextColor(ILI9341_YELLOW, tft.color565(255, 0, 10)); |
103 | tft.print("Thermographie - stoppi"); |
104 | |
105 | tft.drawLine(250, 210 - 0, 258, 210 - 0, tft.color565(255, 255, 255)); |
106 | tft.drawLine(250, 210 - 30, 258, 210 - 30, tft.color565(255, 255, 255)); |
107 | tft.drawLine(250, 210 - 60, 258, 210 - 60, tft.color565(255, 255, 255)); |
108 | tft.drawLine(250, 210 - 90, 258, 210 - 90, tft.color565(255, 255, 255)); |
109 | tft.drawLine(250, 210 - 120, 258, 210 - 120, tft.color565(255, 255, 255)); |
110 | tft.drawLine(250, 210 - 150, 258, 210 - 150, tft.color565(255, 255, 255)); |
111 | tft.drawLine(250, 210 - 180, 258, 210 - 180, tft.color565(255, 255, 255)); |
112 | |
113 | |
114 | tft.setCursor(80, 220); |
115 | tft.setTextColor(ILI9341_WHITE, tft.color565(0, 0, 0)); |
116 | tft.print("T+ = "); |
117 | |
118 | |
119 | // Zeichnen der seitlichen Farbskala |
120 | // ================================= |
121 | |
122 | for (i = 0; i < 181; i++) |
123 | { |
124 | //value = random(180); |
125 | |
126 | getColour(i); |
127 | tft.drawLine(240, 210 - i, 250, 210 - i, tft.color565(R_colour, G_colour, B_colour)); |
128 | } |
129 | |
130 | } |
131 | |
132 | |
133 | |
134 | // ******************************************* |
135 | // ************** HAUPTSCHLEIFE ************** |
136 | // ******************************************* |
137 | |
138 | void loop() |
139 | { |
140 | for (byte x = 0 ; x < 2 ; x++) //Read both subpages |
141 | { |
142 | uint16_t mlx90640Frame[834]; |
143 | int status = MLX90640_GetFrameData(MLX90640_address, mlx90640Frame); |
144 | |
145 | if (status < 0) |
146 | { |
147 | Serial.print("GetFrame Error: "); |
148 | Serial.println(status); |
149 | } |
150 | |
151 | float vdd = MLX90640_GetVdd(mlx90640Frame, &mlx90640); |
152 | float Ta = MLX90640_GetTa(mlx90640Frame, &mlx90640); |
153 | |
154 | float tr = Ta - TA_SHIFT; //Reflected temperature based on the sensor ambient temperature |
155 | float emissivity = 0.95; |
156 | |
157 | MLX90640_CalculateTo(mlx90640Frame, &mlx90640, emissivity, tr, mlx90640To); |
158 | } |
159 | |
160 | |
161 | // determine of T_min and T_max and find out error pixel |
162 | // ===================================================== |
163 | |
164 | mlx90640To[1*32 + 21] = 0.5 * (mlx90640To[1*32 + 20] + mlx90640To[1*32 + 22]); // elininate the error-pixels |
165 | mlx90640To[4*32 + 30] = 0.5 * (mlx90640To[4*32 + 29] + mlx90640To[4*32 + 31]); // elininate the error-pixels |
166 | |
167 | T_min = mlx90640To[0]; |
168 | T_max = mlx90640To[0]; |
169 | |
170 | for (i = 1; i < 768; i++) |
171 | { |
172 | if((mlx90640To[i] > -41) && (mlx90640To[i] < 301)) |
173 | { |
174 | if(mlx90640To[i] < T_min) |
175 | { |
176 | T_min = mlx90640To[i]; |
177 | } |
178 | |
179 | if(mlx90640To[i] > T_max) |
180 | { |
181 | T_max = mlx90640To[i]; |
182 | } |
183 | } |
184 | else if(i > 0) |
185 | { |
186 | mlx90640To[i] = mlx90640To[i-1]; |
187 | } |
188 | else |
189 | { |
190 | mlx90640To[i] = mlx90640To[i+1]; |
191 | } |
192 | } |
193 | |
194 | |
195 | // determine of T_center |
196 | // ===================== |
197 | |
198 | T_center = mlx90640To[11* 32 + 15]; |
199 | |
200 | |
201 | // drawing the picture |
202 | // =================== |
203 | |
204 | for (i = 0 ; i < 24 ; i++) |
205 | { |
206 | for (j = 0; j < 32; j++) |
207 | { |
208 | mlx90640To[i*32 + j] = 180.0 * (mlx90640To[i*32 + j] - T_min) / (T_max - T_min); |
209 | |
210 | getColour(mlx90640To[i*32 + j]); |
211 | |
212 | tft.fillRect(217 - j * 7, 35 + i * 7, 7, 7, tft.color565(R_colour, G_colour, B_colour)); |
213 | } |
214 | } |
215 | |
216 | tft.fillRect(260, 25, 47, 10, tft.color565(0, 0, 0)); |
217 | tft.fillRect(260, 205, 47, 10, tft.color565(0, 0, 0)); |
218 | tft.fillRect(115, 220, 47, 10, tft.color565(0, 0, 0)); |
219 | |
220 | tft.setTextColor(ILI9341_WHITE, tft.color565(0, 0, 0)); |
221 | tft.setCursor(265, 25); |
222 | tft.print(T_max, 1); |
223 | tft.setCursor(265, 205); |
224 | tft.print(T_min, 1); |
225 | tft.setCursor(120, 220); |
226 | tft.print(T_center, 1); |
227 | |
228 | tft.setCursor(310, 25); |
229 | tft.print("C"); |
230 | tft.setCursor(310, 205); |
231 | tft.print("C"); |
232 | tft.setCursor(165, 220); |
233 | tft.print("C"); |
234 | |
235 | 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)); |
236 | 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)); |
237 | |
238 | delay(20); |
239 | } |
240 | |
241 | |
242 | |
243 | // ========================= |
244 | // ===== Farbbestimmung ==== |
245 | // ========================= |
246 | |
247 | void getColour(int j) |
248 | { |
249 | if (j >= 0 && j < 30) |
250 | { |
251 | R_colour = 0; |
252 | G_colour = 0; |
253 | B_colour = 20 + (120.0/30.0) * j; |
254 | } |
255 | |
256 | if (j >= 30 && j < 60) |
257 | { |
258 | R_colour = (120.0 / 30) * (j - 30.0); |
259 | G_colour = 0; |
260 | B_colour = 140 - (60.0/30.0) * (j - 30.0); |
261 | } |
262 | |
263 | if (j >= 60 && j < 90) |
264 | { |
265 | R_colour = 120 + (135.0/30.0) * (j - 60.0); |
266 | G_colour = 0; |
267 | B_colour = 80 - (70.0/30.0) * (j - 60.0); |
268 | } |
269 | |
270 | if (j >= 90 && j < 120) |
271 | { |
272 | R_colour = 255; |
273 | G_colour = 0 + (60.0/30.0) * (j - 90.0); |
274 | B_colour = 10 - (10.0/30.0) * (j - 90.0); |
275 | } |
276 | |
277 | if (j >= 120 && j < 150) |
278 | { |
279 | R_colour = 255; |
280 | G_colour = 60 + (175.0/30.0) * (j - 120.0); |
281 | B_colour = 0; |
282 | } |
283 | |
284 | if (j >= 150 && j <= 180) |
285 | { |
286 | R_colour = 255; |
287 | G_colour = 235 + (20.0/30.0) * (j - 150.0); |
288 | B_colour = 0 + 255.0/30.0 * (j - 150.0); |
289 | } |
290 | |
291 | } |
292 | |
293 | |
294 | //Returns true if the MLX90640 is detected on the I2C bus |
295 | boolean isConnected() |
296 | { |
297 | Wire.beginTransmission((uint8_t)MLX90640_address); |
298 | |
299 | if (Wire.endTransmission() != 0) |
300 | return (false); //Sensor did not ACK |
301 | |
302 | return (true); |
303 | } |
Mit dem eingetroffenen Batteriehalter konnte ich heute meine Wärmebildkamera finalisieren. Ich betreibe die Kamera mit nur einem 18650-Akku und nachfolgendem step-up-Wandler (auf 5V), da sonst der 3.3V-Spannungsregler auf dem ESP32 zu warm wird. Hier https://as-electronic.net/epages/f5f396c6-206d-4fb6-8b4c-7e9832c1a74f.sf/de_DE/?ObjectPath=/Shops/f5f396c6-206d-4fb6-8b4c-7e9832c1a74f/Products/MLX90640ESF-BAB-000 ist der MLX9640-Sensor aus Deutschland für rund 40 Euro zu beziehen. Damit ist es möglich, die Kamera um nur ca. 54 Euro nachzubauen...
Ich weiß der Thread ist älter, habe jedoch eine kurze Frage zu den MLX Sensoren. Muss man Pullup Widerstände auf die SDA- und SCL-Leitungen hinzufügen wenn man den Sensor ohne fertiges Breakout-Board kauft? Sprich, den Sensor wie im letzten Kauflink von as-electronic. Du hast ja von Aliexpress das blaue Breakout-Board benutzt (ich vermute, dass da nämlich Pullups drauf sind). LG
Hallo! Ja, sind auf beiden Leitungen pullups (2.2 kOhm), siehe Bild
vielen Dank für den tollen Thread - das ist wirklich außerordentlich interessant. Bin begeistert über diese tolle IDEE. Ihr seid Super Vg
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.