Do I need millis() and is it even possible?

Hi,

Probably like many I am making my journey from delay() to millis() as when involving many components in a circuit I am noticing some erratic behaviour when there are several delays involved. In trying to build up to transferring my current code over to millis()-based I have done some simple circuits with LEDs and buzzers but cannot yet fathom how to change over my current code.

In summary it is 6 vibration sensors which when each one is triggered it turns the red LED off and the green LED on and the buzzer makes a noise. When all 6 are triggered it turns the solved LED on and triggers the relay:

If someone can tell me it's possible and it's necessary then I'll keep digging but as I said I can't see it yet. Here is the code:

The references to zombies are because it will be a "knock the zombie out" puzzle in an escape game. Many thanks in advance for any help.

//green LEDs

const int redled1 = 22;
const int redled2 = 23;
const int redled3 = 24;
const int redled4 = 25;
const int redled5 = 26;
const int redled6 = 27;

//Green LEDs

const int greenled1 = 2;
const int greenled2 = 3;
const int greenled3 = 4;
const int greenled4 = 5;
const int greenled5 = 6;
const int greenled6 = 7;

//Buzzers

const int buzzer1 = 8;
const int buzzer2 = 9;
const int buzzer3 = 10;
const int buzzer4 = 11;
const int buzzer5 = 12;
const int buzzer6 = 13;

//Vibration Sensors

const int vib1 = 44;
const int vib2 = 45;
const int vib3 = 46;
const int vib4 = 47;
const int vib5 = 48;
const int vib6 = 49;

//General Declarations

int solvedled = 38;
int delaytime = 100;
bool v1, v2, v3, v4, v5, v6 = false; //to trigger all 6 sensors
int f1, f2, f3, f4, f5, f6 = 0;
int relay = 53;

void setup() {
  
  // initiate and turn on all red LEDs
  
pinMode(redled1,OUTPUT);
digitalWrite(redled1,HIGH);
pinMode(redled2,OUTPUT);
digitalWrite(redled2,HIGH);
pinMode(redled3,OUTPUT);
digitalWrite(redled3,HIGH);
pinMode(redled4,OUTPUT);
digitalWrite(redled4,HIGH);
pinMode(redled5,OUTPUT);
digitalWrite(redled5,HIGH);
pinMode(redled6,OUTPUT);
digitalWrite(redled6,HIGH);

 // Initiate and turn off all green LEDs
 
pinMode(greenled1,OUTPUT);
digitalWrite(greenled1,LOW);
pinMode(greenled2,OUTPUT);
digitalWrite(greenled2,LOW);
pinMode(greenled3,OUTPUT);
digitalWrite(greenled3,LOW);
pinMode(greenled4,OUTPUT);
digitalWrite(greenled4,LOW);
pinMode(greenled5,OUTPUT);
digitalWrite(greenled5,LOW);
pinMode(greenled6,OUTPUT);
digitalWrite(greenled6,LOW);

//Initiate all Buzzers

pinMode(buzzer1,OUTPUT);
pinMode(buzzer2,OUTPUT);
pinMode(buzzer3,OUTPUT);
pinMode(buzzer4,OUTPUT);
pinMode(buzzer5,OUTPUT);
pinMode(buzzer6,OUTPUT);

//General initiations

pinMode(solvedled,OUTPUT);
digitalWrite(solvedled,LOW);
pinMode(relay,OUTPUT);
digitalWrite(relay,LOW);

}
void loop() {

 //FIRST ZOMBIE
  
  int val1;
  val1=digitalRead(vib1);
  Serial.println(val1);
  if(val1==1)
  {
   digitalWrite(greenled1,HIGH);
   digitalWrite(redled1,LOW);
   tone(buzzer1,1000);
   delay(delaytime);
   tone(buzzer1,500);
   noTone(buzzer1);
   v1 = true;
   f1 = f1 + 1;
   }

  //2nd Zombie

  int val2;
  val2 = digitalRead(vib2);
  Serial.println(val2);
  if(val2==1)
  {
   digitalWrite(greenled2,HIGH);
   digitalWrite(redled2,LOW);
   tone(buzzer2,1000);
   delay(delaytime);
   tone(buzzer2,500);
   noTone(buzzer2);
   v2 = true;
   f2 = f2 + 1;
   }

  //3rd Zombie

 
  int val3;
  val3 = digitalRead(vib3);
  Serial.println(val3);
  if(val3==1)
  {
   digitalWrite(greenled3,HIGH);
   digitalWrite(redled3,LOW);
   tone(buzzer3,1000);
   delay(delaytime);
   tone(buzzer3,500);
   noTone(buzzer3);
   v3 = true;
   f3 = f3 + 1;
   }

   //4th Zombie

  int val4;
  val4 = digitalRead(vib4);
  Serial.println(val4);
  if(val4==1)
  {
   digitalWrite(greenled4,HIGH);
   digitalWrite(redled4,LOW);
   tone(buzzer4,1000);
   delay(delaytime);
   tone(buzzer4,500);
   noTone(buzzer4);
   v4 = true;
   f4 = f4 + 1;
   }

   //5th Zombie

     int val5;
  val5 = digitalRead(vib5);
  Serial.println(val5);
  if(val5==1)
  {
   digitalWrite(greenled5,HIGH);
   digitalWrite(redled5,LOW);
   tone(buzzer5,1000);
   delay(delaytime);
   tone(buzzer5,500);
   noTone(buzzer5);
   v5 = true;
   f5 = f5 + 1;
   }

  //6th Zombie

       int val6;
  val6 = digitalRead(vib6);
  Serial.println(val6);
  if(val6==1)
  {
   digitalWrite(greenled6,HIGH);
   digitalWrite(redled6,LOW);
   tone(buzzer6,1000);
   delay(delaytime);
   tone(buzzer6,500);
   noTone(buzzer6);
   v6 = true;
   f6 = f6 + 1;
   }

//solved code
   
if (v1 == true && v2 == true && v3 == true && v4 == true && v5 == true && v6 == true) 
  {
    digitalWrite(solvedled,HIGH);
    delay(5000);
   digitalWrite(solvedled,HIGH);
   digitalWrite(relay,HIGH);
   delay(5000);
   digitalWrite(relay,LOW);
   while (1);
    v1 = false;
    v2 = false;
    v3 = false;
    v4 = false;
    v5 = false;
    v6 = false;
    f1 = 0;
    f2 = 0;
    f3 = 0;
    f4 = 0;
    f5 = 0;
    f6 = 0;
   }
}

