Using Millis! HELP!!!

Hi All,
Complete beginner out of his dept and wasting allot of time on one particular issue.
Okay I'm using a sensor to read colors blue, green and red. Once the sensor reads red for example I need a red LED to delay 2 seconds come on for a second and go off again. When the sensor reads blue I want a delay of 4 seconds and with green a delay of 6 seconds to the LEDs. Using delays in the code is slowing the colour sensor, and does not allow my circuit to multitask.

I want to be able to take readings very second, so if the sensor read green (6 second delay needed) then red(2 second delay needed), my code will activate the red LED before the green LED. I think I need a timer here using the millis function but I have tried and made very little progress so far, I need a push in the right direction! Would be extremely appreciative of some input here!!
This is the code I'm using so far, which is not what I what but might help someone understand my problem and what I'm trying to do.

// TCS230 connections:
const int outputEnabled = 2; // write LOW to turn on Note, may not be hooked up.
const int s0 = 3; // sensor pins
const int s1 = 4;
const int s2 = 5;
const int s3 = 6;
const int nLED = 7; // illuminating LED
const int out = 8; // TCS230 output
const int LED = 10;
const int LED2 = 11;
const int LED3 = 12;

 
// variables to store color values
int red = 0;
int green = 0;
int blue = 0;
 
void setup() {
  pinMode(outputEnabled, OUTPUT);
  pinMode(s0, OUTPUT);
  pinMode(s1, OUTPUT);
  pinMode(s2, OUTPUT);
  pinMode(s3, OUTPUT);
  pinMode(nLED, OUTPUT);
  pinMode(LED, OUTPUT);
  pinMode(LED2, OUTPUT);
  pinMode(LED3,OUTPUT);
  pinMode(out, INPUT);
  Serial.begin(9600);
  //This pin may be set to ground and not available on the breakout
  //If not available don't worry about it.
  digitalWrite(outputEnabled, LOW);
  //Set Frequency scaling to largest value
  digitalWrite(s0, HIGH);
  digitalWrite(s1, HIGH);
  digitalWrite(nLED, LOW);
}
 
void loop() {
  color();
  Serial.print("R");
  Serial.print(red, DEC);
  Serial.print(" G");
  Serial.print(green, DEC);
  Serial.print(" B");
  Serial.print(blue, DEC);
  Serial.println();
  //Simple logic to test for color
  if (red < blue && red < green ) {   // RED 
  delay(2000);              // wait for two second
  digitalWrite(LED, HIGH);    // set the LED on
  delay(1000);
  digitalWrite(LED, LOW);
  }
  else { digitalWrite (LED, LOW);}
  
  if (blue < red && blue < green ) {   // BLUE 
  delay(4000);              // wait for four seconds
  digitalWrite(LED2, HIGH);    // set the LED on
  delay(1000);
  digitalWrite(LED2, LOW);
  }
  else { digitalWrite (LED2, LOW);}
  
  if (green < red && green < blue ) {   // GREEN 
  delay(6000);              // wait for six seconds
  digitalWrite(LED3, HIGH);    // set the LED on
  delay(1000);
  digitalWrite(LED3, LOW);
  }
  else { digitalWrite (LED3, LOW);}
  
  
}
 
void color() {
  digitalWrite(s2, LOW);
  digitalWrite(s3, LOW);
  //   count OUT, pRed, RED
  red = pulseIn(out, digitalRead(out) == HIGH ? LOW : HIGH);
  digitalWrite(s3, HIGH);
  //count OUT, pBLUE, BLUE
  blue = pulseIn(out, digitalRead(out) == HIGH ? LOW : HIGH);
  digitalWrite(s2, HIGH);
  // count OUT, pGreen, GREEN
  green = pulseIn(out, digitalRead(out) == HIGH ? LOW : HIGH);
}

Moderator edit:
</mark> <mark>[code]</mark> <mark>

</mark> <mark>[/code]</mark> <mark>
tags added.

That all seems straight forward enough, but I'm a bit unclear about the exact behaviour you want.

Do you want the red LED to come on (after two seconds) if red is sense momentarily, or only if it is sensed continuously during those two seconds?

Describe the COMPLETE behavior of your project with a diagram. You can easily write the code according to the diagram. Right now it's very unclear what the LEDs do in case say a sequence of red, blue, then maybe red again, and green show up at the sensor etc. In programming, every single possible input needs a predetermined output.

Hi,
Thanks for your replies, I was a little worried that the feedback was going to suggest that this was very complex.

So I'm going to describe exactly what I want to do, and maybe someone could suggest the programming functions that would allow me to do this. The project may seem abit strange because I am just practicing with LEDs at the moment I will be swapping these LEDs with solenoids at a later date but I am just trying to get the programming to work with LEDs first. I am using pull solenoids to act a trapdoors releasing the color sensed objects into separate bins, a color sorting machine.

I want my sensor to take readings over ONE second intervals, so for example over a 5 second period I could have a sequence of readings such as blue, blue, red, green, blue. Just using this as an example it could be anything. So in this instance the color sensor reads blue first I then need the corresponding blue LED to be activated in 4 seconds time (HIGH for 1 second), the next reading is blue and I need the same response, next is red I need the corresponding red LED to be activated in 2 seconds time (HIGH for 1 second), with green I need the corresponding green LED to be activated in 6 seconds time (HIGH for 1 second), and finally with blue again the corresponding blue LED to be activated in 4 seconds time (HIGH for 1 second).

Sorry I know there is a better way of getting my point across. But basically the color sensor is going to make readings allot faster than the LEDs are going to be activated. The code I have written at the moment slows down the sensor readings and waits for the an LED to be activated before it reads again. I need the sensor to make a readings and then work the LEDs on a timer but continue reading over its one second intervals.

