Color Sensor question

Hello,

I have this TCS230 color sensor example code.

It samples color every 4000ms.

I need it to sample at least 10 times faster.

I tried to change the delay(4000) lines to delay(400), but it stopped giving numbers and just output zeros.

Is the 4000ms an absolute limit of the hardware or can i accelerate the sample rate?

Here is the code:

Thanks!

#include <TimerOne.h>

#define S0     6
#define S1     5
#define S2     4
#define S3     3
#define OUT    2

int   g_count = 0;    // count the frequecy
int   g_array[3];     // store the RGB value
int   g_flag = 0;     // filter of RGB queue
float g_SF[3];        // save the RGB Scale factor
 
 
// Init TSC230 and setting Frequency.
void TSC_Init()
{
  pinMode(S0, OUTPUT);
  pinMode(S1, OUTPUT);
  pinMode(S2, OUTPUT);
  pinMode(S3, OUTPUT);
  pinMode(OUT, INPUT);
 
  digitalWrite(S0, LOW);  // OUTPUT FREQUENCY SCALING 2%
  digitalWrite(S1, HIGH); 
}
 
// Select the filter color 
void TSC_FilterColor(int Level01, int Level02)
{
  if(Level01 != 0)
    Level01 = HIGH;
 
  if(Level02 != 0)
    Level02 = HIGH;
 
  digitalWrite(S2, Level01); 
  digitalWrite(S3, Level02); 
}
 
void TSC_Count()
{
  g_count ++ ;
}
 
void TSC_Callback()
{
  switch(g_flag)
  {
    case 0: 
         Serial.println("->WB Start");
         TSC_WB(LOW, LOW);              //Filter without Red
         break;
    case 1:
         Serial.print("->Frequency R=");
         Serial.println(g_count);
         g_array[0] = g_count;
         TSC_WB(HIGH, HIGH);            //Filter without Green
         break;
    case 2:
         Serial.print("->Frequency G=");
         Serial.println(g_count);
         g_array[1] = g_count;
         TSC_WB(LOW, HIGH);             //Filter without Blue
         break;
 
    case 3:
         Serial.print("->Frequency B=");
         Serial.println(g_count);
         Serial.println("->WB End");
         g_array[2] = g_count;
         TSC_WB(HIGH, LOW);             //Clear(no filter)   
         break;
   default:
         g_count = 0;
         break;
  }
}
 
void TSC_WB(int Level0, int Level1)      //White Balance
{
  g_count = 0;
  g_flag ++;
  TSC_FilterColor(Level0, Level1);
  Timer1.setPeriod(1000000);             // set 1s period
}
 
void setup()
{
  TSC_Init();
  Serial.begin(9600);
  Timer1.initialize();             // defaulte is 1s
  Timer1.attachInterrupt(TSC_Callback);  
  attachInterrupt(0, TSC_Count, RISING);  
 
  delay(4000);
 
  for(int i=0; i<3; i++)
    Serial.println(g_array[i]);
 
  g_SF[0] = 255.0/ g_array[0];     //R Scale factor
  g_SF[1] = 255.0/ g_array[1] ;    //G Scale factor
  g_SF[2] = 255.0/ g_array[2] ;    //B Scale factor
 
  Serial.println(g_SF[0]);
  Serial.println(g_SF[1]);
  Serial.println(g_SF[2]);
 
}
 
void loop()
{
   g_flag = 0;
   for(int i=0; i<3; i++)
    Serial.println(int(g_array[i] * g_SF[i]));
   delay(4000);
 
}

I need it to sample at least 10 times faster.

Hmmmm, do you understand how this device works, specifically how it outputs data ? My quick read of the data sheet tells me it toggles an output line at a frequency proportional to the light's "intensity". So at low intensities the period is long. If you shorten the observation period (increase the sample rate) you'll limit the darkest measurement you can make.

Also you should know that right now the code seems to makes 4 measurements; an R, a G, a B and white at 1 sec intervals, w/each value printed out after being measured. Some normalized composite is then printed every 4 seconds. The 1 second timing is controlled by setting the statement:

