Experimente mit dem SI1145 UV-Index / IR / sichtbares Licht-Sensor

Heute geht es wieder um das Thema Licht.

Das hatten wir schon einmal, zum Beispiel im Artikel Fotowiderstand mit Arduino auslesen und über serielle Schnittstelle darstellen. Da ging es um einen billigen, einfachen Fotowiderstand als Lichtsensor, der auf ein breites Licht-Spektrum reagiert und uns einen ungefähren Wert über den analogen Eingang eines Arduinos geben kann.

Das ist praktisch, wenn man es günstig möchte und es nicht so genau braucht, zum Beispiel, um zu sehen, wie hell das Umgebungslicht so in etwa ist, um damit eine Anzeige zu dimmen, damit diese unter allen Lichtverhältnissen gut ablesbar bleibt.

Doch so ein Fotowiderstand ist ein träger Geselle. Das habe ich in meinem Experimente Datenübertragung per Laser zwischen zwei Arduinos festgestellt.

Braucht man es schneller, empfehlen sich Fotodioden, wie ich sie im Artikel Optimierung der Datenübertragung per Laser zwischen zwei Arduinos vorgestellt, erklärt und benutzt habe. Dabei kam eine SFH-203-Fotodiode von Osram zum Einsatz, die speziell für Anwendungen im Bereich von 400 nm bis 1100 nm geeignet ist.

Doch was bedeutet dieses "400 nm bis 1100 nm" in der Spezifikation der Fotodiode eigentlich?

Und dann wäre ja auch noch mein Projekt Annäherungs-, Gesten- und Farberkennung mit dem ADPS-9960 Sensor, mit dem man sogar Farben und Bewegungen erkennen kann.

Licht ist nicht gleich Licht

Auf die Dualität des Lichtes will ich gar nicht weiter eingehen. Den Ausflug in die Quantenphysik kann jeder starten, in dem er auf den Wikipedia-Link klickt und sich einliest. Warnung: "Einnerden" in die Quantenmechanik kann zum Umsturz von bisherigen Weltanschauungen führen ;)

Aber mit den unterschiedlichen Wellenlängen des Lichts im elektromagnetischen Spektrum wollen wir uns kurz befassen, denn bei dem Sensor, mit dem wir uns heute beschäftigen geht es um die er messen kann, oder vielleicht auch nicht messen kann - das wird sich noch herausstellen.

Schauen wir uns einmal die folgende Grafik an (Klicken zum Vergrößern):



Das vom Menschen sichtbare Spektrum sind die Wellenlängen von 380 Nanometer bis 690 nm.

Dabei liegen die Farben auf folgenden Wellenlängen: IR fern: 50 µm ... 1 mm Wärmestrahlung IR mittel: 3 µm ... 50 µm CO2-Laser IR nah: 690 nm ... 3 µm IR-LED, IR-Laser rot: 640 nm ... 690 nm sichtbares Licht orange: 600 nm ... 640 nm sichtbares Licht gelb: 570 nm ... 600 nm sichtbares Licht grün: 490 nm ... 570 nm sichtbares Licht blau: 430 nm ... 490 nm sichtbares Licht violett: 380 nm ... 430 nm sichtbares Licht UV-A nah: 315 nm ... 380 nm UV-LED/Laser, Schwarzlicht UV-B mittel: 280 nm ... 315 nm UV-LED/Laser, "Dorno"-Strahlung UV-C fern: 200 nm ... 280 nm UV-LED/Laser UV-C Vakuum: 100 nm ... 200 nm XUV-Röhre, Synchrotron EUV: 10 nm ... 121 nm XUV-Röhre, Synchrotron Röntgen: 10 pm ... 10 nm Röntgenröhre, Synchrotron Gamma: > 0 pm ... 10 pm Radioaktivität Unsere Fotodiode von oben mit "400 nm bis 1100 nm" reagiert also empfindlich auf das gesamte sichtbare Licht ab violett, aber auch auf IR-Strahlung, wie sie von Infrarot-LEDs abgestrahlt wird.

"nm" bei der Wellenlänge bedeutet übrigens Nanometer, also Millardstel Meter (Millionstel Millimeter), die zwei Wellenberge voneinander entfernt sind. Das kann man auch unter Zuhilfenahme der Lichtgeschwindigkeit von ca. 300 Millionen m/s in eine Frequenz umrechnen.

Ein grün mit 530 nm Wellenlänge ergibt eine Frequenz von 299792458 / (530/1000000000), also 565.65 THz. Ein TeraHertz sind eine Billion Hertz. Ein Hertz ist eine Schwingung pro Sekunde.

Schädliche Strahlung

Je höher die Frequenz (je geringer die Wellenlänge) ist, desto energiereicher ist normalerweise die Strahlung. Das bringt einher, dass sie Schaden anrichten kann. Die Schädlichkeit für Augen und Haut geht bei UV-A los und steigert sich mit steigender Frequenz.

