Issue with playing sound and running lights at same time

Hi Arduino community,

I'm having a little trouble with making my setup do what I want it to.

I have LED's, an optical sensor (works similar to a garage door sensor) and an 8ohm speaker

What it's doing currently in this specified order:
(in the void setup( ) )

  1. Arduino turns on
  2. pins 1-5 LED's turn on an off one after the other with a delay of 150 milliseconds
  3. pins 6-8 LED's all turn on and off at same time
  4. they are all on LOW after this has been done

(in the void loop( ) )

  1. If something passes through optical sensor #1 (labeled WINsensor in code), LED's turn on and off one after the other with a delay of 150 milliseconds
  2. pins 6-8 LED's turn on and stay on
  3. The default melody plays
  4. pins 6-8 LED's turn off

What I want it to do:

(in void loop ( ) )

  1. If something passes through optical sensor #1 (labeled WINsensor in code),pins 1-8 complete their sequence while the melody is playing

Here is my program currently:

 #include "pitches.h"



int led13= 13;
int led1 = 1;
int led2 = 2;
int led3 = 3;
int led4 = 4;
int led5 = 5;
int led6 = 6;
int led7 = 7;
int led8 = 8;


int melody[] = {
  NOTE_C4, NOTE_G3,NOTE_G3, NOTE_A3, NOTE_G3,0, NOTE_B3, NOTE_C4};
  int noteDurations[] = {
  4, 8, 8, 4,4,4,4,4 };


void setup() {

 


  pinMode(led1, OUTPUT); 
  
 pinMode(led2, OUTPUT);
 
 pinMode(led3, OUTPUT);
 
   pinMode(led4, OUTPUT);
  
  pinMode(led5, OUTPUT);
   
  pinMode(led6, OUTPUT);
  
  pinMode(led7, OUTPUT);
  
  pinMode(led8, OUTPUT);

  
  pinMode(led13, OUTPUT);
 
  digitalWrite(led13, HIGH);  //One LED will always stay on 
  
  
  
 //*****Sequence for lights*******
  
   digitalWrite(led1, HIGH);
  delay(150);
  digitalWrite(led1, LOW);
  delay(150);
  
  digitalWrite(led2, HIGH);
  delay(150);
  digitalWrite(led2, LOW);
  delay(150);
  
  digitalWrite(led3, HIGH);
  delay(150);
  digitalWrite(led3, LOW);
  delay(150);
  
  digitalWrite(led4, HIGH);
  delay(150);
  digitalWrite(led4, LOW);
  delay(150);
  
  digitalWrite(led5, HIGH);
  delay(150);
  digitalWrite(led5, LOW);
  delay(150);
  
    digitalWrite(led6, HIGH);
  digitalWrite(led7, HIGH);
  digitalWrite(led8, HIGH);
  
  
  delay(1000);

  digitalWrite(led6, LOW);
  digitalWrite(led7, LOW);
  digitalWrite(led8, LOW);
  
  
  
}
  




void loop() {

  

  
  
 int WINsensor = 12;         // **WINNING SENSOR DEFINED HERE** 
pinMode(WINsensor, INPUT);


 if (digitalRead(WINsensor) == HIGH){
 
 
  
 digitalWrite(led1, HIGH);
  delay(150);
  digitalWrite(led1, LOW);
  delay(150);
  
  digitalWrite(led2, HIGH);
  delay(150);
  digitalWrite(led2, LOW);
  delay(150);
  
  digitalWrite(led3, HIGH);
  delay(150);
  digitalWrite(led3, LOW);
  delay(150);
  
  digitalWrite(led4, HIGH);
  delay(150);
  digitalWrite(led4, LOW);
  delay(150);
  
  digitalWrite(led5, HIGH);
  delay(150);
  digitalWrite(led5, LOW);
  delay(150);
  
    digitalWrite(led6, HIGH);
  digitalWrite(led7, HIGH);
  digitalWrite(led8, HIGH);
  
  
 for (int thisNote = 0; thisNote < 9; thisNote++) {
   
    
   
int noteDuration = 1000/noteDurations[thisNote];
 tone(9, melody[thisNote],noteDuration);
 
 
 
    int pauseBetweenNotes = noteDuration * 1.30;
 
  delay(pauseBetweenNotes);
   
 
    
   
   
    noTone(9);
   }
  


  
  
  delay(300);
  
  digitalWrite(led6, LOW);
  digitalWrite(led7, LOW);
  digitalWrite(led8, LOW);
  
  
  delay(250);   
 }
else {
  digitalWrite(led1, LOW);
  digitalWrite(led2, LOW); 
  digitalWrite(led3, LOW); 
  digitalWrite(led4, LOW);  
  digitalWrite(led5, LOW); 
  digitalWrite(led6, LOW); 
digitalWrite(led7, LOW);
 digitalWrite(led8, LOW); 
}
  }

