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
- infrarotes Licht
- (normales, für den Menschen) sichtbares Licht
- ultraviolettes Licht (UV-A/B/C)
- und auch mit der benachbarten Röntgenstrahlung wollen wir uns ein klein wenig beschäftigen
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-Index | Bereich | empfohlenene Schutzmaßnahme |
---|---|---|
0–2 | niedrig | Kein Schutz erforderlich. |
3–5 | mäßig | Schutz erforderlich: Hut, T-Shirt, Sonnenbrille, Sonnencreme. |
6–7 | hoch | Schutz erforderlich: Hut, T-Shirt, Sonnenbrille, Sonnencreme. Mittags in den Schatten |
8–10 | sehr hoch | zusä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. |
>= 11 | extrem | zusä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:
- Messbereich von sichtbarem Umgebungslicht von 6 Lux (empfindlicher Modus ab 1 Lux) bis zu 128'000 Lux.
- 0.1 Lux Messgenauigkeit
- IR-Korrektur für Messung sichtbaren Lichts
- wie schon erwähnt, kalibrierter UV-Index
- unter 500 nA im Standby und 180 mA bei Messung, bei sekündlicher Messung ca. 9 µA Durchschnittswert
- Interrupt-Leitung an Pin 5
- I2C-Übertragungsrate bis 3.4 Mbps
- Standard I2C-Adresse 0x60, I2C-Kommando zum Ändern der Adresse
- Mess-Ergebnisse innerhalb von etwa 285 µs für UV-Index. Variiert je nach ADC-Einstellung (niedrigerer, höherer Messbereich).
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
===================
---------
Ambient Light: 262
Infrared Light: 260
UV-Index: 0.03
---------
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:
- Vis und IR-Wert haben unterschiedliche Maßstäben und können nicht direkt miteinander verglichen werden
- bei UV-Bestrahlung geht der UV-Index am meisten hoch, aber auch Vis und IR werden beeinflusst, wenn auch nicht so stark
- auch bei IR-Bestrahlung geht die IR-Anzeige am meisten hoch, allerdings hat es auch Auswirkungen auf Vis und IR
- bei weißer LED-Bestrahlung geht der Vis Anteil rauf, aber auch sehr der IR-Anteil, mehr als das man erwarten würde.
- mit einer hellen Taschenlampe lassen sich die Werte auch schnell aufs Maximum (65535) bringen.
- die Werte sind bei Laserlicht erwartungsmäßig sehr viel höher, der Sensor nahm aber keinen Schaden.
- der violette Laser zeigt auch einen sehr hohen IR-Wert an, wobei ich nicht glaube, dass der violette Laser IR ausstrahlt
- der grüne Laser zeigt auch IR an, ob dies ein Messfehler ist, oder ob der grüne Laser auch IR ausstrahlt (was wegen der Art der Erzeugung des grünen Lichts aus einer IR-Quelle durchaus denkbar ist), lässt sich mit dem Sensor nicht herausfinden.
- die (schwache) radioaktive Strahlung hat keine Auswirkungen auf die Anzeige.
- die Sonnenbrille blockt erfolgreich UV-Licht, aber auch sichtbares (Vis).
- die Laserschutzbrillen blocken die Laserfarben, für die sie gedacht sind, sehr gut, auch wenn sie sehr billig waren.
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 WikipediaElektromagnetisches Spektrum bei Wikipedia
UV-Strahlung beim Bundesamt für Strahlenschutz
UV-Index bei Wikipedia