Energiereiche radioaktive Gammastrahlung zum Beispiel kann auch schon sehr gesundheitsschädlich sein, auch wenn man ihr nur kurz ausgesetzt ist. Alpha-Strahlung strahlt nicht so weit, schädigt auf kurze Entfernungen aber mehr. Beta-Strahlung liegt in der Mitte und reicht weiter, Gamma-Strahlung durchdringt Materie leichter, reicht noch weiter und ist weniger schädlich wie Alpha-Strahlung. Aber das ist ein anderes Thema.

Zum Glück blockt die Erdatmosphäre UV-C und Gammastrahlen aus dem Weltraum ab. Auf der Erdoberfläche ist man vor dieser natürlichen Strahlung deshalb relativ sicher. Je höher man sich aber begibt, desto dünner wird die schützende Atmosphäre und desto höher wird die Strahlendosis, die man abbekommt. Das kann schon bei regelmäßigen Flügen in hoher Höhe, wie sie Verkehrsmaschinen absolvieren, ins Gewicht fallen. Und Astronauten sind ungeschützt eine hohen Strahlenbelastung ausgesetzt. Wir wollen heute aber mal auf dem Boden, sprich der Erdoberfläche, bleiben.

Radioaktive Strahlung, aber auch schon UV-Strahlung kann menschliche Zellen schädigen, so dass diese ihre Aufgaben nicht mehr richtig wahrnehmen können oder mutieren. Alles ab UV-A kann also krebserregend sein. Je energiereicher (höhere Frequenz) die Strahlung, desto schlimmer. UV-A ist dabei nicht so super gefährlich, aber man sollte sich ihr trotzdem nicht länger ungeschützt aussetzen. Und UV-B ist schon etwas gefährlicher.

Man sollte also nicht ungeschützt stundenlang sonnenbaden, sonst bekommt man schnell die Quittung in Form eines Sonnenbrandes, was eine Hautschädigung ist, die sogar permanente Folgen haben kann, wenn man es übertreibt. Man sollte Schutzmaßnahmen wie Sonnencreme, Sonnenbrille, lange Kleidung etc. benutzen, um dem vorzubeugen.

Im Haus wird die meiste UV-Strahlung übrigens abgeschirmt. Schon normale Fensterscheiben blocken die meiste UV-Strahlung. Vor dem geschlossenen Fenster läuft man also wesentlich weniger Gefahr, sich einen Sonnenbrand zu holen als vor einem offenem.

Der UV-Index

Damit man den Leuten mitteilen kann, wie hoch die UV-Strahlung der Sonne ist, die gerade im Sommer bei wolkenfreiem Himmel dank "Ozonloch" (eine Ausdünnung der schützenden Atmosphäre) gesundheitschädliche Ausmaße annehmen kann, hat man den UV-Index ersonnen. Diesen UV-Index kann man dann in Wettervorhersagen, etwa im Fernsehen, verbreiten und die Menschen können sich anhand des Wertes informieren, wie sie sich verhalten sollten, um gesund zu bleiben.

Der UVI-Wert (UV-Index-Wert) ist weltweit standardisiert und die Weltgesundheitsorganisation (WHO) empfiehlt folgende Schutzmaßnahmen:

UV-IndexBereichempfohlenene Schutzmaßnahme
0–2niedrigKein Schutz erforderlich.
3–5mäßigSchutz erforderlich: Hut, T-Shirt, Sonnenbrille, Sonnencreme.
6–7hochSchutz erforderlich: Hut, T-Shirt, Sonnenbrille, Sonnencreme. Mittags in den Schatten
8–10sehr hochzusätzlicher Schutz erforderlich: Aufenthalt im Freien möglichst vermeiden. Aufenthalt im Freien zwischen 11 und 15 Uhr vermeiden; auch im Schatten: sonnendichtes Oberteil, lange Hosen, Sonnencreme, Sonnenbrille und Sonnenhut.
>= 11extremzusätzlicher Schutz erforderlich: Aufenthalt im Freien möglichst vermeiden. Zwischen 11 und 15 Uhr im Haus bleiben und auch außerhalb dieser Zeit in den Schatten. Auch im Schatten ein sonnendichtes Oberteil, lange Hosen, Sonnencreme, Sonnenbrille und Sonnenhut tragen.

Ob die UV-Strahlung nun durch die Sonne oder durch eine UV-Taschenlampe oder Laser erzeugt wird, ist dabei egal. Die Schädlichkeit ist die selbe.

Darum bitte NIEMALS in UV-LEDs direkt hineinschauen und in UV-Laser oder Höhensonnen schon dreimal nicht! Auch wenn scheinbar nichts "herauskommt", NIEMALS direkt in die UV-LED / den UV-Laser schauen. Die schädlichen UV-Strahlen sind unsichtbar. Sichtbar ist nur ein meist mit abgestrahlter Violett oder Blau-Anteil, der macht aber nicht den Hauptteil der Strahlung und die Gefährlichkeit aus. Die Gefahr selbst ist nicht sichtbar! (Gilt übrigens auch für radioaktive und starke IR-Strahlung!)

