Hey guys, can someone help me with millis and switch case and relays?

Well, im trying to do a timer for four relays, when i touch on the keypad "A,B,C,D" to activate the relays (A for relay1, B for relay2...) and start counting 2 hours after activating the relay, imagining, I activate relay "B" and after an hour I activate relay "D", but relay "B" continues to count without resetting and relay "D" starts counting, that is, independent timers for each of them, and after this time ends, the relay turn off...
Do someone know how to help? Thanks!!!

The actual code is:

#include <Keypad.h>
#include <Password.h>
#include <Key.h>
#include <Keypad_I2C.h>

int buzzer = 11;

int noAccesled = 3;
int AccesLed = 10;

int noAcces = 1;
int passinput = 0;

long flashvarled = 0;
long flashtimeled = 300;

//Relays
int relay1 = 7;
int relay2 = 6;
int relay3 = 5;
int relay4 = 4;

/*

  • tried to do this a lot of time but idk how to do, use this if that's useful
    int statusrelay1 = LOW;
    int statusrelay2 = LOW;
    int statusrelay3 = LOW;
    int statusrelay4 = LOW;

long ant_millis_relay1 = 0;
long ant_millis_relay2 = 0;
long ant_millis_relay3 = 0;
long ant_millis_relay4 = 0;

long inter_relay1 = 2000;
long inter_relay2 = 2000;
long inter_relay3 = 2000;
long inter_relay4 = 2000;
*/

//keypad

#define I2CADDR 0x20

const byte ROWS = 4;
const byte COLS = 4;

char keys [ROWS] [COLS] = {
{'1', '2', '3', 'A'},
{'4', '5', '6', 'B'},
{'7', '8', '9', 'C'},
{'*', '0', '#', 'D'}
};

byte rowPins [ROWS] = {0, 1, 2, 3};
byte colPins [COLS] = {4, 5, 6, 7};
Keypad_I2C keypad (makeKeymap (keys), rowPins, colPins, ROWS, COLS, I2CADDR, PCF8574);

Password password = Password("5"); // change the access code here

void setup() {
Serial.begin(9600);
Wire .begin ();
keypad.begin (makeKeymap (keys));

Serial.begin(9600);
pinMode(relay1, OUTPUT);
digitalWrite(relay1, 0);
pinMode(relay2, OUTPUT);
digitalWrite(relay2, 0);
pinMode(relay3, OUTPUT);
digitalWrite(relay3, 0);
pinMode(relay4, OUTPUT);
digitalWrite(relay4, 0);
pinMode(noAccesled, OUTPUT);
digitalWrite(noAccesled, HIGH);
pinMode(AccesLed, OUTPUT);
digitalWrite(AccesLed, 0);
pinMode(buzzer, OUTPUT);
}

void loop() {
char key = keypad.getKey();
if (noAcces) {
if (passinput) {
unsigned long currentvarled = millis();
if (currentvarled - flashvarled > flashtimeled) {
flashvarled = currentvarled;
digitalWrite(noAccesled, !digitalRead(noAccesled));
}
}
else {
digitalWrite(noAccesled, HIGH);
}
digitalWrite(AccesLed, 0);
}
if (key != NO_KEY) {
Serial.println(key);
password.append(key);
passinput = 1;
digitalWrite(buzzer, HIGH);
delay(100);
digitalWrite(buzzer, LOW);

if (key == '*') {
  password.reset();
  passinput = 0;
  noAcces = 1;
}

}
if (password.evaluate()) {
noAcces = !noAcces;
password.reset();
passinput = 0;
}

if (!noAcces) {

passinput = 0;
digitalWrite(noAccesled, LOW);
digitalWrite(AccesLed, 255);
delay(10);


switch (key) {
  case 'A':
    digitalWrite(relay1, !digitalRead(relay1));
    break;
  case 'B':
    digitalWrite(relay2, !digitalRead(relay2));
    break;
  case 'C':
    digitalWrite(relay3, !digitalRead(relay3));
    break;
  case 'D':
    digitalWrite(relay4, !digitalRead(relay4));
    break;
  case '#':
    digitalWrite(relay1, 0);
    digitalWrite(relay2, 0);
    digitalWrite(relay3, 0);
    digitalWrite(relay4, 0);
    break;
}

password.reset();

}
}

