Blinking LEDs for a set number of times followed by another action

This is my first project with the Arduino and I’ve spent hours trying to figure this out by trial & error and countless Google searches. I still can’t seem to crack the code though and would love some help. Here is what I am attempting to do:

I have 3 LEDs set to pins 2, 3 & 4. I need these 3 LEDs to blink 3x with a 500milli interval between each blink. After these 3 blinks, only one of the LEDs should light up at random. I’ve figured out the blinking of all 3 LEDs using millis:

int pin2 = 2;
int pin3 = 3;
int pin4 = 4;


long timestamp = 0;  // long is a much larger integer
boolean ledState = LOW;   
int delayLength = 500; // how long between intervals 


void setup() {
    
  pinMode(pin2, OUTPUT);
  pinMode(pin3, OUTPUT);
  pinMode(pin4, OUTPUT);
  
  Serial.begin(9600);
  
}

void loop() {

  // basic timer
  if ( millis() - timestamp > delayLength ) {
    // half a second has passed, do something
    ledState = !ledState; // toggles the ledState between true/false
    digitalWrite(pin2, ledState); // make the led change
    digitalWrite(pin3, ledState);
    digitalWrite(pin4, ledState);
    timestamp = millis();
    Serial.println(timestamp); }
  } 
 
 }

I’ve also figured out how to blink a random LED:

int pin2 = 2;
int pin3 = 3;
int pin4 = 4;
int timer = 100;

int ranNum;
int ranDel;

void setup() {
  
  randomSeed(analogRead(0));  
  
  pinMode(pin2, OUTPUT);
  pinMode(pin3, OUTPUT);
  pinMode(pin4, OUTPUT);
  
}

void loop() {
  
  //light up one LED at random
  ranNum=random(2,5);
  delay(500);
  digitalWrite(ranNum, HIGH);
  delay(1000);
  digitalWrite(ranNum, LOW);
  delay(2000);
    
}

I cannot, however, figure out how to bring these 2 together for the life of me. And this is only the first step. I also have another set of LEDs that I need to control with a slide potentiometer. I have this figured out but need to ensure that the LEDs react to the potentiometer in real time without any actual delays which is why I’m trying to use millis in my code here.

What's the problem you're facing in bringing them together? What have you tried, what is going wrong, what don't you understand.

Can you give us an example of how you attempted to bring them together?

Thanks for the response racemaniac. At this point I can’t remember everything that I’ve tried but I’ve been working with a lot of different conditional statements. I tried an if() statement but that didn’t do anything. Most of them don’t do anything except continue to blink all 3 LEDs. If something changes, what seems to always happen is:

a. One LED will blink at random.
b. All 3 will blink.
c. 1/3 of the LEDs will turn off.
d. All 3 will turn off.
e. Loop.

Here is the last attempt I made, which resulted in all 3 LEDs continually blinking:

const int pin2 = 2;
const int pin3 = 3;
const int pin4 = 4;

int maxnum = 3; //Blink LED 3 times
int count = 0; //Blink counter

int ranNum;
int ranDel;

long timestamp = 0;  // long is a much larger integer
boolean ledState = LOW;  
int delayLength = 500; // how long between intervals 


void setup() {
  
  randomSeed(analogRead(0));  
    
  pinMode(pin2, OUTPUT);
  pinMode(pin3, OUTPUT);
  pinMode(pin4, OUTPUT);
  
  Serial.begin(9600);
  
}

void loop() {
    

  // basic timer
  if ( (millis() - timestamp > delayLength) && (count < maxnum) ) {
    // half a s second has passed, do something
    ledState = !ledState; // toggles the ledState between true/false
    digitalWrite(pin2, ledState); // make the led change
    digitalWrite(pin3, ledState);
    digitalWrite(pin4, ledState);
    timestamp = millis();
    Serial.println(timestamp); 
  
    count=0; }
 
  else {
     //light up one LED at random
  ranNum=random(2,5);
  delay(500);
  digitalWrite(ranNum, HIGH);
  delay(1000);
  digitalWrite(ranNum, LOW);
  delay(2000); 
  
  count++; }
  
 }