Infrarot (IR)-Strahlung ist übrigens harmloser. In die unsichtbare Strahlung, die eine Infrarot-Fernbedienung abgibt, zu schauen, dürfte unbedenktlich sein. Wie immer macht auch hier die Dosis das Gift. In den IR-Laser eines DVD-Brenners oder einen 1000 Watt-Infrarot-Strahler zu schauen, ist sicher keine gute Idee.

Die Hardware: Der SI1145 Chip


So, genug der Theorie und der Warnungen. Jetzt wird die Hardware vorgestellt, eine Schaltung aufgebaut und dann reichlich experimentiert. Mit Video am Ende! Versprochen!

Das der SI1145 Chip von Silicon Labs aus Texas / USA mit sichtbarem Licht, Infrarot-Licht und mit ultraviolettem Licht umgehen kann, das hat ja bereits die Überschrift verraten. Doch wie genau macht der das?

"Sehr trickreich" ist die kurze Antwort. Die etwas längere ist für technisch interessierte durchaus spannend, denn eigentlich misst der SI1145 nur das Gesamtlicht und das Infrarotlicht und berechnet daraus den UV-Index anhand eines Algorithmus. Und das funktioniert erstaunlich gut.

Im Datenblatt des SI1145 ist angegeben, dass es zwei IR-Fotodioden und eine Fotodiode für sichtbares Licht gibt. Von einer UV-Fotodiode ist nicht die Rede. Dafür ist von einer Kalibrierung des UV-Index-Wertes die Rede und dass die dafür nötigen Werte im Chip gespeichert sind (abrufbar mit I2C-Cmd 0x18 Val 0x12 und geliefert dann in den Registern 0x22 bis 0x2d).


Rechts habe ich das Chip-Die des SI1145 einmal ganz nah heran geholt mit einem Mikroskop. Man erkennt eine großen, blau schimmernden horizontalen Streifen, von dem ich annehme, dass er das komplette Licht inklusive IR und UV-Licht misst. Nach zwei Dritteln gibt es eine feine vertikale Linie, die das Messfeld hier vielleicht in zwei Felder unterteilt, eines doppelt so groß wie das andere. Vielleicht verfügt eines über einen UV-Filter, so dass ein Teil alles Licht und der andere Teil das Licht minus UV-Strahlung misst.

Unten rechts erkennt man wieder einen horizontalen Streifen (mit kleineren vertikalen Streifen). Hier wird wohl, so meine Vermutung, das IR-Licht gemessen (es kann aber auch anders herum sein). Und das wieder zweimal. Das Messfeld unterteilt sich nämlich wieder in zwei Unterfelder, siehe kleine vertikale Lücke. Das rechte Messfeld ist doppelt so groß wie das linke.

So weiß der Chip wieviel Gesamtlicht (IR+Visible+UV) auftrifft, aber auch wieviel Licht ohne UV (IR+Visible) und wieviel IR-Licht (nur IR). Daraus könnte er errechnen, wie groß der UV-Licht ist.

Ob das genau so funktioniert, kann ich nur mutmaßen. Wichtig ist, dass es anscheinend recht gut funktioniert mit der UV-Index-Messung. Zwei Nachkommastellen lassen das zumindest vermuten. Wie gut das wirklich funktioniert, und durch was sich der Algorithmus vielleicht aus dem Tritt bringen lässt, das soll Teil unserer Experimente sein.

Der SI1145 möchte mit einer Spannung von 1.71 bis 3.6 Volt versorgt werden, absolutes Maximum sind 4 Volt. Er wird über das bekannte I2C-Protokoll angesprochen und liefert seine Messergebnisse digital.

Der Chip lässt sich auch als Annäherungssensor benutzen, wobei er einen Abstand von 1 bis 50 cm unterstützt. Dazu kann er bis zu drei Infrarot-LEDs ansteuern, die IR-Licht ausstrahlen, welches von nahen Objekten reflektiert und wieder vom Chip registriert wird.

Weitere Spezifikationen sind:

Das Modul GY-1145


Der nur 4.9 x 2.85 x 1.2 mm große 10-polige SI1145-Chip im QFN-Format ist natürlich nicht ganz so einfach zu handeln.

Für unsere Experimentier-Zwecke empfiehlt sich daher ein handlicheres Modul mit einem Pin-Abstand von 2.54 mm, an das wir Header anlöten können, um es in einem Breadboard zu betreiben.

Das liefert das Modul GY1145. Auf der Vorderseite sieht man unten rechts den SI1145-Chip und rechts daneben die Lötösen für eine Infrarot-LED für den Gebrauch als Proximity-Sensor. Den benötigen wir nicht und es ist gut, dass der Platz leer ist. So steht der SI1145 freier im Licht.

