How do i run 2 delay situations at a time?

Here is my code...
The code works but i would like both to run at the same time, how is this possible?

Thanks :slight_smile: looking forward to learning!

  digitalWrite(11, HIGH);
    digitalWrite(13, HIGH);
    delay(3000);
    digitalWrite(11, LOW);
    digitalWrite(13, LOW);

    digitalWrite(7, HIGH);
    digitalWrite(9, HIGH);
    delay(1100);
    digitalWrite(7, LOW);
    digitalWrite(9, LOW);

By using millis() instead of delay().

As you've seen, delay() blocks when it's called. You need to be able to take note of when something starts and then look in rapidly to see if it's time to do something else.

Using millis() (which returns the value of a counter that ticks at ~1mS intervals) you can do both. When you set the pins high, grab the value of millis(). Then check every loop() to see if enough millis() ticks have passed to equal your desired delay; when it does, only then take action.

Compiles, not tested. If you want, I can comment it later.

One thing to note: Your request didn't include an off time for either so, in this code, as soon as they turn off they'll turn right back on again with the next loop(). If you have a 'scope you should see both acting as they should. If you want them to be off for a certain time, you can modify the code to do that too.

bool
    flag1113,
    flag79;

uint32_t
    timeNow,
    time1113,
    time79;
    
void setup( void )
{
    pinMode( 11, OUTPUT );
    pinMode( 13, OUTPUT );
    pinMode( 7, OUTPUT );
    pinMode( 9, OUTPUT );
    flag1113 = false;
    flag79 = false;
        
}//setup

void loop( void )
{
    timeNow = millis();
    
    if( flag1113 == false )
    {
        digitalWrite(11, HIGH);
        digitalWrite(13, HIGH);
        time1113 = timeNow;    
        flag1113 = true;
        
    }//if
    else
    {
        if( timeNow - time1113 >= 3000ul )
        {
            digitalWrite(11, LOW);
            digitalWrite(13, LOW);
            flag1113 = false;
            
        }//if
        
    }//else

    if( flag79 == false )
    {
        digitalWrite(7, HIGH);
        digitalWrite(9, HIGH);
        time79 = timeNow;    
        flag79 = true;
        
    }//if
    else
    {
        if( timeNow - time79 >= 1100ul )
        {
            digitalWrite(7, LOW);
            digitalWrite(9, LOW);
            flag79 = false;
            
        }//if
        
    }//else
    
}//loop

Blackfin:
As you've seen, delay() blocks when it's called. You need to be able to take note of when something starts and then look in rapidly to see if it's time to do something else.

Using millis() (which returns the value of a counter that ticks at ~1mS intervals) you can do both. When you set the pins high, grab the value of millis(). Then check every loop() to see if enough millis() ticks have passed to equal your desired delay; when it does, only then take action.

Compiles, not tested. If you want, I can comment it later.

One thing to note: Your request didn't include an off time for either so, in this code, as soon as they turn off they'll turn right back on again with the next loop(). If you have a 'scope you should see both acting as they should. If you want them to be off for a certain time, you can modify the code to do that too.

bool

flag1113,
    flag79;

uint32_t
    timeNow,
    time1113,
    time79;
   
void setup( void )
{
    pinMode( 11, OUTPUT );
    pinMode( 13, OUTPUT );
    pinMode( 7, OUTPUT );
    pinMode( 9, OUTPUT );
    flag1113 = false;
    flag79 = false;
       
}//setup

void loop( void )
{
    timeNow = millis();
   
    if( flag1113 == false )
    {
        digitalWrite(11, HIGH);
        digitalWrite(13, HIGH);
        time1113 = timeNow;   
        flag1113 = true;
       
    }//if
    else
    {
        if( timeNow - time1113 >= 3000ul )
        {
            digitalWrite(11, LOW);
            digitalWrite(13, LOW);
            flag1113 = false;
           
        }//if
       
    }//else

if( flag79 == false )
    {
        digitalWrite(7, HIGH);
        digitalWrite(9, HIGH);
        time79 = timeNow;   
        flag79 = true;
       
    }//if
    else
    {
        if( timeNow - time79 >= 1100ul )
        {
            digitalWrite(7, LOW);
            digitalWrite(9, LOW);
            flag79 = false;
           
        }//if
       
    }//else
   
}//loop