You can considerably simplify your code by using arrays. Read about using arrays, structs and loops.

Yes you do need to use millis() if you want your sketch to be responsive.

Save the value of millis() when an action to start timing occurs and start the action, such as tone() and let loop() run freely.

Each time through loop() compare the current value of millis() with the start value and when the required period has elapsed take appropriate action such as tone() and/or notone()

A boolean variable will be helpful in keeping track as to whether an action is taking place or not

You will, of course need separate variables for each timed action so that they can be kept separate

Personally I would restructure your sketch to use arrays to avoid the repetition of code that it uses at the moment

Having said all of that, what is the purpose of the delay()s as compared with the tone() periods they are small

and tone() is non blocking

consider


struct Zombie {
    const byte      PinVib;
    const byte      PinBuzzer;
    const byte      PinLedRed;
    const byte      PinLedGreen;
    bool            trig;
    int             cntF;
    int             state;
    unsigned long   msecLst;
};

#undef MyHW
#ifdef MyHW
Zombie zombies [] = {
    { A2, 2, 10, 11 },
    { A3, 3, 12, 13 },
};

int solvedled = 10;
int relay     = 12;

#else
Zombie zombies [] = {
    { 44,  8, 22,  2 },
    { 45,  9, 23,  3 },
    { 46, 10, 24,  4 },
    { 47, 11, 25,  5 },
    { 48, 12, 26,  6 },
    { 49, 13, 17,  7 },
};

int solvedled = 38;
int relay     = 53;
#endif

#define N_ZOMBIES   (sizeof(zombies)/sizeof(Zombie))

enum { ST_OFF, ST_BUZ1, ST_BUZ2, ST_TRIG };
enum { Off = HIGH, On = LOW };