Links finden sich die Pins für den I2C-Bus (SCL für Clock und SDA für Data) und natürlich die Spannungsversorgung.


Die Rückseite des Moduls offenbart einen 662K-Spannungswandler, der auch aus angelegten 5 Volt passende 3.3 für den Chip macht. Das Modul kann also auch mit einem 5 Volt-Arduino betrieben werden. Libraries und Source-Code dürften dabei gleich bleiben. Falls ihr das Projekt also mit einem Arduino machen wollt: kein Problem.

Das GY1145-Board ist nur so groß, wie es sein muss und mit 13 x 10 x 5 mm wohl für alle Einsatzzwecke klein genug. Beim Einlöten der Header natürlich darauf achten, dass der kleine Chip nach oben zeigt, damit wir auch einfach damit Lichtmessungen durchführen können.

Der Aufbau auf dem Breadboard

Für den Versuchsaufbau nehme ich wieder mein Standard-Aufbau mit ESP8266 und OLED her, dem ich lediglich noch das GY1145-Modul hinzufügen muss:



Auf einem OLED-Display will ich die Messwerte gleichzeitig und nahe beiander anzeigen lassen, um einen direkten Vergleich zu erleichtern und vielleicht erkennen zu können, wie die Werte voneinander abhängen. Außerdem ist die Ausgabe auf ein Display auf dem Breadboard viel praktischer, weil es dann kein Serial Monitor mehr braucht, ich mir den Rechner sparen kann und nur noch eine kleine Powerbank brauche. Dann bin ich mit dem Versuchsaufbau mobil, wenn ich damit zum Beispiel die UV-Strahlung draußen messen will.

Beim Grundaufbau ist der ESP8266 auf dem Breadboard bereits über I2C mit dem SSD 1306-OLED verbunden. Für das sehr gebräuchliche SSD 1306-OLED gibt es für alle Plattformen Bibliotheken: Raspberry Pi, Arduino, STM32, ESP8266, ESP32. Die passende zu finden, sollte also kein Problem sein.

Das OLED benutzt wie gesagt I2C und ich habe es an die Pins D1 = SCL und D2 = SDA des ESP8266 angeschlossen. Da I2C ein Bus ist, an dem mehrere Geräte angeschlossen sein dürfen und man diese Geräte über deren I2C-Adresse anspricht, geht der I2C-Bus gleich weiter mit SDA und SCL an unser Lichtsensormodul GY-1145.

Als Spannungsversorgung für das GY-1145 reichen 3.3 Volt, die wir direkt dem ESP8266 entnehmen. So kann sich der winzige Spannungswandler auf dem Modul "ausruhen".

Die Software / Libraries / Firmware


Für das SSD 1306-OLED findet man "an jeder Ecke" eine passende Bibliothek.

Ich habe hier die SSD1306 Library von ThingPulse / Fabrice Weinberg hergenommen, weil ich bisher gute Erfahrungen damit gemacht habe und sie nicht so riesig ist. Ich habe aktuell Version 4.1.0 installiert, es gäbe aber eine neue Version 4.3.0, mit der es sicher auch funktioniert.

Für den GY1145-Sensor finde ich zwei Bibliotheken: einmal die Library von Adafruit und dann als zweites noch die Library von Wolles Elektronikkiste.

Die beiden will ich erst einmal ausprobieren, um zu schauen, was diese taugen und um ein Gefühl dafür zu bekommen, was der Sensor praktisch kann.

Wenn mir das dann nicht ausreicht, kann ich ja die Libs ja später erweitern oder was ganz neues schreiben, indem ich den Chip über die im Datasheet dokumentierten I2C Befehle anspreche.

Versuchen wir aber zuerst den bequemen Weg. Die Lib von adafruit hat nur einen kurzen Test-Sketch als Beispiel dabei, der folgendes über den Serial Monitor ausgibt:
=================== Vis: 262 IR: 260 UV: 0.03 ===================
Die Ausgabe von Wolles Lib sieht ganz ähnlich aus:
--------- Ambient Light: 262 Infrared Light: 260 UV-Index: 0.03 ---------
Dabei steht das Breadboard in einer eher dunklen Ecke. Der UV-Index ist sehr gering, das kann gut hinkommen. Aber mich wundern ein bisschen die hohen Werte für Visible und IR. Besonders der IR-Wert. Vis und IR darf man wohl nicht direkt miteinander vergleichen, da muss man wohl jeweils einen anderen Maßstab anlegen. Sonst wäre das Licht ja fast zu 100% IR-Strahlung. Das heißt wenn Vis IR mit einschließt, ansonsten (IR ist aus Vis rausgerechnet) gäbe es genausoviel IR Licht wie sichtbares. Das kann doch irgendwie nicht passen.

Da sich die Ausgaben beider Libs so sehr ähneln, nehme ich an, dass beide beim Beispielprogramm des Herstellers gespickt haben. Vielleicht hat der schon irgendwas was mit Vis und IR falsch gemacht? Das muss ich unbedingt näher testen, zum Beispiel, indem ich den Sensor mit einer IR-Taschenlampe beleuchte...

