Der TSL45315 ist ein digitaler Lichtsensor, der die Messwerte in Lux zurückgibt. Damit hat man – anders als bei den einfachen lichtempfindlichen Widerständen – nicht nur eine anliegende Spannung als Rückgabewert zur Verfügung, sondern eine physikalische Größe, die direkt die eintreffende Lichtmenge pro Quadratmeter angibt.

Einige Eigenschaften des TSL45315

  • direkte Lux-Ausgabe mit großem Dynamikbereich (3 Lux bis 220k Lux)
  • Erkennung von Lichtverhältnissen dem menschlichen Auge sehr ähnlich
  • 3,3V – 5V tolerantes I2C/TWI Interface
  • Eingangsspannungsbereich: 3,3V – 5V

Auf der Website des Herstellers findet man weitere Informationen zum Sensor und das Datenblatt.

Da der Sensor selbst nur etwa 2x2mm groß ist, ist er am einfachsten über ein Breakout-Board anzusprechen, welches z.B. von Watterott angeboten wird.

Der Sensor wird über eine die I²C-Schnittstelle konfiguriert und abgefragt. Im folgende Video zeige ich die Funktionsweise des Sensor und stelle einen kurzen Arduino Sketch vor, der mit dem Sensor kommuniziert.

Hier ist der im Video gezeigte Arduino Sketch. Alternativ findet ihr den Sketch auch auf github.

/*
 Beispielsketch für TSL45315 Breakout Board (Digitaler Licht Sensor)
 
 Basierend auf dem Originalcode von Watterott:
 https://github.com/watterott/TSL45315-Breakout
 
 Beschreibung und Datenblatt des Sensors:
 http://ams.com/eng/Products/Sensor-Driven-Lighting/SDL-Ambient-Light-Sensors/TSL45315
 
 I2C Pins auf den einzelnen Arduino Boards:
 Board I2C/TWI Pins
 SDA, SCL
 ----------------------------
 Uno, Ethernet A4, A5
 Mega 20, 21
 Leonardo 2, 3
 Due 20, 21
 */

// Die Wire Library zur Ansteuerung von I2C Geräten einbinden
#include <Wire.h>

// Der TSL45315 hat werkseitig die I2C ID 0x29
#define I2C_ADDR (0x29)

// Die fünf Register des Sensors
#define REG_CONTROL 0x00
#define REG_CONFIG 0x01
#define REG_DATALOW 0x04
#define REG_DATAHIGH 0x05
#define REG_ID 0x0A

