Go Down

Topic: Measure nightsky with TSL237 (Read 12 times) previous topic - next topic

robtillaart

the .x part error must be seen through "logarithmic glasses"

log(10) = 1
log(11) = 1.041392685
so if the value is around 10 and the math does truncating, the max error is 4% log(10.999999) - log(10)
if the math does rounding, the max error is < 2.2% log(10.499999) - log(10)

log(100) = 2
log(101) = 2.004321374
=> error is max 0.43% ( trunc => 0.22%)

log(1000) = 3
log(1001) = 3.000434077
=> 0.05%

at 10000 it will be max ~0.005%

Rob Tillaart

Nederlandse sectie - http://arduino.cc/forum/index.php/board,77.0.html -
(Please do not PM for private consultancy)

GoForSmoke


I understand that i will lose the .x count of the pulses if the time runs out :)


If you count a certain number of pulses and then see the time, it will be the fraction of a usec that you miss, not a fraction of the much-longer pulse. So in the interrupt routine, we count pulses and get whole pulses that way (detail: have to get start time on a pulse, then count pulses and on the last get end time) and not lose the bigger (pulse is way longer than usec) fraction.
I find it harder to express logic in English than in Code.
Sometimes an example says more than many times as many words.

Corpze



I understand that i will lose the .x count of the pulses if the time runs out :)


If you count a certain number of pulses and then see the time, it will be the fraction of a usec that you miss, not a fraction of the much-longer pulse. So in the interrupt routine, we count pulses and get whole pulses that way (detail: have to get start time on a pulse, then count pulses and on the last get end time) and not lose the bigger (pulse is way longer than usec) fraction.



So, to measure the time between a certain no of pulses, can i use the PulseIn? PulseIn uses just High or Low on a digital pin, I really want to use Rising or something like that?

robtillaart

NO pulse in measures one pulse.

with an IRQ based counter you can count X pulses in e.g. 10.000.000 microseconds and use that

something like this,
Code: [Select]

void setup()
{
  Serial.begin(38400);
  attachInterrupt(0, ISR, RISING);
}
void loop()
{
  unsigned long start = micros();
  interrupts();
  while (micros() - start < 10000000UL); // wait 10 seconds
  noInterrupts();
 
  Serial.println(count);
  count = 0;
}

void ISR()
{
  count++;
}

 
Rob Tillaart

Nederlandse sectie - http://arduino.cc/forum/index.php/board,77.0.html -
(Please do not PM for private consultancy)

GoForSmoke


No i havenĀ“t really used interrupts more then those that allready have been written in existing code... I have read the reference about interrupts and there are two kinds? internal and external? the external ones are located on pin2 and 3 on the uno. Is one of those inputs usable for me?


Okay. You will be using external interrupt on pin 2 or 3 since you want to detect the starting edge of the pulse.

Quote
I think 10sec will be the highest time i want to measure (the original SQM-meter measures on 2sec)

So 10000ms of measurements is a number i can start with.


Just as long as you have a time to aim for. What is reasonable, the data will show like if 1 second consistently gets very close to 10 seconds then 1 second will be good. And if less then that will be good. Of course if 10 seconds does not give consistent values then there is a problem.

I find it harder to express logic in English than in Code.
Sometimes an example says more than many times as many words.

Corpze

Ok, the bits and pieces are starting to fall in place now :)

I will look in to the example sketch and try that when i have the time to do that, after a given no time (10 sec) i will be able to read the count of pulses in the serial monitor, how will i translate that in to Hz? or am i stepping ahead to fast now?

robtillaart


if you have x pulse in 10 seconds that makes  x/10  Hz
Rob Tillaart

Nederlandse sectie - http://arduino.cc/forum/index.php/board,77.0.html -
(Please do not PM for private consultancy)

Corpze

Ok, thanks, i will give this a try!

robtillaart

update :)
Code: [Select]

void loop()
{
  unsigned long start = micros();
  interrupts();
  while (micros() - start < 10000000UL); // wait 10 seconds
  noInterrupts();
 
  Serial.print(count/10);
  Serial.print(".");
  Serial.print(count%10);
  Serial.println("Hz");
  count = 0;
}

Rob Tillaart

Nederlandse sectie - http://arduino.cc/forum/index.php/board,77.0.html -
(Please do not PM for private consultancy)

Corpze


update :)
Code: [Select]

void loop()
{
  unsigned long start = micros();
  interrupts();
  while (micros() - start < 10000000UL); // wait 10 seconds
  noInterrupts();
 
  Serial.print(count/10);
  Serial.print(".");
  Serial.print(count%10);
  Serial.println("Hz");
  count = 0;
}