Bei Wolles Library finde ich noch ein Beispiel, um aus den Werte Lux (die Einheit für die Beleuchtungsstärke) zu berechnen. Da es da nur um mathematische Berechnungen geht, nehme ich die Adafruit-Lib als Grundlage und füge die Lux-Berechnung als Funktion in meinen Code ein.


Dazu kommt natürlich noch, was nötig ist, um die Werte auf dem OLED auszugeben. Das Ergebnis ist beispielhaft rechts zu sehen.

Da das Display nicht sonderlich groß ist, musste ich abkürzen und anordnen: "Vis" steht für "Visible light", also sichtbares Licht. Hier soll mal das Licht ohne IR und UV stehen.

IR ist der Infrarot-Licht-Anteil. Bei UV wird der UV-Index mit zwei Nachkommastellen ausgegeben und daneben die verbale Einstufung (low, med, high, higher, extreme).

Oben rechts unter "Lux:" steht der errechnete Lux-Wert, in diesem Fall 85.3 Lux. Diesmal steht das Breadboard unter hellem Licht und wird fotografiert. Dafür ist der angezeigte Lux-Wert eigentlch viel zu gering.

Außer aus dem UV-Index werde ich nicht so richtig schlau aus den Werten. Klar ist wohl, das man Vis und IR nicht miteinander vergleichen darf. Dazu kommt, dass Vis und IR auch in einem völlig dunklen Raum schon beide ähnliche Werte von knapp über 250 anzeigen.

Und die Lux-Berechnung scheint mir auch nicht so richtig hinzuhauen.

Experimente zum Verstehen der Werte

Ist ist also Zeit für ein paar Experimente, um sich darüber klar zu werden, wie die Werte zu interpretieren sind.

Mit den normalen Library-Routinen funktioniert das Modul unter Sonnenlicht scheinbar ganz gut. Unter LED-Licht aber, geht die Anzeige hektisch auf und ab und zeigt bei derselben Bescheinung einmal hohe Werte und dann wieder Werte nahe bei Null an (siehe Video am Ende der Seite).

Ich erkläre mir das so, dass die LED-Taschenlampen Pulsweitenmodulation (PWM) anwenden, um die Leuchtstärke zu regulieren. Dabei wird die LED ganz schnell ein und ausgeschaltet. Hier höher dabei der Zeitanteil ist, in dem die LED aus ist, desto weniger hell ist das Licht. Das ständige an/aus erzeugt ein schnelles Flackern, dass aber für das träge menschliche Auge nicht wahrnehmbar ist.

Für den SI1145 Sensor aber, der für eine Messung nur etwa eine halbe Millisekunde braucht, kann es gut sein, dass er bei der Messung mal einen dunklen Abschnitt erwischt und dann - korrekterweise muss man sagen - einen Wert nahe Null anzeigt.

Ich habe den Code dann so angepasst, dass mehrere Messungen hintereinander durchgeführt werden und die Messwerte in den Dunkelphase ignoriert werden bzw. einfach den Maximalwert über die Anzahl Messungen genommen. Die Werte für die Mehrwertmessung kann man im Source über die Define-Werte READ_CNT (Anzahl der Messungen) und READ_WAIT (Pause in ms zwischen den Messungen) einstellen.

Ich bin hier mit 13 Messungen in Abständen zu 7 ms sehr gut gefahren und bekomme dann ein ruhiges Bild von Messwerten. Die einzelne Gesamt-Messung dauert damit ungefähr 100 ms. Zwischen den Gesamt-Messungen warte ich jeweils 200 ms. Das ergibt gesamt gesehen eine zügig reagierende Anzeige mit gleichbleibenden Werten bei gleichbleibenden Bedingungen. Auch meine zwei 10 Watt-Wechselstrom-LED-Scheinwerfer, die für den Sensor gesehen ziemlich durcheinander flackern müssen, kann man damit gut messen.

Außerdem nehme ich die ungefähr 250 bis 260 Einheiten aus der Anzeige heraus, die scheinbar immer auf die Vis und IR Werte drauf addiert werden, damit ein vollkommen dunkler Raum auch eine niedrige Anzeige von etwa Null ergibt. Wenn euer Sensor anders reagiert, dann könnt ihr die Werte mit den Defines VIS_MIN (255) und IR_MIN (250) für eure Zwecke einstellen. Aber bitte sicher gehen, dass das nicht in den negativen Bereich laufen kann.

Damit taugt die Anzeige für weitere Experimente, die ich im Video unten zeige. Ich bestrahle den Sensor mit weißem Taschenlampenlicht, mit zwei Arten von UV-Taschenlampe, mit einer IR-Taschenlampe, mit einem kleinen IR-Scheinwerfer und mit rotem, grünemr und violettem Laserpointer-Licht. Dabei teste ich auch die Abdunkelung durch eine Sonnenbrille und Laserschutzbrille. Zum Schluss teste ich noch gegen eine schwach radioaktive Probe, ob der Sensor sich damit aus dem Tritt bingen lässt.