Timer1.setPeriod(1000000); // set 1s period

{I don’t know why this is continually being set}

… but the 4 sec timing is the delay() in loop(). Frankly that’s a bad way to do it IMO. I’d have put the prints and resetting code in an altered state (case 0) of the state machine in :

void TSC_Callback()
{
  switch(g_flag)
  {
    case 0:
         Serial.println("->WB Start");
         TSC_WB(LOW, LOW);              //Filter without Red
         break;
    case 1:
         Serial.print("->Frequency R=");
         Serial.println(g_count);
         g_array[0] = g_count;
         TSC_WB(HIGH, HIGH);            //Filter without Green
         break;
    case 2:
         Serial.print("->Frequency G=");
         Serial.println(g_count);
         g_array[1] = g_count;
         TSC_WB(LOW, HIGH);             //Filter without Blue
         break;
 
    case 3:
         Serial.print("->Frequency B=");
         Serial.println(g_count);
         Serial.println("->WB End");
         g_array[2] = g_count;
         TSC_WB(HIGH, LOW);             //Clear(no filter)   
         break;
   default:
         g_count = 0;
         break;
  }
}

… and skipped the delay(4000). I’d also have measured the periods during each observation period and averaged them to get a truer measurement. Counting pulses means the measurement might be off by almost 1 count. No big deal at high irradiances but potentially a big error when really dark. I guess it all depends on the intended usage.

Note that the present code relies on the 1 sec observation period. Changing it means having to implement a scale factor for g_count to get Hz.

Hey mee_n_mac!

Thanks for replying!

You seem to be way more advanced, in your understanding of hardware and software, than i am. Therefore, i did not understand many of the things you explained.

Basically, you are saying, that i may try to change the Timer1.setPeriod(1000000); line, to a lower number, right?

But then, you add, that if i do this change, i have to take care of other changes, which i don’t quite understand what they are, besides understanding that if the sample goes faster without any other changes, the sampled color will be less accurate or more darker?

Thanks.

The short answer is that you need to change both the 1000000 usec in

Timer1.setPeriod(1000000);

and the 4000 msec in the loop()

delay(4000);

Then you need to add a 2 lines to properly scale g_count in the function TSC_Callback()

void TSC_Callback()
{
  if(looping){                    //add these lines to scale g_count back into Hz
    g_count = g_count * X;}       //add these lines to scale g_count back into Hz
    
  switch(g_flag)
  {
    case 0:
         Serial.println("->WB Start");
         TSC_WB(LOW, LOW);              //Filter without Red
         break;
    case 1:
         Serial.print("->Frequency R=");
         Serial.println(g_count);
         g_array[0] = g_count;
         TSC_WB(HIGH, HIGH);            //Filter without Green
         break;
    case 2:
         Serial.print("->Frequency G=");
         Serial.println(g_count);
         g_array[1] = g_count;
         TSC_WB(LOW, HIGH);             //Filter without Blue
         break;
 
    case 3:
         Serial.print("->Frequency B=");
         Serial.println(g_count);
         Serial.println("->WB End");
         g_array[2] = g_count;
         TSC_WB(HIGH, LOW);             //Clear(no filter)   
         break;
   default:
         g_count = 0;
         break;
  }
}

The X in the above is the ratio of 1 sec to whatever new sample period you choose. If you choose it to be 0.1 sec, then replace the X with 10.

I would leave the sampling done in setup() as it is. And because of this you need a new variable, looping, to distinguish when running in setup() or loop(). This means declaring it w/a new line

boolean looping = false;    //new variable = true after setup is complete
int   g_count = 0;    // count the frequecy
int   g_array[3];     // store the RGB value
int   g_flag = 0;     // filter of RGB queue
float g_SF[3];        // save the RGB Scale factor

… and setting it as the (new) last line in setup().

  Serial.println(g_SF[0]);
  Serial.println(g_SF[1]);
  Serial.println(g_SF[2]);
  looping = true;        //new variable = true, setup is done
}

