Home
JAQForum Ver 24.01
Log In or Join  
Active Topics
Local Time 03:46 17 Jun 2024 Privacy Policy
Jump to

Notice. New forum software under development. It's going to miss a few functions and look a bit ugly for a while, but I'm working on it full time now as the old forum was too unstable. Couple days, all good. If you notice any issues, please contact me.

Forum Index : Microcontroller and PC projects : uM2(+): TLS2561 lux measurement

Author Message
matherp
Guru

Joined: 11/12/2012
Location: United Kingdom
Posts: 8648
Posted: 07:49am 23 Mar 2016
Copy link to clipboard 
Print this post

This code was written at the request of Lew247 who supplied me with the TLS2561 module.

This is a 6-pin chip with an I2C interface that measures light levels in both the visible and IR spectrums and then uses the IR measurement to correct the visible measurement.

The program uses the default measurement rate of every 402msec and uses an interrupt to trigger the calculation after each conversion.

The chip has programmable gain settings of 1 and 16 which coupled with a measurement range of 16-bits gives a 1:1000000 dynamic range. The program autromatically switches between the gain ranges to optimise the measurement

The program calculates the light falling on the chip in LUX (one LUX == one lumen per square metre)

Lew: I don't know if this chip will do what you want. It has a maximum measurement of about 0.0304 * 65535 (assuming no IR, lower in the presence of IR) which gives maximum 1992 lux whereas outdoor average sunlight ranges from 32000 to 100000 lux. You may be able to compensate for this with a neutral density filter but this gets way outside my levels of knowledge of light. The chip is clearly intended primarily for indoor uses


option explicit
option default none
const intpin = 12 'connect to the INT pin on the TLS2561
const TLSaddr=&B0111001 'Floating, GND is &B0101001, VCC is &B1001001
const TLScontrol = &H00
const TLStiming = &H01
const TLSINTERRUPT = &H06
const TLSCRC = &H08
const TLSID = &H0A
const TLSDATA0LOW = &H0C
const TLSDATA0HIGH = &H0D
const TLSDATA1LOW = &H0E
const TLSDATA1HIGH = &H0F
const TLSCMD = &H80
const TLSCLEAR = &H40
const TLSPOWER = &H03
const TLSLOWGAIN = &H00
const TLSHIGHGAIN = &H10
CONST TLSINTEG402 = &H02
dim integer C1datalow,C1datahigh,C0datalow,C0datahigh,useresult=1
dim float CH1,CH0,lux,gain=1.0

i2c open 400,1000 'device will run at full speed
i2c write TLSaddr,0,2,TLSCMD OR TLScontrol,TLSPOWER ' turn on the device
i2c write TLSaddr,0,2,TLSCMD OR TLStiming,TLSINTEG402 OR TLSLOWGAIN 'set output every 402msec, gain = 1
setpin intpin,intl,TLS2561int,PULLUP
i2c write TLSaddr,0,2,TLSCMD OR TLSCLEAR OR TLSINTERRUPT,&H10 ' enable interrupts every ADC conversion
'
do
pause 1000
loop
'
sub TLS2561int
i2c write TLSaddr,1,1,TLSCMD OR TLSDATA0LOW
i2c read TLSaddr,0,1,C0datalow
i2c write TLSaddr,1,1,TLSCMD OR TLSDATA0HIGH
i2c read TLSaddr,0,1,C0datahigh
CH0=(C0datahigh*256 + C0datalow)/gain
i2c write TLSaddr,1,1,TLSCMD OR TLSDATA1LOW
i2c read TLSaddr,0,1,C1datalow
i2c write TLSaddr,1,1,TLSCMD OR TLSDATA1HIGH
i2c read TLSaddr,0,1,C1datahigh
CH1=(C1datahigh*256 + C1datalow)/gain
i2c write TLSaddr,0,2,TLSCMD OR TLSCLEAR OR TLScontrol,TLSPOWER 'clear the interrupt
if CH0*gain < 500 and gain = 1.0 then 'switch to low light
i2c write TLSaddr,0,2,TLSCMD OR TLStiming,TLSINTEG402 OR TLSHIGHGAIN 'switch to high gain
useresult=0
gain=16.0
Print "Switching to high gain"
elseif CH0*gain > 10000 and gain = 16.0 then 'switch to normal light
i2c write TLSaddr,0,2,TLSCMD OR TLStiming,TLSINTEG402 OR TLSLOWGAIN 'switch to high gain
useresult=0
gain=1.0
Print "Switching to low gain"
else
select case CH1/CH0 'normal processing
case IS > 0,<=0.5
lux = 0.0304 * CH0 - 0.062 * CH1 * ((CH1/CH0)^1/4)
case IS >0.5,<=0.61
lux = 0.0224 * CH0 - 0.031 * CH1
case IS >0.61, <=0.8
lux = 0.0128 * CH0 - 0.0153 * CH1
case IS >0.8, <=1.3
lux = 0.00146 * CH0 - 0.00112 * CH1
case else
lux = 0
end select
if useresult then 'skip the first result after gain change
print "ADC count visible + IR=",CH0;
print " ADC count IR only=",CH1;
print " converts to ",lux," Lux"
else
useresult=1 'enable for next time
endif
endif
end sub
 