Erkenntnisse aus den Experimenten sind:

Berechnung des Lux-Wertes

In der Library von Wolle findet sich ein Beispiel für die Berechnung des Lux-Wertes (offizielle Einheit für Beleuchtungsstärke). Die dort eingetragenen Werte stammen aus dem Datenblatt des SI1145 und dem Anhang AN523.

Allerdings haut der Lux-Wert bei mir unter LED-Licht so gar nicht hin. Also habe ich Wolles Berechnung mit den Angaben im Datenblatt verglichen: die sind korrekt übernommen worden.

Allerdings habe ich mit den Datenblättern ein Problem: Je nach Lichtart (Sonne, Glühbirne, Neonröhre) gibt es Werte für den Vis-Sensor sowie den kleinen und den großen IR-Sensor, wobei der Wert für den großen ungefähr 6 mal großer ist als für den kleinen. Man kann aber nur den Vis-Wert und einen gemeinsamen IR-Wert aus dem Sensor lesen. Hier muss ich noch durch Expermientieren herausfinden, welcher Wert bzw. Zwischenwert sich für eine Berechnung eignet.

Weiteres Problem: Werte für die Lichtart "LED" fehlen ganz, dabei wären doch die gerade interessant für mich, um die Leuchtstärke verschiedener Taschenlampen miteinander zu vergleichen. Okay, Taschenlampen misst man in Lumen und nicht in Lux, aber trotzdem. Es wäre doch hilfreich, einen Wert zu haben, wie hell eine Oberfläche zum Beispiel beim Fotografieren ausgeleuchtet ist, um die richtige Belichtungszeit beim manuellen Fotografien wählen zu können.

Da die Art des Lichts doch für die Berechnung des Luxwertes einen beträchtlichen Unterschied macht, will ich versuchen, die Lichtart anhand des Vis und IR-Anteils einzuschätzen und dann entsprechend zu berechnen. Ob das in sinnvollen Grenzen geht, werden weitere Experimente zeigen.

Das gelingt mir, indem ich das Verhältnis zwischen sichtbarem Lichtwert (Vis) und infrarotem Lichtwert (IR) in Relation setze und einen Quotienten erhalte. Daran kann ich ganz gut erkennen, wann welche Lichtbedingungen herrschen. Für die Berechnung bei Sonnenlicht passt die Formel ganz gut. Bei der Berechnung des Lux-Wertes bei LED-Licht brauche ich noch einen Verstärkungsfaktor. Hier fahre ich mit 2.1 ganz gut.

Dadurch gelingt es mir, einen halbwegs passablen Lux-Wert zu berechnen und anzuzeigen, der in etwa mit dem Wert meiner Smartphone-App übereinstimmt:




Ein richtiges Lux-Meter habe ich leider nicht, dazu brauche ich es zu selten.

Auch die Anzeige habe ich noch ein bisschen angepasst:

Oben rechts wird nun der Quotient angezeigt und welche Lichtart (LED oder Sun) erkannt wurde.

Direkt darunter befindet sich dann der errechnete Lux-Wert unter Berücksichtigung der Lichtart.

Alle Parameter sind im Quellcode konfigurierbar, falls sie bei euch abweichen sollten und befinden sich in Define-Statements am Anfang des Source-Codes, so dass ihr euch nicht mit dem Programmcode selbst herumschlagen müsst, wenn ihr das nicht möchtet - wobei das natürlich auch interessant ist.

Source-Code

Wie immer kommt der Source-Code gut dokumentiert und mit zahlreichen Kommentaren daher, damit man auch verstehen kann, was vor sich geht.

Darauf, den Chip mittels I2C-Befehlen selbst abzufragen habe ich verzichtet, weil das nicht nötig war, denn die Adafruit-Library, die ich eingebunden habe, leistet hier gute Dienste.

