Correct sequence order of input

I'm all new to Arduino and I've searched here in the forum and the internet to find an answer - but I don't think I've found the correct one.

I have a small project - where I receive input from 4 micro switches in the right order - first pin2 then pin3 then pin4 and finally pin5.
If the sequence is correct, pin12 is set to HIGH.
If the registered order is not the correct one - nothing should happen.
You have to manually reset the micro switches again and try again.

I can't really figure out if I should use a CASE or IF ELSE or an Array as control of the sequence.

Is there anyone who can help.

Welcome to the forum

Please clarify what type of switches you are using. Are they switches that stay open/closed when toggled or are they pushbuttons that stay closed only when pushed and held down ?

You can use a counter to accomplish this.

Counter = 0

Sw1 closed counter++

Sw2 closed counter++

Sw3 closed counter++

Sw4 closed counter++

If counter ever gets to 4 . . .

Out of sequence closing counter = 0

consider

// check multiple buttons and toggle LEDs

enum { Off = HIGH, On = LOW };

byte pinsLed [] = { 10, 11, 12 };
byte pinsBut [] = { A1, A2, A3 };
#define N_BUT   sizeof(pinsBut)

byte butState [N_BUT];

// -----------------------------------------------------------------------------
int
chkButtons ()
{
    for (unsigned n = 0; n < sizeof(pinsBut); n++)  {
        byte but = digitalRead (pinsBut [n]);

        if (butState [n] != but)  {
            butState [n] = but;

            delay (10);     // debounce

            if (On == but)
                return n;
        }
    }
    return -1;
}

// -----------------------------------------------------------------------------
int state;
void
loop ()
{
    switch (chkButtons ())  {
    case 0:
        if (state == 0)
            state = 1;
        else
            Serial.println ("wrong");
        break;

    case 1:
        if (state == 1)
            state = 2;
        else  {
            Serial.println ("wrong");
            state = 0;
        }
        break;

    case 2:
        if (state == 2)  {
            state = 0;
            Serial.println ("release");
        }
        break;

    }
}

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

    for (unsigned n = 0; n < sizeof(pinsBut); n++)  {
        pinMode (pinsBut [n], INPUT_PULLUP);
        butState [n] = digitalRead (pinsBut [n]);
    }

    for (unsigned n = 0; n < sizeof(pinsLed); n++)  {
        digitalWrite (pinsLed [n], Off);
        pinMode      (pinsLed [n], OUTPUT);
    }
}
void loop()
{
  static boolean error = false;

  byte state = digitalRead(2) * 8 +  digitalRead(3) * 4 + digitalRead(4) * 2 + digitalRead(5);

  if (state == 0) // None set
    error == false;
  else if (state == 15)  // All four set
  {
    if (!error)
      digitalWrite(25, HIGH);
  }
  else if (!(state == 8 || state == 12 || state == 14))
    error = true; // Invalid pattern
}

sequence not AND

SequenceState = 0
If pin1 = HIGH
SequenceState =1
If SequenceState = 1 and pin 3 =HIGH or pin 4 = Hi
iGH or pin 1 equals HIGH SequenceState =0
Else if pin 2 = HIGH SequenceState = 2
Etc

You need to build in debouncing that also picks up the change in state back to LOW. Easy enough and just apply to all button presses

Try this.

Change the combination by re-ordering the initial values in combo[];

Remove the "Bzzzt!" to provide no clue as to progress.

const unsigned char combo[] = {1, 2, 4, 8, 16,};

void setup() {
  Serial.begin(115200);   // hello, it's 2022
  Serial.println("Hello Combination World!\n");

  DDRD &= ~0xf8;
  PORTD |= 0xf8;
}

void loop() {
  static unsigned long lastTime;
  static unsigned char lastEntry;
  static unsigned char next;

  unsigned long now = millis();

  if (now - lastTime < 20) return;    // throttled loop. get over it.
  lastTime = now;

  unsigned char entry = (PIND ^ 0xff) >> 3;
  unsigned char delta = entry & ~lastEntry;
  lastEntry = entry;

  if (!delta)
    return;

  if (delta == combo[next]) next++;
  else {
    Serial.println("Bzzzt!");
    next = 0;
  }

  if (next == 5) {
    Serial.println("OKAY!");
    next = 0;
  }
}

Of course I did. I just grabbed the hardware description from the wokwi @dlloyd posted. (THX!)

a7

Wow... what an experience! Thank you all for taking the time to help me!
I will try the different solution suggestions - however, it will be a while before I have the time to do so.

Just to make things clearer - my switches are mechanical - so you have to manually change it from NC to NO.

But shout out to all of you for your help.

Hi,

It is the right sequence.

------ Original Meddelelse ------

Actually, you can use the NC connection from a limit switch (microswitch) directly.

Here's a simulation where:

  • a pushbutton and relay creates each limit switch
  • limit switch NC (normally closed) is connected to a digital input
  • the digital input is configured INPUT_PULLUP by the Toggle library
  • detects "onRelease" when limit switch opens
  • led progress bar

