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...:
what is this pin in the arduino (analog 5, analog 4, or any other digital or analog pin?
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
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.
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:
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);
}
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.
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.
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.
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.
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?
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 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.
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.
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.
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.