bigfix
Senior Member

Joined: 20/02/2014
Location: Austria
Posts: 124
Posted: 09:15am 23 Mar 2016
Copy link to clipboard 
Print this post

Great - saves me a lot of time !
I was just going to add one to my shade control

Minor Correction
I assume it is the TSL2561 - not TLS2561Edited by bigfix 2016-03-24
 
lew247

Guru

Joined: 23/12/2015
Location: United Kingdom
Posts: 1676
Posted: 09:41am 23 Mar 2016
Copy link to clipboard 
Print this post

Thanks matherp
It's just what I needed

Out of curiousity do you think there's be an easy way to measure just the UV light?
ie so it can show the uv index?
or would I need to get a Si1145 as well?Edited by lew247 2016-03-24
 
matherp
Guru

Joined: 11/12/2012
Location: United Kingdom
Posts: 8648
Posted: 12:36pm 23 Mar 2016
Copy link to clipboard 
Print this post

  Quote  Out of curiousity do you think there's be an easy way to measure just the UV light?


The TSL2561 just measures visible and IR. It has no capability of measuring UV
 
matherp
Guru

Joined: 11/12/2012
Location: United Kingdom
Posts: 8648
Posted: 10:24pm 23 Mar 2016
Copy link to clipboard 
Print this post

HankR sent me a PM about this code and prompted me to have another look at the datasheet as the LUX limitations in my code don't seem to correspond to the Adafruit materials.

I think I have a x16 scale problem but it is difficult to tell from the datasheet.

The key equation is:

lux = 0.0304 * CH0 - 0.062 * CH1 * ((CH1/CH0)^1/4)

assuming the IR measurement is 0 then this can be simplified to:

lux = 0.0304 * CH0

so the absolute limit on lux given a 16-bit ADC would be 65535 * 0.0304 = 1992

This is with gain = 1x

However, reading the datasheet again and looking at the Adafruit code it appears they are treating the 16x gain mode as default and 1x gain as dividing the reading by 16 rather than the other way round as assumed in my code. Changing this makes the maximum lux reading:

65535 * 0.0304 / (1/16) = 26592

This makes more sense to the usability of the device so to make this change in the code just substitute these lines for the originals.

NB this still won't deal with light levels seen in normal outdoor sunshine

dim float CH1,CH0,lux,gain=0.0625



sub TLS2561int
i2c write TLSaddr,1,1,TLSCMD OR TLSDATA0LOW
i2c read TLSaddr,0,1,C0datalow
i2c write TLSaddr,1,1,TLSCMD OR TLSDATA0HIGH
i2c read TLSaddr,0,1,C0datahigh
CH0=(C0datahigh*256 + C0datalow)/gain
i2c write TLSaddr,1,1,TLSCMD OR TLSDATA1LOW
i2c read TLSaddr,0,1,C1datalow
i2c write TLSaddr,1,1,TLSCMD OR TLSDATA1HIGH
i2c read TLSaddr,0,1,C1datahigh
CH1=(C1datahigh*256 + C1datalow)/gain
i2c write TLSaddr,0,2,TLSCMD OR TLSCLEAR OR TLScontrol,TLSPOWER 'clear the interrupt
if CH0*gain < 500 and gain = 0.0625 then 'switch to low light
i2c write TLSaddr,0,2,TLSCMD OR TLStiming,TLSINTEG402 OR TLSHIGHGAIN 'switch to high gain
useresult=0
gain=1.0
Print "Switching to high gain"
elseif CH0*gain > 10000 and gain = 1.0 then 'switch to normal light
i2c write TLSaddr,0,2,TLSCMD OR TLStiming,TLSINTEG402 OR TLSLOWGAIN 'switch to high gain
useresult=0
gain=0.0625
Print "Switching to low gain"
else
select case CH1/CH0 'normal processing
case IS > 0,<=0.5
lux = 0.0304 * CH0 - 0.062 * CH1 * ((CH1/CH0)^1.4)
case IS >0.5,<=0.61
lux = 0.0224 * CH0 - 0.031 * CH1
case IS >0.61, <=0.8
lux = 0.0128 * CH0 - 0.0153 * CH1
case IS >0.8, <=1.3
lux = 0.00146 * CH0 - 0.00112 * CH1
case else
lux = 0
end select
if useresult then 'skip the first result after gain change
print "ADC count visible + IR=",CH0;
print " ADC count IR only=",CH1;
print " converts to ",lux," Lux"
else
useresult=1 'enable for next time
endif
endif
end sub

