How do I remove all delays from my code?

I am wondering if it is possible to remove all delays from my code, but working exactly as it is, so that I can do other things during those 'delays'?

#include <LiquidCrystal_I2C.h>
#include <SPI.h>
#include <MFRC522.h>
#include <Wire.h>
LiquidCrystal_I2C lcd(0x27, 16, 2);

unsigned long startMillis; //set up millis for reset
unsigned long currentMillis; //pull up millis for reset
const unsigned long period = 604800000; //the value is a number of milliseconds, ie 7 days

unsigned long previousMillis = 0;        // will store last time LCD was updated

const long interval = 1000;           // interval at which to turn off (milliseconds)

#define SS_PIN 10
#define RST_PIN 9
#define RELAY 3 //relay pin
#define BUZZER 2 //buzzer pin
MFRC522 mfrc522(SS_PIN, RST_PIN);   // Create MFRC522 instance.
void setup(){
  Serial.begin(9600);   // Initiate a serial communication
  Serial.println(F("Initializing SPI, mfrc522, Relay, and Buzzer"));
  SPI.begin();
  mfrc522.PCD_Init();
  pinMode(RELAY, OUTPUT);
  pinMode(BUZZER, OUTPUT);
  Serial.println(F("No sound from Buzzer until instructed otherwise"));
  noTone(BUZZER);
  Serial.println(F("Initialize LCD"));
  lcd.init();
  Serial.println(F("Clear LCD"));
  lcd.clear();
  Serial.println(F("LCD backlight on"));
  lcd.backlight();
  Serial.println(F("Buzzer activated at 1KHz"));
  tone(BUZZER, 1000);
  Serial.println(F("Buzzer sounding for 100 milliseconds"));
  delay(100);
  Serial.println(F("Buzzer deactivated"));
  noTone(BUZZER);
  Serial.println(F("LCD print 'ARDUINO SECURITY DOOR' for 2 seconds"));
  lcd.print(F("ARDUINO SECURITY"));
  lcd.setCursor(0, 1);
  lcd.print(F("      DOOR  "));
  delay(2000);
  Serial.println(F("Clear LCD"));
  lcd.clear();
  Serial.println(F("LCD print 'ACTIVATING SYSTEM' for 2 seconds"));
  lcd.print(F("   ACTIVATING    "));
  lcd.setCursor(0, 1);
  lcd.print(F("     SYSTEM    "));
  delay(2000);
  Serial.println(F("Clear LCD"));  
  lcd.clear();
  Serial.println(F("Relay test - activated for 2 milliseconds"));
  digitalWrite(RELAY, HIGH);
  delay(2);
  digitalWrite(RELAY, LOW);
  Serial.println(F("LCD print 'PLEASE BE PATIENT' for 2 seconds"));
  lcd.print("   PLEASE BE ");
  lcd.setCursor(0, 1);
  lcd.print("    PATIENT  ");
  delay(2000);
  Serial.println(F("Relay default is LOW"));
  digitalWrite(RELAY, LOW);
  Serial.println(F("Buzzer activated at 1KHz"));
  tone(BUZZER, 1000);
  Serial.println(F("Buzzer sounding for 1 second"));
  delay(1000);
  Serial.println(F("Buzzer deactivated"));
  noTone(BUZZER);
  Serial.println(F("Clear LCD"));
  lcd.clear();
  Serial.println(F("LCD print 'SCAN CARD TO UNLOCK' forever, or until card is scanned"));
  lcd.print("   SCAN CARD ");
  lcd.setCursor(0, 1);
  lcd.print("   TO UNLOCK  ");
  Serial.println(F("LCD backlight is to be turned off after 30 seconds if no card is scanned"));
  previousMillis = millis();
  Serial.println(F("Set up resetFunc"));
  Serial.println(F("If 7 days have elapsed, call reset"));
}
void(*resetFunc) (void)=0;
void loop(){
  currentMillis = millis();  //get the current "time" (actually the number of milliseconds since the program started)
  if (currentMillis - startMillis >= period)  //test whether the period has elapsed
  {
    Serial.println(F("get the current 'time'"));
    Serial.println(F("test whether the period has elapsed"));
    Serial.println(F("call reset"));
    resetFunc(); //call reset
  }
  currentMillis = millis();
  if (millis() - previousMillis > 30 * 1000UL)  {    lcd.noBacklight(); lcd.clear();  }
  if ( ! mfrc522.PICC_IsNewCardPresent())      return;   // Look for new cards
  if ( ! mfrc522.PICC_ReadCardSerial())    return;  // Select one of the cards
  Serial.print(F("UID tag :"));
  String content = "";
  byte letter;
  for (byte i = 0; i < mfrc522.uid.size; i++)
  {
    Serial.print(mfrc522.uid.uidByte[i] < 0x10 ? " 0" : " ");
    Serial.print(mfrc522.uid.uidByte[i], HEX);
    content.concat(String(mfrc522.uid.uidByte[i] < 0x10 ? " 0" : " "));
    content.concat(String(mfrc522.uid.uidByte[i], HEX));
  }
  Serial.println();
  content.toUpperCase();
  if ((content.substring(1) == "93 6D BE 0D") 
  ||(content.substring(1) == "51 67 DC B0")
  ||(content.substring(1) == "A3 23 74 11")//change here the UID of the card/cards that you want to give access A3 23 74 11
  ||(content.substring(1) == "55 42 2B 0D"))
  {
    previousMillis = millis();
    Serial.println(F("Clear LCD"));
    lcd.clear();
    Serial.println(F("LCD backlight is on"));
    lcd.backlight();
    Serial.println(F("LCD print 'ACCESS GRANTED' for 7 seconds"));
    lcd.print("     ACCESS     ");
    lcd.setCursor(0, 1);
    lcd.print("    GRANTED!    ");
    Serial.println(F("Relay activated for 7 seconds"));
    digitalWrite(RELAY, HIGH);
    Serial.println(F("Buzzer activated at 1KHz"));
    tone(BUZZER, 1000);
    Serial.println(F("Buzzer sounding for 400 milliseconds"));
    delay(400);
    Serial.println(F("Buzzer deactivated"));
    noTone(BUZZER);
    delay(6600);
    Serial.println(F("Relay deactivated"));
    digitalWrite(RELAY, LOW);
    Serial.println(F("Clear LCD"));
    lcd.clear();
    Serial.println(F("LCD print 'SCAN CARD TO UNLOCK' forever, or until card is scanned"));
    lcd.print("   SCAN CARD ");
    lcd.setCursor(0, 1);
    lcd.print("   TO UNLOCK  ");
    Serial.println(F("LCD backlight is to be turned off after 30 seconds if no card is scanned"));
  }

  else   {
    previousMillis = millis();
    Serial.println(F("Clear LCD"));
    lcd.clear();
    Serial.println(F("LCD backlight is on"));
    lcd.backlight();
    Serial.println(F("LCD print 'ACCESS DENIED' for 1.75 seconds"));
    lcd.print("     ACCESS     ");
    lcd.setCursor(0, 1);
    lcd.print("     DENIED     ");
    Serial.println(F("Buzzer activated at 1KHz"));
    tone(BUZZER, 1000);
    delay(150);
    noTone(BUZZER);
    delay(25);
    Serial.println(F("Buzzer activated at 1KHz"));
    tone(BUZZER, 1000);
    Serial.println(F("Buzzer sounding for 150 milliseconds"));
    delay(150);
    Serial.println(F("Buzzer deactivated for 25 milliseconds"));
    noTone(BUZZER);
    delay(25);
    Serial.println(F("Buzzer activated at 1KHz"));
    tone(BUZZER, 1000);
    Serial.println(F("Buzzer sounding for 150 milliseconds"));
    delay(150);
    Serial.println(F("Buzzer deactivated for 25 milliseconds"));
    noTone(BUZZER);
    delay(25);
    Serial.println(F("Buzzer activated at 1KHz"));
    tone(BUZZER, 1000);
    Serial.println(F("Buzzer sounding for 150 milliseconds"));
    delay(150);
    Serial.println(F("Buzzer deactivated for 25 milliseconds"));
    noTone(BUZZER);
    delay(25);
    Serial.println(F("Buzzer activated at 1KHz"));
    tone(BUZZER, 1000);
    Serial.println(F("Buzzer sounding for 150 milliseconds"));
    delay(150);
    Serial.println(F("Buzzer deactivated for 1 second"));
    noTone(BUZZER);
    delay(1000);
    Serial.println(F("Clear LCD"));
    lcd.clear();
    Serial.println(F("LCD print 'SCAN CARD TO UNLOCK' forever, or until card is scanned"));
    lcd.print("   SCAN CARD ");
    lcd.setCursor(0, 1);
    lcd.print("   TO UNLOCK  ");
    Serial.println(F("LCD backlight is to be turned off after 30 seconds if no card is scanned"));
  }
}