Why UL on the micros?

robtillaart

the ul makes the compiler interpret the number as unsigned long.
Rob Tillaart

Nederlandse sectie - http://arduino.cc/forum/index.php/board,77.0.html -
(Please do not PM for private consultancy)

GoForSmoke


NO pulse in measures one pulse.

with an IRQ based counter you can count X pulses in e.g. 10.000.000 microseconds and use that

something like this,


May I suggest a change or two?

I base how I get start and end time on the pulses being expected to come in at less than 10 kHz. Far less, possibly 100's of millis apart, but I'd like to see if this can handle brighter light too.  

Anyway, this is more what I had in mind:

Code: [Select]

volatile unsigned long pulseCount = 0UL;
unsigned long startT, endT, freq, pC;

void counter()
{
 pulseCount++; // counting pulses
}

void setup()
{
 Serial.begin(38400);
 Serial.println( "Frequency counter" );
 attachInterrupt(0, counter, RISING);
}

void loop()
{
 noInterrupts();
 pC = pulseCount;
 interrupts();
 
 if ( pC == 1UL )
 {
   startT = micros(); // start time very close to on a pulse edge
   // getting end time should have the same lag within a few cycles
 }

 // if pulses are 5/second, 10 seconds will take 50 pulses --- check the 5/sec!
 if ( pC >= 51UL ) // 50 pulses -after- pulse #1 which was used to start time ON a pulse
 {
   endT = micros();

   endT -= startT; // end now holds elapsed micros

   // frequency = pulses/second, we have pulses and microseconds, 1000000 usecs/sec
   // Hz = pulses x 1000000 / microseconds  

   freq = pC * 1000000UL / endT;

   Serial.print( "\n count " );
   Serial.println( pC );
   Serial.print( " micros " );
   Serial.println( endT );
   Serial.print( " freq " );
   Serial.println(freq);

   noInterrupts();
   pulseCount = 0UL;
   interrupts();
 }
}

 
Anyway it compiles and runs but for my test pulses I grounded pin2 through 4.7k ohms and then tapped a jumper (with 5V through a resistor and led) end on the resistor leg connected to the pin.

Maybe it's bounce but I got my pulses without having to tap more than once.

A little debug, it seems I need to copy pulseCount to pC at the speed I got pulses. The math was wrong until I did!



I find it harder to express logic in English than in Code.
Sometimes an example says more than many times as many words.

Corpze

The code seems to work fine and for every 50 (+1) pulse it prints the time it took to gather those 50 pulses right? Is there any way to add a decimal or two to the frequencies (float?)

Code: [Select]
count 51
micros 934564
freq 54

count 51
micros 3450896
freq 14

count 51
micros 8804244
freq 5

count 51
micros 2095280
freq 24

count 51
micros 796124
freq 64

count 51
micros 2395064
freq 21

count 51
micros 975288
freq 52

count 51
micros 13221620
freq 3

count 51
micros 956156
freq 53

minaya

Just change 'unsigned long freq' to 'float freq'.

The problem I see with the interrupt approach is the large range of frequencies that the TSL is able to output. If you try the program at daytime or pointing at a light source (lets say, 500,000Hz, or even more!), maybe that can overflow?, or hang the Arduino and force you to press reset or power it off/on?.

Even at nightime the frequency output can change if the moon is present.

GoForSmoke

Those frequencies are integer pulse per second Hz because of the 1000000 / microseconds part of the math.
They could as easily be pulse per msec by using 1000 / micros and give Hz to 3 places.
The other half of that trick is in placing a decimal point in the printout rather than resorting to floats.

Say I have 1234 pulse/msec in a variable named mFreq and I want to print Hz.
I print mFreq / 1000 and get the integer "1"
and then I print a decimal point.

Then I look at mFreq % 1000 which gives the remainder of mFreq / 1000.
If it's less than 100, I print a zero.
{
  If it's less than 10, I print another zero. Note I only check for < 10 if the value is < 100.
}
Then I print the remainder.

And yes, it can be rounded up or down but you best do that when calculating what you will display.

Remember that display is for looks. Don't let looks dictate substance, they should only reflect it.
On a full-blown PC, I'd go with doubles but with Arduino I go with what works best and happens to be fastest as well. And this time I didn't need to use long-long's for intermediate steps!   

Let me know if you need more. Maybe Rob or someone else won't get there first. My posts are just my attempts to help.

I find it harder to express logic in English than in Code.
Sometimes an example says more than many times as many words.

Go Up