The TSL2561 Luminosity Sensor is used to measure ambiant light levels more accuratly and across a wider range of light levels than a Light Dependant Resistor or LDR.
The TSL2561 has two light sensors, one photo diode detects a range from infrared through full spectrum visible light. The other photo diode just detect infrared light. The visible light levels are then calculated by taking the IR reading away from the reading of the IR+visible reading. From this the Lux can be calculated. The sensors can detect a LUX of 0.1 to 40,000. To put that in perspective from a partially moon lit night to brighter than daylight on sunny day, not looking at the sun. Lux examples on Wikipedia
This type of sensor is used to get light readings for photography and video, used in electronics to manage light levels such as the brightness of a display and also useful for security devices.
The pins are not supplied with the board
The TSL2561 measures only 15mm x 18mm and has 5 connectors but only 4 are required to use it. It is powered by 3.3V and uses the i2c connectors on the Raspberry Pi's GPIO ports. The 5th connector can be used as an interupt when certain light levels are detected. The board is supplied with no pins.
There are 3 i2c addresses that can be used to access the TSL2561 light sensor, the default one is 039 the others of 029 and 049 are set by solder jumpers or pins depending on the manufacturer of the board.
The controls of the TSL2561 allow you to:
- turn it on and off
- set the Gain levels, light sensitivity, between normal x1 and low light x16
- Exposure time between 0.402ms , 101ms, 13.7ms or manual exposure length
- Interupt thresholds for use with the 5th pin, INT.
- Display Part Number
- Retreive results from the two photo diode channels.
To program the sensor there are a few drivers around for C and Python. For this article I will cover what is required to program in Python3.
First of all make sure you have the 12c libraries installed on your Raspberry Pi.
dpkg -s python3-smbusdpkg -s i2c-tools
If it is not installed then install it with
sudo apt-get install python3-smbussudo apt-get install i2c-tools
The I2C interface will also need activating on the Raspberry Pi. This is done either in the Raspbian desktop in preferences and Raspberry Configuration. Go to the Interfaces tab and enable I2C.
To do this in the terminal enter
sudo raspi-config
Go to the Interfacing Options, then P5 I2C, then select yes.
Ok your way out and select reboot.
You are now set to start programming the Light Sensor.
to confirm the TSL2561's i2c address is 039 run the command
i2cdetect -y 1
You should see a table with lots of dashes and a number. The number will be the address of the I2C device attached. This should be 39.
To setup the Luminosity sensor you need to write to the sensors memory with the settings you want. This consists of the (i2c address, Function address, Command, setting).
For example, to switch it on the command is
bus.write_byte_data(0x39, 0x00 | 0x80, 0x03)
(I2C address, function address | Command, setting)
if you want to change the gain to x16 then you would use
bus.write_byte_data(0x39, 0x01 | 0x80, 0x12)
I will explain the options in more detail to make this a bit clearer.
The I2C address (0x39) and comand (0x80) don't change, you will only change the other two options. The second position is the function you wish to use.
- 0x00 = used to switch on and off
- 0x01 = Timing, used to set exposure speed or manual mode
- 0x02 - 0x05 = Set the low and high threshold for the Interupt
- 0x06 = Set Interrupt
- 0x0A = Part number / ID
- 0x0C = Channel 0 Photo Diode 1 results
- 0x0D = second part of Photo Diode 1 results but can only be accessed through a block read of 0x0C
- 0x0E = Channel 1 Photo Diaode 2 results
- 0x0F = second part of Photo Diode 2 results but can only be accessed through a block read of 0x0E
List of TSL2561 Command Options
This list shows the entries between the brackets of bus.write_byte_data(0x39, 0x00 | 0x80, 0x03) which activate each setting. The entries are in hexidecimal but can be entered in decimal. ie bus.write_byte_data(57, 0 | 128, 3). To be consistant with the datasheet I will use Hexidecimal.
- (0x39, 0x00 | 0x80, 0x03 ) = Switch on
- (0x39, 0x00 | 0x80, 0x00) = Switch off
- (0x39, 0x01 | 0x80, 0x00) = Gain at 1x and exposure at 13.7ms
- (0x39, 0x01 | 0x80, 0x01) = Gain at 1x and exposure at 100ms
- (0x39, 0x01 | 0x80, 0x02) = Gain at 1x and exposure at 402ms
- (0x39, 0x01 | 0x80, 0x03) = Gain x1 and Manual exposure
- (0x39, 0x01 | 0x80, 0x10) = Gain x16 low light and exposure at 13.7ms
- (0x39, 0x01 | 0x80, 0x11) = Gain x16 low light and exposure at 100ms
- (0x39, 0x01 | 0x80, 0x12) = Gain x16 low light and exposure at 402ms
- (0x39, 0x01 | 0x80, 0x13) = Gain x16 low light and Manual exposure
- (0x39, 0x01 | 0x80, 0x1F) = Start Manual Exposure
- (0x39, 0x01 | 0x80, 0x1E) = Stop Manual Exposure
I haven't used the interrupts with the 5th pin so have not included the commands for this. They are documented in the datasheet at the bottom of this article.
Next are the read commands:
To read the part number and ID enter the command is bus.read_byte_data(0x39, 0x8A)
To read the two sets of numbers in the IR_Visible sensor for channel 0 use
bus.read_i2c_block_data(0x39, 0x0C | 0x80, 2)
and for the two sets of data for the IR sensor for channel 1 use
bus.read_i2c_block_data(0x39, 0x0E | 0x80, 2)
Convert the photo diodes output
The sensors return results from the two channels like [210,16] and [74,1]. These should be converted to a integer before being used with the following calculation, where [210,16) is data0 and [74,1] is data1
channel0 = data0[1] * 256 + data0[0]
channel1 = data1[1] * 256 + data1[0]
This gives you the sensors readings. To get the visible light result minus channel1 (IR) from channel0 (IR+Visible).
The visible light result can then be used to calculate the lux level. This involves various calculations based on the gain and exposure time. Lux calculation examples are shown in the datasheet at the bottom of this article.
Some Example TSL2561 Light Readings
Some readings taken in a halogen lit room.
- 1x Gain at 402ms: V+IR 484 IR 301
- 16x Gain at 402ms: V+IR 7222 IR 4510
Enclosed in hands
- 1x Gain at 402ms: V+IR 1 IR 1
- 16x Gain at 402ms: V+IR 26 IR 18
IR Remote control pointed at sensor
- 1x Gain at 402ms: V+IR 1637 IR 1427
- 16x Gain at 402ms: V+IR 40567 IR 39371
Depending on the exposure there is a maximum readings the sensor will return.
For 402ms the readings will go up to 65535, 101ms the maximum is 37177 and 13.7ms it is 5047. Any light exceding these levels will not be recorded. If these levels are met then the reading should be treated as bad.
Python 3 Script to test the TSL2561 Luminosity Sensor
I have written a python 3 script to test the sensor in different condition. There are a few scripts and libraries found elsewhere online but have written this to get a better understanding of the features for future projects.
It can be downloaded from here
#!/usr/bin/python3 #Output test for TSL2561 Luminosity Sensor #RaspberryConnect.com import smbus import time TSLaddr = 0x39 #Default I2C address, alternate 0x29, 0x49 TSLcmd = 0x80 #Command chan0 = 0x0C #Read Channel0 sensor date chan1 = 0x0E #Read channel1 sensor data TSLon = 0x03 #Switch sensors on TSLoff = 0x00 #Switch sensors off #Exposure settings LowShort = 0x00 #x1 Gain 13.7 miliseconds LowMed = 0x01 #x1 Gain 101 miliseconds LowLong = 0x02 #x1 Gain 402 miliseconds LowManual = 0x03 #x1 Gain Manual HighShort = 0x10 #LowLight x16 Gain 13.7 miliseconds HighMed = 0x11 #LowLight x16 Gain 100 miliseconds HighLong = 0x12 #LowLight x16 Gain 402 miliseconds HighManual = 0x13 #LowLight x16 Gain Manual #Manual Settings ManDelay = 2 #Manual Exposure in Seconds StartMan = 0x1F #Start Manual Exposure EndMan = 0x1E #End Manual Exposure #Number of sensor readings vRepeat = 20 try: #Enter in [] the Exposure Setting to use sequence = [HighLong]*vRepeat #repeat reading vRepeat times for setting in [] except: print("Unknown Exposure Setting used, defaulting to LowLong (x1 402ms") sequence = [LowLong]*vRepeat # Get I2C bus bus = smbus.SMBus(1) writebyte = bus.write_byte_data #Power On writebyte(TSLaddr, 0x00 | TSLcmd, TSLon) def luxcalc(Result0, Result1): """Basic Lux Calculation value""" #see data sheet for lux calculation details #and to calculate lux correctly for all modes ResDiv = int(Result1)/int(Result0) if ResDiv 0.52 and ResDiv 0.65 and ResDiv 0.8 and ResDiv 1.3: lux = 0 return lux def manual(delay,mode): """manual exposure""" bus.write_byte_data(TSLaddr, 0x01 | TSLcmd, mode) #sensativity mode bus.write_byte_data(TSLaddr, 0x01 | TSLcmd, StartMan) #start detection time.sleep(delay) #exposure bus.write_byte_data(TSLaddr, 0x01 | TSLcmd, EndMan) #stop detection return def CurTime(): """Returns the current date and time""" t1 = time.asctime(time.localtime(time.time())) return t1 print("Part Number", bus.read_byte_data(TSLaddr, 0x8A)) for item in sequence: if item != 3 and item != 19: #Selected built in delay for exposure. If Manual mode not set (0x03 or 0x13) writebyte(TSLaddr, 0x01 | TSLcmd, item) #Give sensor time to write results before collecting reading. #13.7ms write several readings before sleep complete, 402ms would write once at 0.5sec sleep. time.sleep(0.5) else: #use manual exposure manual(ManDelay,item) #Read Ch0 Word data = bus.read_i2c_block_data(TSLaddr, chan0 | TSLcmd, 2) #Read CH1 Word data1 = bus.read_i2c_block_data(TSLaddr, chan1 | TSLcmd, 2) # Convert the data to Integer ch0 = data[1] * 256 + data[0] ch1 = data1[1] * 256 + data1[0] # Output data to screen vTime = CurTime() if ch0 > 0: vLux = round(luxcalc(ch0, ch1),5) print(vTime," V+IR",ch0, " IR",ch1, "Lux",vLux) else: #either no light or clipping value exceeded due to too much light print(vTime, " V+IR",ch0, " IR",ch1, "No Light") #Power Off writebyte(TSLaddr, 0x00 | TSLcmd, TSLoff)
The script will give 20 readings for the exposure setting used.
To change the exposure use a varible from the "#Exposure Settings" and put it in the line
sequence = [HighLong]*vRepeat #repeat reading vRepeat times for setting in []
options are LowShort, LowMed, LowLong, LowManual, HighShort, HighMed, HighLong, HighManual
changing; vRepeat = 20, will change the amount of readings recorded from 20.
For the LowManual and HighManual exposure settings change the exposure length, in seconds, with;
ManDelay = 2 #Manual Exposure in Seconds
Other scripts can be found at:
- learn.adafruit.com/tsl2561/use
- pypi.python.org/pypi/tsl2561/2.0
- github.com/ControlEverythingCommunity/TSL2561
The TAOS TSL2560 and TSL2561 Light to Digital Converter datasheet is available here