switches and relays and delays but not delays!

Hello

I’m relatively new to the Arduino and its coding.

I am creating an interface between two pieces of equipment and thought an Arduino would be a perfect solution.

Here’s my problem. I have 16 switched inputs which are operated externally. These switches connect to an Arduino Mega. Once the switch has been triggered, the Arduino, stops taking an input from that switch for the next few seconds. The output is 16 relays which only need to be pulsed.

The code I have sort of put together with help from books and the web works great.
BUT… Relay 16 needs to be pulsed 20 seconds AFTER the switch has been pressed not immediately like the others.
How do I do this? Where does the code fit? I know I can’t use the delay functoiun!

Any help will be gratefully received.
Thanks

Bob

const int inputPins[] = {38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53}; // create an array of pins for switch inputs
const int relayPins[] = {22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37}; // create array of output pins for relays

int butpress[16];
int timnow[16];
int timthen[16];
int deltim;
void setup()
{  
  deltim=5000;
for(int index = 0; index < 16; index++)
{
pinMode(relayPins[index], OUTPUT); // relay as output
pinMode(inputPins[index], INPUT); // switch as input
digitalWrite(inputPins[index],HIGH);

butpress[index]= 0;
timnow[index]=0;
timthen[index]=0;
}
}
void loop(){
for(int index = 0; index < 16; index++)
{
  timnow[index]=millis();
 
   if (index ==0)
  deltim = 3000;   //release time for relay 1
   if (index ==1)
  deltim = 3000;   //release time for relay 2
   if (index ==2)
  deltim = 3000;   //release time for relay 3
   if (index ==3)
  deltim = 3000;   //release time for relay 4
   if (index ==4)
  deltim = 3000;   //release time for relay 5
   if (index ==5)
  deltim = 3000;   //release time for relay 6
   if (index ==6)
  deltim = 3000;   //release time for relay 7
   if (index ==7)
  deltim = 3000;   //release time for relay 8
   if (index ==8)
  deltim = 3000;   //release time for relay 9
   if (index ==9)
  deltim = 3000;   //release time for relay 10
   if (index ==10)
  deltim = 3000;   //release time for relay 11
   if (index ==11)
  deltim = 3000;   //release time for relay 12
   if (index ==12)
  deltim = 3000;   //release time for relay 13
   if (index ==13)
  deltim = 3000;   //release time for relay 14
   if (index ==14)
  deltim = 3000;   //release time for relay 15
   if (index ==15)
  deltim = 3000;   //release time for relay 16
  
  if (timnow[index]-timthen[index]>deltim)
  {
  butpress[index]=0;
  timthen[index]=timnow[index]; 
  }
  int val = digitalRead(inputPins[index]); // read input value
if (val == LOW) // check if the switch is pressed
{
  if (butpress[index]==0) 
  {
  digitalWrite(relayPins[index], LOW); // turn relay on if switch is pressed
  butpress[index]=1;
  timthen[index]=timnow[index];
  }
}
else
{
digitalWrite(relayPins[index], HIGH); // turn relay off
}
}

}

A for loop that iterates 16 times, doing 16 different things, is just wrong.

I don't understand the timthen and timnow arrays. Is it really that difficult to spell out time? A 3 letter abbreviation for a 4 letter word is lazy.

Neither array appears to actually hold a time, since there are no calls to millis(), micros(), or an RTC.

millis() and micros() return unsigned longs, since in our universe times does not move backwards. Does it move forwards and backwards in yours?

Paul,

Firstly, thank you for taking the time to reply to my first post.

The comments you make are, I guess fair if you have programed before.
I have not really undertaken vast programming and what I have done is minimal.
The code I have used is taken and adapted from the internet and a selection of books.

Your sarcasm is more destructive than constructive in its nature which is not a positive step forward for me.

The code can be changed as a work in progress with help and assistance from people more in the know. I am not sure of all the coding structure so am at the bottom of the ladder when it comes to Arduino. I do not always understand what the coding is doing either which does not help!

Thank you again for your reply but ‘assistance’ rather than ‘resistance’ would have been much more appreciated at this time.

Best regards

Bob

Can't you delete all of the code on lines 29 to 59 without any impact on the program?

I don't see how this line

timnow[index]=millis();

adds any value. I would just use

currentMillis = millis();

and then I would change this

  if (timnow[index]-timthen[index]>deltim)
  {
  butpress[index]=0;
  timthen[index]=timnow[index];
  }

to

  if (currentMillis - timthen[index] > deltim)
  {
     butpress[index] = 0;
     timthen[index] = currentMillis;
  }

I can understand your comments about @PaulS's style but I have a lot of sympathy with his underlying message that you are not doing yourself any favour by skimping on the typing. Look how much easier it is to read when a bit of whitespace is added.