Thanks for your help!

It will take some work, but the basic idea is demonstrated and explained in this excellent tutorial: https://www.baldengineer.com/blink-without-delay-explained.html

And this one: https://gammon.com.au/blink

1 Like

But what would I do instead of this:


const int ledPin =  13;

I am not using any pins specificaly like that as I am using a mfrc-522 module, an I2C LCD, a relay, and a buzzer. What do I do instead?

The basic idea, as applied to blinking an LED in the first example, also works for a buzzer, or anything else you want to activate/deactivate on a timed basis.

Once you have studied the tutorials that should become clear.

It is a mistake for a beginner to start with a large, complicated program, before the basics are understood.

Okay...I just tried that for the 100 millisecond buzzer delay (the first delay in the code), and absolutely NOTHING happens - the buzzer goes forever and the LCD doesn't say anything - it stays blank. Why is that? Am I doing something wrong?

#include <LiquidCrystal_I2C.h>
#include <SPI.h>
#include <MFRC522.h>
#include <Wire.h>
LiquidCrystal_I2C lcd(0x27, 16, 2);

unsigned long startMillis; //set up millis for reset
unsigned long currentMillis; //pull up millis for reset
const unsigned long period = 604800000; //the value is a number of milliseconds, ie 7 days

unsigned long previousMillis = 0;        // will store last time LCD was updated

