Color change timer

Hi, all

I am new to C and new to the arduino.
I basically don't have any background of C and electronics....

I'm currently making a color change timer by using tri-color (RGB) LED.
My initial idea is that I just want to change the color from green, blue to red within 10 seconds, but I don't want to use "delay".
I used a light sensor(Photocell) as a switch. I also used "MsTimer2.h" in the sketch.

I'll show my sketch below. It doesn't work properly, because of my lack of programming skill... Tri-color LED flashes with "purple" and "green" with this sketch. I don't know why...
Please help me!!

Here is my sketch. Please modify it.-----
If I can't complete my idea with this sketch, please give me any idea.
Thanks heaps!!

#include <MsTimer2.h>

int ledPinG=10; //Green LED
int ledPinB=11; //BLUE LED
int ledPinR=12; //RED LED
int switchPin=2;  //Light sensor
int val;// Switch connected to digital pin 2


void setup() {
  Serial.begin(9600);           // set up Serial library at 9600 bps
  pinMode(switchPin, INPUT);  // Light sensor as a switch
  pinMode(ledPinG,OUTPUT);  // sets the digital pin as input to read switch
  pinMode(ledPinB,OUTPUT);  // sets the digital pin as input to read switch
  pinMode(ledPinR,OUTPUT);  // sets the digital pin as input to read switch

  MsTimer2::set(1000, flash); // 1000ms period
  MsTimer2::start();
}
void flash() {
static boolean output = HIGH;
   if (digitalRead(switchPin) ==LOW) //if the light sensor is uncovered
   {
      digitalWrite(ledPinB, output); //blink Blue LED
      output = !output;
      digitalWrite(ledPinG, output);  //blink Greene LED
      output = !output;
      digitalWrite(ledPinR, output);  //blink Red LED
      output = !output;

   }
}

void loop() {
    val = digitalRead(switchPin);   // read input value and store it in val
    if (val == HIGH) {              // if the light sensor is covered
    digitalWrite(ledPinG, LOW);    // turn LED off
    digitalWrite(ledPinB, LOW);    // turn LED off
    digitalWrite(ledPinR, LOW);    // turn LED off
  }

}

digitalWrite(ledPinB, output); //blink Blue LED
output = !output;
digitalWrite(ledPinG, output); //blink Greene LED
output = !output;
digitalWrite(ledPinR, output); //blink Red LED
output = !output;

If you enter that sequence with output HIGH then blue is high, green is low and red is high and you exit with output LOW.

If you enter it with output LOW (e.g. looping around a second time), then blue is low, green is high and red is low, and you exit with output HIGH.

In other words, you always have either green on alone, or blue and red on together: green and purple.

If you want to cycle thru three states (blue, red and green) you need a state variable (e.g. output) that can hold three values, so not a boolean. For flexibility, you might want three booleans, one per LED.

Thanks Mathieu!
But, I still can't get it...

If it possible, could someone tell me how I can change the sketch?
(what variable should I add & which part shuould I change?)

I wonder if you are unnecessarily making things difficult for yourself. Why not try it using delay instead of the timer. That way you can sequence through each of the colors you want. Once you have that code running it will be easier to see how you can modify it for use with a timer if you really need to do that.

Thanks for your suggention!

I tried color timer setting with "delay" function, but I can't turn off the "color changing" immediately during the loop . It always stops after the RED LED blink.
When I cover the light sensor, I want to turn off it immediately.
How should I change the sketch?

Here is the sketch.

int ledPinG=10; //Green LED
int ledPinB=11; //BLUE LED
int ledPinR=12; //RED LED
int switchPin=2;  //Light sensor
int val;// Switch connected to digital pin 2

void setup() {
  Serial.begin(9600);           // set up Serial library at 9600 bps
  pinMode(switchPin,INPUT);  // Light sensor as a switch
  pinMode(ledPinG,OUTPUT);  // sets the digital pin as input to read switch
  pinMode(ledPinB,OUTPUT);  // sets the digital pin as input to read switch
  pinMode(ledPinR,OUTPUT);  // sets the digital pin as input to read switch
}