If you decrease the sample time (increase the rate) you decrease the resolution of your measurement and the lowest light level that can be measured. You have to decide if these have any practical impact in your usage.

OK,

i think i understand now more or less what should be done and will be able to implement your explanations.

Thanks a lot!

Also you do a big no-no by printing from inside your interrupt handler. Handlers should do their stuff as quickly as possible and then return.

KeithB:
Also you do a big no-no by printing from inside your interrupt handler. Handlers should do their stuff as quickly as possible and then return.

While the above is often good advice, it's just not true all the time. I've worked embedded projects where all the important processing occurred in various ISRs. If the background processing can allow it, why not print in the ISR ?

I typed up the following post in some spare segments of time figuring the OP would return next week w/more questions and after I’ve forgotten how the code worked. :doh: See if you agree and then, if you can still find a reason, in this case, not to print in the ISR.

While it’s fresh in my mind …

The thing that bothers w/the original (and above) code is that there are 2 independent process timings going on and, because the code in one depends on the other, they should be synchronized … or incorporated together.

Specifically there’s the state machine in function TSC_Callback() that runs whenever the timer1 interrupt goes off. That’s every second in the original code as set by;

Timer1.attachInterrupt(TSC_Callback);

… and …

Timer1.setPeriod(1000000); // set 1s period

When TSC_Callback() runs, it does some processing, including the printing of last measured count of pulses from the red or green or blue channels of the TCS230. For some reason the clear channel data is collected but not printed out. Also called is function TSC_WB(), which commands the next channel, zeros the pulse count and increments the variable g_flag. g_flag controls the state of the aforementioned state machine. g_flag, when actually used by the state machine, should cycle from 0 to 3, 0 - 3, ad naseum. But it depends on the code in loop(), which runs every ~4 secs to reset g_flag = 0. And so g_flag actually runs 0 - 4, but (ideally) only stays = 4 briefly before being reset = 0 … which better happen before the next timer1 interrupt otherwise the state machine will run w/g_flag = 4 which will result in an error condition.

And the above error is guaranteed to happen if the system is run long enough. That’s because the 4 sec delay in loop() isn’t exactly 4 secs. Additionally, while the timer1 interrupt will be pretty stable, it’s getting reset (I think) in TSC_WB(), with printing in between each reset. That code and printing take some finite amount of time. The result is that cycling through all 4 states takes a bit longer than 4 secs. And so like 2 clocks, the two “4 sec” timings will eventually get enough out of sync to cause an error.

A simple (though not the best) fix would be too add some code to TSC_Callback(), before the state machine code, that checks for g_flag = 4 and if true, then resets g_flag = 0. Then delete this line from loop().

g_flag = 0;

Now when the the processes get de-synced, the state machine will run OK. Only the printout of “scale factors” in loop() may become “odd”, perhaps using RGB data from the last frame mixed w/RGB data from an older frame. If that’s annoying, the print code in loop() could be moved into the state machine (and thus always be sync’ed) … perhaps into the case 0 state. An empty loop() function might look funny but all the code will run, driven by interrupts.

I understand that you guys, are discussing the fact that this code, calls some kind of deeper hidden code, that is situated somewhere behind some command, which i could not recognize as the magical portal it came from, although, i could see that the pinMode(SX, OUTPUT); commands in the code, had no recognizable follow-up commands in the rest of the visible code.

Anyway…i will leave all this wizardry to you advanced dudes…

I have changed the Timer1.setPeriod(1000000); to Timer1.setPeriod(100000);

and the delay(4000); to delay (400);

And magic! it works fast enough for my project needs and i get good enough RGB numeral result differences! Thanks!

Now, My next question is:

Is there a simple way to make this code work, with more than one TC230 color sensor? i need 3-7 of them working on my Arduino Mega…

Thanks!

@ the OP - What Arduino are you using ? Why the 10x increase in sample rate ? Has the system been working and if so, what range of reported frequencies have been reported ?