const long interval = 1000;           // interval at which to turn off (milliseconds)

unsigned long delayTime;  // declare variable

#define SS_PIN 10
#define RST_PIN 9
#define RELAY 3 //relay pin
#define BUZZER 2 //buzzer pin
MFRC522 mfrc522(SS_PIN, RST_PIN);   // Create MFRC522 instance.
void setup(){
  Serial.begin(9600);   // Initiate a serial communication
  Serial.println(F("Initializing SPI, mfrc522, Relay, and Buzzer"));
  SPI.begin();
  mfrc522.PCD_Init();
  pinMode(RELAY, OUTPUT);
  pinMode(BUZZER, OUTPUT);
  Serial.println(F("No sound from Buzzer until instructed otherwise"));
  noTone(BUZZER);
  Serial.println(F("Initialize LCD"));
  lcd.init();
  Serial.println(F("Clear LCD"));
  lcd.clear();
  Serial.println(F("LCD backlight on"));
  lcd.backlight();
  Serial.println(F("Buzzer activated at 1KHz"));
  tone(BUZZER, 1000);
  Serial.println(F("Buzzer sounding for 100 milliseconds"));
  delayTime = millis ();  // note the time now
  if ((millis () - delayTime) >= (100UL))
  {
  Serial.println(F("Buzzer deactivated"));
  noTone(BUZZER);
  Serial.println(F("LCD print 'ARDUINO SECURITY DOOR' for 2 seconds"));
  lcd.print(F("ARDUINO SECURITY"));
  lcd.setCursor(0, 1);
  lcd.print(F("      DOOR  "));
  delay(2000);
  Serial.println(F("Clear LCD"));
  lcd.clear();
  Serial.println(F("LCD print 'ACTIVATING SYSTEM' for 2 seconds"));
  lcd.print(F("   ACTIVATING    "));
  lcd.setCursor(0, 1);
  lcd.print(F("     SYSTEM    "));
  delay(2000);
  Serial.println(F("Clear LCD"));  
  lcd.clear();
  Serial.println(F("Relay test - activated for 2 milliseconds"));
  digitalWrite(RELAY, HIGH);
  delay(2);
  digitalWrite(RELAY, LOW);
  Serial.println(F("LCD print 'PLEASE BE PATIENT' for 2 seconds"));
  lcd.print("   PLEASE BE ");
  lcd.setCursor(0, 1);
  lcd.print("    PATIENT  ");
  delay(2000);
  Serial.println(F("Relay default is LOW"));
  digitalWrite(RELAY, LOW);
  Serial.println(F("Buzzer activated at 1KHz"));
  tone(BUZZER, 1000);
  Serial.println(F("Buzzer sounding for 1 second"));
  delay(1000);
  Serial.println(F("Buzzer deactivated"));
  noTone(BUZZER);
  Serial.println(F("Clear LCD"));
  lcd.clear();
  Serial.println(F("LCD print 'SCAN CARD TO UNLOCK' forever, or until card is scanned"));
  lcd.print("   SCAN CARD ");
  lcd.setCursor(0, 1);
  lcd.print("   TO UNLOCK  ");
  Serial.println(F("LCD backlight is to be turned off after 30 seconds if no card is scanned"));
  previousMillis = millis();
  Serial.println(F("Set up resetFunc"));
  Serial.println(F("If 7 days have elapsed, call reset"));
  }
}
void(*resetFunc) (void)=0;
void loop(){
  currentMillis = millis();  //get the current "time" (actually the number of milliseconds since the program started)
  if (currentMillis - startMillis >= period)  //test whether the period has elapsed
  {
    Serial.println(F("get the current 'time'"));
    Serial.println(F("test whether the period has elapsed"));
    Serial.println(F("call reset"));
    resetFunc(); //call reset
  }
  currentMillis = millis();
  if (millis() - previousMillis > 30 * 1000UL)  {    lcd.noBacklight(); lcd.clear();  }
  if ( ! mfrc522.PICC_IsNewCardPresent())      return;   // Look for new cards
  if ( ! mfrc522.PICC_ReadCardSerial())    return;  // Select one of the cards
  Serial.print(F("UID tag :"));
  String content = "";
  byte letter;
  for (byte i = 0; i < mfrc522.uid.size; i++)
  {
    Serial.print(mfrc522.uid.uidByte[i] < 0x10 ? " 0" : " ");
    Serial.print(mfrc522.uid.uidByte[i], HEX);
    content.concat(String(mfrc522.uid.uidByte[i] < 0x10 ? " 0" : " "));
    content.concat(String(mfrc522.uid.uidByte[i], HEX));
  }
  Serial.println();
  content.toUpperCase();
  if ((content.substring(1) == "93 6D BE 0D") 
  ||(content.substring(1) == "51 67 DC B0")
  ||(content.substring(1) == "A3 23 74 11")//change here the UID of the card/cards that you want to give access A3 23 74 11
  ||(content.substring(1) == "55 42 2B 0D"))
  {
    previousMillis = millis();
    Serial.println(F("Clear LCD"));
    lcd.clear();
    Serial.println(F("LCD backlight is on"));
    lcd.backlight();
    Serial.println(F("LCD print 'ACCESS GRANTED' for 7 seconds"));
    lcd.print("     ACCESS     ");
    lcd.setCursor(0, 1);
    lcd.print("    GRANTED!    ");
    Serial.println(F("Relay activated for 7 seconds"));
    digitalWrite(RELAY, HIGH);
    Serial.println(F("Buzzer activated at 1KHz"));
    tone(BUZZER, 1000);
    Serial.println(F("Buzzer sounding for 400 milliseconds"));
    delay(400);
    Serial.println(F("Buzzer deactivated"));
    noTone(BUZZER);
    delay(6600);
    Serial.println(F("Relay deactivated"));
    digitalWrite(RELAY, LOW);
    Serial.println(F("Clear LCD"));
    lcd.clear();
    Serial.println(F("LCD print 'SCAN CARD TO UNLOCK' forever, or until card is scanned"));
    lcd.print("   SCAN CARD ");
    lcd.setCursor(0, 1);
    lcd.print("   TO UNLOCK  ");
    Serial.println(F("LCD backlight is to be turned off after 30 seconds if no card is scanned"));
  }

  else   {
    previousMillis = millis();
    Serial.println(F("Clear LCD"));
    lcd.clear();
    Serial.println(F("LCD backlight is on"));
    lcd.backlight();
    Serial.println(F("LCD print 'ACCESS DENIED' for 1.75 seconds"));
    lcd.print("     ACCESS     ");
    lcd.setCursor(0, 1);
    lcd.print("     DENIED     ");
    Serial.println(F("Buzzer activated at 1KHz"));
    tone(BUZZER, 1000);
    delay(150);
    noTone(BUZZER);
    delay(25);
    Serial.println(F("Buzzer activated at 1KHz"));
    tone(BUZZER, 1000);
    Serial.println(F("Buzzer sounding for 150 milliseconds"));
    delay(150);
    Serial.println(F("Buzzer deactivated for 25 milliseconds"));
    noTone(BUZZER);
    delay(25);
    Serial.println(F("Buzzer activated at 1KHz"));
    tone(BUZZER, 1000);
    Serial.println(F("Buzzer sounding for 150 milliseconds"));
    delay(150);
    Serial.println(F("Buzzer deactivated for 25 milliseconds"));
    noTone(BUZZER);
    delay(25);
    Serial.println(F("Buzzer activated at 1KHz"));
    tone(BUZZER, 1000);
    Serial.println(F("Buzzer sounding for 150 milliseconds"));
    delay(150);
    Serial.println(F("Buzzer deactivated for 25 milliseconds"));
    noTone(BUZZER);
    delay(25);
    Serial.println(F("Buzzer activated at 1KHz"));
    tone(BUZZER, 1000);
    Serial.println(F("Buzzer sounding for 150 milliseconds"));
    delay(150);
    Serial.println(F("Buzzer deactivated for 1 second"));
    noTone(BUZZER);
    delay(1000);
    Serial.println(F("Clear LCD"));
    lcd.clear();
    Serial.println(F("LCD print 'SCAN CARD TO UNLOCK' forever, or until card is scanned"));
    lcd.print("   SCAN CARD ");
    lcd.setCursor(0, 1);
    lcd.print("   TO UNLOCK  ");
    Serial.println(F("LCD backlight is to be turned off after 30 seconds if no card is scanned"));
  }
}