//General Declarations
const unsigned long DelayTime = 100;

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

    pinMode      (solvedled, OUTPUT);
    digitalWrite (solvedled, Off);
    pinMode      (relay, OUTPUT);
    digitalWrite (relay, Off);

    Zombie *p = zombies;
    for (unsigned n = 0; n < N_ZOMBIES; n++, p++)  {
        pinMode      (p->PinVib, INPUT_PULLUP);

        pinMode      (p->PinBuzzer, OUTPUT);
        digitalWrite (p->PinBuzzer, Off);

        pinMode      (p->PinLedRed, OUTPUT);
        digitalWrite (p->PinLedRed, On);

        pinMode      (p->PinLedGreen, OUTPUT);
        digitalWrite (p->PinLedGreen, Off);
    }
}

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

    bool trigAll = true;

    Zombie *p = zombies;
    for (unsigned n = 0; n < N_ZOMBIES; n++, p++)  {
        if (On == digitalRead (p->PinVib))  {
            Serial.print   (n);
            Serial.println (" trig");

            digitalWrite (p->PinLedGreen, On);
            digitalWrite (p->PinLedRed,   Off);

            p->msecLst = msec;
            tone (p->PinBuzzer, 1000);
            p->state = ST_BUZ1;
        }

        if (ST_OFF != p->state)  {
            if ( (msec - p->msecLst) > DelayTime)  {
                Serial.print   (n);
                Serial.println (" timer");

                p->msecLst = msec;

                switch (p->state)  {
                case ST_BUZ1:
                    tone (p->PinBuzzer, 500);
                    p->state = ST_BUZ2;
                    break;

                case ST_BUZ2:
                default:
                    noTone (p->PinBuzzer);
                    p->state = ST_OFF;
                    p->trig  = true;
                    break;
                }
            }
        }

        trigAll = trigAll && p->trig;
    }

    //solved code
    if (trigAll) {
        digitalWrite (solvedled, On);
        digitalWrite (relay,     On);
        delay (5000);
        digitalWrite (relay,     Off);
        while (1)
            ;
    }
}
1 Like

or this



const byte redLEDs [] = {22, 23, 24, 25, 26, 27};
const byte greenLEDs [] = {2, 3, 4, 5, 6, 7};
const byte buzzers [] = {8, 9, 10, 11, 12, 13};
const byte vibrators [] = {44, 45, 46, 47, 48, 49};

const byte num  = sizeof(redLEDs) / sizeof(redLEDs[0]);  // this will return 6 in your case

byte solvedled = 38;
byte relay = 53;

int delaytime = 100;


void initPins() {
  for ( byte x = 0; x < num; x++ ) {
    setPinAsOutput(redLEDs[x]);
    setPinAsOutput(greenLEDs[x]);
    setPinAsOutput(buzzers[x]);
    // setPinAsOutput(vibrators[x]);
  }
}

void setPinAsOutput(byte pin_  ) {
  pinMode(pin_, OUTPUT);
  digitalWrite(pin_, LOW);
}

void setup() {

  // initiate and turn on all red LEDs

  initPins();

  setPinAsOutput(solvedled);
  setPinAsOutput(relay);
}

void loop() {

  static byte increment = 0;  // start with zero
  static uint32_t prevMillis = 0;
  static bool startTiming = false;

  bool checkState = digitalRead(vibrators[increment]);  // check the input stat

  if ( checkState && ! startTiming ) {  // if input is high and timing NOT started
    digitalWrite(greenLEDs[increment], HIGH);
    digitalWrite(redLEDs[increment], LOW);
    tone(buzzers[increment], 1000);
    prevMillis = millis();
    startTiming = true;
  }


  if ( startTiming && ( millis() - prevMillis >= delaytime ) ) {  // delay time elapsed
    startTiming = false;
    tone(buzzers[increment], 500);
    noTone(buzzers[increment]);
    increment++;  // go to next zombie step
  }


  if ( increment >= num ) {  // all zombie cycle is done
    increment = 0; // reset this
    // do your the rest here
  }


}
1 Like

Ah that's amazing, really appreciate you all taking the time to reply and write code for answering. Looking forward to trying it out and wrapping my head around it, this will help with no end of future projects as well.

Many thanks!
Ben