What's the easiest way to switch outputs in a sequence?

I'm trying to switch some relays sequentially and things are going sideways.

Basically I have 13 outputs and 1 input
Outputs 1 - 9 need to switch on and off in sequence when the input button is pressed.

Then with each of those, outputs 10, 11 and 12 need to turn on and off. - output 10 triggering a few moments before 11 and 12. Then all 4 active outputs go off toeather before moving to the next one.

Essentially the switching order is as follows:
Output 13 is high indicating its at the start of the loop
Push momentary input 1
Output 13 goes low showing the loop has started
Output 1 high
200ms
Output 10 high
200ms
Output 11 & 12 high
200ms
All off

Then repeat with output 2 and so on.

What's the best way to program this in?
Can anyone give me an example to work from?

No, but research how to use arrays.

Maybe I am "anyone" :wink:

Here is a solution for what you mentioned with output 1:

const byte pins[] {2,3,10,11};
byte NoOfPins = sizeof pins / sizeof pins[0];

const byte buttonPin = 13;

const int delayTime = 2000;

enum Outputs {
   OUT01,
   OUT10,
   OUT11,
   OUT12
};

enum states {
  IDLE,
  ALL_OFF,
  WAIT,
  HIGH01,
  HIGH10,
  HIGH11_12,
};

byte state = IDLE;
byte nextState = IDLE;
unsigned long waitTime = 0;
unsigned long timeStamp;

void setup() {
  Serial.begin(115200);
 for (byte i=0;i < NoOfPins;i++){
   pinMode(pins[i],OUTPUT);
   digitalWrite(pins[i],LOW);
 }
 pinMode(buttonPin, INPUT_PULLUP);
 Serial.println("Start");
}

void loop() {
  if (state == IDLE && buttonWasPressed()) state = HIGH01;
  stateMachine();
}

void stateMachine(){
   switch (state){
     case IDLE:
       break;
     case ALL_OFF:
          for (byte i=0;i < NoOfPins;i++){
              digitalWrite(pins[i],LOW);
         }
       state = IDLE;  // No delay time required         
       break;
     case WAIT:
        if (TimeIsOver()) state = nextState;
       break;
     case HIGH01:
        Serial.println("HIGH01");
        digitalWrite(pins[OUT01], HIGH);
        SetWaitTimeAndNextState(delayTime,HIGH10);
       break;
     case HIGH10:
        Serial.println("HIGH10");
        digitalWrite(pins[OUT10], HIGH);
        SetWaitTimeAndNextState(delayTime,HIGH11_12);
       break;
     case HIGH11_12:
        Serial.println("HIGH11_12");
        digitalWrite(pins[OUT11], HIGH);
        digitalWrite(pins[OUT12], HIGH);
        SetWaitTimeAndNextState(delayTime,ALL_OFF);
       break;
     default:
       break;
   }
}

void SetWaitTimeAndNextState(unsigned long w, byte s){
  timeStamp = millis();
  waitTime = w;
  nextState = s;
  state = WAIT;
}

boolean TimeIsOver(){
  if (millis()-timeStamp > waitTime) return true;
                                else return false;

}


boolean buttonWasPressed() {
  static unsigned long lastPressTime = 0;   // Stores the last time when the button state changed from HIGH to LOW
  static boolean lastState = HIGH;          // Stores the last detected state of the button for the "next round"
  int buttonState = digitalRead(buttonPin);    // Reads the actual button state
  if (buttonState == LOW && lastState == HIGH) lastPressTime = millis(); // Store the time when the state hase changed to LOW 
  lastState = buttonState;   // Now store the recent state for the "next round"
  if (lastState == LOW && millis() - lastPressTime > 50)  return true; // If lastState is still LOW for minimum 50 msec ... accept it
  else return false;                   // else do not accept the LOW state (debouncing!)
}

You can test it on Wokwi and make your own copy there for further coding and testing ...

https://wokwi.com/projects/331934995655426643

It uses a 2 seconds wait time per step so that you can follow each one ...

It is a non blocking state machine.

What does this term ”easiest” mean ? :thinking:

Hello bnet
Post a timing diagram.
Have a nice day and enjoy coding in C++.
Дайте миру шанс

Hi @paulpaulson

If you put the following into WaveDrom Editor

You'll see what I'm trying to achieve

{signal: [
{name: 'Ready', wave: '10...................................1..... '},
{name: 'Start', wave: '010.........................................'},
{name: 'Running', wave: '0..10..10..10..10..10..10..10..10..10.......'},
{name: 'Focus', wave: '0.1.0.1.0.1.0.1.0.1.0.1.0.1.0.1.0.1.0.......'},
{name: 'Shutter', wave: '0..10..10..10..10..10..10..10..10..10.......'},
{name: 'Pin 1', wave: '0.1.0.......................................'},
{name: 'Pin 2', wave: '0.....1.0...................................'},
{name: 'Pin 3', wave: '0.........1.0...............................'},
{name: 'Pin 4', wave: '0.............1.0...........................'},
{name: 'Pin 5', wave: '0.................1.0.......................'},
{name: 'Pin 6', wave: '0.....................1.0...................'},
{name: 'Pin 7', wave: '0.........................1.0...............'},
{name: 'Pin 8', wave: '0.............................1.0...........'},
{name: 'Pin 9', wave: '0.................................1.0.......'},
]}

@ec2021

that's given me a lot to play with, thank you very much

That's pretty neat. Too bad it doesn't have an "export Arduino code" option!
(Hmm. There is probably something more blinking-lights oriented. All those fancy Christmas displays don't spring out of nothing! Maybe https://manual.xlights.org/ or similar? )

You could make an Arduino get pretty close to that as far as processing input, but the program would be more complicated.

  signal ready(WAVE, 13, "10...................................1.....");
  signal focus(WAVE, 12, "0.1.0.1.0.1.0.1.0.1.0.1.0.1.0.1.0.1.0.......");
  signal signame(type, pinNo, patternString);
  // etc

Or you can make a simpler program that is more difficult to change the sequences...

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