Can you show me what you mean by editing my code?

Non-blocking timing tutorials:
Blink without delay().
Beginner's guide to millis().
Several things at a time.

1 Like

There is a serious problem with your placement of curly braces.

Before posting again, hit CTRL-T in the Arduino IDE editor to autoformat the code. The brace problem will become obvious.

@groundFungus Yes I've spent hours studying these, but they don't work in my code, I'm probably missing something.

Why do you say that @jremington

Why not think for a few seconds before posting a reply?

This is why I asked:
image
That is what it tells me.

Once you understand the idea of millis timing, you might look into simple state-machines.

Personally, I’d strip your program into a number of separate functions, then apply the millis and state machine concepts.

2 Likes

Oh okay.. That kinda makes sense, but I'm still stuck on the millis...

#include <LiquidCrystal_I2C.h>
#include <SPI.h>
#include <MFRC522.h>
#include <Wire.h>
LiquidCrystal_I2C lcd(0x27, 16, 2);

unsigned long startMillis;               //set up millis for reset
unsigned long currentMillis;             //pull up millis for reset
const unsigned long period = 604800000;  //the value is a number of milliseconds, ie 7 days

unsigned long previousMillis = 0;  // will store last time LCD was updated

const long interval = 1000;  // interval at which to turn off (milliseconds)

