Delay and millis together in same program

Hello. I have an instance where it would be beneficial to use both "delay" and millis" in the same program.I am still learning about millis so thats why I'm asking. I am using a PIR and it takes about 60 seconds to account for the thermal energy of where ever it is at, when it is turned on. Until it settles there are false readings which is not good because the PIR OUTPUT triggers my Attiny85 to do stuff. if I use delay I can block the output signal until it settles down during those 60 seconds and then continue on with other tasks. However, there are other parts in the program where millis would be more appropriate/practical so I can run multiple tasks. as said, I am just beginning to learn about millis. The question is can I use them both in the same program without conflicts. THANKS, Fred? There is a bunch of "use this one / use that one" but not a whole lot of using each of their unique capabilities at the same time.

Put the delay in setup
Forget about it after that.

In setup(), you can delay as you see fitting.

In loop(), I would only use millis() for timing.

1 Like

Whandall, so the answer is YES?. I can utilize both millis and delays in the same sketch? As said, I'm just learning millis. However I already have "delay" imposed in the loop. And I want dalay (to block) Once the "delay" is finished, can I use millis for the balance of the program? appreciate your input. Fred

If you have delay in the loop it will happen every time unless you have conditional code to skip it.

So much hand-waving...

As a rule, you can't use delay and millis in the same loop().

In your case, using a delay in one case is meaningless. If you have used millis in all cases but one, which prevents you from replacing the latter???

OK, here's the deal. When you turn on a PIR, it takes about a minute for it to what I call acclimate to it's new surroundings , or from waking up from "sleep mode". It gives out false readings for about a minute that screws everything up. If I can turn on the PIR and "delay" for 60 seconds I can avoid the random digital output that is expected from the PIR upon start up. It cycles about 4 or 5 times before it LEARNS where it is and what the thermal parameters are. After that, you "walk by" and it IS going to SEE you. A "delay" would be an excellent choice. BUT! further down the line, millis would be exceptionally more beneficial. Because I would be able to "multi task"? yes ? no? just trying to learn. THANKS, Fred

As already said - put the sixty second delay in setup, then use non-blocking after that.

It's a complex code from my stand point. Let me post with comments so you can see, what i'm looking at. give me a few minutes.

type// ATMEL ATTINY 25/45/85 / ARDUINO
// Pin 1 is /RESET
//
//                  +-\/-+
// Ain0 (D 5) PB5  1|    |8  Vcc
// Ain3 (D 3) PB3  2|    |7  PB2 (D 2) Ain1
// Ain2 (D 4) PB4  3|    |6  PB1 (D 1) pwm1
//            GND  4|    |5  PB0 (D 0) pwm0
//                  +----+

/*

  Pin 2 (PB3) <-- LDR (GL5539) --> Pin 7 (PB2) <----> 56 k <----> Gnd

  Pin 5 (PB0) <---- LED ---> 100 R <-----> Gnd

*/


#include <avr/sleep.h>    // Sleep Modes
#include <avr/power.h>    // Power management
#include <avr/wdt.h>      // Watchdog timer
const byte servoPin = 0; // servo connected to digital pin 0, {was const byte servoPin = 0;}
const byte PIR = 1; //Sends power to MOS gate
const byte LDR_ENABLE = 3;   // pin 2
const byte LDR_READ = 1;     // Ain1 (PB2) pin 7
const int LIGHT_THRESHOLD = 200;  // Flash LED when darker than this

// when ADC completed, take an interrupt
EMPTY_INTERRUPT (ADC_vect);

// Take an ADC reading in sleep mode (ADC)
float getReading (byte port)
{
  power_adc_enable() ;
  ADCSRA = bit (ADEN) | bit (ADIF);  // enable ADC, turn off any pending interrupt

  // set a2d prescale factor to 128
  // 8 MHz / 128 = 62.5 KHz, inside the desired 50-200 KHz range.

  ADCSRA |= bit (ADPS0) | bit (ADPS1) | bit (ADPS2);

  if (port >= A0)
    port -= A0;

#if defined(__AVR_ATtiny85__)
  ADMUX = (port & 0x07);  // AVcc
#else
  ADMUX = bit (REFS0) | (port & 0x07);  // AVcc
#endif

  noInterrupts ();
  set_sleep_mode (SLEEP_MODE_ADC);    // sleep during sample
  sleep_enable();

  // start the conversion
  ADCSRA |= bit (ADSC) | bit (ADIE);
  interrupts ();
  sleep_cpu ();
  sleep_disable ();

  // reading should be done, but better make sure
  // maybe the timer interrupt fired

  // ADSC is cleared when the conversion finishes
  while (bit_is_set (ADCSRA, ADSC))
  { }

  byte low  = ADCL;
  byte high = ADCH;

  ADCSRA = 0;  // disable ADC
  power_adc_disable();

  return (high << 8) | low;

}  // end of getReading

// watchdog interrupt
ISR (WDT_vect)
{
  wdt_disable();  // disable watchdog
}  // end of WDT_vect

#if defined(__AVR_ATtiny85__)
#define watchdogRegister WDTCR
#else
#define watchdogRegister WDTCSR
#endif

void setup ()
{
  wdt_reset();
  //pinMode(servoPin, OUTPUT); // sets the servoPin to be an output, was {pinMode(servoPin, OUTPUT);}
  pinMode(PIR, OUTPUT); //sets the MOSPWR to be an output
  pinMode (LDR_ENABLE, OUTPUT);
  ADCSRA = 0;            // turn off ADC
  power_all_disable ();  // power off ADC, Timer 0 and 1, serial interface
}  // end of setup

void loop ()
{
  // power up the LDR, take a reading
  digitalWrite (LDR_ENABLE, HIGH);
  int value = getReading (LDR_READ);
  // power off the LDR
  digitalWrite (LDR_ENABLE, LOW);

  // if it's dark,
  if (value < LIGHT_THRESHOLD)

  {

    power_timer0_enable ();

       //HERE I WANT TO TURN ON THE PIR---SEND OUT A DIGITAL SIGNAL, WHEN THE NIGHT IS DONE GO BACK TO SLEEP.
    
    delay (1);  // let timer reach a known point
    delay(3000);                   //SUCKS UP POWER 5 + mA'S
       analogWrite(PIR, 255);
delay(10000);                      //DELAYS SUCK UP POWER!!!!!
    
    analogWrite(PIR, 0);
   
    //delay(30000);
    //analogWrite(PIR, 0);}



    /*analogWrite(servoPin, 255);
      delay (2.4);
      analogWrite (servoPin, 0);
      delay (20);
      {
      delay (100);
      }
      analogWrite(servoPin, 255);
      delay (2.4);
      analogWrite (servoPin, 0);
      delay (20);
      {
      delay (100);
      }

      analogWrite(servoPin, 255);
      delay (.5);
      digitalWrite (servoPin, 0);
      delay (20);
      {
      delay (100);
      }
      analogWrite(servoPin, 255);
      delay (1.5);
      analogWrite (servoPin, 0);
      delay (20);
      {
      delay (2000);
      }
      analogWrite(servoPin, 255);
      delay (.5);
      analogWrite (servoPin, 0);
      delay (20);
      {
      delay (3000);
      }
      analogWrite(servoPin, 255);
      delay (2.4);
      analogWrite (servoPin, 0);
      delay (20);
      {
      delay (2000);
      }
      analogWrite(MOSPWR, 0);
      delay(300000);
    */

  } power_timer0_disable ();


  goToSleep ();

}  // end of loop

void goToSleep ()
{
  set_sleep_mode (SLEEP_MODE_PWR_DOWN);
  noInterrupts ();       // timed sequence coming up

  // pat the dog
  wdt_reset();

  // clear various "reset" flags
  MCUSR = 0;
  // allow changes, disable reset, clear existing interrupt
  watchdogRegister = bit (WDCE) | bit (WDE) | bit (WDIF);
  // set interrupt mode and an interval (WDE must be changed from 1 to 0 here)
  watchdogRegister = bit (WDIE) | bit (WDP2) | bit (WDP1) | bit (WDP0);    // set WDIE, and 2 seconds delay

  sleep_enable ();       // ready to sleep
  interrupts ();         // interrupts are required now
  sleep_cpu ();          // sleep
  sleep_disable ();      // precaution


}  // end of goToSleep










/*
   or paste code here
**power_timer0_enable ();**

delay (1); // let timer reach a known point
//HERE I WANT TO TURN ON THE PIR---SEND OUT A DIGITAL SIGNAL, WHEN THE NIGHT
IS DONE GO BACK TO SLEEP

Sorry, it isn't commented out very well.......

So....delay(1) // let timer reach a known point**. after this statement I need
to turn on the PIR, BUT.....It needs to be blocked for at least 60 seconds
for the PIR to stabilize. Otherwise it sends faulty signals and digitalreads
back to the tiny85. I'm new to millis, but don't mind learning it. Just
don't want to waste a bunch of time on something that will not be effective.
Can you BLOCK a millis call? To be clear....

power_timer0_enable ();

delay (1); // let timer reach a known point {{{REPLACE DELAY WITH MILLIS???}}}

Turn on PIR ---------WAIT 60 seconds / stabilize and then continue LOOP.

Thanks for helping out if you can, Fred

I dont understand this

If you only want to do One Thing At A Time then delay() works.

When you want to say blink a led and watch a button at the same time, delay inside of loop makes the button less responsive.

I use some techniques to replace delays in cut&dry fashion that I came up with while fixing automated greenhouse with GSM code that -- I had no idea HOW the device code parts worked (learning curve ducked), I fixed the WHEN parts and added a detailed run log and the debug went quick considering we were 6 time zones apart.

You can convert working code that has delays into code with timers that works the same except that it then can merge in with other sketches and they all run like they did unless they interact

delay makes wait

on time does not mean wait. It means "on time".

Every time void loop() goes around is later than last time.
When you sense events in and across time and make events on times, you are writing real time code and in top-down-land anymore.

Instead of waiting, why not read the hell out of the sensor until it settles then change the led13 status-blink (a sub-task showing that loop() is running, not locked up or off-frequency) to signal READY and do a test wave as part of start up?

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.