The main problem I’m having is trying to get the 3 LEDs to blink 3 times, stop, have only one LED light up up at random, and repeat. This wouldn’t be an issue if I could use delays but I can’t use delays as it causes other problems so I’m trying to stick with millis. The ultimate goal is to replicate the rock, paper, scissors game. So the 3 blinks is how much time the player will have to make their move. The random blink will be the machine’s move. On the other side is 3 LEDs that will be controlled by the player with a slide potentiometer to position their LED to either the rock, paper or scissor icons.

I hope this helps or provides some context. I feel like I’m missing something very obvious.

looking at your attempt, i see a few strange things in the code:

the errors i see:

  • you’re trying to blink your leds 3 times, but at the end of the blinking part you put “count = 0”, so you can’t keep track of how often they blinked yet…

-on the other hand, after lighting a random led you do increase count, but i thought it’s the blinking of the 3 leds you’re trying to count?

-If the 3 leds blinking are not yet triggered since “millis() - timestamp > delayLength” is false, you’ll immediatly go to lighting a random led.

If i read this code, my expectations of the flow would be:

  • you loop the first time.
  • millis() - timestamp > delayLength is false, so you go to the else statement
  • you light a random led (which takes about 3.5 seconds), count is increased to 1
  • you loop the second time
  • millis() - timestamp > delayLength is true (since at least 3.5 seconds have passed due to lighting the random led)
  • count < maxnum is also true, since you only increased count once so far, it’s 1 now
  • you light up all 3 leds.
  • count is set to 0
  • you loop the third time
  • millis() - timestamp > delayLength is false, so you go to the else statement
  • you would light a random led (but it’s still lit), but will turn it off afterwards, so only 2 leds are lit anymore
    -count is increased to 1 again
  • you loop the 4th time
  • millis() - timestamp > delayLength is true (since at least 3.5 seconds have passed due to lighting the random led)
  • count < maxnum is also true (count is 1)
  • you turn off all the leds again

And this will be repeated forever.

So this indeed exactly described the pattern you described. The arduino is doing exactly what you coded it to do :).

I hope this makes you understand reading your if-else statements a bit better. In the beginning this is very hard.
A good tip would be to read about the serial communication: http://arduino.cc/en/Serial/Println
There are some demo sketches in the IDE that show how to setup the serial communication, and how to print out data.
In your loop, and in your IF & ELSE branches, put some println statements saying for example “i’ve entered the if statement” , “count = 1”, “ledstate is true”, etc… You’ll get immediate insight into what your program is doing, how it’s behaving each loop :).

and btw, sounds like a fun project. very original, and very doable for a novice :).

I thought of some additional suggestions that might help you :).

  • try making a program that blinks the led 3 times, and then stops doing anything at all.
  • try making a program that just once selects a random led to light, and then stops doing anything at all.

If you make these programs, they're far easier to combine than having programs just constantly looping trough both those actions :).

Racemaniac, you are one of the best strangers I've met on the Internet. Thanks for your input and feedback! I didn't think it would be possible to get the LEDs to do something a set number of times and then stop because I assumed it would forever do a constant loop, no matter what. That is good to know. I think I will start there. XD

Ok, I think I’m getting a bit closer but am not sure if this is the best way of going about it. In fact, I’m sure there must be a better way. Here is the combined code:

int pin2 = 2;
int pin3 = 3;
int pin4 = 4;


long timestamp = 0;  // long is a much larger integer
boolean ledState = LOW;   
int delayLength = 500; // how long between intervals 

int ranNum;
int ranDel;

int maxnum = 1; //Blink random LED 1 time
int count = 0; //Blink counter