si1145-light-sensor-vis-ir-uv-lux.ino (klicken, um diesen Abschnitt aufzuklappen)
//////////////////////////////////////////////////////// // (C) 2023 by Oliver Kuhlemann // // Bei Verwendung freue ich mich über Namensnennung, // // Quellenangabe und Verlinkung // // Quelle: http://cool-web.de/esp8266-esp32/ // //////////////////////////////////////////////////////// // Dokumentation: https://cool-web.de/esp8266-esp32/gy1145-si1145-uv-index-ir-visible-ambient-light-sensor-licht-experimente.htm #define PIN_SCL D1 // I2C-Bus für OLED und SI1145-Licht-Sensor #define PIN_SDA D2 #define VIS_MIN 260 // Mindestwert, der vom Sensor für Visible Light zurückgeliefert wird #define IR_MIN 254 // Mindestwert für IR #define READ_CNT 13 // Anzahl Einzel-Messungen (höchste wir genommen) #define READ_WAIT 7 // Pause in ms zwischen Einzel-Messungen #define IR_VIS_EDGE 6.8 // IR/Vis-Quotient-Mittelwert LED 4.9, Sonne 8.7 #include <Arduino.h> #include <Wire.h> #include <SSD1306Wire.h> // für OLED (legacy: #include "SSD1306.h") // #include "fontArimo30.h" // größerer Font zur Anzeige der Uhrzeit // Available default fonts: ArialMT_Plain_10, ArialMT_Plain_16, ArialMT_Plain_24 #include "Adafruit_SI1145.h" // https://github.com/adafruit/Adafruit_SI1145_Library // Initialize the OLED displayusing SSD1306Wire SSD1306Wire oled(0x3c, PIN_SDA, PIN_SCL); // ADDRESS, SDA, SCL // Initialize the Light-Sensor Adafruit_SI1145 si1145 = Adafruit_SI1145(); uint16_t ir, vis, uv; // globale Variablen, die auch von der Lux-Berechnung gefüllt werden void setup(void) { pinMode(LED_BUILTIN, OUTPUT); Serial.begin(9600); // wird nur für evtl. Debug-Ausgaben benötigt Serial.print(F("Program started")); Wire.begin(); if (!oled.init()) errorStop ("OLED not found!"); oled.flipScreenVertically(); // falls anders herum eingebaut oled.clear(); oled.setTextAlignment(TEXT_ALIGN_LEFT); oled.setFont(ArialMT_Plain_16); delay(100); if (!si1145.begin()) errorStop ("SI1145 not found!"); } void loop(void) { float uvidx, lux; char tmp[100]; int x2=30; // OLED-Positionen int x3=70; digitalWrite(LED_BUILTIN, LOW); readSi1145(); // liest mehrmals hintereinander aus für stabile Werte // vis = si1145.readVisible(); // ir = si1145.readIR(); uvidx = uv/100.0; // es wird das hundertfache des UV-Index zurückgegeben lux = estimateLux(vis, ir); vis -= VIS_MIN; // die ca. 260, die selbst im Dunkeln da sind, abziehen ir -= IR_MIN; float irVisQuot = (float) ir / (float) vis; // IR-Visible-Verhältnis // Ausgabe der Werte auf dem OLED oled.clear(); oled.drawString(0, 0, F("Vis:")); // Visible, sichtbares Licht oled.drawString(0, 20, F("IR:")); // infrarotes Licht oled.drawString(0, 40, F("UV:")); // ultraviolettes Licht snprintf(tmp, sizeof(tmp), "%0.1f %s", irVisQuot, irVisQuot>IR_VIS_EDGE?"Sun":"LED"); oled.drawString(x3, 0, tmp); // TOF = Time-of flight //oled.drawString(x3, 0, F("Lux:")); // TOF = Time-of flight if (vis > 9999) { snprintf(tmp, sizeof(tmp), "%dk", vis/1000); oled.drawString(x2, 0, tmp); } else { snprintf(tmp, sizeof(tmp), "%d", vis); oled.drawString(x2, 0, tmp); } if (ir > 9999) { snprintf(tmp, sizeof(tmp), "%dk", ir/1000); oled.drawString(x2, 20, tmp); } else { snprintf(tmp, sizeof(tmp), "%d", ir); oled.drawString(x2, 20, tmp); } if (uvidx >= 11) snprintf(tmp, sizeof(tmp), "%0.2f (extreme)", uvidx); else if (uvidx >= 8) snprintf(tmp, sizeof(tmp), "%0.2f (higher)", uvidx); else if (uvidx >= 6) snprintf(tmp, sizeof(tmp), "%0.2f (high)", uvidx); else if (uvidx >= 3) snprintf(tmp, sizeof(tmp), "%0.2f (med)", uvidx); else snprintf(tmp, sizeof(tmp), "%0.2f (low)", uvidx); oled.drawString(x2, 40, tmp); snprintf(tmp, sizeof(tmp), "%0.0f lx", lux); oled.drawString(x3, 20, tmp); oled.display(); digitalWrite(LED_BUILTIN, HIGH); delay (200); // kleinerer Wert für mehr Aktualisierungen in der Sekunde } void errorStop(char *msg) { // bei nicht behebbarem Fehler Meldung anzeigen und stoppen / schnell blinken Serial.println(msg); oled.clear(); oled.drawString(0, 0, msg); oled.display(); while (1) { digitalWrite(LED_BUILTIN, LOW); delay(100); digitalWrite(LED_BUILTIN, HIGH); delay(100); } } int readSi1145() { // den Sensor für stablie Werte mehrmals hintereinander auslesen und Max-Wert nehmen char tmp[100]; uint16_t v, i , u; uint16_t vmax = 0; uint16_t imax = 0; uint16_t umax = 0; for (int cnt=0; cnt < READ_CNT; cnt++ ) { v = si1145.readVisible(); i = si1145.readIR(); u = si1145.readUV(); if (v > vmax) vmax=v; if (i > imax) imax=i; if (u > umax) umax=u; //snprintf (tmp, sizeof(tmp), "Vis %d (%d), IR %d (%d), UV %d (%d)", v, vmax, i, imax, u, umax); //Serial.println(tmp); delay (READ_WAIT); } //Serial.println("-----"); vis = vmax; ir = imax; uv = umax; return 0; } float estimateLux(uint16_t vis, uint16_t ir) { // annähernden Lux-Wert berechnen // Material: No Cover const float visCoeff = 5.41; // AN523 const float irCoeff = -0.08; // AN523 // Lichtarten /////////////////////////////////////////// // Sonnenlicht (IR/Vis-Quot. ca. 8.7) const float visRespSun = 0.282; const float irsRespSun = 2.44; // s = small IR sensor const float irlRespSun = 14.07; // l = large IR sensor // Glühlampe (IR/Vis-Quot. ca. ???) const float visRespBulb = 0.319; const float irsRespBulb = 8.46; const float irlRespBulb = 50.47; // Neon-Leuchtstoffröhre "cool white" (IR/Vis-Quot. ca. 5.7) const float visRespNeon = 0.146; const float irsRespNeon = 0.71; const float irlRespNeon = 3.97; // LED-Licht (IR/Vis-Quot. ca. 4.9) const float visRespLED = 0.146; // ? const float irsRespLED = 0.71; // ? const float irlRespLED = 3.97; // ? unsigned int vis_dark = VIS_MIN; unsigned int ir_dark = VIS_MIN; if (vis - vis_dark < 0) vis = vis_dark; if (ir - ir_dark < 0) ir = ir_dark; float irVisQuot = (float) ir / (float) vis; float visResp = visRespLED; // LED/Neon float irResp = irlRespLED; float gainFactor = 2.1; // selbst hergeleiteter Wert für LED if (irVisQuot > IR_VIS_EDGE) { // Sonnenlicht visResp = visRespSun; irResp = irlRespSun; gainFactor = 1.0; } // Doc Cools Formel float lux = (((vis - vis_dark) / visResp) * visCoeff + ((ir - ir_dark) / irResp) * irCoeff) * gainFactor; // Silicon Labs Formel Application notes AN523 Rev. 0.5, S. 3 (6.) // float lux = ( (vis - vis_dark) * visCoeff + (ir - ir_dark) * irCoeff ) * gainFactor; // Wolles Formel // the equation above does not consider the counts/Lux depending on light source type // I suggest the following equation // float lux = (((vis - vis_dark) / visCountPerLux) * visCoeff - ((ir - ir_dark) / irCountPerLux) * irCoeff) * gainFactor * corrFactor; if (lux < 0) lux=0; return lux; }

