How to: Light to Frequency Converter - TSL235R?

I would like to know how to wire and use this light-to-frequency converter sensor (TSL235R):

The datasheet explains how to wire it: Vcc to 5V, GND to GND, with a 0.1uF (to 0.01uF) capacitor between ground and Vcc. The OUT leg goes to the micro-controler unit (Page 5 of the datasheet):

However, i have a lot of questions...:

  1. what is this pin in the arduino (analog 5, analog 4, or any other digital or analog pin?
  2. how to obtain data from it?

I think that it should not be so much different from this other sensor TSL230R (Arduino and the Taos TSL230R Light Sensor: Getting Started | The Roaming Drone) although may be something different since it only have one data leg and not as much outs as the TSL230R.

So, any idea about how to wire it to arduino and how to extract interesting data from this sensor?
Thanks!

what is this pin in the arduino

use any of the digital pins set for an input.

how to obtain data from it?

Use the pulse in function to measure the frequency and hence the light level.

Connect it to one of the IRQ lines so you don't miss any pulse.

long count = 0;
long threshold = 100;

void setup()
{
  attachInterrupt(0, MyIRQ, CHANGE);
}

void loop()
{
  ...
  if (count > threshold)
  {
     // do some action
     // ...
     count = 0;  // reset the counter
  }
}

void MyIRQ()
{
  count++;
}

Thanks to both!

Just only one question: what are the IRQ lines?
Thanks!

digital pin2 is IRQ 0
digital pin3 is IRQ 1

I see. Thanks! i will try soon.
Cheers!

Two issues with the code example:

First the long count = 0; should be modified to: volatile long count = 0; as the per this reference: http://arduino.cc/en/Reference/Volatile

Second is your use of an long for the count variable. As it is a four byte variable it is possible that the value can change between the main loops reading of the variable as an interrupt can happen between the fetching of the variable's value in the main loop. While this is not frequent event, it can lead to a very hard to find 'bug'. If you require a longer then byte variable that is going to be changed inside a ISR function, then one should surround the reading of the variable with interrupts() and noInterrupts() functions to force the variable read to be 'atomic'. http://arduino.cc/en/Reference/NoInterrupts

volatile long count = 0;
long threshold = 100;

void setup()
{
attachInterrupt(0, MyIRQ, CHANGE);
}

void loop()
{
...
noInterrupts;
if (count > threshold)
{

// do some action
// ...
count = 0; // reset the counter
interrupts();
}
}

void MyIRQ()
{
count++;
}

Lefty

thanx,

point 1 volatile: agree 100%
point 2 : disabling IRQ implies possible loss of pulses; How bad is that? depends....
At least if you disable the IRQ's it should be as short as possible. e.g. only around the line count =0;

And yes the value of count might change during the loop, so working with a copy might be needed.

Hi,

I am writing a complete code to start to test this sensor.

I copied your code (retrolefty), and it return an error.
(Yes, i know that your code is not complete, just only an idea, but is my starting point. I exteded the code, but the error is related to the basic code)
"nointerrupts" is highlighted and this message appear on arduino IDE:
"In function 'void loop()':
error: 'noInterrupts' was not declared in this scope"

Any idea?

[edit]Ok, i reply to my self. Reading the reference from the arduino webpage, it must be "nointerrupts()" and not "nointerrupts". So this part is solved. I will prepare the code and share it here. Thanks[/edit]

Here is the example code in which i am working. For the moment it only reads the signal from the sensor. It is still not converted to irradiance.

/* Example: TSL235R
   Collaborative ideas from:
   retrofelty, robtillaart, Gumpy_Mike, and madepablo
   
   Wiring:
   TSL235R    Arduino pins
   GND        GND
   Vcc        +5V
   Out        Digital pin 2
   Wire a 0.1uF capacitator between Vcc and GND
*/

// Pin definitions
# define Sensor 2

// Variables
volatile long count = 0;   // Counter of measurements of the TSL235R
long threshold = 100;      // Minimum of measurements
long counter = 0;          // Counter of measurements during the test
int frequency;             // Read the frequency from the digital pin

void setup()
{
  Serial.begin(9600);                           // Start and configure the serial port
  pinMode(frequency, INPUT);                    // Declare the pin such as an input of data
  attachInterrupt(0, MyIRQ, CHANGE);
  Serial.println("Testing a TSL235R sensor:");  // Splash screen
  Serial.println("-------------------------");
  Serial.println();  
}

void loop()
{
 counter = counter + 1;       // Increase the number of measurement
 noInterrupts();
 if (count > threshold)
 {
   frequency=digitalRead(Sensor);  // Read the sensor
   Serial.print(counter);     // Print the measurement number
   Serial.print("  ");
   Serial.println(frequency); // print the signal
   count = 0;                 // reset the counter
   interrupts();  
 }
 delay (1000);               // wait 1 seconds until the next measurement
}

void MyIRQ()
{
 count++;
}

Binary sketch size: 3138 bytes

However, the code is not correct, since what it produces is:

Testing a TSL235R sensor:

1 1
2 0
3 0
4 1
5 0
6 1
7 0
8 1
9 0
10 1

I will read different posts about other sensor (TSL230R) in order to see how should i modify the code:

Updates coming soon...

Ok, second round!

I saw this other code for TSL230R:

I taked this idea to modify the first code a little bit to apply it to the TSL235R, and it seems to run.

This is the code of my second try:

/* Example: TSL235R
   Collaborative ideas from:
   retrofelty, robtillaart, Gumpy_Mike, and madepablo
   
   Sensor:
   http://www.sparkfun.com/datasheets/Sensors/Imaging/TSL235R-LF.pdf
   measurement area: 0.92mm2
   
   Wiring:
   TSL235R    Arduino pins
   GND        GND
   Vcc        +5V
   Out        Digital pin 2
   Wire a 0.1uF capacitator between Vcc and GND close to the sensor
*/

// Pin definitions
# define TSL235R 2                      // Out of TSL235R connected to Digital pin 2

// Constants
int period = 1000;                     // Miliseconds of each light frecuency measurement
int ScalingFactor = 1;                 // Scaling factor of this sensor
float area = 0.0092;                   // Sensing area of TSL235R device (cm2)

// Variables
unsigned long counter = 0;             // Counter of measurements during the test
unsigned long currentTime = millis();  
unsigned long startTime = currentTime; 
volatile long pulses = 0;              // Counter of measurements of the TSL235R
unsigned long frequency;               // Read the frequency from the digital pin (pulses/second)
float irradiance;                      // Calculated irradiance (uW/cm2)


void setup() {
  Serial.begin(9600);                           // Start and configure the serial port
  attachInterrupt(0, PulseCount, RISING);
  pinMode(TSL235R, INPUT);                    // Declare the pin such as an input of data
  Serial.println("Testing a TSL235R sensor:");  // Splash screen
  Serial.println("-------------------------");
  Serial.println();  
}

void loop(){
  counter++;                           // Increase the number of measurement
  Serial.print(counter);               // Print the measurement number
  getfrequency();                      // Request to measure the frequency
  Serial.print("  ");
  Serial.print(frequency);             // print the frequency (pulses/second)
  Serial.print(" pulses/second    ");
  getirradiance();                     // Request to calculate the irradiance (uW/cm2)
  Serial.print("  ");
  Serial.print(irradiance);             // print the frequency (pulses/second)
  Serial.println(" uW/cm2");
  pulses = 0;                          // reset the pulses counter
  delay (4000);                        // wait 4 seconds until the next measurement
}


void PulseCount()
{
 pulses++;
}

unsigned long getfrequency () {
  noInterrupts();
  frequency = pulses /(period/1000);    // Calculate the frequency (pulses/second)
  interrupts();
  return (frequency);
}

float getirradiance () {
  irradiance = frequency / area;      // Calculate Irradiance (uW/cm2)
  return (irradiance);
}

Binary sketch size: 4556 bytes

And those are some results:

Testing a TSL235R sensor:

1 829 pulses/second 90108.70 uW/cm2
2 58078 pulses/second 6312826.00 uW/cm2
3 58699 pulses/second 6380326.00 uW/cm2
4 59522 pulses/second 6469782.50 uW/cm2
5 60496 pulses/second 6575652.00 uW/cm2
6 61998 pulses/second 6738913.00 uW/cm2
7 63468 pulses/second 6898695.50 uW/cm2
8 65027 pulses/second 7068152.00 uW/cm2
9 66750 pulses/second 7255434.50 uW/cm2
10 68678 pulses/second 7465000.00 uW/cm2
11 63612 pulses/second 6914347.50 uW/cm2
12 69222 pulses/second 7524130.50 uW/cm2
13 73932 pulses/second 8036087.00 uW/cm2
14 75284 pulses/second 8183043.50 uW/cm2
15 76368 pulses/second 8300869.50 uW/cm2
16 76559 pulses/second 8321630.50 uW/cm2
17 76397 pulses/second 8304021.50 uW/cm2
18 76609 pulses/second 8327065.00 uW/cm2
19 76452 pulses/second 8310000.00 uW/cm2
20 76103 pulses/second 8272065.00 uW/cm2
21 75690 pulses/second 8227173.50 uW/cm2
22 75322 pulses/second 8187173.50 uW/cm2
23 75044 pulses/second 8156956.50 uW/cm2
24 74896 pulses/second 8140869.50 uW/cm2
25 28622 pulses/second 3111087.00 uW/cm2
26 11296 pulses/second 1227826.00 uW/cm2
27 10381 pulses/second 1128369.50 uW/cm2
28 10275 pulses/second 1116847.75 uW/cm2
29 63848 pulses/second 6940000.00 uW/cm2
30 76921 pulses/second 8360978.00 uW/cm2
31 77279 pulses/second 8399891.00 uW/cm2
32 76754 pulses/second 8342826.00 uW/cm2
33 78276 pulses/second 8508261.00 uW/cm2
34 78996 pulses/second 8586522.00 uW/cm2
35 80594 pulses/second 8760217.00 uW/cm2
36 82096 pulses/second 8923478.00 uW/cm2
37 83554 pulses/second 9081956.00 uW/cm2
38 85081 pulses/second 9247935.00 uW/cm2
39 86520 pulses/second 9404348.00 uW/cm2
40 87924 pulses/second 9556956.00 uW/cm2

I saw a lot of fluctuations and a clear increase in pulses/second in few seconds, so is it normal?
May be is better to calculate it along 5 seconds and return an average value?

I am interested on measurements time to time, not continuous, so may be it is better??

I will modify a little bit the code in order to express the results in Hz, KHz, MHz... and also in W/m2 depending of the results in each moment.

Any other ideas about this code or how to improve it?
Thanks

If I was starting such a project I think I might try to use an existing proven frequency counter library as a starting point, rather then roll my own. Just a thought.

http://interface.khm.de/index.php/lab/experiments/arduino-frequency-counter-library/

Lefty

Ummh! Good point Lefty.

However, it made me ask more things... TSL235R should be connected to pin 2 (or pin3) or to pin 5 to use this library according to the information provided in the link?

Is it necessary extra hardware (amplifiers proposed in the webpage) to obtain accurate data from this sensor? or not in the case of this sensor?

What is the compensation? and how it runs?

I think that this library could be great if it increase the accuracy of the lecture. However, it could be an small problem if it is necessary extra hardware, and if it increase so much the bytes of the final code. In any case, i will explore this option to see whats happend.

Thanks Lefty for the link!

Is it necessary extra hardware (amplifiers proposed in the webpage) to obtain accurate data from this sensor? or not in the case of this sensor?

Not the case for this sensor, it already outputs TTL logic voltages. The input conditioning circuits show are for when you are trying to measure low level analog signals.

What is the compensation? and how it runs?

I haven't used this library yet, but the compensation function seems to allow for small digital trimming factor used to make small calibration corrections if desired. Probably something you can ignore.

Lefty

Thanks Lefty,

I was checking yesterday the library, and it doesn´t run for me. Ok, at least the examples. I downloaded the library and the example, and i tested it. The examples (this one from the webpage and the other that could be downloaded) does do anything except to write the first line in the serial monitor, but no data.

I tested quickly so i assume that the problem is the wiring of my sensor. I will try again in few days to see if i could obtain something from this library.

Thanks for your answers!

I tested both sensors, TSL230R and the TSL235R, and the results are not comparable at all.

So, i assume that the previous code that i posted here for the TSL235R is not correct. Let me study in detail the code and rewrite it... soon.

[edit]Just only one question:

In the datasheet of both TSL235R and TSL230R, Figure 1 shows that 10KHz is about (not exactly, but just for discussion is enough) 10uW/cm2. So now it let me think... those 10uW/s are acorrected to 1cm2 sensing area?

What i mean is... if i obtain a measurement of 10kHz just only measuring the pulses and dividing by the time in seconds, does it means that i have 10uW/cm2? or i need to correct the 10Khz to about 108KHz assuming a 0.0092cm2 sensing area?

Any idea? Thanks![/edit]

Here are the datasheets:

TSL230R http://www.sparkfun.com/datasheets/Sensors/TSL230R-LF-e3.pdf
TSL235R http://www.sparkfun.com/datasheets/Sensors/Imaging/TSL235R-LF.pdf

Okay,

I made a new version of the code to read the TSL235R:

/* Example: TSL235R
  
   Sensor:
   http://www.sparkfun.com/datasheets/Sensors/Imaging/TSL235R-LF.pdf
   Measurement area: 0.92mm2
   
   Wiring:
   TSL235R    Arduino pins
   GND        GND
   Vcc        +5V
   Out        Digital pin 2
   Wire a 0.1uF capacitator between Vcc and GND close to the sensor
   Wire a led between pin 13 and GND
*/

// Pin definitions
# define TSL235R 2                   // Pin to TSL235R output
# define LEDpin 13                   // Led to show when the sensors is measuring

// Constants
int period = 2000;                   // measurement period, in miliseconds
int ScalingFactor = 1;               // Scaling factor of this sensor
float area = 0.0092;                 // Sensing area of TSL25R device, in cm2

// Variables
unsigned long counter = 0;           // Counter of measurements
volatile unsigned long pulses = 0;   // Counter pf pulses in each measurement period
unsigned long frequency;             // Store the frequency calculated
float irradiance;                    // Store the irradiance calculated
unsigned long startTime;             // Stablish the time when measurement starts
unsigned long currentTime;           // Used to measure the time during measurement
 

void setup(){
  Serial.begin(9600);    // Starts the serial port
  pinMode(TSL235R, INPUT);                    // Declare the pin such as an input of data
  pinMode(LEDpin, OUTPUT);
  Serial.println("Testing a TSL235R sensor:");  // Splash screen
  Serial.println("-------------------------");
  Serial.println(" v0.2      20100720");  
  Serial.println();
}

void loop(){
  digitalWrite(LEDpin, HIGH);
  counter++;
  Serial.print(counter);
  Serial.print("   ");
  startTime = millis();
  currentTime= millis();
  while (currentTime - startTime <= period){
    attachInterrupt(0, count_pulses, RISING);
    //detachInterrupt(0);                          // Stop to sensing pulses from TSL235R sensor
  }
  digitalWrite(LEDpin, LOW);
  Serial.print("pulses: ");
  Serial.print(pulses);
  Serial.print(";  ");
  Serial.print("frequency: ");
  Serial.print(getfrequency(), DEC);
  Serial.print("  Hz;  ");
  Serial.print("irradiance: ");
  Serial.print(getirradiance(), DEC);
  Serial.println("  uW/cm2");
  pulses = 0;                                   // Reset the pulses counter for the next measurement
  delay(5000);                                  // Wait 5 seconds until next measurement
}

void count_pulses()
{
 pulses++;
 currentTime=millis();
}
 

unsigned long getfrequency(){
 frequency = pulses/(period/1000);
 return(frequency);
}

long getirradiance() {
  irradiance = frequency / area;                // Calculate Irradiance (uW/cm2)
  return (irradiance);
}

it is 4210 bytes.

and here is and example of the results:

Testing a TSL235R sensor:

v0.2 20100720

1 pulses: 4800; frequency: 2423 Hz; irradiance: 263369 uW/cm2
2 pulses: 16850; frequency: 8448 Hz; irradiance: 918260 uW/cm2
3 pulses: 16698; frequency: 8373 Hz; irradiance: 910108 uW/cm2
4 pulses: 16709; frequency: 8378 Hz; irradiance: 910652 uW/cm2
5 pulses: 16807; frequency: 8427 Hz; irradiance: 915978 uW/cm2
6 pulses: 17101; frequency: 8574 Hz; irradiance: 931956 uW/cm2
7 pulses: 16581; frequency: 8314 Hz; irradiance: 903695 uW/cm2
8 pulses: 16592; frequency: 8319 Hz; irradiance: 904239 uW/cm2
9 pulses: 16530; frequency: 8285 Hz; irradiance: 900543 uW/cm2
10 pulses: 15568; frequency: 7807 Hz; irradiance: 848586 uW/cm2
11 pulses: 16450; frequency: 8248 Hz; irradiance: 896521 uW/cm2
12 pulses: 25021; frequency: 12535 Hz; irradiance: 1362500 uW/cm2
13 pulses: 1145288; frequency: 572674 Hz; irradiance: 62247172 uW/cm2
14 pulses: 24702; frequency: 12378 Hz; irradiance: 1345434 uW/cm2
15 pulses: 229165; frequency: 114604 Hz; irradiance: 12456956 uW/cm2
16 pulses: 855675; frequency: 427856 Hz; irradiance: 46506084 uW/cm2
17 pulses: 1901801; frequency: 950916 Hz; irradiance: 103360432 uW/cm2
18 pulses: 11109; frequency: 5571 Hz; irradiance: 605543 uW/cm2
19 pulses: 12433; frequency: 6233 Hz; irradiance: 677500 uW/cm2

it seems to run (although i still didn´t check with TSL230R). However, there is one problem. When the light is intense (i tested taking so near a red led), the lecture take infinite time.... it does not stop to measure until to move a little bit the led far from the sensor... any idea? it is a problem of the code i assume.... but i don´t know where.

Your ideas are welcome. Thanks!

IF you are hooking the pin up to the interrupt, when the chip is put in a bright area the frequency may become so great that it trips the interrupt fast enough to freeze the rest of your code. I have several light meters made with these chips and I created a routine to adjust the sensitivity and frequency division to keep the interrupt frequency between 300Hz and about 7kHz. When I have tried running without the auto-scaling code, it would definitely freeze up the rest of my code when I took the chip outside. I could get you numbers, but I would guess the chip goes into MHz range frequencies if you leave it on max sensitivity and no frequency division.

This is why the new, smaller version on sparkfun is probably not very useful for use as a light meter that must cover a very wide range of brighnesses. I like the small package, but I think the frequency division and sensitivity adjustment is probably necessary for the most part.

Thanks Bettersense,

I see the problem.. i also love this small device TSL235R, because the TSL230R (what is really complete and more accurate) needs a lot of pins in my arduino duemilanove... what i don´t have. May i could solve it by the use of shift registers, but i don´t know.

In any case, thanks so much for your clear explanation.

Cheers,

I've gotten this to work pretty well, but unfortunately not for my purposes, yet.

I adopted someone elses code to do the pulse counting in the interrupt & poll it periodically to get the counts, or freq, etc.

I'm graphing in Processing, again adopting someone elses code, and outputting the various values such as pulse count, time elapsed, etc.

The light levels are fine, although I'm working indoors. I need it accurate at a temporal resolution of about 10 or 20 msec & for fairly subtle light level changes. It's pretty clean, but I get these odd spikes semi-periodically. I'm trying to clean it up, by creating a buffer of prior samples & trying to throw out the bad ones.

I'm using an infrared led on it, powered by the board.

The brighter the light, the bigger the spikes, so it seems to be inherent noise that gets amplified. Although the spiking seems different, depending on the light source.

The strange thing is, that the noise spikes seem to increase whenever the light level stays constant, which is bad for my project.

I wanted to post a couple of pics, but it said I couldn't on my first post, so hopefully the pics will follow this post.