I ask because the TCS230 can be set to output differing output frequencies for the same light level. It outputs a ~2 Hz pulse-train when completely dark. When exposed to the max light level it can measure, that pulse-train can be selected to be ~10 kHz or ~100 kHz or ~500 kHz. The max rate would likely be too fast for an Uno. I’m not sure about the middle rate. Presently the code sets S0, S1 for the lowest rate. But at your 0.1 sec sampling period the lowest frequency you can measure is ~10 Hz. There will be “large” errors in the reported frequency until it’s bright enough to make the TCS230 output a 100 Hz pulse-train. Depending on your range of light levels, this may or may not matter to you.

The only alternatives would be to decrease the sample rate to slower than the 10X increase you wanted and/or to select the middle range … which, depending on your Arduino, may be “iffy”. :mrgreen:

roineust:
Is there a simple way to make this code work, with more than one TC230 color sensor? i need 3-7 of them working on my Arduino Mega…

Simple ? Hmmmm. The Mega has 6 external interrupt pins so w/o some non-simple code changes you could *at best* have 6 devices attached. I'd have to think about the timing though. And the timing requirement would depend on the expected frequencies and thus the expected light level range. What freqs have you been measuring ?

Do-able … maybe. :think:

i need to be able to distinguish between yellow-white and dark-brown.

Why is it, that i took out S2 and S3 wires, and still can detect in the serial monitor, numerical value differences, of these above colors i am working with? For my needs it is good, since it spares 2 more digital pins per sensor…

BTW, one sensor works well with the updated code, for my needs, also on an Uno.

roineust:
i need to be able to distinguish between yellow-white and dark-brown.

Aaaaah, this is a case that demonstrates the more you tell "us", the better answers "we" can give you. I can now say you can delete the code in *loop()* that prints out the "scale factors" every 4 secs. That info is redundant given the 1 sec printouts. Also since you don't need an accurate frequency report, you don't need to do the scaling I added to account for the increased sampling rate. In truth I'm sure you could code it so instead of printing frequencies, it could decide what color was present and report that instead. If you told us more like the above, I wouldn't have wasted my time on potential troubles that your usage will never encounter.

And, as you’ve discovered, you may not even need to use all the color sensors, 1 sensor might do. And that has implications for monitoring more devices and speeding things up at the same time. Right now you could recode not to measure the clear/white channel and loose no info that you’re using and speed things up by 33%.

I’m still waiting for some numbers from you to know if 6 devices will work on your Mega … simply. Capture a couple of secs of data on the serial monitor and attach it as a .txt file in your next post.

roineust:
Why is it, that i took out S2 and S3 wires, and still can detect in the serial monitor, numerical value differences, of these above colors i am working with? For my needs it is good, since it spares 2 more digital pins per sensor…

My guess is that leaving both lines open/unconnected means the sensor is measuring only the greenish content of the light. So the R and B printouts are really both more green measurements . How much green would you expect in each of your 2 colors ?

http://en.wikipedia.org/wiki/Brown

http://en.wikipedia.org/wiki/Yellow

Obviously there’s enough of a difference that you can see it. Do you think there’s a number that’s between the 2 colors measurements that could used to decide something like;

if(green_freq > number){
  color = 'color1';
  } else {
  color = 'color2';
}
Serial.println(color);

http://arduino.cc/en/Reference/Else

roineust:
BTW, one sensor works well with the updated code, for my needs, also on an Uno.

An Uno has 2 external interrupt lines (pins 2, 3) and so, w/o major code changes, could run 2 devices. I'm fairly sure that even in the brightest light, an Uno could handle the 2 devices running simultaneously.

I’m still waiting for some numbers from you to know if 6 devices will work on your Mega … simply. Capture a couple of secs of data on the serial monitor and attach it as a .txt file in your next post.

I had a few minutes to think about it and I'm fairly certain that you can run 6 devices on your Mega w/o any trouble at all. I'd still like to see some data for each (?all?) of the colors that the sensor will "see", per my post above. I'd like to know how you use the data you presently get. I'm also sure the code can be drastically simplified to make it easier for you to understand and modify, for adding sensors and/or deciding what color it/they "saw".