void loop() {
     val = digitalRead(switchPin);   // read input value and store it in val
      if (val == LOW) {              // the light sensor is uncovered by a hand
      digitalWrite(ledPinG, HIGH);  //blink Greene LED
      digitalWrite(ledPinB, HIGH); //blink Blue LED
      digitalWrite(ledPinR, HIGH);  //blink Red LED
      delay(2000);
      digitalWrite(ledPinG, HIGH);  //blink Greene LED
      digitalWrite(ledPinB, LOW); //
      digitalWrite(ledPinR, LOW);  /
      delay(2000);
      digitalWrite(ledPinG, HIGH);  //blink Greene LED
      digitalWrite(ledPinB, HIGH); //blink Blue LED
      digitalWrite(ledPinR, LOW);  //
      delay(2000);
      digitalWrite(ledPinG, LOW);  //
      digitalWrite(ledPinB, HIGH); //blink Blue LED
      digitalWrite(ledPinR, LOW);  //
      delay(2000);
      digitalWrite(ledPinG, LOW);  //
      digitalWrite(ledPinB, HIGH); //blink Blue LED
      digitalWrite(ledPinR, HIGH);  //blink Red LED
      delay(2000);
      digitalWrite(ledPinG, LOW);  /
      digitalWrite(ledPinB, LOW); //
      digitalWrite(ledPinR, HIGH);  //blink Red LED
      delay(2000);
      }
    
    val = digitalRead(switchPin);   // read input value and store it in val
    if (val == HIGH) {              // if the light sensor is covered by a hand
    digitalWrite(ledPinG, LOW);    // turn LED off
    digitalWrite(ledPinB, LOW);    // turn LED off
    digitalWrite(ledPinR, LOW);    // turn LED off
  }
}

This may give you some ideas of how to proceed. Its not tested so may need some work but I hope points you in the right direction. After you get it going, you can improve it by using an array to define your colors and looping through the array elements in for loop. This would let you replace those repeated checks for sensor state with a single check at the top of the loop.

Have fun!

int ledPinG=10; //Green LED
int ledPinB=11; //BLUE LED
int ledPinR=12; //RED LED
int switchPin=2;  //Light sensor
int val;// Switch connected to digital pin 2

void setup() {
  Serial.begin(9600);           // set up Serial library at 9600 bps
  pinMode(switchPin,INPUT);  // Light sensor as a switch
  pinMode(ledPinG,OUTPUT);  // sets the digital pin as input to read switch
  pinMode(ledPinB,OUTPUT);  // sets the digital pin as input to read switch
  pinMode(ledPinR,OUTPUT);  // sets the digital pin as input to read switch
}

void loop() {
  if( digitalRead(switchPin) == LOW)
    setColor(1,1,1,2000);        
  if( digitalRead(switchPin) == LOW)
    setColor(0,1,0,2000);  
  if( digitalRead(switchPin) == LOW)         
    // do your other colors ....


  if( digitalRead(switchPin) == HIGH)
     setColor(0,0,0,0);  // turn LEDs off
} 


void setColor(int R, int G, int B, int delayMs){
  // set the LED colors and delay for the given number of milliseconds 
  // but return if sensor is covered 
  digitalWrite(ledPinG, R);
  digitalWrite(ledPinB, G);
  digitalWrite(ledPinR, B); 
  while(delayMs--){
    // this loop checks the sensor every millisecond
    delay(1);
    if( digitalRead(switchPin) == HIGH)
      return; // exit the while loop if sensor is covered
  }   
}

Thanks for your quick reply, mem!!
It works perfectly!!

I'll try to add more functions and develop this color timer.
Thanks a lot!!

Hi, all

I added some codes to create "10 seconds color timer", below.
This timer changes its color every 2 seconds.
sec.
0~1: white
2~3: green
4~5: light blue
6~7: blue
8~9: purple
10: red

Now, I want to add another function that
"when timer is over 10 seconds, it blinks quickly with red color till the light sensor is covered by a hand".
Is there any way to do that? Please, help me!!
Thanks!!

int ledPinG=10; //Green LED
int ledPinB=11; //BLUE LED
int ledPinR=12; //RED LED
int switchPin=2;  //Light sensor
int val;// Switch connected to digital pin 2

void setup() {
  Serial.begin(9600);           // set up Serial library at 9600 bps
  pinMode(switchPin,INPUT);  // Light sensor as a switch
  pinMode(ledPinG,OUTPUT);  // sets the digital pin as input to read switch
  pinMode(ledPinB,OUTPUT);  // sets the digital pin as input to read switch
  pinMode(ledPinR,OUTPUT);  // sets the digital pin as input to read switch
}