void setup() {
  
  randomSeed(analogRead(0));  
    
  pinMode(pin2, OUTPUT);
  pinMode(pin3, OUTPUT);
  pinMode(pin4, OUTPUT);
    
  Serial.begin(9600);
  
}

void loop() {

  // make all 3 LEDs flash 3x
  if ( (millis() - timestamp > delayLength) && (timestamp < 2506) ) {
    // half a second has passed and timestampe is less than 2506, do:
    ledState = !ledState; // toggles the ledState between true/false
    digitalWrite(pin2, ledState); // make the led change
    digitalWrite(pin3, ledState);
    digitalWrite(pin4, ledState);
    timestamp = millis();
    Serial.println(timestamp); 
  } 
  
    //light up one LED at random for 4 seconds
  if ( (timestamp > 2510) && (count < maxnum) ) {
  ranNum=random(2,5);
  digitalWrite(ranNum, HIGH);
  delay(4000);
  digitalWrite(ranNum, LOW);
  delay(2000);
  Serial.println(count);
  
  count++; //increments count making if statement false
  }
  
}

When I run this code, it flashes all 3 LEDs 3x and then turns off 2 of them at random leaving 1 random LED on. This more or less achieves what I want; however, I’d prefer that 1 random LED turn ON rather than 2 random LEDs turning off. The other, more significant problem, is that I don’t know how to now loop this. As it stands, it runs once and then stops altogether because I’ve based my if() statements on timestamps and I’m not sure that timestamps can be reset.

And while I don’t want to get too ahead of myself, I have to keep in mind that I also have to be able to use a slide potentiometer on a completely different set of LEDs and have these LEDs react to the pot in real time.

halfnote: ...however, I'd prefer that 1 random LED turn ON rather than 2 random LEDs turning off.

How many milliseconds do you think it would take to turn them all off, and then randomly lite one of them?

Answer: unnoticeable to human perception.

Either way is the same, unless you may be getting graded on following the instructions, then that are not the same.

Also, how many times does setup() run?

halfnote:
Ok, I think I’m getting a bit closer but am not sure if this is the best way of going about it. In fact, I’m sure there must be a better way. Here is the combined code:

int pin2 = 2;

int pin3 = 3;
int pin4 = 4;

long timestamp = 0;  // long is a much larger integer
boolean ledState = LOW;   
int delayLength = 500; // how long between intervals

int ranNum;
int ranDel;

int maxnum = 1; //Blink random LED 1 time
int count = 0; //Blink counter

void setup() {
 
  randomSeed(analogRead(0)); 
   
  pinMode(pin2, OUTPUT);
  pinMode(pin3, OUTPUT);
  pinMode(pin4, OUTPUT);
   
  Serial.begin(9600);
 
}

void loop() {

// make all 3 LEDs flash 3x
  if ( (millis() - timestamp > delayLength) && (timestamp < 2506) ) {
    // half a second has passed and timestampe is less than 2506, do:
    ledState = !ledState; // toggles the ledState between true/false
    digitalWrite(pin2, ledState); // make the led change
    digitalWrite(pin3, ledState);
    digitalWrite(pin4, ledState);
    timestamp = millis();
    Serial.println(timestamp);
  }
 
    //light up one LED at random for 4 seconds
  if ( (timestamp > 2510) && (count < maxnum) ) {
  ranNum=random(2,5);
  digitalWrite(ranNum, HIGH);
  delay(4000);
  digitalWrite(ranNum, LOW);
  delay(2000);
  Serial.println(count);
 
  count++; //increments count making if statement false
  }
 
}




When I run this code, it flashes all 3 LEDs 3x and then turns off 2 of them at random leaving 1 random LED on. This more or less achieves what I want; however, I'd prefer that 1 random LED turn ON rather than 2 random LEDs turning off. The other, more significant problem, is that I don't know how to now loop this. As it stands, it runs once and then stops altogether because I've based my if() statements on timestamps and I'm not sure that timestamps can be reset. 

