 # 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
*/
// 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);

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];

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];

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];

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

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.