When I get a chance I’ll post my reasoning for why 6 devices is no sweat.

mee_n_mac!

Thanks a lot for helping!

Sorry for calling you in the “plural” and for not relating enough information…that’s a lot of stuff i am learning here, ‘on the run’!

Yes!

The ‘else’ statement code, is exactly where i am aiming at!

i will try to log the numbers on the serial monitor and attach them as text tomorrow. I am working now with the Uno and not with the Mega. Does it matter if, for the meantime, i log the Uno serial monitor results and not the Mega?

Are you actually saying, that if i use 1 wire per sensor, i might be able to use this code, as is, for multiple (2-3) sensors and get the results in such a way, that each color numeral output out of the R,G,B will correspond to a distinct sensor? As much as i recall, and i will be much smarter when i have the log, when moving from white to brown, all the three R,G,B numeral values, were showing differences of about 200 in a scale of thousands.

roineust:
i will try to log the numbers on the serial monitor and attach them as text tomorrow. I am working now with the Uno and not with the Mega. Does it matter if, for the meantime, i log the Uno serial monitor results and not the Mega?

Nope, it doesn't matter, Uno vs Mega, so long as you've got the wiring and pin definitions in the code in agreement for the Arduino in use. That's pretty obvious and the only 'gotcha' is that the TCS230 output pin must be connected to an external interrupt pin on the Arduino. As it happens the code uses "interrupt 0" which is pin 2 on both the Uno and Mega.

You should read these short articles on interrupts, as they (interrupts) are critical to your design and a very useful concept/tool to use w/any micro.

https://www.sparkfun.com/tutorials/326

http://arduino.cc/en/Reference/AttachInterrupt

This one’s goes quite a bit ‘deeper’, but the intro is good.

http://www.gammon.com.au/forum/?id=11488

roineust:
Are you actually saying, that if i use 1 wire per sensor, i might be able to use this code, as is, for multiple (2-3) sensors and get the results in such a way, that each color numeral output out of the R,G,B will correspond to a distinct sensor?

The code will have to be modified but it's almost a cut'n'paste. What's done for 1 TCS230 device is done for each of the others, but with the (variable) names changed. You could get the RGB values and/or a color decision for each device. That's a lot of data so you may wish to increase the baud rate from the plebeian 9600 (that's 1 character every 1 msec) it is now to 57.6k (6X faster for 6X the data).

Here’s my reasoning as to why I think 6 TCS230’s running on a Mega will work. If I’m wrong or missed something, hopefully someone will chime in w/a correction.

Just for review here’s how the system works. The TCS230 sensor has 4 different color sensing groups but only 1 output line. Two input lines are used to select which color is to be output. That output is a pulse-train whose frequency varies in proportion to the “brightness” (irradiance actually) of light, in the selected color-band, falling on the TCS230. The dark frequency is ~ 2 Hz. The max freq is selectable via another 2 input lines. At present the lowest setting is used and that means an upper frequency of 10 - 12 kHz.

The TCS230 output line is connected to an Arduino external interrupt line. Whenever a rising edge is detected an interrupt is triggered. The associated interrupt service routine (ISR) implements a simple counter. Each rising edge bumps the count by 1.

A 0.1 sec intervals, due to a timer1 interrupt, the modified code implements a state machine; retrieving that count and calculating the pulse-train frequency. That frequency is sent over the serial link. Then the next color is selected, the count zeroed and the sampling period timer restarted. This process is repeated for the whole color set (white/clear, red, green and blue). Then the state machine is reset and the entire process repeated, endlessly.

Some no-longer-needed processing is also done on a separate ~4 sec basis. This will be deleted in a future revision of code.

Adding more TCS230’s would mean using more external interrupt lines, adding an ISR counter for each and more printing. A Mega has 6 external interrupt pins so adding 5 more TCS230’s shouldn’t be an issue. What could go wrong ?