And while I don't want to get too ahead of myself, I have to keep in mind that I also have to be able to use a slide potentiometer on a completely different set of LEDs and have these LEDs react to the pot in real time.

you’re making great progress :).

a next suggestion: how about just using timestamps for timing your led action, and not for also seeing what you have to do? it right now makes your timestamps pretty complicated to keep track of.
make a second variable, named state. state 0 = for example could mean that you’re blinking your leds. After the leds have blinked 3 times, have the code blinking the leds put the state to 1. state 1 is selecting a random led and lighting it for a certain amount of time. After this time has expired, the lighting a random led could can put the state back to 0. and you’ll loop nicely trough the 2 behaviors.

If you then want to expand this with more actions, you can just add more states. If multiple actions need to happen together, you can have multiple pieces of code share the same state (so when state = 0, both the flashing of the leds is triggered, but also the reading of the potentiometer).

it is possible to make everything timing based, and keep track of all information in 1 variable, but it makes everything a lot more complicated, and unless you’re making a huge sketch and need every byte you can get, you’re just making it hard for yourself :).

And as bulldog already set, why 2 leds are turning off, rather than 1 turning on, is becasue after turning off all 3 leds, your code doesn’t wait before turning 1 on again. so you won’t be able to see it turning off those 3 leds, it’s just way too fast :).

good luck :).

That totally makes sense @bulldogLowell. Good point. :)

Thanks again for the input @racemaniac! I was actually doing some research on just that last night--trying to wrap my head around states and figure out how to work w/ those instead of the way I have it currently set up. Your explanation helps clarify a few things. Hopefully I'll have this squared away soon and can share my code in this thread for anyone else that might encounter a similar situation. XD

Progress has been made! But still running into some problems. Namely, I can’t get only one random LED to blink. Anytime the serial monitor returns a 3 or 4 for randNum, I get two LEDs. I introduced a delay and confirmed that they’re lighting up separately, I’m guessing because of the gameState, but I find it odd that it only does it when randNum is 3 or 4, and never for 2. I can’t figure out for the life of me how to get the program to select a single LED, turn it on and keep it on without turning any others on. I tried commenting out the line in void showResults that also states digitalWrite(randNum, HIGH); but that didn’t actually do the trick. Any help would be greatly appreciated!

//LEDs for the machine
int pin2 = 2;
int pin3 = 3;
int pin4 = 4;

int blinkCounter = 0;
long timestamp = 0;  // long is a much larger integer
boolean ledState = LOW;   
int delayLength = 500; // how long between intervals 

int randNum;

//int maxnum = 1; //Blink LED 1 times
//int count = 0; //Blink counter

int gameState = 0; // 0 = 3 LEDs blinking + potentiometer / game play
              //  1 = results

int val = 0; //used to store the state of the input pin

// INPUT: Potentiometer should be connected to 5V and GND
int potPin = 3; // Potentiometer output connected to analog pin 3
int potVal = 0; // Variable to store the input from the potentiometer
int potChoice; // the final choice from each game round

boolean gameResult = false; // did i win or not
boolean tieGame = false;

// LEDs for the potentiometer
int rockPin = 9;   // Red LED,   connected to digital pin 9
int paperPin = 10;  // Green LED, connected to digital pin 10
int scissorsPin = 11;  // Blue LED,  connected to digital pin 11

// Program variables
int rockVal = 0;   // Variables to store the values to send to the pins
int paperVal = 0;
int scissorsVal = 0;

// SOUND
int speakerPin = 8;

void setup() {
  
  randomSeed(analogRead(0));  
    
  pinMode(pin2, OUTPUT);
  pinMode(pin3, OUTPUT);
  pinMode(pin4, OUTPUT);
  
  pinMode(rockPin, OUTPUT);   // sets the players pins as output
  pinMode(paperPin, OUTPUT);   
  pinMode(scissorsPin, OUTPUT); 
  
   // init Button Sound
   pinMode(speakerPin, OUTPUT);  
    
  Serial.begin(9600);
  
  startGame();
  
}