the password is "5" and to reset the password to lock you can use "*", and to turn down all the relays you can use "#", i want this to turn off and if i turn on it counts, and it can't interfer with the other relays, independence!!! xD, thanks one more time!

Please format your code with </> button... It will be more readable

how?

Click on </> button and paste your code inside

sry, but, where? xD

#include <Keypad.h>
#include <Password.h>
#include <Key.h>
#include <Keypad_I2C.h>




int buzzer = 11;

int noAccesled = 3;
int AccesLed = 10;

int noAcces = 1;
int passinput = 0;

long flashvarled = 0;
long flashtimeled = 300;

//Relays 
int relay1 = 7;
int relay2 = 6;
int relay3 = 5;
int relay4 = 4;

/*
 * tried to do this a lot of time but idk how to do, use this if that's useful
int statusrelay1 = LOW;
int statusrelay2 = LOW;
int statusrelay3 = LOW;
int statusrelay4 = LOW;

long ant_millis_relay1 = 0;
long ant_millis_relay2 = 0;
long ant_millis_relay3 = 0;
long ant_millis_relay4 = 0;

long inter_relay1 = 2000;
long inter_relay2 = 2000;
long inter_relay3 = 2000;
long inter_relay4 = 2000;
*/




//keypad

#define I2CADDR 0x20

const byte ROWS = 4;
const byte COLS = 4;


char keys [ROWS] [COLS] = {
  {'1', '2', '3', 'A'},
  {'4', '5', '6', 'B'},
  {'7', '8', '9', 'C'},
  {'*', '0', '#', 'D'}
};

byte rowPins [ROWS] = {0, 1, 2, 3};
byte colPins [COLS] = {4, 5, 6, 7};
Keypad_I2C keypad (makeKeymap (keys), rowPins, colPins, ROWS, COLS, I2CADDR, PCF8574);

Password password = Password("5"); // change the access code here

void setup() {
  Serial.begin(9600);
  Wire .begin ();
  keypad.begin (makeKeymap (keys));

  Serial.begin(9600);
  pinMode(relay1, OUTPUT);
  digitalWrite(relay1, 0);
  pinMode(relay2, OUTPUT);
  digitalWrite(relay2, 0);
  pinMode(relay3, OUTPUT);
  digitalWrite(relay3, 0);
  pinMode(relay4, OUTPUT);
  digitalWrite(relay4, 0);
  pinMode(noAccesled, OUTPUT);
  digitalWrite(noAccesled, HIGH);
  pinMode(AccesLed, OUTPUT);
  digitalWrite(AccesLed, 0);
  pinMode(buzzer, OUTPUT);
}

void loop() {
  char key = keypad.getKey();
  if (noAcces) {
    if (passinput) {
      unsigned long currentvarled = millis();
      if (currentvarled - flashvarled > flashtimeled) {
        flashvarled = currentvarled;
        digitalWrite(noAccesled, !digitalRead(noAccesled));
      }
    }
    else {
      digitalWrite(noAccesled, HIGH);
    }
    digitalWrite(AccesLed, 0);
  }
  if (key != NO_KEY) {
    Serial.println(key);
    password.append(key);
    passinput = 1;
    digitalWrite(buzzer, HIGH);
    delay(100);
    digitalWrite(buzzer, LOW);


    if (key == '*') {
      password.reset();
      passinput = 0;
      noAcces = 1;
    }




  }
  if (password.evaluate()) {
    noAcces = !noAcces;
    password.reset();
    passinput = 0;
  }



  if (!noAcces) {

    passinput = 0;
    digitalWrite(noAccesled, LOW);
    digitalWrite(AccesLed, 255);
    delay(10);


    switch (key) {
      case 'A':
        digitalWrite(relay1, !digitalRead(relay1));
        break;
      case 'B':
        digitalWrite(relay2, !digitalRead(relay2));
        break;
      case 'C':
        digitalWrite(relay3, !digitalRead(relay3));
        break;
      case 'D':
        digitalWrite(relay4, !digitalRead(relay4));
        break;
      case '#':
        digitalWrite(relay1, 0);
        digitalWrite(relay2, 0);
        digitalWrite(relay3, 0);
        digitalWrite(relay4, 0);
        break;
    }

    password.reset();
  }
}