void setup()
{

 // Serielle Übertragung zum PC starten (für Ausgabe in Serial Monitor)
 Serial.begin(9600);
 // nur für Arduino Leonardo und Micro: Warten bis serielle
 // Schnittstelle bereit ist
 while(!Serial);

 // Wire-Library initialisieren und dem I2C-Bus als Master beitreten
 Wire.begin();

 // ID auslesen, der TSL45315 liefert hier ein Byte der Form 1000xxxx
 // zurück (nur die oberen 4 Bit zählen).
 Serial.print("ID: ");
 // Übertragung an I2C Device mit Adresse 0x29 starten
 Wire.beginTransmission(I2C_ADDR);
 // Ein Byte an den Sensor schicken
 // Der Sensor erwartet bei diesen Kommandos, dass das
 // MSB (Most Significant Bit = das höherwertigste Bit)
 // gesetzt ist. 
 // Das erfolgt am einfachsten mit dem bitweisen Operator | (=OR)
 // 0x80 ist die hexadezimale Darstellung von 1000 0000 (=128 im Dezimalsystem)
 // 
 // 0x80|REGID bedeutet soviel
 // 0x80 = 1000 0000
 // OR 0x0A = 0000 1010
 // ---------
 // ergibt 1000 1010
 //
 // Dieses Byte wird dann mit Wire.write in die Warteschlange gesteckt
 Wire.write(0x80|REG_ID);
 // und mit Wire.endTransmission an den Sensor geschickt
 Wire.endTransmission();

 // Mit dem obigen Befehl 0x80|REG_ID haben wir dem Sensor mitgeteilt,
 // dass wir bei der nächsten Abfrage den Inhalt des ID-Register auslesen möchten
 // Nun kündigen wir an, dass wir 1 Byte abholen möchten
 Wire.requestFrom(I2C_ADDR, 1); //request 1 byte
 // Wire.available gibt die Anzahl der Bytes an, die abgeholt werden können,
 // ist also TRUE solange noch etwas abgeholt werden kann
 while(Wire.available())
 {
 // Der Datentyp unsigned char entspricht 1 Byte. Dieses Byte abholen
 unsigned char c = Wire.read();
 // Vom zurückgelieferten Byte des ID Registers interessieren uns nur die oberen 4 Bit.
 // Die unteren 4 Bit wollen wir einfach auf Null setzen.
 // Also diesmal den binären Operator AND anwenden, d.h.
 // Inhalt von char c = 1010 xxxx (x = egal ob 0 oder 1, interessiert uns nicht)
 // AND 1111 0000
 // ---------
 // ergibt 1010 0000 = 0xA0
 // Ergebnis der Berechnung hexadezimal ausgeben, zeigt "ID: A0" 
 Serial.print(c&0xF0, HEX);
 }
 Serial.println("");

 // Dann den Sensor einschalten
 Serial.println("Power on...");
 // Wieder Übertragung beginnen
 Wire.beginTransmission(I2C_ADDR);
 // Ankündigen, dass nächstes Byte an das Register CONTROL gesendet wird
 Wire.write(0x80|REG_CONTROL);
 // Dann Byte 0x03 senden, bedeutet laut Datenblatt "Normal Operation" (power on)
 Wire.write(0x03);
 // Warteschlange übertragen, Übertragung beenden
 Wire.endTransmission();

 // Und noch eine Konfigurationseinstellung an den Sensor schicken
 Serial.println("Config...");
 Wire.beginTransmission(I2C_ADDR);
 // Achtung: Nächstes Byte ist für das Register CONFIGURATION gedacht
 Wire.write(0x80|REG_CONFIG);
 // Der Sensor kann auf verschiedene Messdauer eingestellt werden
 Wire.write(0x00); //M=1 T=400ms
 // Wire.write(0x01); //M=2 T=200ms
 // Wire.write(0x02); //M=4 T=100ms
 // Schicken und I2C Bus freigeben
 Wire.endTransmission();

 // Im setup() ist einiges passiert, wir wissen jetzt die ID, also den Typ des Sensors
 // und haben ihn eingeschaltet und die Messdauer auf 400ms gestellt.
}


// In der loop() wird der Sensor 1 x pro Sekunde ausgelesen 
void loop()
{
 // Variablen für HIGH und LOW Byte
 uint16_t low, high;
 // Errechneter Wert in Lux
 uint32_t lux;

 // Übertragung beginnen
 Wire.beginTransmission(I2C_ADDR);
 // Der gemessene Wert passt nicht in 1 Byte, wir brauchen 2 Byte dazu (HIGH & LOW)
 // Wir wollen den Inhalt des Registers DATALOW abfragen 
 Wire.write(0x80|REG_DATALOW);
 Wire.endTransmission();
 // Schick uns 2 Byte
 Wire.requestFrom(I2C_ADDR, 2);
 // Erstes Byte in low einlesen. 
 low = Wire.read();
 // Der Registerzeiger im Sensor springt automatisch auf das nächste Register,
 // Das ist DATAHIGH
 // Zweites Byte in high einlesen 
 high = Wire.read();
 // Sicherheitshalber noch schauen, ob noch Bytes übertragen werden wollen
 // Das sollte aber eigentlich nie der Fall sein
 while(Wire.available()){ 
 Wire.read(); 
 }

 // Jetzt den Lux-Wert aus den beiden Bytes ausrechnen. Hier wird auch klar, warum 
 // weiter oben low und high als 16-bit Integers definiert wurden, obwohl in DATALOW und
 // DATAHIGH ja nur je 1 Byte steht.
 //
 // Also: Angenommen unser Messwert wäre dezimal 2025, das ist 
 // ausgedrückt in 16 Bit: 0000 0111 1110 1001
 // oder in Dezimalzahlen: 256 * 7 + 233 = 2025
 // Damit steht im Register DATAHIGH: 0000 0111
 // und in DATALOW: 1110 1001
 //
 // In uint16_t high (16 bit!) steht also: 0000 0000 0000 0111
 // und in low: 0000 0000 1110 1001
 //
 // Die Anweisung high<<8 in der folgende Zeile schiebt nun die Bits in high um 
 // 8 Stellen nach links, also haben wir jetzt
 // in high : 0000 0111 0000 0000 = 1792
 // und in low: 0000 0000 1110 1001 = 233
 // Diese Werte werden -------------------
 // mit | (OR) verknüpft: 0000 0111 1110 1001 = 2025
 lux = (high<<8) | low;

 // Je nach gewählter Messdauer muss der Messwert laut Datenblatt
 // mit einem Faktor multipliziert werden 
 lux *= 1; //M=1
 // lux *= 2; //M=2
 // lux *= 4; //M=4
 // Messwert ausgeben und 500ms warten
 Serial.print("Lux: ");
 Serial.println(lux, DEC);
 delay(1000);
}

