![]() |
Raspberry-Pi-Projekte: Helligkeitssensoren TSL2561, TSL25911, TSL45315Prof. Jürgen Plate |
Der Helligkeitssensor TSL2561 ist ein digitaler Lichtsensor für den Einsatz in einem weiten Bereich von Lichtsituationen. Im Vergleich zu kostengünstigen Photozellen ist dieser Sensor präziser. Es lässt sich aus den gewonnen Daten die Helligkeit in Lux berechnen. Der Sensor kann per Programmierung auf verschiedene Helligkeitsbereiche konfiguriert werden und erlaubt so einen weiten Messbereich. Der Sensor besitzt zwei Photodetektoren, einer für Infrarot und einer für das volle Spektrum. Sie können also das Infrarotspektrum, das Vollspektrum oder das sichtbare Licht berechnen. Durch Subtrahieren des Infrarot-Anteils ergibt sich die Stärke des sichtbaren Lichts.
Der Sensor verfügt über eine digitale I2C-Schnittstelle. Der eingebaute Analog/Digital-Wandler erlaubt den Einsatz mit jedem Mikrocontroller, auch wenn er nicht über analoge Eingänge verfügt. Er eignet sich also bestens für den Raspberry Pi. Der Strombedarf ist extrem niedrig: ca. 0.5 mA im Betrieb und weniger als 15 μA im Powerdown-Modus. Der Sensor wird mit 3.3 V Spannung betrieben, passt also auch von dieser Seite her zum RasPi.
Es können maximal drei Sensoren an einem Bus angeschlossen werden. Die Adressierung erfolgt hierbei über den Anschluss "Addr." des TSL2561. Die folgende Beschaltung zur Adressierung ist möglich:
GND = 0x29 offen = 0x39 VDD = 0x49Für die nun beschreibenen Experimente bleibt der Anschluss für die Adressauswahl unbeschaltet (Baustein-Adresse 0x39).
Zusätzlich bietet der Sensor die Möglichkeit, über einen Interrupt-Ausgang zu melden, dass ein eingestellter Schwellwert überschritten wurde. Dies ist interessant, wenn der exakte Helligkeitswert nicht so wichtig ist und man ständiges Pollen des Sensors vermeiden will. Auf die dazu notwendigen Registerwerte (Threshold, Interrupt) wird hier nicht eingegangen.
Primär interessieren die Register mit den Adressen 0xC bis 0xF, in denen die Helligkeitswerte stehen.
Bei den Registern des Sensors ist zu beachten, dass die höherwertigen vier Bits (7 - 4) das Kommando bestimmen und die niederwertigen vier Bits (3 - 0) die Adresse des Datenregisters für die folgenden Leseoperationen festlegen. Für jede lesende oder schreibende Operation ist mindestens das Bit 7 (CMD - Select Command Register) auf "1" zu setzen. Möchte man beispielsweise das Register mit der Adresse 0xA (Part number/Rev ID) abfragen, so lautet der entsprechende Registerbefehl hierfür 0x83.
Der Sensor kann über die folgenden Befehle ein- bzw. ausgeschaltet werden. Dabei wird das Control-Register (Adresse 0) angesprochen, bei dem nur die Bits 0 und 1 eine Rolle spielen. "00" bedeutet "aus, "11" bedeutet "ein":
# ausschalten i2cset -y 1 0x39 0x80 0x00 # einschalten i2cset -y 1 0x39 0x80 0x03Die Abtastrate des Sensors wird im Register "Timing" (0x1) eingestellt. Voreinstellung ist hierbei die geringste Rate mit der höchsten Genauigkeit. Ist die Umgebung sehr dunkel, muss gegebenenfalls die Rate ("Gain", Bit 4) von 1x auf 16x umgestellt werden. Die Auflösung ("Integration Time") wird über die Bits 0 und 1 eingestellt. Die folgenden Befehle erlauben die Einstellung der unterschiedlichen Abtastraten auf der Kommandozeile. Bei der Berechnung der Lux-Werte muss dann auch der Skalierungsfaktor beachtet werden:
# 13.7 ms, geringste Auflösung, Skalierungsfaktor 0.034 i2cset -y 1 0x39 0x81 0x00 # 101 ms, mittlere Auflösung, Skalierungsfaktor 0.252 i2cset -y 1 0x39 0x81 0x01 # 402 ms, beste Auflösung, Skalierungsfaktor 1.0 i2cset -y 1 0x39 0x81 0x02Die Skalierungswerte ergeben sich aus der Frequenz des Oszillators und der Integrationszeit:
i2cset -y 1 0x39 0x81 0x03 # manuelle Abtastung einschalten i2cset -y 1 0x39 0x81 0x07 # Start der Messung i2cset -y 1 0x39 0x81 0x03 # Ende der Messung
Mit dem folgenden Python-Programm kann der Lichtsensor getestet werden. Es gibt die Ausgelesenen Werte für Infrarot- und Gesamthelligkeit aus. Anschließend werden der Wert für das sichtbare Licht, das Verhältnis Gesamt/Infrarot und der Lux-Wert berechnet und ausgegeben.
#!/usr/bin/env python import smbus from time import sleep # ---------- Konfigurationsbereich: # die Adressse des TSL2561 kann # 0x29, 0x39 oder 0x49 sein BUS = 1 TSL2561_ADDR = 0x39 # --------------------------------- #Instanzieren eines I2C Objektes i2cBus = smbus.SMBus(BUS) # Starten des Messvorganges mit 402 ms # (Skalierungsfaktor 1) i2cBus.write_byte_data(TSL2561_ADDR, 0x80, 0x03) while True: # Gesamthelligkeit auslesen # niederwertiges Byte lesen LSB = i2cBus.read_byte_data(TSL2561_ADDR, 0x8C) # hoeherwertiges Byte lesen MSB = i2cBus.read_byte_data(TSL2561_ADDR, 0x8D) Ambient = (MSB << 8) + LSB print "Ambient: %d" % Ambient # Infrarothelligkeit auslesen # niederwertiges Byte lesen LSB = i2cBus.read_byte_data(TSL2561_ADDR, 0x8E) # hoeherwertiges Byte lesen MSB = i2cBus.read_byte_data(TSL2561_ADDR, 0x8F) Infrared = (MSB << 8) + LSB print "Infrared: %d" % Infrared # Berechnen des sichtbaren Spektrums Visible = Ambient - Infrared print "Visible: %d" % Visible # Berechnen des Faktors Infrared/Ambient Ratio = 0 Lux = 0 if Ambient != 0: Ratio = float(Infrared)/float(Ambient) print "Ratio: %f" % Ratio # Berechnung Lux-Wert gemaess Datenblatt TSL2561T # T, FN, and CL Package if 0 < Ratio <= 0.50: Lux = 0.0304*float(Ambient) - 0.062*float(Ambient)*(Ratio**1.4) elif 0.50 < Ratio <= 0.61: Lux = 0.0224*float(Ambient) - 0.031*float(Infrared) elif 0.61 < Ratio <= 0.80: Lux = 0.0128*float(Ambient) - 0.0153*float(Infrared) elif 0.80 < Ratio <= 1.3: Lux = 0.00146*float(Ambient) - 0.00112*float(Infrared) else: Lux = 0 print "Lux = %f\n" % Lux sleep (0.5)Startet man das Programm, ergibt beispielsweise folgender Output:
Revision 0x50 Ambient 522 Infrared 183 Visible 339 Ratio 0.35 Lux 8.41 Ambient 409 Infrared 165 Visible 244 Ratio 0.40 Lux 5.32 Ambient 405 Infrared 164 Visible 241 Ratio 0.40 Lux 5.23 Ambient 537 Infrared 179 Visible 358 Ratio 0.33 Lux 9.17 Ambient 1038 Infrared 201 Visible 837 Ratio 0.19 Lux 25.09 ^CBye
Es hat sich gezeigt, dass der Sensor bei großer Helligkeit (Sonnenschein, aussen) in die Begrenzung geht und Maximalwerte für sichtbares wie infrarotes Licht liefert. Das hat zur Folge, dass die Berechnung der Lux-Werte daneben geht. Das Extrembeispiel 65535 65535 0 1.00 22.28 verdeutlicht das. Deshalb wurden weitere Sensoren untersucht.
Der Helligkeitssensor TSL25911 ist ein digitaler Lichtsensor, der dem vorhergehenden Modell ziemlich ähnlich ist. Auch dieser Sensor kann per Programmierung auf verschiedene Helligkeitsbereiche konfiguriert werden und erlaubt so einen weiteren Messbereich als der TSL2561. Der Sensor besitzt zwei Photodetektoren, einer für Infrarot und einer für das volle Spektrum. Sie können also das Infrarotspektrum, das Vollspektrum oder das sichtbare Licht berechnen. Durch Subtrahieren des Infrarot-Anteils ergibt sich die Stärke des sichtbaren Lichts.
Der TSL25911 hat ebenfalls eine digitale I2C-Schnittstelle und eignet sich daher ebenfalls bestens für den Raspberry Pi. Der Strombedarf ist extrem niedrig: ca. 0.3 mA im Betrieb. Der Sensor wird mit 3.3 V Spannung betrieben, passt also auch von dieser Seite her zum RasPi. Der Sensor liegt fest auf der I2C-Adresse 0x29.
Technische Daten:
Das Breakout-Board mit dem TSL25911 enthält einen Spannungsregler, das Board kann mit Spannungen zwischen 3,3 V und 5 V betrieben werden. Die Spannungsanpassung an den I2C-Bus ist ebenfalls auf den Board realisiert.
Bei den Registern des Sensors ist zu beachten, dass die höherwertigen drei Bits (7 - 5) das Kommando bestimmen und die niederwertigen vier Bits (4 - 0) die Adresse des Datenregisters für die folgenden Leseoperationen festlegen. Für jede lesende oder schreibende Operation ist mindestens das Bit 7 (CMD - Select Command Register) auf "1" zu setzen. Die nächsten beiden Bits erlauben die Wahl zwischen normalem Betrieb und speziellen Transaktionen. Für den Normalbetrieb gilt hier die Kmbination "01", so dass das höherwertige Nibble des Kommandowortes - abhängig von der Registeradresse den Wert 0xA oder 0xB besitzt.
Das Enable-Register auf Adresse 0 erlaubt das Ein- und Ausschalten deS Energiesparmodus sowie die Freigabe von Messung und Interrupts. Für die Freigabe der Messung und Power-On muss 0x03 in das Register (KOmmandowort 0xA0) geschrieben werden.
Über das Control-Register werden (neben einem möglichen Soft-Reset) Integrationszeit (Bits 2 - 0) und Gain (Bits 5 und 4) festgelegt. Die Bitpostion kann in die Konstantendefinition des Programms übernommen werden. Auf diese Weise kann dann die Einstellung des Chips durch eine bitweise Oder-Verknüpfung der beiden Konstanten erfolgen:
# Konstantendefinition fuer Integrationszeit (Control-Reg.) ITIME_100 = 0x00 # Integrationszeit [ms] ITIME_200 = 0x01 ITIME_300 = 0x02 ITIME_400 = 0x03 ITIME_500 = 0x04 ITIME_600 = 0x05 # Konstantendefinition fuer Gain (Control-Reg.) GAIN_LOW = 0x00 # low gain (1x) GAIN_MED = 0x10 # medium gain (25x) GAIN_HIGH = 0x20 # high gain (428x) GAIN_MAX = 0x30 # maximum gain (9876x)Das Controlregister (Adresse 1) wird über das Kommandowort 0xA1 ausgewählt. Abhängig von Integrationszeit und Gain müssen auch noch zwei Rechenkonstanten für die Lux-Berechnung als Gleitpunktzahlen festgelegt werden. Bei der Integrationszeit entspricht der Wert der Zeit im Millisekunden, die Faktoren für Gain sind oben im Klammern angegeben. Im Programm werden dafür zwei assoziative Arrays angelegt.
Es gibt auch wieder eine Device-Id (Register 0x12) und ein Statusregister (0x13) sowie die diversen Interruptregister. Diesbezüglich sei auf das Datenblatt verwiesen. Die Daten (Gesamtlicht und Infrarot-Anteil) werden als zwei 16-Bit-Werte gespeichert. Wenn das niederwertige Byte eines sogenannten Channels gelesen wird, speichert der Chip gleichzeitig das höherwertige Byte des gleichen Channels wird in einem Schattenregister. Dieses Schattenregister sorgt dafür, dass beide Bytes das Ergebnis des gleichen Integrationszyklus sind. Die vier Register haben die Adressen:
Mit dem folgenden Python-Programm kann der Lichtsensor getestet werden. Es gibt die ausgelesenen Werte für Infrarot- und Gesamthelligkeit aus. Anschließend werden der Wert für das sichtbare Licht, das Verhältnis Gesamt/Infrarot und der Lux-Wert berechnet und ausgegeben. Im Programm lassen sich Gain und Integrationszeit durch Angabe der oben gezeigten Konstanten festlegen:
... # Auswahl von Gain und Integrationszeit Gain = GAIN_LOW Integrationtime = ITIME_400 ...Die Berechnung des Lux-Wertes nach einer empirischen Formel ist wesentlich einfacher als beim TSL2561. Nach Auswahl der Rechenkonstanten für Gain und Integrationszeit genügen vier Berechnungen. Das Programm läuft in einer Endlosschleife, die mit [Strg]-[C] abgebrochen werden kann.
#!/usr/bin/env python import smbus from time import sleep # Busnummer und Deviceadresse BUS = 1 TSL2561_Adr = 0x29 # Konstantendefinition fuer Integrationszeit (Control-Reg.) ITIME_100 = 0x00 # Integrationszeit [ms] ITIME_200 = 0x01 ITIME_300 = 0x02 ITIME_400 = 0x03 ITIME_500 = 0x04 ITIME_600 = 0x05 # Konstantendefinition fuer Gain (Control-Reg.) GAIN_LOW = 0x00 # low gain (1x) GAIN_MED = 0x10 # medium gain (25x) GAIN_HIGH = 0x20 # high gain (428x) GAIN_MAX = 0x30 # maximum gain (9876x) # Rechenfaktoren fuer Lux-Berechnung abhaengig # von Integrationszeit und Gain Integ_sel = { ITIME_100: 100.0, ITIME_200: 200.0, ITIME_300: 300.0, ITIME_400: 400.0, ITIME_500: 500.0, ITIME_600: 600.0, } Gain_sel = { GAIN_LOW: 1.0, GAIN_MED: 25.0, GAIN_HIGH: 428.0, GAIN_MAX: 9876.0, } # Auswahl von Gain und Integrationszeit Gain = GAIN_LOW Integrationtime = ITIME_400 # Instanzieren eines I2C Objektes i2cBus = smbus.SMBus(BUS) # Starten des Messvorganges i2cBus.write_byte_data(TSL2561_Adr, 0xA0, 0x03) sleep(0.5) # Gain und Integrationszeit einstellen i2cBus.write_byte_data(TSL2561_Adr, 0xA1, Gain | Integrationtime) sleep (1.0) # Id auslesen Id = i2cBus.read_byte_data(TSL2561_Adr, 0xB2) print "Id: 0x%2X\n" % Id while True: # Auslesen LSB = i2cBus.read_byte_data(TSL2561_Adr, 0xB4) MSB = i2cBus.read_byte_data(TSL2561_Adr, 0xB5) Ambient = float(MSB*256) + float(LSB) print "Ambient %d" % Ambient LSB = i2cBus.read_byte_data(TSL2561_Adr, 0xB6) MSB = i2cBus.read_byte_data(TSL2561_Adr, 0xB7) Infrared = float(MSB*256) + float(LSB) print "Infrared %d" % Infrared # Berechnen des sichtbaren Spektrums Visible = Ambient - Infrared print "Visible %d" % Visible # Berechnen des Faktors IR/Ambient Ratio = Infrared/Ambient print "Ratio %.2f" % Ratio # Berechnung Lux-Wert if Gain in Gain_sel.keys(): again = Gain_sel[Gain] else: again = 1.0 if Integrationtime in Integ_sel.keys(): atime = Integ_sel[Integrationtime] else: atime = 100.0 cpl = (atime*again)/408.0 if cpl != 0.0: lux1 = (Ambient - (1.64*Infrared))/cpl lux2 = ((0.59*Ambient) - (0.86*Infrared))/cpl Lux = max([lux1, lux2]) else: Lux = 0 print "Lux = %.2f\n" % Lux sleep(1.0)Die Ausgabe des Programms ergibt beispielsweise:
Id: 0x50 Ambient 651 Infrared 158 Visible 493 Ratio 0.24 Lux = 399.72 Ambient 12632 Infrared 1785 Visible 10847 Ratio 0.14 Lux = 9898.69 Ambient 18147 Infrared 2539 Visible 15608 Ratio 0.14 Lux = 14262.70 Ambient 25350 Infrared 3522 Visible 21828 Ratio 0.14 Lux = 19965.40 Ambient 46318 Infrared 6361 Visible 39957 Ratio 0.14 Lux = 36603.68 Ambient 65535 Infrared 9668 Visible 55867 Ratio 0.15 Lux = 50673.07
Da der Sensor selbst nur etwa 2x2 mm groß ist, greift man am einfachsten zu einem Breakout-Board, welches z. B. von Watterott angeboten wird. Das bietet auch noch als Features einen Eingangsspannungsbereich von 3,3 V bis 5 V und ein 3,3 V bis 5 V tolerantes I2C-Interface.
Der Sensor liegt auf Adresse 0x29 des I2C-Bus. Unter der Typbezeichnung TSL45311 ist eine Variante für die Adresse 0x39 verfügbar. Auch existieren Sensoren, die mit 1,8 V Betriebsspannung arbeiten. Da der I2C-Bus bei Raspberry Pi mit 3,3 V arbeitet, bleibt es beim TSL45315.
Der ADC-Ausgangswert ist eine 16-Bit-Zahl, die direkt proportional zur Luminanz (lux) ist. Die Luminanz kann nach folgender Formel berechnet werden:
Luminanz (lux) = FAKTOR × ((DATAHIGH << 8) + DATALOW)Dabei gilt für den Faktor:
Das Control-Register (Adresse 0) verwendet nur die unteren beiden Bits (1 und 0):
00 Power Down 01 Reserved 10 Run a single ADC cycle and return to PowerDown 11 Normal OperationDas Configuration-Register (Adresse 1) verwendet nur Bit 3 und die unteren beiden Bits (1 und 0). Bit 3 (PSAVESKIP) legt den Energiesparmodus fest. Wenn aktiviert, werden die Energiespar-Zustände nach einem Integrationszyklus übersprungen, um eine kürzere Abtastrate zu erreichen. Bei PSAVESKIP = 0 ist die typische Gesamtzykluszeit Integrationszeit + (60/FAKTOR) ms. Ist PSAVESKIP = 1, dauert der typische Gesamtzyklus nur so lange wie die Integrationszeit. Die Bits 0 und 1 legen die Integrationszeit und damit den FAKTOR fest:
00 Faktor = 1, Integrationszeit = 400 ms 01 Faktor = 2, Integrationszeit = 200 ms 10 Faktor = 4, Integrationszeit = 100 ms 11 reserviertDie beiden Datenregister liefern den Wert der Luminanz (Register 4 LSB, Register 5 MSB), siehe Beispielprogramm. Das letzte Register mit der Adresse 0x0A (!) erlaubt die Indentifizierung des Chips:
0x08 TSL45317 0x09 TSL45313 0x0A TSL45315 0x0B TSL45311
Mit dem folgenden Python-Programm kann der Lichtsensor getestet werden. Es gibt die ausgelesenen Werte für Id und Luminanz aus.
#!/usr/bin/env python import smbus import time # ---------- Konfigurationsbereich: # die Adressse des TSL45315 BUS = 1 TSL45315_ADDR = 0x29 # --------------------------------- #Instanzieren eines I2C Objektes bus = smbus.SMBus(BUS) # Control Register, 0x00 # start normal operation bus.write_byte_data(TSL45315_ADDR, 0x80, 0x03) # Configuration Register, 0x01 # Multiplikator 1x, Integrationszeit 400 ms # Je nach gewaehlter Messdauer muss der Messwert laut # Datenblatt mit einem Faktor multipliziert werden bus.write_byte_data(TSL45315_ADDR, 0x81, 0x00) time.sleep(0.5) # Id lesen id = bus.read_byte_data(TSL45315_ADDR, 0x8A) >> 4 # Daten lesen von Register 0x04, 2 bytes, LSB first data = bus.read_i2c_block_data(TSL45315_ADDR, 0x84, 2) # 16-Bit-Wert (Lux) #luminance = (data[1] * 256) + data[0] luminance = (data[1] << 8) + data[0] # Output data to screen print "Id: 0x0%X" %id print "Luminanz: %d lux" %luminanceStartet man das Programm, ergibt beispielsweise folgender Output:
Id: 0x0A Luminanz: 489 luxMit mehr Licht ergibt sich beispielsweise:
Id: 0x0A Luminanz: 65535 lux