void loop() {
  
  
  if (gameState == 0) {
    // do the 3 blinks
    blinkThreeTimes(); //this will blink and play sounds
    checkPotentiometer(); // this will check the slider, and turn on corresponding LEDs
    //checkResults(); // keep both LEDs on HIGH
  } else {
     // results 
    showResults(); // turn on the chosen random LED
    playResultSounds(); // play either victory or defeat sound
  }
  
 
}

    


 

 
  void startGame() {
  gameState = 0;
  timestamp = millis(); 
  blinkCounter = 0;
  randomSeed(analogRead(0)); 
}

void playTone(int tone, int duration) {
  for (long i = 0; i < duration * 1000L; i += tone * 2) {
    digitalWrite(speakerPin, HIGH);
    delayMicroseconds(tone);
    digitalWrite(speakerPin, LOW);
    delayMicroseconds(tone);
  }
}


void blinkThreeTimes() {

  if ( (millis() - timestamp > delayLength)) {
    ledState = !ledState; // toggles the ledState between true/false
    digitalWrite(pin2, ledState); // make the led change
    digitalWrite(pin3, ledState);
    digitalWrite(pin4, ledState);
    timestamp = millis();
    blinkCounter++;

    Serial.print("blink:");
    Serial.println(blinkCounter);

    if (blinkCounter == 6) {
      checkResults(); 
    }
  } 

}

void checkPotentiometer() {
  potVal = analogRead(potPin);   // read the potentiometer value at the input pin
  //potChoice = map(potVal, 0, 1023, 4, 2);

  if (potVal < 341)  // Lowest third of the potentiometer's range (0-340)
  {                  
    potVal = (potVal * 3) / 4; // Normalize to 0-255

    rockVal = 256 - potVal;  // Rock from full to off
    paperVal = 1;        // Paper from off to full
    scissorsVal = 1;             // Scissor off
    potChoice = 2;
  }
  else if (potVal < 682) // Middle third of potentiometer's range (341-681)
  {
    potVal = ( (potVal-341) * 3) / 4; // Normalize to 0-255

    rockVal = 1;            // Rock off
    paperVal = 256 - potVal; // Paper from full to off
    scissorsVal = 1;       // Scissor from off to full
    potChoice = 3;
  }
  else  // Upper third of potentiometer"s range (682-1023)
  {
    potVal = ( (potVal-683) * 3) / 4; // Normalize to 0-255

    rockVal = 1;       // Rock from off to full
    paperVal = 1;            // Paper off
    scissorsVal = 256 - potVal; // Scissor from full to off
    potChoice = 4;
  }
  analogWrite(rockPin, rockVal);   // Write values to LED pins
  analogWrite(paperPin, paperVal); 
  analogWrite(scissorsPin, scissorsVal); 
}


void checkResults() {
  
   //gameState = 1; 

  //select random lED
  randNum=random(2,5);
  //turn random LED on
  digitalWrite(randNum, HIGH);
  delay(1000);
  digitalWrite(randNum, LOW);
  
  Serial.print("potChoice:");
  Serial.print(potChoice);

  Serial.print("     random:");
  Serial.println(randNum);

  if (randNum == potChoice) {
    Serial.println("TIE GAME"); 
    // TIE GAME
    tieGame = true;
  } 
  else {
    // it's not a tie. you either won or lost
    gameResult = judgeGame(potChoice, randNum);
  }

  gameState = 1;


} 

boolean judgeGame(int potChoice, int randNum) {

  boolean finalResult;

  switch (potChoice) {
  case 2:
    //do something when var equals 2
    if (randNum == 4) {
      finalResult = true; 
    } 
    else {
      finalResult = false;
    }
    break;
  case 3:
    //do something when var equals 3
    if (randNum == 2) {
      finalResult = true; 
    } 
    else {
      finalResult = false;
    }
    break;
  case 4:
    //do something when var equals 4
    if (randNum == 3) {
      finalResult = true; 
    } 
    else {
      finalResult = false;
    }
    break;
  default: 
    // if nothing else matches, do the default
    // default is optional
    Serial.print("the switch case broke");
    Serial.println(potChoice);
    finalResult = false;
  }

  return finalResult;
}