Video

Die im einzelnen durchgeführten Experimente mit Worten genau zu beschreiben, erschien mir zu umständlich, darum habe ich die Kamera mitlaufen lassen, so dass ihr sie in folgendem Video live mitverfolgen könnt:


Anmerkung zum Video: Leider habe ich Pause und Aufnahme einmal verwechselt und so den Abschnitt mit den Laser-Messungen nicht aufgenommen. Darum hier noch einmal in Worten:

Alle Laser haben ungefiltert den Sensor gleich auf Überlauf getrieben, was nicht weiter verwunderlich ist. Die Laserschutzbrille mit dem grünen Glas schirmte den roten Laser (ca. 5 mW) zu fast 100% ab, auf jeden Fall konnte ich, sie aufgesetzt, den Laserpunkt nicht mehr sehen. Die Laserschutzbrille mit dem roten Glas schirmte den grünen Laser (ca. 50 mW) sehr gut ab, es war dadurch gesehen nur noch ein schwach leuchtendes Pünktlein zu sehen. Und die Laserschutzbrille mit dem gelben Glas schirmte den violetten Laser (ca. 5 mW) recht gut ab, er war zwar noch zu erkennen, aber deutlich schwächer.

Ab der blau-violette Laser auch UV-Anteil hatte, ließ sich nicht exakt sagen, weil irgendwie alle Laser auch IR und UV nach oben trieben. Das gleiche gilt für den grünen Laser, bei dem ich mir vorstellen konnte, dass dort zusätzliche IR-Strahlung austritt. Auch hier konnte ich keine Aussage treffen, weil alle Sensoren auf alle Wellenlängen ein wenig reagieren.

Vielleicht wiederhole ich den Test irgendwann noch einmal mit IR bzw. UV-Filtern davor bzw. mit Fotodioden, die nur in einem bestimmten Wellenlängenbereich reagieren (so es das denn gibt).

Quellen, Literaturverweise und weiterführende Links

Welle-Teilchen-Dualismus bei Wikipedia
Elektromagnetisches Spektrum bei Wikipedia
UV-Strahlung beim Bundesamt für Strahlenschutz
UV-Index bei Wikipedia