Thank you, the way i am triggering those to do what they need is an incoming value like so,

if(Incoming_value == 'h')
  {
    digitalWrite(11, HIGH);
    digitalWrite(13, HIGH);
    delay(3000);
    digitalWrite(11, LOW);
    digitalWrite(13, LOW);

    digitalWrite(7, HIGH);
    digitalWrite(9, HIGH);
    delay(1100);
    digitalWrite(7, LOW);
    digitalWrite(9, LOW);
  }

A one-shot timer needs a variable to keep track of the state - running or idle. The timing sequence has to observe the variable.

@OP, can you post your whole sketch instead of snippets?

char Incoming_value = 0;               



void setup() 
{
  Serial.begin(9600);
  pinMode(13, OUTPUT);       
  pinMode(12, OUTPUT);
  pinMode(11, OUTPUT);
  pinMode(10, OUTPUT);
  pinMode(9, OUTPUT);
  pinMode(8, OUTPUT);
  pinMode(7, OUTPUT);
  pinMode(6, OUTPUT);
}


void loop()
{
  if(Serial.available() > 0)  
  {
    Incoming_value = Serial.read();      
    Serial.print(Incoming_value);        
    Serial.print("\n");       

     
    if(Incoming_value == '1')            
      digitalWrite(13, HIGH);  
    else if(Incoming_value == '0')      
      digitalWrite(13, LOW);   

      
       if(Incoming_value == '3')             
      digitalWrite(12, HIGH);  
    else if(Incoming_value == '2')      
      digitalWrite(12, LOW);  


       if(Incoming_value == '5')             
      digitalWrite(11, HIGH);  
    else if(Incoming_value == '4')     
      digitalWrite(11, LOW);   


       if(Incoming_value == '7')          
      digitalWrite(10, HIGH);  
    else if(Incoming_value == '6')     
      digitalWrite(10, LOW);   


       if(Incoming_value == '9')            
      digitalWrite(9, HIGH);  
    else if(Incoming_value == '8')       
      digitalWrite(9, LOW);   


       if(Incoming_value == 'A')           
      digitalWrite(8, HIGH);  
    else if(Incoming_value == 'B')       
      digitalWrite(8, LOW);   


       if(Incoming_value == 'C')             
      digitalWrite(7, HIGH); 
    else if(Incoming_value == 'D')      
      digitalWrite(7, LOW);  


       if(Incoming_value == 'E')    
      digitalWrite(6, HIGH);  
    else if(Incoming_value == 'F')    
      digitalWrite(6, LOW);   
  }                            

  
if(Incoming_value == 'h')
  {
    digitalWrite(11, HIGH);
    digitalWrite(13, HIGH);
    delay(1500);
    digitalWrite(11, LOW);
    digitalWrite(13, LOW);

    digitalWrite(7, HIGH);
    digitalWrite(9, HIGH);
    delay(1000);
    digitalWrite(7, LOW);
    digitalWrite(9, LOW);
  }
}

What you call, “triggering” is actually “testing” since it’s in loop() which repeats over and over. You do need to “trigger” when a ‘h’ character is detected, by changing the state variable from IDLE to RUNNING. Separately, in your timing routine, you check millis() as well as state==RUNNING and change the state back to IDLE when you are done.

aarg:
What you call, "triggering" is actually "testing" since it's in loop() which repeats over and over. You do need to "trigger" when a 'h' character is detected, by changing the state variable from IDLE to RUNNING. Separately, in your timing routine, you check millis() as well as state==RUNNING and change the state back to IDLE when you are done.

You can be checking input in the RUNNING state because you can test both continuously in loop().

So maybe something like this (compiles, not tested):

char
Incoming_value = 0;
uint8_t
bTimingFlag;
uint32_t
timeNow,
time1113,
time79;