void loop() {
  if( digitalRead(switchPin) == LOW)
    setColor(1,1,1,2000);
  if( digitalRead(switchPin) == LOW)
    setColor(1,0,0,2000);    
  if( digitalRead(switchPin) == LOW)
    setColor(1,1,0,2000);  
  if( digitalRead(switchPin) == LOW)
    setColor(0,1,0,2000);
  if( digitalRead(switchPin) == LOW)
    setColor(0,1,1,2000);    
  if( digitalRead(switchPin) == LOW)
    setColor(0,0,1,2000);    
    // do your other colors ....
    
  if( digitalRead(switchPin) == HIGH)
     setColor(0,0,0,0);  // turn LEDs off
}

void setColor(int R, int G, int B, int delayMs){
  // set the LED colors and delay for the given number of milliseconds
  // but return if sensor is covered
  digitalWrite(ledPinG, R);
  digitalWrite(ledPinB, G);
  digitalWrite(ledPinR, B);
  while(delayMs--){
    // this loop checks the sensor every millisecond
    delay(1);
    if( digitalRead(switchPin) == HIGH)
      return; // exit the while loop if sensor is covered 
  } 
}

There are many ways you can do that. Why not add some code in loop to keep track of time and check if more then ten seconds have elapsed.

You can use the millis function to get the time (in milliseconds) since the sketch started and if you save the value in a variable each time the timer is restarted you can calculate the elapsed time (elapsed time is the current time minus the start time).

Another way. Because the time for each color change is hard coded in your sketch, you would know its time to flash after the color goes to red (i.e. after ten seconds). For this to work you need to restart the color sequence from the first color when the sensor is covered.

I checked about :Millis" function.
I'm a Newbie, so I did't understand how I can use it in my sketch :cry:
Should I make "void redBlink..." or something??
Can I use "mills" directly into the loop?

Thank you for your help many times!!

The reference page for millis is here: millis() - Arduino Reference

And there are a few tutorials with examples of how to use it to determine elapsed time, here is one: http://www.arduino.cc/en/Tutorial/BlinkWithoutDelay

Try either of both of those examples and when you see how it works you can think about adding to your sketch.

Have fun

Thanks for your information!

I added a function of RED LED blink after RGB color changing.
Firstly, I tried Red LED blink code separately and it was working.
However when I added this sketch into the color timer sketch,
it doesn't work.... Could you help me to modify this sketch?

int ledPinG=10; //Green LED
int ledPinB=11; //BLUE LED
int ledPinR=12; //RED LED
int switchPin=2;  //Light sensor
int val;// Switch connected to digital pin 2
int value = LOW;                // previous value of the LED
long previousMillis = 0;        // will store last time LED was updated
long interval = 250;           // interval at which to blink (milliseconds)


void setup() {
  Serial.begin(9600);           // set up Serial library at 9600 bps
  pinMode(switchPin,INPUT);  // Light sensor as a switch
  pinMode(ledPinG,OUTPUT);  // sets the digital pin as input to read switch
  pinMode(ledPinB,OUTPUT);  // sets the digital pin as input to read switch
  pinMode(ledPinR,OUTPUT);  // sets the digital pin as input to read switch
}

void loop() { // G, B, R color change
  if( digitalRead(switchPin) == LOW) // light blue
    setColor(1,1,0,2000);
  if( digitalRead(switchPin) == LOW) // blue
    setColor(0,1,0,2000);    
  if( digitalRead(switchPin) == LOW) //green
    setColor(1,0,0,2000);  
  if( digitalRead(switchPin) == LOW) //yellow
    setColor(1,0,1,2000);
  if( digitalRead(switchPin) == LOW) //purple
    setColor(0,1,1,2000);    
  if( digitalRead(switchPin) == LOW) //red
    setColor(0,0,1,2000);    
  // add more colors--------------
  
  // Red LED blinks
   if ( (millis() - previousMillis > interval) ) {
         previousMillis = millis();                         // remember the last time - blinked the LED
         // if the LED is off turn it on and vice-versa.
         if (value == LOW)
            value = HIGH;
         else
            value = LOW;
         digitalWrite(ledPinR, value);
   }
   
   // turn LEDs off
   if( digitalRead(switchPin) == HIGH)
   setColor(0,0,0,0);

}

void setColor(int R, int G, int B, int delayMs){
  // set the LED colors and delay for the given number of milliseconds
  // but return if sensor is covered
  digitalWrite(ledPinG, R);
  digitalWrite(ledPinB, G);
  digitalWrite(ledPinR, B);
  while(delayMs--){
    // this loop checks the sensor every millisecond
    delay(1);
    if(digitalRead(switchPin) == HIGH)
      return; // exit the while loop if sensor is covered  
        }
}