Sorry I've even confused myself abit here, but I don't think the concept is very complex, I'm just unsure of the best way of programming this solution or what functions to use.

So Peter I just want the red LED to come on (after two seconds) if red is sense momentarily!

Take a look at both the Blink Without Delay example in the IDE and Functional State Machine. You'll need both of those methods.

I'm still confused. If your sensor senses fast, then the blue ball comes in, and it gets sensed many times. How can you then tell there are 2 blue balls, not a whole bunch?

liudr:
I'm still confused. If your sensor senses fast, then the blue ball comes in, and it gets sensed many times. How can you then tell there are 2 blue balls, not a whole bunch?

He's reading the sensor once a second, presumably the balls come in at that rate. I get that he wants the balls to roll as far as the appropriate solenoid before operating it. Different (colour) solenoids will be at different distances from the sensor, so he needs a different delay for each colour.

OK, if your system is willing to wait, I recommend sorting one ball at a time and not letting the next ball roll down until the current ball is sorted.

Simple scheduling issue. This assumes no more than one ball of any color in the "track" at a time -- you don't describe the eventual sorting hardware, so you may have no choice ...

Set three colored flags to "Not doing anything" and three "future_time" values to millis(). Not that this matters -- the flags say you're not doing anything ...

You see a color, you calculate the time, IN THE FUTURE, when the LED must be driven HIGH. You set the colored flag to "Open the trap door". You set the future_time to millis() plus the delay. You know you're still in the past (relative to the target time) because "millis() - future_time" will go from being HUGE to being very small. Oh, the joys of unsigned math.

You check flags indicating which colors have "Open the trap door" events scheduled IN THE FUTURE and determine if the FUTURE is now. When the future has arrived, you digitalWrite(colored_ball_pin, HIGH) and change the flag to "Close the trap door". Add 1000ms to your future_time variable.

You check flags indicating which colors have "Close the trap door" events and again determine if the future time has arrived. When it has, digitalWrite(colored_ball_pin, LOW) and change the flag to "Not doing anything".

I think you need to write down in English (or your own language) step by step what you want to happen as though you were describing the process in a story book. The purpose is to describe what you want to happen - NOT to describe how a program might do it. The more detail you put into the description of the process the easier you will be able to design a program to do the same thing.

Nobody has so far said it, but you MUST get rid of all the delay() functions from your program. They just get in the way by paralyzing the Arduino.

As @Henry_Best has said the concepts in the Blink Without Delay example and the State Machine concept will enable you to achieve what you want. I wrote a demo program here Demonstration code for several things at the same time - Project Guidance - Arduino Forum that shows how to use those techniques to manage several tasks at the same time - in your case, read the sensor, flash the led, open the gate.

...R

(This was also sent as a private message.)

Without a much better understanding of the machinery, I'm afraid I really can't help you much more. However, I've pretty much described what you need to do.

Let's start with an enum giving the colors --

enum {red, blue, green} color;

You'll use the color names to access your arrays, and you'll have two of them.

You need an array of 3 solenoid "states". That's just an array of enum's, or something like that --

enum { do_nothing = 0, wait_to_open, wait_to_close } actions[3];

The millis() function tells you the current time, in milliseconds, since the Arduino was started. The time is an unsigned 32-bit value -- there are no negative values, the number goes from 0 to 4 billion, then immediately back to 0. The cool thing about unsigned math is that you can subtract a huge number from a small number and get a small number because the negative number that you'd get with signed math isn't negative. For example 0x0002 - 0xFFFE (that's 2 - 65534) is 4, not -65532. The reason is that as a 16-bit value, there is no place for the "borrow". As a 32-bit value it would be 0xFFFF0004, but those extra 16-bits don't exist. They just get lost, and the result is the value 4.

So the next part is knowning when it is time to act. For that you need an array of unsigned long values for the action times --

unsigned long times[3];
unsigned long now;

In each of those elements you'll either have "nothing" or a millisecond time to "do something". You'll know based on the actions array. And that's simple --

now = millis();
if (actions[color] != do_nothing) {
  /*
   * I have to do something, some time.
   */
  if (((long) (now - times[color])) > 0) {
    if (actions[color] == wait_to_open) {
      do_open(color);
      actions[color] = wait_to_close;
      times[color] = now + 1000L;
    } else {
      do_close(color);
      actions[color] = do_nothing;
    }
  }
}

That bit of magic with (((long) (now - times)) > 0) exploits what I wrote about unsigned numbers -- subtracting a time in the future from the present time, as unsigned numbers, is always greater than 0. That's why I "cast" the result of the subtraction to a signed value.

You'll also notice that I used the variable "color" and not some giant blob of code. Now I can do this --

for (color = red;color <= green;color++) {
    /* that blob of code up there */
}

and all three colors get processed. If I define a new color -- let's call it "last_color" -- I can change that to

for (color = red;color <= last_color;color++) {
    /* that blob of code up there */
}

and now I can add more colors in the future.

Now all you have to do is define the two functions do_open() and do_close().

(I neglected this in the private response -- editing in a form like this is tedious ...)

Alright, how to get this thing started?

Each time your color detector sees a bead, it sets the color variable to the color is found --

int color_delay[] = { 2000, 4000, 6000 };
.
.
.
  if (have_a_bead()) {
    color = read_color();
    actions[color] = wait_to_open;
    times[color] = millis() + color_delay[color];
  }

  /*
   * paste that for-loop here.
   */

Anyway, I apologize for syntax and other such errors.