void setup()
{
Serial.begin(9600);
pinMode(13, OUTPUT);
pinMode(12, OUTPUT);
pinMode(11, OUTPUT);
pinMode(10, OUTPUT);
pinMode(9, OUTPUT);
pinMode(8, OUTPUT);
pinMode(7, OUTPUT);
pinMode(6, OUTPUT);

}//setup

void loop()
{
timeNow = millis();

if(Serial.available() > 0)
{
Incoming_value = Serial.read();
Serial.print(Incoming_value);
Serial.print("\n");

switch( Incoming_value )
{
case '0':
case '1':
//this form writes a HIGH if Incoming_value is equal to '1', otherwise a LOW
digitalWrite( 13, (Incoming_value == '1') ? HIGH:LOW );
break;

case '2':
case '3':
digitalWrite( 12, (Incoming_value == '3') ? HIGH:LOW );
break;

case '4':
case '5':
digitalWrite( 11, (Incoming_value == '5') ? HIGH:LOW );
break;

case '6':
case '7':
digitalWrite( 10, (Incoming_value == '7') ? HIGH:LOW );
break;

case '8':
case '9':
digitalWrite( 9, (Incoming_value == '9') ? HIGH:LOW );
break;

case 'A':
case 'B':
digitalWrite( 8, (Incoming_value == 'A') ? HIGH:LOW );
break;

case 'C':
case 'D':
digitalWrite( 7, (Incoming_value == 'C') ? HIGH:LOW );
break;

case 'E':
case 'F':
digitalWrite( 6, (Incoming_value == 'E') ? HIGH:LOW );
break;

case 'h':
//when we get an 'h', set the pins high
digitalWrite(11, HIGH);
digitalWrite(13, HIGH);
digitalWrite(7, HIGH);
digitalWrite(9, HIGH);
//save the time we set them high
time1113 = timeNow;
time79 = timeNow;
//and set a couple of flags indicating we're timing
bTimingFlag = 0b00000011;
// |+--- bit is used as a flag for pins 11 and 13
// +---- bit is used as a flag for pins 7 and 9
break;

}//switch

}//if serial available

//is the bit flag for pins 11 & 13 high?
if( bTimingFlag & 0b00000001 )
{
//yes; we're timing the high-time. has the time elapsed?
if( timeNow - time1113 >= 1500ul )
{
//yes; set the pins low and clear the flag
digitalWrite(11, LOW);
digitalWrite(13, LOW);
//by ANDing with the compliment ('~') we clear the bit
bTimingFlag &= ~0b00000001;

}//if

}//if

//repeat for pins 7 & 9. note the other flag bit being used
if( bTimingFlag & 0b00000010 )
{
if( (timeNow - time79) >= 1000ul )
{
digitalWrite(7, LOW);
digitalWrite(9, LOW);
bTimingFlag &= ~0b00000010;

}//if

}//if

}//loop

blackfin!!!
it worked, thank you so much.
Would it be the same concept if i wanted to make each one of those pins stay on for their own assigned time instead of having pin 7,9 and 11,13 go together, have each pin 7,9,11,13 turn off on a set time i assign? basically now i want to do this but do each independently. like pin 7 1100ms, pin 9 1200ms, pin 11, 1300ms, and pin 13 1400ms.

yourwhyphy:
blackfin!!!
it worked, thank you so much.
Would it be the same concept if i wanted to make each one of those pins stay on for their own assigned time instead of having pin 7,9 and 11,13 go together, have each pin 7,9,11,13 turn off on a set time i assign? basically now i want to do this but do each independently. like pin 7 1100ms, pin 9 1200ms, pin 11, 1300ms, and pin 13 1400ms.

Absolutely. The code here (should!) do that. Note that we could use the same model, just using 4 bits in the flag byte and add additional timer variables for each pin etc, I’ll use a different tactic here.

Because the pins share very similar behaviors and characteristics, I’ve created a structure and made it a type. I then create an array of this type, one member for each pin. Each pin then has its own flag, timer, delay value etc. We can use for loops (or other methods) to check each pin’s state and timing requirements independently of the others. And because it’s an array we’re checking the code is ends up being a bit neater and tidier.

The code might look a little weird compared to the first code but if you walk through it you should be able to see what it’s doing.

Once again: Compiles, not tested.

#define NUM_PINS    4

char 
    Incoming_value = 0;               
uint32_t
    timeNow;

//because we're doing similar actions on multiple pins, we
//can create a structure and denote it a "type", just like
//char or int etc. This way, we can create an array of this type
//specifically to service a number of pins that have similar
//behaviors
typedef struct
{
    bool        flag;           //the flag tells us if we're timing a high-state (true=timing)
    uint8_t     pin;            //the pin number
    uint32_t    timePin;        //time time the pin went high (millis)
    uint32_t    timeDelay;      //the time we want this pin to stay high
    
}PinControl_t;

//here's the array of size 4 (the number of pins: 7, 9, 11 and 13). 
//we can initialize it with parameters we know now:
PinControl_t pinControl[NUM_PINS] = 
{
    {
        //for pin 7:
        .flag = false,          //pin's not timing right now
        .pin = 7,               //pin number
        .timePin = 0ul,
        .timeDelay = 1100ul     //how long we want it to stay on 
    },
    {
        //repeat for pins 9, 11 and 13
        .flag = false,
        .pin = 9,
        .timePin = 0ul,
        .timeDelay = 1200ul     //1200mS for pin 9
    },
    {
        .flag = false,
        .pin = 11,
        .timePin = 0ul,
        .timeDelay = 1300ul     //1300mS for pin 11
    },
    {
        .flag = false,
        .pin = 13,
        .timePin = 0,
        .timeDelay = 1400ul    //1400mS for pin 13
    }
    
};

void setup()
{
    Serial.begin(9600);
    pinMode(13, OUTPUT);       
    pinMode(12, OUTPUT);
    pinMode(11, OUTPUT);
    pinMode(10, OUTPUT);
    pinMode(9, OUTPUT);
    pinMode(8, OUTPUT);
    pinMode(7, OUTPUT);
    pinMode(6, OUTPUT);
    
}//setup


void loop()
{
    timeNow = millis();
        
    if(Serial.available() > 0) 
    {
        Incoming_value = Serial.read();     
        Serial.print(Incoming_value);       
        Serial.print("\n");       

        switch( Incoming_value )
        {
            case    '0':
            case    '1':
                //this form writes a HIGH if Incoming_value is equal to '1', otherwise a LOW
                digitalWrite( 13, (Incoming_value == '1') ? HIGH:LOW ); 
            break;
                     
            case    '2':
            case    '3':
                digitalWrite( 12, (Incoming_value == '3') ? HIGH:LOW ); 
            break;
            
            case    '4':
            case    '5':
                digitalWrite( 11, (Incoming_value == '5') ? HIGH:LOW ); 
            break;
            
            case    '6':
            case    '7':
                digitalWrite( 10, (Incoming_value == '7') ? HIGH:LOW ); 
            break;
            
            case    '8':
            case    '9':
                digitalWrite( 9, (Incoming_value == '9') ? HIGH:LOW ); 
            break;
            
            case    'A':
            case    'B':
                digitalWrite( 8, (Incoming_value == 'A') ? HIGH:LOW ); 
            break;
            
            case    'C':
            case    'D':
                digitalWrite( 7, (Incoming_value == 'C') ? HIGH:LOW ); 
            break;
            
            case    'E':
            case    'F':
                digitalWrite( 6, (Incoming_value == 'E') ? HIGH:LOW ); 
            break;
        
            case    'h':
                //when we get an 'h', set all four pins high and set their flags and timers
                for( uint8_t i=0; i<NUM_PINS; i++ )
                {
                    digitalWrite( pinControl[i].pin, HIGH );    //pins high
                    pinControl[i].flag = true;                  //flags set
                    pinControl[i].timePin = timeNow;            //grab the time
                    
                }//for
                
            break;            
            
        }//switch
    
    }//if serial available

    //each pass through loop, check the flags to see if any pins' timers need attention
    for( uint8_t idx=0; idx<NUM_PINS; idx++ )
    {
        //is this pin's flag set?
        if( pinControl[idx].flag == true )
        {
            //yes, so pin is still high. is it time to put it low?
            if( (timeNow - pinControl[idx].timePin) >= pinControl[idx].timeDelay )
            {
                //yes...clear the pin and its flag
                digitalWrite( pinControl[idx].pin, LOW );
                pinControl[idx].flag = false;
                
            }//if
            
        }//if        
        
    }//for
 
}//loop