unsigned long delayTime;  // declare variable

#define SS_PIN 10
#define RST_PIN 9
#define RELAY 3                    //relay pin
#define BUZZER 2                   //buzzer pin
MFRC522 mfrc522(SS_PIN, RST_PIN);  // Create MFRC522 instance.
void setup() {
  Serial.begin(9600);  // Initiate a serial communication
  Serial.println(F("Initializing SPI, mfrc522, Relay, and Buzzer"));
  SPI.begin();
  mfrc522.PCD_Init();
  pinMode(RELAY, OUTPUT);
  pinMode(BUZZER, OUTPUT);
  Serial.println(F("No sound from Buzzer until instructed otherwise"));
  noTone(BUZZER);
  Serial.println(F("Initialize LCD"));
  lcd.init();
  Serial.println(F("Clear LCD"));
  lcd.clear();
  Serial.println(F("LCD backlight on"));
  lcd.backlight();
  Serial.println(F("Buzzer activated at 1KHz"));
  tone(BUZZER, 1000);
  Serial.println(F("Buzzer sounding for 100 milliseconds"));
  delayTime = millis();  // note the time now
  if ((millis() - delayTime) >= (100UL)) {
    Serial.println(F("Buzzer deactivated"));
    noTone(BUZZER);
  }
  Serial.println(F("LCD print 'ARDUINO SECURITY DOOR' for 2 seconds"));
  lcd.print(F("ARDUINO SECURITY"));
  lcd.setCursor(0, 1);
  lcd.print(F("      DOOR  "));
  if ((millis() - delayTime) >= (2000UL)) {
    Serial.println(F("Clear LCD"));
    lcd.clear();
    Serial.println(F("LCD print 'ACTIVATING SYSTEM' for 2 seconds"));
    lcd.print(F("   ACTIVATING    "));
    lcd.setCursor(0, 1);
    lcd.print(F("     SYSTEM    "));
    delay(2000);
    Serial.println(F("Clear LCD"));
    lcd.clear();
    Serial.println(F("Relay test - activated for 2 milliseconds"));
    digitalWrite(RELAY, HIGH);
    delay(2);
    digitalWrite(RELAY, LOW);
    Serial.println(F("LCD print 'PLEASE BE PATIENT' for 2 seconds"));
    lcd.print("   PLEASE BE ");
    lcd.setCursor(0, 1);
    lcd.print("    PATIENT  ");
    delay(2000);
    Serial.println(F("Relay default is LOW"));
    digitalWrite(RELAY, LOW);
    Serial.println(F("Buzzer activated at 1KHz"));
    tone(BUZZER, 1000);
    Serial.println(F("Buzzer sounding for 1 second"));
    delay(1000);
    Serial.println(F("Buzzer deactivated"));
    noTone(BUZZER);
    Serial.println(F("Clear LCD"));
    lcd.clear();
    Serial.println(F("LCD print 'SCAN CARD TO UNLOCK' forever, or until card is scanned"));
    lcd.print("   SCAN CARD ");
    lcd.setCursor(0, 1);
    lcd.print("   TO UNLOCK  ");
    Serial.println(F("LCD backlight is to be turned off after 30 seconds if no card is scanned"));
    previousMillis = millis();
    Serial.println(F("Set up resetFunc"));
    Serial.println(F("If 7 days have elapsed, call reset"));
  }
}
void (*resetFunc)(void) = 0;
void loop() {
  currentMillis = millis();                   //get the current "time" (actually the number of milliseconds since the program started)
  if (currentMillis - startMillis >= period)  //test whether the period has elapsed
  {
    Serial.println(F("get the current 'time'"));
    Serial.println(F("test whether the period has elapsed"));
    Serial.println(F("call reset"));
    resetFunc();  //call reset
  }
  currentMillis = millis();
  if (millis() - previousMillis > 30 * 1000UL) {
    lcd.noBacklight();
    lcd.clear();
  }
  if (!mfrc522.PICC_IsNewCardPresent()) return;  // Look for new cards
  if (!mfrc522.PICC_ReadCardSerial()) return;    // Select one of the cards
  Serial.print(F("UID tag :"));
  String content = "";
  byte letter;
  for (byte i = 0; i < mfrc522.uid.size; i++) {
    Serial.print(mfrc522.uid.uidByte[i] < 0x10 ? " 0" : " ");
    Serial.print(mfrc522.uid.uidByte[i], HEX);
    content.concat(String(mfrc522.uid.uidByte[i] < 0x10 ? " 0" : " "));
    content.concat(String(mfrc522.uid.uidByte[i], HEX));
  }
  Serial.println();
  content.toUpperCase();
  if ((content.substring(1) == "93 6D BE 0D")
      || (content.substring(1) == "51 67 DC B0")
      || (content.substring(1) == "A3 23 74 11")  //change here the UID of the card/cards that you want to give access A3 23 74 11
      || (content.substring(1) == "55 42 2B 0D")) {
    previousMillis = millis();
    Serial.println(F("Clear LCD"));
    lcd.clear();
    Serial.println(F("LCD backlight is on"));
    lcd.backlight();
    Serial.println(F("LCD print 'ACCESS GRANTED' for 7 seconds"));
    lcd.print("     ACCESS     ");
    lcd.setCursor(0, 1);
    lcd.print("    GRANTED!    ");
    Serial.println(F("Relay activated for 7 seconds"));
    digitalWrite(RELAY, HIGH);
    Serial.println(F("Buzzer activated at 1KHz"));
    tone(BUZZER, 1000);
    Serial.println(F("Buzzer sounding for 400 milliseconds"));
    delay(400);
    Serial.println(F("Buzzer deactivated"));
    noTone(BUZZER);
    delay(6600);
    Serial.println(F("Relay deactivated"));
    digitalWrite(RELAY, LOW);
    Serial.println(F("Clear LCD"));
    lcd.clear();
    Serial.println(F("LCD print 'SCAN CARD TO UNLOCK' forever, or until card is scanned"));
    lcd.print("   SCAN CARD ");
    lcd.setCursor(0, 1);
    lcd.print("   TO UNLOCK  ");
    Serial.println(F("LCD backlight is to be turned off after 30 seconds if no card is scanned"));
  }

  else {
    previousMillis = millis();
    Serial.println(F("Clear LCD"));
    lcd.clear();
    Serial.println(F("LCD backlight is on"));
    lcd.backlight();
    Serial.println(F("LCD print 'ACCESS DENIED' for 1.75 seconds"));
    lcd.print("     ACCESS     ");
    lcd.setCursor(0, 1);
    lcd.print("     DENIED     ");
    Serial.println(F("Buzzer activated at 1KHz"));
    tone(BUZZER, 1000);
    delay(150);
    noTone(BUZZER);
    delay(25);
    Serial.println(F("Buzzer activated at 1KHz"));
    tone(BUZZER, 1000);
    Serial.println(F("Buzzer sounding for 150 milliseconds"));
    delay(150);
    Serial.println(F("Buzzer deactivated for 25 milliseconds"));
    noTone(BUZZER);
    delay(25);
    Serial.println(F("Buzzer activated at 1KHz"));
    tone(BUZZER, 1000);
    Serial.println(F("Buzzer sounding for 150 milliseconds"));
    delay(150);
    Serial.println(F("Buzzer deactivated for 25 milliseconds"));
    noTone(BUZZER);
    delay(25);
    Serial.println(F("Buzzer activated at 1KHz"));
    tone(BUZZER, 1000);
    Serial.println(F("Buzzer sounding for 150 milliseconds"));
    delay(150);
    Serial.println(F("Buzzer deactivated for 25 milliseconds"));
    noTone(BUZZER);
    delay(25);
    Serial.println(F("Buzzer activated at 1KHz"));
    tone(BUZZER, 1000);
    Serial.println(F("Buzzer sounding for 150 milliseconds"));
    delay(150);
    Serial.println(F("Buzzer deactivated for 1 second"));
    noTone(BUZZER);
    delay(1000);
    Serial.println(F("Clear LCD"));
    lcd.clear();
    Serial.println(F("LCD print 'SCAN CARD TO UNLOCK' forever, or until card is scanned"));
    lcd.print("   SCAN CARD ");
    lcd.setCursor(0, 1);
    lcd.print("   TO UNLOCK  ");
    Serial.println(F("LCD backlight is to be turned off after 30 seconds if no card is scanned"));
  }
}