Well there are a number of different approaches shown, so to try them all (you did say "suggestions" plural) will be quite a task. If I were you, and assuming you want to figure it out rather than run some turnkey code, I'd go with @pmagowan 's state machine suggestion in post #7 since as pseudocode it gives you enough of a clue as to how to proceeed, but doesn't let all the cats out the bag.

Hello plauborg
Welcome to the best ever Arduino Forum.

Here is a simple example that uses classless object-oriented programming.
The mirco switches are declared in the INPUTS object and then initialised. The pattern for the order of the switches is set in the SEQUENCE object.
In this way, you can easily change both the set of micro-switches and the pattern for the order of the buttons without changing the programme code.
Try it out. You only need to adapt the port pin addresses to your project.

/* BLOCK COMMENT
  ATTENTION: This Sketch contains elements of C++.
  https://www.learncpp.com/cpp-tutorial/
  Many thanks to LarryD
  https://europe1.discourse-cdn.com/arduino/original/4X/7/e/0/7e0ee1e51f1df32e30893550c85f0dd33244fb0e.jpeg
  https://forum.arduino.cc/t/correct-sequence-order-of-input/1019627
  Tested with Arduino: Mega[x] - UNO [ ] - Nano [ ]
*/
#define ProjectName "Correct sequence order of input"
// HARDWARE AND TIMER SETTINGS
// YOU MAY NEED TO CHANGE THESE CONSTANTS TO YOUR HARDWARE AND NEEDS
constexpr byte MicroSwitches[] {A0, A1, A2, A3};      // portPin o---|button|---GND
constexpr byte LedPins[] {9};     // portPin o---|220|---|LED|---GND
constexpr unsigned long Blink512Hz {9};     // blinkrate for heartbeat function
#define OutPutTest
constexpr  unsigned long OutPutTestTime {1000};
// CONSTANT DEFINITION
enum InputOutput {One, Two, Three, Four};
// VARIABLE DECLARATION AND DEFINITION
unsigned long currentTime;
// -- objects -----------------------------------------
struct TIMER {              // has the following members
  unsigned long duration;   // memory for interval time
  unsigned long stamp;      // memory for actual time
  int onOff;               // control for stop/start/repeat
};
struct BUTTON {             // has the following members
  byte pin;                 // port pin
  bool statusOld;           // current state
  TIMER scan;               // see timer struct
};
struct INPUTS {
  int   ident;
  BUTTON knop;
} inputs [] {
  {One, MicroSwitches[One], false, 20, 0, false},
  {Two, MicroSwitches[Two], false, 20, 0, false},
  {Three, MicroSwitches[Three], false, 20, 0, false},
  {Four, MicroSwitches[Four], false, 20, 0, false},
};
struct SEQUENCE {
  int counter;
  int pattern[4];
}sequence {0,{One,Two,Three,Four}};
int sequenceSize {(sizeof(sequence.pattern)/sizeof(sequence.pattern[0])-1)};
// -- services  -----------------------------------------
void heartBeat(int rate)
{
  bool myBlink {currentTime & bit(rate)};
  digitalWrite(LED_BUILTIN, myBlink);
}
// -------------------------------------------------------------------
void setup() {
  Serial.begin(9600);
  Serial.println(F("."));
  Serial.print(F("File   : ")), Serial.println(__FILE__);
  Serial.print(F("Date   : ")), Serial.println(__DATE__);
  Serial.print(F("Project: ")), Serial.println(ProjectName);
  pinMode (LED_BUILTIN, OUTPUT);  // used as heartbeat indicator
  //  https://www.learncpp.com/cpp-tutorial/for-each-loops/
  for (auto MicroSwitch : MicroSwitches) pinMode(MicroSwitch, INPUT_PULLUP);
  for (auto LedPin : LedPins) pinMode(LedPin, OUTPUT);
#ifdef OutPutTest
  // check outputs
  for (auto LedPin : LedPins) digitalWrite(LedPin, HIGH), delay(OutPutTestTime);
  for (auto LedPin : LedPins) digitalWrite(LedPin, LOW), delay(OutPutTestTime);
#endif
}
void loop () {
  currentTime = millis();
  heartBeat(Blink512Hz);
  for (auto &input : inputs)
  {
    if (currentTime - input.knop.scan.stamp >= input.knop.scan.duration)
    {
      input.knop.scan.stamp=currentTime;
      int statusNew = !digitalRead(input.knop.pin);
      if (input.knop.statusOld != statusNew)
      {
        input.knop.statusOld = statusNew;
        if (statusNew)
        {
          if (sequence.pattern[sequence.counter]==input.ident) 
          {
            if (sequence.counter==sequenceSize)
            {
              digitalWrite(LedPins[One],HIGH);
              sequence.counter=0;
            }
            else 
            {
              sequence.counter++;
              digitalWrite(LedPins[One],LOW);
            }
          }
          else
          {
            digitalWrite(LedPins[One],LOW);
            sequence.counter=0;
          }
        }
      }
    }
  }
}

Have a nice day and enjoy programming in C++ and learning.
MIND THE GAP