More better, thanks :slight_smile:

So you want create a delay ON timer?
Or simple store a time for each relay?

the project consists of an electric bicycle charger, and every time someone loads the bicycle, it did the count and after that time it turned off by itself in case they didn't deactivate it with the button.
(im using a little of google translate, so, sry if someone is wrong).

and if someone activates it, it counts and then turns off, or they click on the button to turn off and it is turned off.
each relay with its timing without interfering with anything.
when i tried to do this, or everything just stopped or the relay didn't turned off, only reseting arduino..

You can declare 4 different unsigned long variable, like timer1, time2, timer3, timer4 and store the value of millis() in switch section.

switch (key) {
      case 'A':
        if (stateRelay1 == false)
        {
            stateRelay1 = true;
            digitalWrite(relay1, stateRelay1);
            timer1 = millis();
            
       }      
      break;
      

Then in loop cycle put in If condiction and check if the time elapsed

if( stateRelay1 == true)
{
   if( millis() > timer1 + (chargingTime))
   {
      stateRelay1 = false;
      digitalWrite(relay1, stateRelay1);
   }
}

for now i can't check it because im doing the project in automation classes, so, can't do it right now, but, i need this on each case "digitalWrite(relay1, !digitalRead(relay1));" and that was another problem because that its fundamental, because that's responsable to on/off when we want, and that didn't worked in all of my attempts, he only work one time, to activate.. now with this idk, i need to see, thank you Z4KK4, i will notice you asaf!!

Since you have four relays that all do the same thing it is good to use arrays, like this:

const unsigned long SECOND = 1000UL;
const unsigned long MINUTE = 60 * SECOND;
const unsigned long HOUR = 60 * MINUTE;

//Relays
const byte RelayCount = 4;
const byte RelayPins[RelayCount] = {7, 6, 5, 4};
boolean RelayOn[RelayCount];
unsigned long RelayOnStartTime[RelayCount];
unsigned long RelayOnInterval = 2 * HOUR;

Then you can use loops to have all relays do the same thing:

void loop()
{
  // Check for timeouts
  for (int r = 0; r < RelayCount; r++)
  {
    if (RelayOn[r] && millis() - RelayOnStartTime[r] > RelayOnInterval)
    {
      digitalWrite(RelayPins[r], LOW);
      RelayOn[r] = false;
    }
  }
      case '#':
        // All relays off
        for (int r = 0; r < RelayCount; r++)
        {
          digitalWrite(RelayPins[r], LOW);
          RelayOn[r] = false;
        }
        break;

Or calculate an index for which relay you are acting on.

      case 'A':
      case 'B':
      case 'C':
      case 'D':
        {
          int relayIndex = key - 'A';
          if (RelayOn[relayIndex])
          {
            // Relay is on.  Turn off.
            digitalWrite(RelayPins[relayIndex], LOW); // Relay Off
            RelayOn[relayIndex] = false;
          }
          else
          {
            // Relay is off.  Turn on and start timer.
            digitalWrite(RelayPins[relayIndex], HIGH); // Relay On
            RelayOn[relayIndex] = true;
            RelayOnStartTime = millis();
          }
        }
        break;

Hi calistow,

your project has two main functionalities:

  1. entering a password
  2. start / stop charging by presses of a button or after 2h of time

This means you should code both parts independent from each other with one sharp defined interface between them: This means one single place in the code where these two parts interact.

There is an online-simulator for the Arduino-Uno that can simulate a lot of things.
This simulator is sure able to simulate the timer-part of your project.
Using this simulator enables that you can write code, test your code from wherever you are and have a computer with browser and internetconnection.
It is called the wokwi-simulator.

It is generally a good strategy to develop code one functionality at a time.
So start writing a program that does the timing
switching on/off the relay-outputs by pressing a key
or if charging-time (the two hours) are over to switch off the relay-outputs.

And this part can surely be coded in the wokwi-simulator.

best regards Stefan

well, thanks but, how can i put this in my code? i didn't understood this part, how can i put it?

  case 'A':
  case 'B':
  case 'C':
  case 'D':
     {    
    int relayIndex = key - 'A';
     
        if (RelayOn[relayIndex])
          {
            // Relay is on.  Turn off.
            digitalWrite(RelayPins[relayIndex], LOW); // Relay Off
            RelayOn[relayIndex] = false;
          }
          else
          {
            // Relay is off.  Turn on and start timer.
            digitalWrite(RelayPins[relayIndex], HIGH); // Relay On
            RelayOn[relayIndex] = true;
            RelayOnStartTime = millis();
          }
        }
        break;

how can i put this? what kinda of variables i need to do?

Ok, it's very easy but you have to know how "switch.. case" works.
You'll need 3 variable for each recharging station:

  • stateRelay1 that hold the actual state of the relay
  • timer1 that is used to store the start time of charging
  • chargingTime is the time of charging (for example 2 hours) ; pay attention: is defined in milliseconds, so 2 hours are 2(hours) * 60(minutes) * 60(seconds) * 1000 => 7200000.

When you press the "A" button, you fall inside "A" case of switch, here the stateRelay1 change in true, the program store the value of millis() in timer1 and activate the output pin.
Outside the switch case, program check if the stateRelay1 is true (therefore the station1 is charging) and compare the actual value of millis() with the start time + the charging time.
If actual value is greater it changes the value of the relay and de-activate the output pin.

This must be replied for the other 3 stations, clearly you have to define other 9 variables.

You are almost asking for "can somenody write the code for me?"
No me personal I will not.

You really need to understand how the switch-case-statement works.
So my suggestion is:
If you did not t nderstand the proposed code. You should go two steps back and work with a simpler demo-code that demontrates the principles.

best regards Stefan

1 Like

You put it in your 'switch' statement in place of case 'A', case 'B', case 'C', and case 'D'.

Here is your code with all of my suggested changes made:

#include <Keypad.h>
#include <Password.h>
#include <Key.h>
#include <Keypad_I2C.h>

int buzzer = 11;

int noAccesled = 3;
int AccesLed = 10;

int noAcces = 1;
int passinput = 0;

unsigned long flashvarled = 0;
const unsigned long flashtimeled = 300;

//Relays
//int relay1 = 7;
//int relay2 = 6;
//int relay3 = 5;
//int relay4 = 4;

/*
   tried to do this a lot of time but idk how to do, use this if that's useful
  int statusrelay1 = LOW;
  int statusrelay2 = LOW;
  int statusrelay3 = LOW;
  int statusrelay4 = LOW;

  long ant_millis_relay1 = 0;
  long ant_millis_relay2 = 0;
  long ant_millis_relay3 = 0;
  long ant_millis_relay4 = 0;

  long inter_relay1 = 2000;
  long inter_relay2 = 2000;
  long inter_relay3 = 2000;
  long inter_relay4 = 2000;
*/




//keypad

#define I2CADDR 0x20

const byte ROWS = 4;
const byte COLS = 4;


char keys [ROWS] [COLS] =
{
  {'1', '2', '3', 'A'},
  {'4', '5', '6', 'B'},
  {'7', '8', '9', 'C'},
  {'*', '0', '#', 'D'}
};

byte rowPins [ROWS] = {0, 1, 2, 3};
byte colPins [COLS] = {4, 5, 6, 7};
Keypad_I2C keypad (makeKeymap (keys), rowPins, colPins, ROWS, COLS, I2CADDR, PCF8574);

Password password = Password("5"); // change the access code here


const unsigned long SECOND = 1000UL;
const unsigned long MINUTE = 60 * SECOND;
const unsigned long HOUR = 60 * MINUTE;

//Relays
const byte RelayCount = 4;
const byte RelayPins[RelayCount] = {7, 6, 5, 4};
boolean RelayOn[RelayCount];
unsigned long RelayOnStartTime[RelayCount];
unsigned long RelayOnInterval = 2 * HOUR;

void setup()
{
  Serial.begin(9600);
  Wire .begin ();
  keypad.begin (makeKeymap (keys));

  Serial.begin(9600);

  //  pinMode(relay1, OUTPUT);
  //  digitalWrite(relay1, 0);
  //  pinMode(relay2, OUTPUT);
  //  digitalWrite(relay2, 0);
  //  pinMode(relay3, OUTPUT);
  //  digitalWrite(relay3, 0);
  //  pinMode(relay4, OUTPUT);
  //  digitalWrite(relay4, 0);
  for (int r = 0; r < RelayCount; r++)
  {
    pinMode(RelayPins[r], OUTPUT);
    digitalWrite(RelayPins[r], LOW);
    RelayOn[r] = false;
  }

  pinMode(noAccesled, OUTPUT);
  digitalWrite(noAccesled, HIGH);
  pinMode(AccesLed, OUTPUT);
  digitalWrite(AccesLed, 0);
  pinMode(buzzer, OUTPUT);
}

void loop()
{
  // Check for timeouts
  for (int r = 0; r < RelayCount; r++)
  {
    if (RelayOn[r] && millis() - RelayOnStartTime[r] > RelayOnInterval)
    {
      digitalWrite(RelayPins[r], LOW);
      RelayOn[r] = false;
    }
  }

  char key = keypad.getKey();
  if (noAcces)
  {
    if (passinput)
    {
      unsigned long currentvarled = millis();
      if (currentvarled - flashvarled > flashtimeled)
      {
        flashvarled = currentvarled;
        digitalWrite(noAccesled, !digitalRead(noAccesled));
      }
    }
    else
    {
      digitalWrite(noAccesled, HIGH);
    }
    digitalWrite(AccesLed, 0);
  }
  if (key != NO_KEY)
  {
    Serial.println(key);
    password.append(key);
    passinput = 1;
    digitalWrite(buzzer, HIGH);
    delay(100);
    digitalWrite(buzzer, LOW);


    if (key == '*')
    {
      password.reset();
      passinput = 0;
      noAcces = 1;
    }




  }
  if (password.evaluate())
  {
    noAcces = !noAcces;
    password.reset();
    passinput = 0;
  }



  if (!noAcces)
  {

    passinput = 0;
    digitalWrite(noAccesled, LOW);
    digitalWrite(AccesLed, 255);
    delay(10);


    switch (key)
    {
      //      case 'A':
      //        digitalWrite(relay1, !digitalRead(relay1));
      //        break;
      //      case 'B':
      //        digitalWrite(relay2, !digitalRead(relay2));
      //        break;
      //      case 'C':
      //        digitalWrite(relay3, !digitalRead(relay3));
      //        break;
      //      case 'D':
      //        digitalWrite(relay4, !digitalRead(relay4));
      //        break;

      case 'A':
      case 'B':
      case 'C':
      case 'D':
        {
          int relayIndex = key - 'A';
          if (RelayOn[relayIndex])
          {
            // Relay is on.  Turn off.
            digitalWrite(RelayPins[relayIndex], LOW); // Relay Off
            RelayOn[relayIndex] = false;
          }
          else
          {
            // Relay is off.  Turn on and start timer.
            digitalWrite(RelayPins[relayIndex], HIGH); // Relay On
            RelayOn[relayIndex] = true;
            RelayOnStartTime[relayIndex] = millis();
          }
        }
        break;


      //      case '#':
      //        digitalWrite(relay1, 0);
      //        digitalWrite(relay2, 0);
      //        digitalWrite(relay3, 0);
      //        digitalWrite(relay4, 0);
      //        break;

      case '#':
        // All relays off
        for (int r = 0; r < RelayCount; r++)
        {
          digitalWrite(RelayPins[r], LOW);
          RelayOn[r] = false;
        }
        break;
    }

    password.reset();
  }
}

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