Thats what I have so far, but it gets jammed on

  lcd.print(F("ARDUINO SECURITY"));
  lcd.setCursor(0, 1);
  lcd.print(F("      DOOR  "));

and doesn't go any further. It never does the rest of the code.

Hello cowboydaniel
Beside your project take some time and study and understood the BLINKWITHOUTDELAY example from the IDE.

Have a nice day and enjoy coding in C++.
Дайте миру шанс!

2 Likes

non-blocking timing becomes much easier to understand if the principle is explained with

1. an everyday example

2. carefully named variable-names

So here is another approach to explain how non-blocking timing based on function millis() works

and here is a demcode showing how state-machines are working

best regards Stefan

2 Likes

I couldn't work it out.

I'm not sure what this....

.... has to do with your question being about delays @outbackhut, but you have handled the naming of the relay's and the buzzer's pins using an alternative method, thus:

Either way has the effect of giving the pin a name, so that in other commands you use the more human-friendly name not the number, for example:

digitalWrite(RELAY, HIGH);
// rather than
digitalWrite(3, HIGH);

But that question is a bit odd given the general thread of your thread being about delay().

so start asking specific questions

first of all you are asking for a medium advanced functionality. And this medium advanced functionality needs a few more lines of code than
switch LED on
wait 1 second
switch LED off
repeat