Well … keeping to a 0.1 sec sampling period (per color) and running 6 interrupts simultaneously means those 6 interrupts could all occur at the same time (or near enough so as to make no difference). Since the Mega can only run 1 ISR at a time, the time spent “servicing” each ISR has to be short enough to complete all 6 before they occur again. The other interrupts will be noted as having occurred and their ISRs run in order as the prior ISRs complete. If the servicing time is too long then pulses will be missed and the count will be low.

What’s the max time allotted for servicing any of these ISRs ? The worst case is the the light is very bright and the output is at it’s max frequency, 12 kHz. That’s a pulse-pulse time of 83.3 usec. Dividing that by 6 leaves a worst case time of 13.9 usec. How long does it take to service and run the present ISR ?

I think a Mega is the same as an Uno when it comes to this. To “service” an interrupt means you have to stop what code is running, store where it was running and a bunch of registers, that may have the results of calculations in progress, into RAM and then transfer control to the code you wrote in the ISR itself. When that code completes, all those registers have to be restored and the program returned to where it was interrupted. A prior link gives the time to get to, and return from, the ISR code as 82 clock cycles. I’ll be conservative and opine he missed the up-to 3 clock cycles the hardware (HW) takes to sync the external signal to the internal clock. So it’s 85 clocks of overhead just to service any external interrupt. So how long does it take to run the existing ISR code itself ?

Let’s say it’s a clock each to fetch the counter from memory, increment it by 1 and then store it back into RAM. Heck, let’s double it; 6 clocks + 85 = 91. Since I like certain numbers let’s be more conservative and call it 100 clocks. At 16 MHz a clock cycle is 62.5 nsec. 100 clocks is 6250 nsec or 6.25 usec. That’s comfortably under the 13.9 usec limit we set above. Thus I say it’ll work … as I don’t see any other deal breaker concerns.

I’d like to return to KeithB’s (widely held and often stated by many) advice from page 1. As you can see there’s not a lot of extra time to run more code in this ISR. Certainly no time to “print” anything. That’s most often the case so his advice is a good general rule to follow. But it’s not w/o exception. The architecture of the code and a timing analysis is the true limiter of how much code can be stuffed into any ISR.

So what to do next ? I’d optimize the code for a single sensor case before expanding it for more TCS230’s. Get it to do and report what you want as an end result. I have some ideas along the line of making it simpler and more familiar to your admittedly newbie eyes.

I must admit, it was extremely interesting, to read what you wrote above, and get the general impression of considerations that should be made, in such a case as changing the code of that color sensor. Although for me, it was more like appreciating the general aesthetics of a calligraphy art, painted in some far away language :violin: . You seem to be considering things at the machine language level…while i am paddling several leagues above, on the surface of the water, in my rescue boat of light scripting attempts. :doh:

Here’s a revised sketch that should be functionally very similar to what you last ran. I say very similar because I eliminated the “scale factors” coding, thus getting rid of the ~4sec printing in loop(). I kept the timing the same (0.1 secs/color, analyze 4 colors) and since the code collected the white/clear data, I decided to print it out. So the reported data set is now RGBW. I added a data set counter just because its nice to see something running.

The big change is that I moved the state machine processing from the timer1 ISR into the empty loop() and eliminated the timer1 interrupt. This should simplify the code and make it similar, in “looks”, to other sketches you’re used to.

The counts now printed out should agree with the prior reported frequencies if you account for the 10X scaling (that the new code doesn’t bother to do). That is :

new counts = old freqs / 10

See if the above holds true.

Read this re: state machines and then look over the new code. W/o a TCS230 I can’t really test it. That’s up to you. It should work on both Uno and Mega.

http://classes.soe.ucsc.edu/cmpe118/Spr … chines.pdf

http://arduino.cc/en/Reference/SwitchCase

And here’s the code;

//version 0.1 of TSC230 code

//declare the constants
#define S0     6
#define S1     5
#define S2     4
#define S3     3
#define OUT    2

const int smpl_period = 100; //sample period in msec

