Blinking a single LED at multiple speeds (within a larger program)

Strap in, because there’s a bit of context here.

My goal here is to improve a concept I saw in a journal, “The Physics Teacher”, designed to teach kids the RGB color system. The Arduino produces static RGB values and outputs them to an example RGB LED, then the user adjusts 3 potentiometers (one for each color) to try to reproduce the color on a second RGB LED. A yellow LED turns on when the user comes within 5% of the computer-generated value for every color, and there is a button that tells the Arduino to generate new static RGB values (essentially resetting the program).

For clarity’s sake, you can find a (slightly messy) representation of this circuit here. The resistors are 220Ω, and the potentiometers are 10kΩ.

Nick Gammon says to “post your complete sketch”, but I ran out of character space. I’ll post it as the first reply to this thread.


So here's my issue: I want the yellow LED to flash at an increasing pace as the user gets closer to matching his RGB LED with the computer's. If one color matches(within 5%), it blinks every second; if two match, it blinks every half second; if all three match, it becomes constant. I found out quickly that **delay()** is a bad choice to try accomplish this.

After viewing the [Blink Without Delay](http://www.arduino.cc/en/Tutorial/BlinkWithoutDelay) tutorial, I applied the **millis()** function to my own code. The problem is, I am not sure how to implement it to use for more than one "LED flash interval", and especially how to implement it when my LED only flashes within an **if** statement. Here is what I am currently working with for creating this interval system: 

```
void loop() {

  // internal clock
  unsigned long runningTime = millis();
  unsigned long previousTimeShort;
  unsigned long previousTimeLong;
  unsigned long previousTimeEnd;
  const long shortInterval = 500;
  const long longInterval = 1000;
  const long endInterval = 2000;
  int ledStatusShort;
  int ledStatusLong;
  if (runningTime - previousTimeShort >= shortInterval) {
   previousTimeShort = runningTime;
   ledStatusShort = 1;
  }
  if (runningTime - previousTimeLong >= longInterval) {
    previousTimeLong = runningTime;
    ledStatusShort = 0;
    ledStatusLong = 1;
  }
  if (runningTime - previousTimeEnd >= endInterval) {
    previousTimeEnd = runningTime;
    ledStatusLong = 0;
  }
  /* 
  omitting parts of the program that are not pertinent to the above code. you can find the full program
  below in the comments. 
  */
  // program end
  if ((abs(lastAverageRedValue-randRed)<=12.75) || (abs(lastAverageBlueValue-randBlue)<=12.75) || (abs(lastAverageGreenValue-randGreen)<=12.75) && (redCase==0) && (blueCase==0) && (greenCase==0)) {

     if ( ledStatusLong == 1) {
        digitalWrite(ledYellow, HIGH);
     }
     else {
        digitalWrite(ledYellow, LOW);
     }
  }

  if (((abs(lastAverageRedValue-randRed)<=12.75) && (abs(lastAverageBlueValue-randBlue)<=12.75)) || ((abs(lastAverageRedValue-randRed)<=12.75) && (abs(lastAverageGreenValue-randGreen)<=12.75)) || ((abs(lastAverageBlueValue-randBlue)<=12.75) && (abs(lastAverageGreenValue-randGreen)<=12.75)) && (redCase==0) && (blueCase==0) && (greenCase==0)) {

     if ( ledStatusShort == 1) {
        digitalWrite(ledYellow, HIGH);
     }
     else {
        digitalWrite(ledYellow, LOW);
     }
  }
  
  if ((abs(lastAverageRedValue-randRed)<=12.75) && (abs(lastAverageBlueValue-randBlue)<=12.75) && (abs(lastAverageGreenValue-randGreen)<=12.75) && (redCase==0) && (blueCase==0) && (greenCase==0)) {
    Serial.println("Color Match Within 5%");
    
    redCase=1;
    blueCase=1;
    greenCase=1;
    
    digitalWrite(ledYellow, HIGH);
  }
  
  delay(10);

}
```

I had originally tried tracking time within my **if** statements, but that didn't work for obvious reasons. My solution was to track time at the beginning of my loop, then use two variables (**ledStatusShort** and **ledStatusLong**) that will be used when the **if** statements are true. 

By troubleshooting, I discovered that my __previousTime*__ variable values were just being fed **runningTime**, yet I can't figure out why. And even if that were working, my **if** statements have a problem: if the conditions for the **if** statements change while either __ledStatus*__ variable == 1, the LED won't have an opportunity to turn off until the **if** statement is true again. 

Feel free to let me know if I am going down the completely wrong trail. I have come to the forums because I have hit a brick wall in my own abilities, and I would greatly appreciate any help that can be offered.

Here is the whole sketch for the project:

// rgb_led_tuning_smooth

int switchButton=2;                      // fixed color reset switch
int ledYellow=7;                         // "success" indicator

int rgbRed=6;                            // user controlled LEDs
int rgbBlue=5;
int rgbGreen=3;

int fixedRed=9;                          // computer generated LED
int fixedBlue=10;
int fixedGreen=11;

int pinPotentiometerRed=A1;              // potentiometer inputs
int pinPotentiometerGreen=A3;
int pinPotentiometerBlue=A5;

long randRed, randBlue, randGreen;       // random values for computer generated LED

int redCase=0;                           // simple paramaters used to stop program when colors match
int blueCase=0;
int greenCase=0;

const int NUM_SAMPLES=5;                 // edit to alter # of samples needed to recalculate avg

int redSamples[NUM_SAMPLES];             // temp storage values for calculating avg value
int greenSamples[NUM_SAMPLES];
int blueSamples[NUM_SAMPLES];

int redIndex=0;                          // indexing?
int greenIndex=0;
int blueIndex=0;

int totalRedValue=0;                     // for calculating avg value
int totalGreenValue=0;
int totalBlueValue=0;

int lastAverageRedValue=0;
int lastAverageGreenValue=0;
int lastAverageBlueValue=0;

const int CHANGE_THRESHOLD=4;            // edit to alter minimum color change required to set new avg

void setup() {
  
  Serial.begin(9600); 
  
  randomSeed(analogRead(0));

  pinMode(switchButton, INPUT);
  pinMode(ledYellow, OUTPUT);
  pinMode(rgbRed, OUTPUT);
  pinMode(rgbBlue, OUTPUT);
  pinMode(rgbGreen, OUTPUT);
  pinMode(fixedRed, OUTPUT);
  pinMode(fixedBlue, OUTPUT);
  pinMode(fixedGreen, OUTPUT);

  analogWrite(fixedRed, 0);
  analogWrite(fixedBlue, 0);
  analogWrite(fixedGreen, 0);
  digitalWrite(ledYellow, LOW);

  for (int i=0; i<NUM_SAMPLES; i++) {     // building the averaging index
    redSamples[i]=0;
    greenSamples[i]=0;
    blueSamples[i]=0;
  }

void loop() {

  // internal clock
  unsigned long runningTime = millis();
  unsigned long previousTimeShort;
  unsigned long previousTimeLong;
  unsigned long previousTimeEnd;
  const long shortInterval = 500;
  const long longInterval = 1000;
  const long endInterval = 2000;
  int ledStatusShort;
  int ledStatusLong;
  if (runningTime - previousTimeShort >= shortInterval) {
   previousTimeShort = runningTime;
   ledStatusShort = 1;
  }
  if (runningTime - previousTimeLong >= longInterval) {
    previousTimeLong = runningTime;
    ledStatusShort = 0;
    ledStatusLong = 1;
  }
  if (runningTime - previousTimeEnd >= endInterval) {
    previousTimeEnd = runningTime;
    ledStatusLong = 0;
  }
  
  // red potentiometer input setup
  totalRedValue -= redSamples[redIndex];
  
  int currentRedValue=analogRead(pinPotentiometerRed);
  currentRedValue=map(currentRedValue, 0, 1023, 0, 255);
  
  totalRedValue += currentRedValue;
  redSamples[redIndex] = currentRedValue;

  redIndex++;
  if (redIndex>NUM_SAMPLES-1) redIndex=0;

  int averageRedValue=totalRedValue/NUM_SAMPLES;

  int changeR = abs(averageRedValue-lastAverageRedValue);
  if (changeR >= CHANGE_THRESHOLD){
    lastAverageRedValue = averageRedValue;
  }

  if (currentRedValue == 0 ) {                                          // compensates for average at 0 not meeting change threshold
    lastAverageRedValue=0;
  }

  // green potentiometer input setup
  totalGreenValue -= greenSamples[greenIndex];
  
  int currentGreenValue=analogRead(pinPotentiometerGreen);
  currentGreenValue=map(currentGreenValue, 0, 1023, 0, 255);

  totalGreenValue += currentGreenValue;
  greenSamples[greenIndex] = currentGreenValue;

  greenIndex++;
  if (greenIndex>NUM_SAMPLES-1) greenIndex=0;

  int averageGreenValue=totalGreenValue/NUM_SAMPLES;

  int changeG = abs(averageGreenValue-lastAverageGreenValue);
  if (changeG >= CHANGE_THRESHOLD) {
    lastAverageGreenValue = averageGreenValue;
  }

  if (currentGreenValue == 0) {                                        // compensates for average at 0 not meeting change threshold
    lastAverageGreenValue=0;
  }
  
  // blue potentiometer input setup
  totalBlueValue -= blueSamples[blueIndex];
  
  int currentBlueValue=analogRead(pinPotentiometerBlue);
  currentBlueValue=map(currentBlueValue, 0, 1023, 0, 255);

  totalBlueValue += currentBlueValue;
  blueSamples[blueIndex] = currentBlueValue;

  blueIndex++;
  if (blueIndex>NUM_SAMPLES-1) blueIndex=0;

  int averageBlueValue=totalBlueValue/NUM_SAMPLES;

  int changeB = abs(averageBlueValue-lastAverageBlueValue);
  if (changeB >= CHANGE_THRESHOLD) {
      lastAverageBlueValue = averageBlueValue;
  }

  if (currentBlueValue == 0) {                                        // compensates for average at 0 not meeting change threshold
    lastAverageBlueValue=0;
  }

  // user input --> output
  analogWrite(rgbRed, lastAverageRedValue);
  analogWrite(rgbGreen, lastAverageGreenValue);
  analogWrite(rgbBlue, lastAverageBlueValue);

  // computer output setup
  if(digitalRead(switchButton)==HIGH) {

    digitalWrite(ledYellow, LOW); 
    
    randRed=random(0,201);
    randBlue=random(0,201);
    randGreen=random(0,201);

    // prints the random rgb values
    Serial.print("Red");
    Serial.print(randRed);
    Serial.print(" | ");
    Serial.print("Green");
    Serial.print(randGreen);
    Serial.print(" | ");
    Serial.print("Blue");
    Serial.print(randBlue);
    Serial.println(" | ");

    redCase=0;
    greenCase=0;
    blueCase=0;

    delay(10);
  }
  
  // computer output
  analogWrite(fixedRed, randRed);
  analogWrite(fixedBlue, randBlue);
  analogWrite(fixedGreen, randGreen);

  // live printing of potentiometer rgb values
  if((redCase==0) && (greenCase==0) && (blueCase==0)) {
    Serial.print("Red");
    Serial.print(randRed);
    Serial.print(" | ");
    Serial.print("Green");
    Serial.print(randGreen);
    Serial.print(" | ");
    Serial.print("Blue");
    Serial.print(randBlue);
    Serial.print(" | ");
    Serial.print(" |-|=|-| ");
    Serial.print("Red");
    Serial.print(lastAverageRedValue);
    Serial.print(" | ");
    Serial.print("Green");
    Serial.print(lastAverageGreenValue);
    Serial.print(" | ");
    Serial.print("Blue");
    Serial.print(lastAverageBlueValue);
    Serial.print(" |-|=|-| ");
    Serial.println(runningTime);
    delay(10);
  }
  
  // program end
  if ((abs(lastAverageRedValue-randRed)<=12.75) || (abs(lastAverageBlueValue-randBlue)<=12.75) || (abs(lastAverageGreenValue-randGreen)<=12.75) && (redCase==0) && (blueCase==0) && (greenCase==0)) {

     if ( ledStatusLong == 1) {
        digitalWrite(ledYellow, HIGH);
     }
     else {
        digitalWrite(ledYellow, LOW);
     }
  }

  if (((abs(lastAverageRedValue-randRed)<=12.75) && (abs(lastAverageBlueValue-randBlue)<=12.75)) || ((abs(lastAverageRedValue-randRed)<=12.75) && (abs(lastAverageGreenValue-randGreen)<=12.75)) || ((abs(lastAverageBlueValue-randBlue)<=12.75) && (abs(lastAverageGreenValue-randGreen)<=12.75)) && (redCase==0) && (blueCase==0) && (greenCase==0)) {

     if ( ledStatusShort == 1) {
        digitalWrite(ledYellow, HIGH);
     }
     else {
        digitalWrite(ledYellow, LOW);
     }
  }
  
  if ((abs(lastAverageRedValue-randRed)<=12.75) && (abs(lastAverageBlueValue-randBlue)<=12.75) && (abs(lastAverageGreenValue-randGreen)<=12.75) && (redCase==0) && (blueCase==0) && (greenCase==0)) {
    Serial.println("Color Match Within 5%");
    
    redCase=1;
    blueCase=1;
    greenCase=1;
    
    digitalWrite(ledYellow, HIGH);
  }
  
  delay(10);

}
static unsigned long previousTimeLong;

Would make more sense, IMO.

Good luck with color blind students. They don't like to advertise.