...R

Hello

I am back working on this project again after purchasing a selection of books on the Arduino subject.

Thinking about my original post with the replies from PaulS and Robin2 - I did not make it clear that whilst there are 16 inputs which are momentarily triggering 16 relays, the pause of no action after each activation is different.
i.e. a pulse to relay 1 'Trip' then the relay becomes inactive for x seconds. A pulse to relay 2 'Trip' and the relay becomes inactive for y seconds - hence the extra lines of coding (release times all at 3000 ms for testing)

The project I have undertaken is going OK - I have moved forwards - perhaps not the best, but I am on a learning curve.

Thank you for taking the time to read digest and perhaps reply

Bob

Bobster35:
i.e. a pulse to relay 1 'Trip' then the relay becomes inactive for x seconds. A pulse to relay 2 'Trip' and the relay becomes inactive for y seconds - hence the extra lines of coding (release times all at 3000 ms for testing)

Then you should have a multidimensional array or an array of structs that associates each relay with some delay value. Once you have that, you can iterate through all of them with the same code.

Bobster35:
I am back working on this project again after purchasing a selection of books on the Arduino subject.

your use case begs for object-oriented programming, and it is a long way from buying the book to getting that happening.... But the good news is that once you understand classes, problems like yours become trivial.

here is an example where you can set the relay/switch pair and the delay for turning relay on and the duration of the relay (in an array):

#define MAX_RELAY_COUNT 16
#define DEBOUNCE_MILLIS 100

class SwitchRelay{
  public:
    SwitchRelay(const uint8_t relay, const uint8_t button, uint32_t delayOn, uint32_t duration);
    static void begin();
    static void update();
    static size_t instanceCount;
  protected:
    byte lastButtonState;
    bool pressed();
    enum State { 
        WAITING,
        BUTTON_PRESSED,
        PULSING_SOLENOID,
      }currentState = WAITING;
    int relayPin;
    int buttonPin;
    uint32_t lastMillis;
    uint32_t pressedMillis;
    uint32_t actuateDelay;
    uint32_t pulseDuration;
    uint32_t lastPulseMillis;
};

size_t SwitchRelay::instanceCount = 0;
SwitchRelay* instances[MAX_RELAY_COUNT] = {nullptr};

SwitchRelay::SwitchRelay(const uint8_t relay, const uint8_t button, uint32_t delayOn, uint32_t duration)
{
  relayPin = relay;
  buttonPin = button;
  actuateDelay = delayOn;
  pulseDuration = duration;
  instances[instanceCount++] = this;
}

void SwitchRelay::begin(void)
{
  for (auto i : instances)
  {
    if(i)
    {
      pinMode(i->buttonPin, INPUT_PULLUP);
      pinMode(i->relayPin, OUTPUT);
    }
  }
}

void SwitchRelay::update(void)
{
  for (auto i : instances)
  {
    if(i)
    {
      
      switch(i->currentState)
      {
        case WAITING:
        if (i->pressed())
        {
          i->pressedMillis = millis();
          i->currentState = BUTTON_PRESSED;
        }
          break;
        case BUTTON_PRESSED:
          if (millis() >= (i->pressedMillis + i->actuateDelay))
          {
            digitalWrite(i->relayPin, HIGH);
            i->currentState = PULSING_SOLENOID;
          }
          break;
        case PULSING_SOLENOID:
          if (millis() > (i->pressedMillis + i->actuateDelay + i->pulseDuration))
          {
            digitalWrite(i->relayPin, LOW);
            i->currentState = WAITING;
          }
          break;
      }
    }
  }
}

bool SwitchRelay::pressed(void)
{
  byte nowState = digitalRead(buttonPin);
  if(nowState != lastButtonState)
  {
    if(millis() - lastMillis < DEBOUNCE_MILLIS) 
      return false;
    if(nowState == LOW)
    {
      lastMillis = millis();
      lastButtonState = nowState;
      return true;
    }
    lastButtonState = nowState;
  }
  return false;
}

/***************************************************************/
/******************* END OF CLASS DEFINITION *******************/
/***************************************************************/

SwitchRelay relay[] = {
  {13, 5, 500, 2000},  // relayPin, buttonPin, onDelay, pulseLength
  //{12, 4, 100, 2000},
  // another set here,
  // and so on....
};

void setup() 
{
  Serial.begin(9600);
  Serial.print(F("There are "));
  Serial.print(SwitchRelay::instanceCount);
  Serial.print(F(" SwitchRelays attached\n"));
  
  SwitchRelay::begin();
}

void loop() 
{
  SwitchRelay::update();
}

compiled and tested IDE version 1.8.2