void showResults() {

  if (tieGame == true) {
    // do the tie blinky thing

  } 
  else {
    //lights go solid

    //keep random LED on
    digitalWrite(randNum, HIGH);

    // if the pot value is faded
    digitalWrite(potChoice, HIGH);

  }
 

}

void playResultSounds() {

  /*if (tieGame == true) {
    // play tie sounds
  } 
  else {
    if (gameResult == true) {
      //sound of victory
      int length = 13; // power up.
    int tempo = 30;
    int tones[] = {5800, 5700, 5500, 4000, 3000, 2000, 1000, 500, 250, 200, 150, 120, 110}; 
    int beats[] = {1,    1,    1,    1,    1,    1,    1,    1,   1,   1,   1,   1,   1  };  
    
    for (int i=0; i < length; i++) {
      if (tones[i] == 0) {
        delay(beats[i] * tempo); // rest
      } else {
        playTone(tones[i], beats[i] * tempo);
      }
    }


    } 
    else {
      // play sound of defeat
      int length = 4; // crazy, high, machine
      int tempo = 30;
      int tones[] = {1915, 1014, 700, 1915}; 
      int beats[] = {1,   1,   1, 1 };
      
      
      
      for (int i=0; i < length; i++) {
        if (tones[i] == 0) {
          delay(beats[i] * tempo); // rest
        } else {
          playTone(tones[i], beats[i] * tempo);
        }
      }
        }     
  } */
  
}

as your code is now, i think it’ll never move to blinking a random led (as you said, you commented that part out).
if i would remove the comment, i would expect it to immediately go to selecting a random led (since there’s nothing stopping it), that can’t be the goal either?

About the problem you have: it shouldn’t be that hard to figure out yourself. You’re sure it’s wired correctly? if it is, either you’re setting both pins high, or you haven’t set the pin low before moving to the random part.
Which leds are on when the value is 3 or 4? is it the first led, and the led that is supposed to be on? then when the first led is the only one being lit, it’s probably just because you didn’t turn it off before going to the random led part. So it’s still on, if random selects the first one, it keeps it lit, if it’s one of the other 2, it lights them too, but doesn’t turn off the first one.

:roll_eyes:I think the random() function on arduino should work well for this! Here is an example: long randNumber;

void setup(){ Serial.begin(9600);

// if analog input pin 0 is unconnected, random analog // noise will cause the call to randomSeed() to generate // different seed numbers each time the sketch runs. // randomSeed() will then shuffle the random function. randomSeed(analogRead(0)); }

void loop() { // print a random number from 0 to 299 randNumber = random(300); Serial.println(randNumber);

// print a random number from 10 to 19 randNumber = random(10, 20); Serial.println(randNumber);

delay(50); }

Instead of printing the numbers you may use array for the leds with constrain() function to set the max and min , and use the random numbers!

Just wanted to follow up here and share my post on the project now that it's completed. There's a link to download the code if anyone is interested.

http://anakhachatrian.tumblr.com/post/89113030182/rock-paper-scissors

Well done, i'm going to have a look at it :). (maybe quickly build one myself to have a go with it). Thanks for mentioning me in your post (that's awesome), and the reverse is also true, it's great being able to help someone that's trying to figure things out themselves :). When reading this forum it's sometimes frustrating to have people just come ask every little thing, and getting annoyed when you don't do all the work/thinking/searching for them (although it's probably often younger people who don't have the patience yet). It's always nice to be able to help someone who likes pointers on where to go next, and doesn't just want more experienced people to do the work for them :).

And pretty awesome that you post your results here too, that should happen more often XD.