//declare the variables
volatile int   count = 0; //a count of pulses from TSC230
int   state = 0;          //state machine control variable
unsigned long set = 0;    //a count of the RGBW sets processed

void setup() {
  //set the baud rate
  Serial.begin(9600);
  //set the pins to be I or O
  pinMode(S0, OUTPUT);
  pinMode(S1, OUTPUT);
  pinMode(S2, OUTPUT);
  pinMode(S3, OUTPUT);
  pinMode(OUT, INPUT);
  //set the max freq of the TSC230 output
  digitalWrite(S0, LOW);  // OUTPUT FREQUENCY SCALING 2%
  digitalWrite(S1, HIGH); // OUTPUT FREQUENCY SCALING 2%
  //set the 1st color to be analyzed
  //this color is red
  digitalWrite(S2, LOW);
  digitalWrite(S3, LOW);
  //attach and enable the external interrupt(s)
  attachInterrupt(0, TSC_Count, RISING);
  //wait 1 sample period to collect counts from TCS230
  delay(smpl_period);
  //go to state machine ready to process 1st color
}

void loop() {
  //run state machine to collect and process data
  switch (state)
  {
    case 0:
      //process the collected red count data
      //freeze the counter(s)
      noInterrupts();
      //send the data
      Serial.print("Data set number = ");
      Serial.println(set);
      Serial.print("Counts R = ");
      Serial.println(count);
      //reset the counter
      count = 0;
      //set next state
      state ++;
      //set next color to green
      digitalWrite(S2, HIGH);
      digitalWrite(S3, HIGH);
      //re-enable the counter(s)
      interrupts();
      break;
    case 1:
      //process the collected green count data
      //freeze the counter(s)
      noInterrupts();
      //send the data
      Serial.print("Counts G = ");
      Serial.println(count);
      //reset the counter
      count = 0;
      //set next state
      state ++;
      //set next color to blue
      digitalWrite(S2, LOW);
      digitalWrite(S3, HIGH);
      //re-enable the counter(s)
      interrupts();
      break;
    case 2:
      //process the collected blue count data
      //freeze the counter(s)
      noInterrupts();
      //send the data
      Serial.print("Counts B = ");
      Serial.println(count);
      //reset the counter
      count = 0;
      //set next state
      state ++;
      //set next color to white
      digitalWrite(S2, HIGH);
      digitalWrite(S3, LOW);
      //re-enable the counter(s)
      interrupts();
      break;
    case 3:
      //process the collected "white" count data
      //freeze the counter(s)
      noInterrupts();
      //send the data
      Serial.print("Counts W = ");
      Serial.println(count);
      Serial.println(" ");
      //reset the counter
      count = 0;
      //set next state
      state = 0;
      //increment the data set counter
      set ++;
      //set next color to red
      digitalWrite(S2, LOW);
      digitalWrite(S3, LOW);
      //re-enable the counter(s)
      interrupts();
      break;
    default:
      //code should never get here
      Serial.println("Error");
      //reset the state machine
      count = 0;
      state = 0;
      //set next color to red
      digitalWrite(S2, LOW);
      digitalWrite(S3, LOW);
      break;

    //wait 1 sample period to collect counts from TCS230
    delay(smpl_period);
    //state machine end
  }
}

//this is the external interrupt / counter ISR
void TSC_Count()
{
  count ++ ;
}

No text shows up, when i open the serial monitor, with the above code you posted. I tried to press the reset button and it wrote ‘da’ and then ‘dada’ is that the beginning of the word ‘data’ or has the Homer Simpson worm overtaken my computer? :lol:

Any way, as you asked me to do, here is the log of the serial monitor results, from the previous code, just to remind you, s2 and s3 wires are totally disconnected, so do we need them at all in the new code?

The attached images are a print screen samples of the results, when the sensor is above the white color and then, again, over the dark color.

The white color sampling outputs numbers of around 2700-2800 and the dark color sample outputs numbers of around 2500-2600.

BTW,

i read the first parts of the state machine explanation and it seems to be an interesting concept. Anyway, i was not able to get into the more elaborate parts of that explanation.