Edited by matherp 2016-03-25
 
lew247

Guru

Joined: 23/12/2015
Location: United Kingdom
Posts: 1676
Posted: 04:36am 11 May 2016
Copy link to clipboard 
Print this post

IF it helps, I found this Bascom code
It "should" be relatively easy to modify for the Micromite but I don't have enough knowledge to do it

[code]$ Sim

$ Regfile = "m8def.dat '' for use microcontroller
$ Crystal = 8000000 'clock

$ Hwstack = 40 'Hardware Stack
$ Swstack = 32 'SW Stack
$ Frame size = 60 'Frame

$ Baud = 9600

Waitms 250

Declare Sub POWER_UP 'enable TSL2561
Declare Sub Power_down 'disable TSL2561
Read Declare Sub GET_DATA 'data from TSL2561 (Read Word Protocol)
Declare Sub Calclux 'Lux calculate values
Send Declare Sub output 'values ??via UART
Declare Sub Control_ack 'Check whether ACK has been received
Declare Sub Lux_1 'first part Lux Calculation
Declare Sub Lux_2 'second part Lux Calculation
Declare Sub Lux_ges' Lux1 - Lux2 (see data sheet "Calculating lux")

Led Alias ??Portd.5 'LED lights = TSL2561 powered up
Config Led = Output
Led = 0

Config = Sda Portc.4
Config Scl = Portc.5

Config I2cdelay = 10

I2cinit

Dim Slave Address As Byte
Dim Lux1 As Single
Lux1 = 0
Dim Lux2 As Single
Lux2 = 0
Dim Lux As Single
Lux = 0
Dim Ctrl As String * 10

Dim C0low As Byte
Dim C0high As Byte
Dim C0 As Word
Dim C1low As Byte
Dim C1high As Byte
Dim C1 As Word
Dim C As Single

Dim Y1 As Single
Dim Y2 As Single

'' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' ''70
'' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' ''
'' I2C bus scan and output slave addresses ''
'' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' ''
'' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' ''

Print "I2C slave"
Print "Looking for ..."
Wait 2

For slave address = 0 To 254 Step 1 'for all straight (Step2) / odd and even (Step1) addresses
Send I2cstart 'start condition
Send I2cwbyte slave address' Address

If Err = 0 Then 'I2C slave found? (ACK received?)
Print "Slave dec"; slave address
Print "h"; Hex (slave address); "B"; Bin (slave address)
Wait 2
End If

Releasing I2cstop 'Bus
Next

Print "end scanning"
Wait 2

'' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' ''70
'' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' ''
'' Main Loop: Calculate values, calculate and output '
'' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' ''
'' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' ''

do

I2cinit
power_up
Waitms 50
get_data
Waitms 50
Power_down
Calclux
output

loop

End



Sub POWER_UP

I2cstart
I2cwbyte & H72 'device address

Ctrl = "POWER_UP"
Control_ack

I2cwbyte & H80
I2cwbyte & H03 'Power up device
I2cstop
Led = 1
End Sub


Sub Power_down

I2cstart
I2cwbyte & H72 'device address
I2cwbyte & H80
I2cwbyte & H00 'Power down device
I2cstop
Led = 0
End Sub


'' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' ''70
'' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' ''
'Read data from the ADC register the sensor' ''
'' (I2C Read Word Protocol) ''
'' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' ''
'' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' ''
Sub gET_DATA

Waitms 420 'Integration Time max.402ms
I2cstart
I2cwbyte & H72 'device address

Ctrl = "GET_DATA"
Control_ack

I2cwbyte & HAC
I2cstop
I2cstart
I2cwbyte & H73 'device address + 1 (read)
I2crbyte C0low, Ack
I2crbyte C0high, Nack
I2cstop

I2cstart
I2cwbyte & H72 'device address
I2cwbyte & HAE
I2cstop
I2cstart
I2cwbyte & H73 'device address + 1 (read)
I2crbyte C1low, Ack
I2crbyte C1high, Nack
I2cstop

C0 = Makeint (c0low, C0high)
C1 = Makeint (c1low, C1high)
End Sub


'' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' ''70
'' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' ''
'' Calculate Lux value (see data sheet "Calculating lux") ''
'' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' ''
'' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' ''
Sub Calclux

C = C1 / C0
If C> 0 And C <= 0.5 Then

Y1 = 0.0304
Lux_1

Lux2 = C1 / C0
Lux2 = Lux2 ^ 1.4
Lux2 = Lux2 * C0
Lux2 = Lux2 * 0.062