Here is also a picture of my setup:

(if it doesn't come up, here's a link: Imgur: The magic of the Internet )

~I understand that it's the delay function that is causing my problem, but I'm not sure how I can incorporate the millis( ) into my program to make it do what I want to do.

I will gladly take any suggestions/tips/similar project code that you've done etc.

Thank you in advance!!

To make your MCU do 'multitasking' you must rewrite...
Use 'millis()' to decide when an action is to take place.
Remove all delays.

make a timetable where every change has its place.
let the loop take care of changes at correct time

alternative: let one (of two) tasks be driven by an interrupt (set up a timer to generate it at your decided pace)

If it is any consolation your code is doing exactly what you wrote it to do.

make a timetable where every change has its place.
let the loop take care of changes at correct time

alternative: let one (of two) tasks be driven by an interrupt (set up a timer to generate it at your decided pace)

Thank you knut_ny for replying. Can you please show me how I'd go about doing that? I haven't grasped the concept of the millis( ) when used with a variable to manipulate actions.

I haven't grasped the concept of the millis( ) when used with a variable to manipulate actions.

See:-

http://www.thebox.myzen.co.uk/Tutorial/State_Machine.html

I have not tried this, but I hope i shows one way to solve this..

#include "pitches.h"

byte power = 13; //power on led
byte led[] = { 1,2,3,4,5,6,7,8};
//sequence contains:  starttime(ms),pin,status,tonetoplay,duration(ms)  
// if pin=0 no change.. if note=0  no change
int sequence[][5]={
{0   ,1,HIGH,NOTE_C4,250},
{150 ,1,LOW,0,0},
{300 ,2,HIGH,NOTE_G3,500},
{450 ,2,LOW,0,0},
{600 ,3,HIGH,0,0},
{750 ,3,LOW,NOTE_G3,500},
{1000,4,HIGH,0,0},
{1250,4,LOW,0,0},
{1500,5,HIGH,NOTE_A3,250},
{1750,5,LOW,0,0},
{2000,6,HIGH,NOTE_G3,250},
{2000,7,HIGH,0,0},
{2000,8,HIGH,0,0},
{2300,6,LOW,NOTE_B3,250},
{2300,7,LOW,0,0},
{2300,8,LOW,0,0},
{2600,0,0,NOTE_C4,250}
};
int lines_in_array= sizeof(sequence)/10;

int melody[] = {
  NOTE_C4, NOTE_G3,NOTE_G3, NOTE_A3, NOTE_G3,0, NOTE_B3, NOTE_C4};
byte WINsensor = 12;         // **WINNING SENSOR DEFINED HERE** 
boolean running=false; //sequence is running
long time;
int pos; // position in sequence

void setup() 
{
  pinMode(WINsensor, INPUT);
  Serial.begin(9600);
  Serial.println(sizeof(led));
  for (byte i=0; i<sizeof(led); i++) pinMode(led[i], OUTPUT); 
  pinMode(power, OUTPUT);
  digitalWrite(power, HIGH);  //One LED will always stay on 
  //*****Sequence for lights*******
  for (byte i=0; i<6; i++)
  {
    digitalWrite(led[i], HIGH);
    delay(150);
    digitalWrite(led[i], LOW);
    delay(150);
  }
  for (byte i=6; i<=8; i++)digitalWrite(led[i], HIGH);
  delay(1000);
  for (byte i=6; i<=8; i++)digitalWrite(led[i], LOW);
}

void loop() 
{
  if ((digitalRead(WINsensor) == HIGH) && (!running))
  { running=true; time=millis(); pos=0; } // now start the sequence

  if (running)
  {
    if (millis()-time >= sequence[pos][0]) // found hit in this position..execute it
    { 
      if(sequence[pos][0]>0) digitalWrite(sequence[pos][1],sequence[pos][2]);
      if(sequence[pos][3]>0) tone(9,sequence[pos][3],sequence[pos][4]);
      pos++;
      if (pos >= lines_in_array)
      {
        pos=0;
        running=false;
      }
      noTone(9); // dont know if needed
    }
  }
}

I'm very appreciative of the Arduino community, let me first say that. Secondly, thank you Grumpy_Mike for the link, it really breaks this millis function down to an easily understandable format, the best I've seen all over the net.

Also, thank you knut_ny for your sample code. I'll admit it's quite intimidating at first glance but when I look at code I like to spend as much time looking at it until I fully understand what it will do. Thank you to all. If I have any further questions I will post again! :slight_smile: