Creating my own delay_ function but not working

Hi,

I am trying to create my own delay function but my sketch keeps crashing.

i want to call a function in the main loop:

manual_delay_function(3000UL) // delay for 3 seconds

where the manual_delay_function is:
`

void manual_delay_function( unsigned long delay_time)
{
  unsigned long current_time = millis();
 
  bool delay_flag = true;
  
  while(delay_flag)
  {
  if (millis() > current_time+ delay_time)
  {
  delay_flag = false;
  } 
  }
 
}

but my code just keeps crashing.

any idea on what im doing wrong?

Well, the while function has the same exact functionality as delay, so need to get rid of the while loop.

Describe this crash.

Also put your new delay function in some context.

Post a complete sketch that compiles, runs and crashes because of your function.

a7

It seems to work as intended... it blocks for the intended time.

However... do you really want blocking code?

And... the millis logic will not handle overflow correctly.

Should use while(millis() - current_time < delay_time). You don't need the bool.

Yes, the OP's function works. I assume it was written just to see if.

Yes, in 49.7 days you'd get in trouble with the way you s/he does it.

This is what @red_car has in mind:

void myDelay( unsigned long delay_time)
{
  unsigned long current_time = millis();

  while(millis() - current_time < delay_time);
}

a7

no thats the issue, i dont want blocking code. trying to figure out a better way to perform this task. the issue is I have 3000+ lines of code.

And the order is:

Task 1 (wait 3 seconds) task 2, etc....

Well, the issue is i dont want blocking code. trying to figure out a better way to perform this task. the issue is I have 3000+ lines of code.

For example, I want to do

Task 1 (wait 3 seconds) task 2, etc....

Then your topic is wrong, your problem description is wrong and you have wasted time, yours and ours.

Tell us what you are really trying to do, carefully. Perhaps we can help.

a7

Then you can't do it with a while loop.

You need to start a timer... then keep checking it every loop... when enough time has gone by you do whatever you need to.

Have a look at this example that use a small class to hold each timer. For each timer you declare it with it's required duration, then you start it, then you keep checking it.


// Timer class ---------

class timer
{
  public:
    timer(unsigned long duartion);
    void start();
    boolean isUp();
  private:
    unsigned long start_;
    unsigned long duration_; 
};

timer::timer (unsigned long duration)
{
  duration_ = duration;
}

void timer::start ()
{
  start_ = millis();
}

boolean timer::isUp()
{
  if (millis() - start_ < duration_)
    return false;
  else
    return true;
}



 // Main code -----------

timer timer1(1000);
timer timer2(5000);

void setup()
{
  Serial.begin(115200);
  Serial.print("Start");
  
  timer1.start();
  timer2.start();
}

void loop()
{
  if (timer1.isUp())
  {
    Serial.println("Timer 1 is up");
    timer1.start();
  }
  
  if (timer2.isUp())
  {
    Serial.println("Timer 2 is up");
    timer2.start();
  }
}


A while loop is blocking code.

There's at least a dozen non-blocking timer libraries available. I am using ticker.h in my current project.

same question comes up periodically, consider

// demonstrate multiple jobs

// -------------------------------------
void
funcA (
    int arg)
{
    Serial.print   (__func__);
    Serial.print   (" ");
    Serial.println (arg);
}

// -------------------------------------
#define FuncBmax  5
void
funcB (
    int arg)
{
    static int n = 0;

    if (FuncBmax <= ++n)
        n = 0;

    Serial.print   (" ");
    Serial.print   (__func__);
    Serial.print   (" ");
    Serial.println (n);
}


// -------------------------------------
void
funcC (
    int arg)
{
    digitalWrite (arg, ! digitalRead (arg));
}

// -----------------------------------------------------------------------------
struct Job {
    void        (*func) (int arg);
    int           arg;
    unsigned long Period;
    unsigned long msecLst;
};

Job jobs [] = {
    { funcA,  2, 1000 },
    { funcB,  0,  800 },
    { funcA,  3, 1100 },
    { funcC, LED_BUILTIN , 500 },
};
#define Njob    (sizeof(jobs)/sizeof(Job))

// -----------------------------------------------------------------------------
void
loop (void)
{
    unsigned long msec = millis ();

    Job *j = jobs;
    for (unsigned n = 0; n < Njob; n++, j++)  {
        if (msec - j->msecLst > j->Period)  {
            j->msecLst = msec;
            j->func (j->arg);
        }
    }
}

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

    pinMode (LED_BUILTIN, OUTPUT);
}

The basics are simple once you understand them.

To write a non-blocking delay function

/*
  non-blocking delay
  In:
    delay duration
*/
bool myDelay(uint32_t duration)
{
  static uint32_t startTime;
  static bool inProgress = false;
  
  // if delay not started yet
  if(inProgress == false)
  {
    // remember the start time
    startTime = millis();
    // indicate that delay is in progress
    inProgress = true;
  }
  // if delay is in progress
  else
  {
    // check if time has lapsed
    if(millis() - startTime >= duration)
    {
      // indicate that the delay has finished
      inProgress = false;
      // tell caller that delay is finished
      return true;
    }
  }
  
  // tell caller that delay is still in progress
  return false;
}

You will have to call this function repeatedly (something that loop() will do for you). The static keyword indicates that the variables will be remembered between successive calls of the function.

Typical use

void loop()
{
  if(myDelay(1000) == true)
  {
    digitalWrite(LED_BUILTIN, !digitalread(LED_BUILTIN));
  }
}

The above will blink the builtin LED. Note that you can not use this function multiple times. E.g.

void loop()
{
  if(myDelay(1000) == true)
  {
    digitalWrite(LED_BUILTIN, !digitalread(LED_BUILTIN));
  }

  if(myDelay(10000) == true)
  {
    Serial.println(F("It's time"));
  }

}

The two calls will interfere with each other because the shortest 'delay' in loop() will reset the inProgress flag.

Therefore it will be far better to write dedicated functions for that. Use the myDelay approach to blink a LED would look like

/*
  non-blocking blink
  In:
    delay duration
*/
bool blink(uint32_t duration)
{
  static uint32_t startTime;
  static bool inProgress = false;
  
  // if delay not started yet
  if(inProgress == false)
  {
    // switch the LED on
    digitalWrite(LED_BUILTIN, HIGH);    
    // remember the start time
    startTime = millis();
    // indicate that delay is in progress
    inProgress = true;
  }
  // if delay is in progress
  else
  {
    // check if time has lapsed
    if(millis() - startTime >= duration)
    {
      // switch the LED off
      digitalWrite(LED_BUILTIN, LOW);    
      // indicate that the delay has finished
      inProgress = false;
      // tell caller that delay is finished
      return true;
    }
  }
  
  // tell caller that delay is still in progress
  return false;
}

and to print the millis every 10 seconds

/*
  non-blocking print time
  In:
    delay duration
*/
bool printTime(uint32_t duration)
{
  static uint32_t startTime;
  static bool inProgress = false;
  
  // if delay not started yet
  if(inProgress == false)
  {
    // switch the LED on
    Serial.println(millis());
    // remember the start time
    startTime = millis();
    // indicate that delay is in progress
    inProgress = true;
  }
  // if delay is in progress
  else
  {
    // check if time has lapsed
    if(millis() - startTime >= duration)
    {
      // indicate that the delay has finished
      inProgress = false;
      // tell caller that delay is finished
      return true;
    }
  }
  
  // tell caller that delay is still in progress
  return false;
}

Each of these functions has now its own timing. The functions still return a bool to indicate when they are finished but you don't have to use it.

And in loop()

void loop()
{
  blink(1000);
  printTime(10000);
}

So for each functionality in your code, you write a function that maintains its own timing.

PS
Code not compiled.

Very nice example. I think you can shorten it a bit:

class timer
{
  public:
    void start() {timeStamp = millis();}
    boolean operator() (const unsigned long duration) {
      return (millis() - timeStamp >= duration) ?  true : false;
    }  
  private:
    unsigned long timeStamp {0};
};

 // Main code -----------

timer timer1;
timer timer2;

void setup()
{
  Serial.begin(115200);
  Serial.println("Start");
  
  timer1.start();
  timer2.start();
}

void loop()
{
  if (timer1(1000))
  {
    Serial.println("Timer 1 is up");
    timer1.start();
  }
  
  if (timer2(5000))
  {
    Serial.println("Timer 2 is up");
    timer2.start();
  }
}

Some Arduino microcontrollers (ESP32 for example) have multiple cores and the Arduino implementation core brings in freeRTOS.
Other microcontrollers with a single core can utilize an RTOS or can utilize some software tom-foolery to give you pseudo threading:
How to "Multithread" an Arduino (Protothreading Tutorial) - Arduino Project Hub

what the hell is UL, Unsigned 8 bit integer needs something like 128. they also limited to be in range of 0-255

Try this

//#include <Arduino.h>

#define onTimeout(timer, period)\
  static unsigned long timer = millis();\
  for (unsigned long now = millis(); (now - timer) > (unsigned long)period; timer = now)


////TimeOut SetUp//
//#define onTimeout(timer, period)\
//  static unsigned long timer = millis();\
//  for (unsigned long now = millis(); (now - timer) < period; now = millis())

void setup()
{
  Serial.begin(115200);
  pinMode(LED_BUILTIN, OUTPUT);
  
}

void loop()
{
  test();
  onTimeout(timerA, 100)
  {
    digitalWrite(LED_BUILTIN, !digitalRead(LED_BUILTIN));
  }
  onTimeout(timerB, 1009)
  {
    Serial.println("TimeB");

  }
  onTimeout(timerC, 5000)
  {
    Serial.println("TimerC");

  }
}

void test()
{
  onTimeout(timerD, 1000)
  {
    Serial.println("TimeD");
  }
}

@Proietti You're fired!

a7