Lux_ges

Elseif C> 0.5 And C <= 0.61 Then

Y1 = 0.0224
Lux_1
Y2 = 0.031
Lux_2

Lux_ges

Elseif C> 0.61 And C <= 0.8 Then

Y1 = 0.0128
Lux_1
Y2 = 0.0153
Lux_2

Lux_ges

Elseif C> 0.8 And C <= 1.3 Then

Y1 = 0.00146
Lux_1
Y2 = 0.00112
Lux_2

Lux_ges

else

Lux = 0

End If
End Sub


'' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' ''70
'' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' ''
'' Read ADC Channel0 / Channel1 values ??and calculated lux value ''
'' Via UART Send ''
'' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' ''
'' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' ''
Sub output

Print "C0 value"; C0
Print "C1 value"; C1
Print "Lux"; lux
End Sub


'' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' ''70
'' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' ''
'' Check whether an ACK from the slave came back ''
'' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' ''
'' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' ''
Sub Control_ack

If Err = 0 Then
Print Ctrl; "ACK"
else
Print Ctrl; "NACK"
End If
End Sub


Sub Lux_1

Lux1 = Y1 * C0
End Sub


Sub Lux_2

Lux2 = Y2 * C1
End Sub


Sub Lux_ges

Lux = Lux1 - Lux2
End Sub[/code]
 
matherp
Guru

Joined: 11/12/2012
Location: United Kingdom
Posts: 8648
Posted: 06:39am 11 May 2016
Copy link to clipboard 
Print this post

  Quote  IF it helps, I found this Bascom code
It "should" be relatively easy to modify for the Micromite but I don't have enough knowledge to do it


The code I posted works properly. The only question was whether the "default" scaling was x1 or x16. I think based on a further reading of the datasheet and Hank's comments that it is x16 hence the second version of the subroutine should be used.

Lew - please also check the PM from me
 
lew247

Guru

Joined: 23/12/2015
Location: United Kingdom
Posts: 1676
Posted: 07:15am 11 May 2016
Copy link to clipboard 
Print this post

ah, after a third pm I found the problem
I actually replied to you earlier today and also sent you a message 2 weeks ago
[code]matherp has exceeded the maximum number of Private Messages they are allowed to receive[/code]
 
matherp
Guru

Joined: 11/12/2012
Location: United Kingdom
Posts: 8648
Posted: 07:27am 11 May 2016
Copy link to clipboard 
Print this post

  Quote  ah, after a third pm I found the problem


That is bizarre, I was sure I cleared them out and they seem to have re-appeared. Anyway cleared again so there should be room now.Edited by matherp 2016-05-12
 
Phil23
Guru

Joined: 27/03/2016
Location: Australia
Posts: 1664
Posted: 12:59pm 11 May 2016
Copy link to clipboard 
Print this post

Following this with interest.

I'm interested in measuring energy falling on my Solar water panels.

As mentioned in this thread, I,m just using a garden light solar panel ATM, not the ideal choice, but it has been connected to a LCD panel meter for a few weeks now and it's surprising how close to the Real solar meter it's readings are.
Just based on voltage alone without doing any power calculations.

I have a few other light sensors I planned to try, but to day this solutions is working well.

I also own a few high end photographic exposure meters, and can add that they all employ some sort of optical attenuation in their outdoor reading modes.

Not so much a Neutral density filter (as in grey glass), more the density of the white dome over the sensor & it's thickness.

Two of them are actually supplied with 2 domes. (German Gossen meters).

This page is worth a read on light, Lux etc.

Exposure Values

Cheers.

 
lew247

Guru

Joined: 23/12/2015
Location: United Kingdom
Posts: 1676
Posted: 10:34pm 21 Jun 2016
Copy link to clipboard 
Print this post

I've just seen the comment in red in Matherp's original post above

I found this on the module - is it right or wrong?

[quote]The TSL2561 luminosity sensor is an advanced digital light sensor, ideal for use in a wide range of light situations. Compared to low cost CdS cells, this sensor is more precise, allowing for exact lux calculations and can be configured for different gain/timing ranges to detect light ranges from up to 0.1 - 40,000+ Lux on the fly. The best part of this sensor is that it contains both infrared and full spectrum diodes! That means you can separately measure infrared, full-spectrum or human-visible light. Most sensors can only detect one or the other, which does not accurately represent what human eyes see (since we cannot perceive the IR light that is detected by most photo diodes)[/quote]

0.1 - 40,000+ Lux on the fly
The best part of this sensor is that it contains both infrared and full spectrum diodes!
That means you can separately measure infrared, full-spectrum or human-visible light.
 
Print this page


To reply to this topic, you need to log in.

© JAQ Software 2024