Silver bullet approach?

#include <idlers.h>
#include <mechButton.h>



// ************ oneShot class decleration ************


class oneShot  : public idler  {

   public:   
                enum states { preInit, preFire, startFire, firing };

                oneShot(int pinNum,float delayMs=0,float pulseMs=20);
   virtual    ~oneShot(void);

                void   setDelay(float inDelayMs);
                void   setPulse(float inPulseMs);
                void   fire(void);
                void   idle(void);

                int        mPinNum;
                timeObj   delayTimer;
                timeObj   pulseTimer;
                int           mState;
};


// ************ oneShot class code ************


// Constructor. Puts together the initial stuff, sets defaults.
oneShot::oneShot(int pinNum,float delayMs=0,float pulseMs=20) {

   mPinNum = pinNum;
   setDelay(delayMs);
   setPulse(pulseMs);
   mState = preInit;
}


// Destructor has really nothing to do. Drinks a lot.
oneShot::~oneShot(void) {  }

hot. 
void oneShot::setDelay(float inDelayMs) {
   delayTimer.setTime(inDelayMs,false);
   if (mState!=preInit) {
      digitalWrite(mPinNum, LOW);
      mState = preFire;
   }
}


// Change the pulse timer. Resets the state of the oneSHot. 
void oneShot::setPulse(float inPulseMs) {
   pulseTimer.setTime(inPulseMs,false);
   if (mState!=preInit) {
      digitalWrite(mPinNum, LOW);
      mState = preFire;
   }
}


// The trigger. Click this, and the sequence starts.
void oneShot::fire(void) {

   delayTimer.start();
   if (mState == preInit) {
      hookup();
      pinMode(mPinNum, OUTPUT);
   }
   mState = startFire;
}


// Idle() this is where all the real work happens. Kinda' like our own slice of loop().
void oneShot::idle(void) {

   switch(mState) {
      case preInit   :
      case preFire   : break;
      case startFire :
         if (delayTimer.ding()) {
            digitalWrite(mPinNum, HIGH);
            pulseTimer.start();
            mState = firing;
         }
      break;
      case firing    :
         if (pulseTimer.ding()) {
            digitalWrite(mPinNum, LOW);
            mState = preFire;
         }
      break;
   }
}



// ************ PROGRAM STARTS HERE ************


oneShot     ourOneShot(13,500,100); // Our oneShot. You can have as many as you like.
mechButton  ourButton(8);           // Demounced button.


// Not much to do during setup..
void setup(void) {

   Serial.begin(9600);     // If you want serial, start it here.
   pinMode(13, OUTPUT);    // If you -really- must have the oneShot pin off to start, you can do this.
   digitalWrite(13,LOW);   // Otherwise, it won't be initialized until the first time you call shot.
}


// Our loop(). Call idle() to let everyting run. Check the button for firing.
void loop(void) {

   idle();                                         // Give all the idlers time to do their thing.
   if (!ourButton.trueFalse()) {                   // If the button has been grounded..
      ourOneShot.fire();                           // Fire the oneShot.
      Serial.println("bang!");                     // Send out a message.
      while(!ourButton.trueFalse()) {              // While the button is still grounded..
         sleep(10);                                // Run the background tasks. ( Like a friendly delay() that works. )
      }
   }
}

This gives you a oneShot object you can have as many as you like each has a delay after “firing” then a time for them to hold the pin high.

If you’d like to try this approach, you’ll need LC_baseTools from the library manager.

-jim lee

thank again blackfin!

I am about to test it. you are a absolute savior. I have been working on this project for way to long, giving up many times. Since I don't have much experience, I haven't got anywhere. spent hours trying different things... Your explanations and comments freakin rock!

UPDATE: it works!!!!

Have a look at how millis() is used to manage timing without blocking in Several Things at a Time.

And see Using millis() for timing. A beginners guide if you need more explanation.

...R