Code-Sprache: Arduino (arduino)

Fragen, Kommentare, Hinweise und Fehler und sonstige Kritik bitte in die Kommentare.

Vielen Dank!

4 thoughts on “Digitaler Lichtsensor TSL45315 über I²C am Arduino

  • 28. Juli 2016 at 17:45
    Permalink

    Hallo,
    ich bin gerade auf der Suche nach einem Helligkeitsmesser, den ich via Raspberry Pi und der Software FHEM auslesen möchte. Es sollen damit dann andere Komponenten (Licht etc.) gesteuert werden.

    Meine Frage: Sind die Werte via Arduino (WLAN) zu FHEM übertragbar, ggf. mit einem etwas abgeänderten Sketch? Vielleicht eine dumme Frage, mag sein. Aber als Anfänger tut man sich schwer gute Anleitungen zu finden die den Einstieg ermöglichen. Dies hier ist eine gute Anleitung.

    Diesen TSL 45315 gibt es in Deutschland leider nicht (ELV, Conrad etc.). Gibt es eine aktuelle Empfehlung eines Sensors der oben beschriebenes leisten kann?

    Vielen Dank für die Auskunft und ich hoffe auf weitere Tutorials.

    Reply
  • 9. Mai 2017 at 23:28
    Permalink

    Hallo,

    Vielen Dank für ausführliche Beschreibung ! Man sieht leider nicht häufig eine so gut strukturierte Dokumentation mit soviel Liebe fur die Details.

    Die Schaltung hat bei mir auf Anhieb funktioniert. Es hätte unglaublich viel Zeit gekostet, das alles selbst aus den Datenblättern herauszufiltern.

    Das Datenblatt vom TSL45315 gibt es nicht mehr bei AMS, aber z.B. noch bei alldatasheet:
    http://www.alldatasheet.com/datasheet-pdf/pdf/454515/TAOS/TSL45315.html

    Die aktuelle Übersicht von AMS, mit den ähnlichen Typen TSL45311 und TSL45313:
    http://ams.com/eng/Products/Light-Sensors

    Mit herzlichen Grüssen aus München !

    Reply
  • 12. Juli 2019 at 12:22
    Permalink

    Danke für dein Video und die Bereitstellung solch toller und gut vorbereiteter Inhalte!

    Eine Frage habe ich dazu: Laut Datenblatt soll der Sensor bis 220k Lux messen können. In deinem Code sehe ich, dass du 2 Byte als Messwert zurückbekommst und man damit nur auf maximal 65k Lux kommen wird, wenn ich es richtig verstehe?
    Wie schafft man es den Messbereich bis auf 220k Lux auszudehnen. Gibt es dafür eine Einstellung um die Messgenauigkeit zu reduzieren oder kann man mehr als 2 Byte als Ergebnis anfordern?

    Beste Grüße
    Timo

    Reply

Schreibe einen Kommentar zu Fred Antworten abbrechen

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert

Time limit is exhausted. Please reload the CAPTCHA.

Diese Website verwendet Akismet, um Spam zu reduzieren. Erfahre mehr darüber, wie deine Kommentardaten verarbeitet werden.