Eclipse,

I believe your problem stems from this little snippet of code:

  if ( (millis() - previousMillis > interval) ) {
         previousMillis = millis();                         // remember the last time - blinked the LED
         // if the LED is off turn it on and vice-versa.
         if (value == LOW)
            value = HIGH;
         else
            value = LOW;
         digitalWrite(ledPinR, value);
   }
  
   // turn LEDs off
   if( digitalRead(switchPin) == HIGH)
   setColor(0,0,0,0);

In the first {} clause, you correctly flip the value of the red LED every 250ms. However in the very next line, you turn ALL the LEDs off, per the comment. If you turn an LED on and immediately turn it off, you won't be able to see it.

Mikal

Thanks for your feedback, mikalhart.

I tried to use "millis" function, but I couldn't manage "RGB color changing" part with this "RED LED blinks" part in my sketch...
Sorry, I'm new to programming... If it possible, could someone modify it?
Thanks so much!

Hi Eclipsemints,

When you tried the red blink code by itself, it was the only thing in the main loop of the sketch... that is, inside void loop(). Anything inside void loop() will repeat forever, so in that case, the red link blinked.

When you moved it into your original code, it no longer repeats, because only the entire void loop() repeats. So you flash the various leds, toggle the red led once, and then immediately, either turn everything off if switchpin is high, and restart the loop or go straight to restarting the loop and if switchpin is low, start with cyan (light blue) in which the red led is off.

What you need to do is put the red blink code into its own loop, for example a while loop, which will continue looping as long as (i.e. while) switchpin is low.

Here is the reference for the while loop, see if you can change your code to put the red blink inside one, with the stay-in-loop-while-this-is-true condition (switchpin == low).

Good luck! :wink:

It may help you to see what is happening if you familiarize yourself with millis by playing around with a simpler sketch.

Perhaps try a sketch that just turns on an LED after a few seconds using millis.

Then try adding code some millis code to turn the led off a few seconds after its turned on.

Although using delay would be a more natural choice in this exercise, doing this using millis should give you insight as to how to apply it in your timer application.

Try it and see how you get on

Thanks so much everyone!! :wink: and
thanks, mem for your "millis" information again!!

I used "while" function into the loop in the last part, like below.

  while ( digitalRead(switchPin) == LOW){
    digitalWrite(ledPinR,HIGH);
  delay(250);
    digitalWrite(ledPinR,LOW);
  delay(250);
     if( digitalRead(switchPin) == HIGH)
   setColor(0,0,0,0);  // turn LEDs off      
  }
       if( digitalRead(switchPin) == HIGH)
   setColor(0,0,0,0);  // turn LEDs off

It probably looks a strange sketch for you guys (professionals),
but the timer is somehow working well that what I want to do.
Mills function is still diffucult for me at this stage :frowning:
But I will keep learn more about the program!!

Thanks again :wink: You guys helped me a lot!!
(But I will ask another question sometime in new topic. c u then!)

Using delay instead of millis is cheating :wink:
It's a good thing programming is one of the few places where cheating is not only acceptable, its often highly desirable.

Delay works because you don't need to do anything during the delay period. But if you enhance your application and do need to do something like flash LEDs within the delay period then you may want to reconsider using millis.

Think of that millis code as if it was like telling time using a clock. You look at the clock (call millis) to get the current time and save it in a variable. You can then always tell how much time has elapsed by looking at the clock again (calling millis) and taking the difference between the current time and the time you saved. You will know the desired time has elapsed when the difference between the current time and the start time is at least as big as your desired elapsed time.

Hope that makes sense. Have fun!

Keep having fun with Arduino and pretty soon, this will all be second nature. :wink:

Using delay instead of millis is cheating.

Mem's commentary is right on, eclipse. As soon as you decide you want to make just the tiniest extension to your program's function, you're going to facing some complicated surgery.

Any but the most trivial of my Arduino programs usually end up looking something like this:

static unsigned long old_millis = 0;
... // other state variables

void loop()
{
  unsigned long new_millis() = millis();

  Based on new_millis, old_millis, input pins and the state variables
  {
    do some stuff and modify the state variables
  }
  old_millis = new_millis;
}

And as Mathieu said, keep at it! This can be really fun.

Mikal