one guessing I have is that you might try to see a delay()-similar-thing in non-blocking-timing
which it really isn't ! non-blocking-timing is fundamentally different.

non-blocking timing is a often repeated comparing how much time has passed by since a certain point in time where this certain point of time is stored in a variable.

often repeated comparing is the opposite of "sit and wait flipping thumbs" before doing the next thing = delay()

The second thing you should do is learning how to divide code into functions

There should be one function "buzzing()" that does the buzzing

The other approach is using a state-machine.

So there are things to learn new that will take more than 20 minutes.
Trying to apply these things immidiately to your application makes it harder to understand as you don't have divided your code into senseful functions.

It is not done by inserting 8 to 12 lines of code.
Doing things in parallel requires re-designing your code.
Doing this re-designing and applying in parallel to learning it will take more time and frustration than
learning the new design and the new principles on an simpler and therefore easier to understand demo-code will take less time than applying it immidiately o your application.

best regards Stefan

The easiest way to insert a delay without delay() is to break the process into steps or 'states'. A state is any part of your sketch that is waiting for an event to happen (button press, operation completed, delay finished) and when the event happens, you go on to the next state. Since there are a limited number of states each process can be in, the process is known as a Finite State Machine.

For example: Let's say you wanted two LEDs to blink at the same time but at different speeds. You can't even do that easily with a simple delay():

void loop()
{
  digitalWrite(LED1, HIGH);
  delay(3000);
  digitalWrite(LED1, LOW);
  delay(2000);

  digitalWrite(LED2, HIGH);
  delay(1000);
  digitalWrite(LED2, LOW);
  delay(2500);
}

This will obviously not do what you want because the 'delay()' calls allow only one LED to be active at a time.

The way to make it work is to make each independent process a separate Finite State Machine. I like to use an 'enum' to give names to each state. In this case, the states are the same for both so we can get by with one 'enum' for both:

  enum
  {
    Idle, TurnOn, OnDelay, TurnOff, OffDelay
  } StateLED1 = TurnOn, StateLED2 = TurnOn;

Now you can see that each 'delay()' is spread across two states. The first state starts the delay timer and changes to the second state. The second state checks the timer and, if the timer has expired, goes on to the next state. The process repeats when the "OffDelay" state ends and goes to the "TurnOn" state.

The "Idle" state is there in case you want to turn off either or both blinkers.

const byte LED1 = 4;
const byte LED2 = 5;

enum
  {
    Idle, TurnOn, OnDelay, TurnOff, OffDelay
  } StateLED1 = TurnOn, StateLED2 = TurnOn;

void setup()
{
  pinMode(LED1, OUTPUT);
  pinMode(LED2, OUTPUT);
}

void loop()
{
  unsigned long currentMillis = millis();
  static unsigned long Delay1Start;
  static unsigned long Delay2Start;

  switch (StateLED1)
  {
    case Idle:
      digitalWrite(LED1, LOW);
      break;

    case TurnOn:
      digitalWrite(LED1, HIGH);
      Delay1Start = currentMillis;
      StateLED1 = OnDelay;
      break;

    case OnDelay:
      if (currentMillis - Delay1Start >= 3000)
        StateLED1 = TurnOff;
      break;

    case TurnOff:
      digitalWrite(LED1, LOW);
      Delay1Start = currentMillis;
      StateLED1 = OffDelay;
      break;

    case OffDelay:
      if (currentMillis - Delay1Start >= 2000)
        StateLED1 = TurnOn;
      break;
  }
  
  
  switch (StateLED2)
  {
    case Idle:
      digitalWrite(LED2, LOW);
      break;

    case TurnOn:
      digitalWrite(LED2, HIGH);
      Delay2Start = currentMillis;
      StateLED2 = OnDelay;
      break;

    case OnDelay:
      if (currentMillis - Delay2Start >= 1000)
        StateLED2 = TurnOff;
      break;

    case TurnOff:
      digitalWrite(LED2, LOW);
      Delay2Start = currentMillis;
      StateLED2 = OffDelay;
      break;

    case OffDelay:
      if (currentMillis - Delay2Start >= 2500)
        StateLED2 = TurnOn;
      break;
  }
}

And there we go. No delay(). No wait loops.

Here @outbackhut I have taken the liberty of showing @johnwasser 's statemachines as a diagram: