simple 5 button code input to trigger output

Hello

This is my first post, so please forgive any inadvertent etiquette mistakes.

I’m trying, without much success, to code a simple 5 button input sequence to change an output from HIGH to LOW if the correct sequence is entered, so that I can trigger an external event.

I’m very new to coding, it’s not my background at all, and I am certain I have made a big mistake, or many…

I’ve read many example codes, and to honest, I get completely lost in the weeds, and despite significant time searching for an applicable sketch, I haven’t been able to find one that I can understand sufficiently well to adapt.

below is where I have go to so far. It turns on the LED, but that’s about it…

I have played with the physical setup of the breadboard, used it with and without resistors to short the buttons to earth, tried the code with the pins set to PULLUP and not, tinkered for hours, and I’m just a bit lost here, and could really use some simple advice that a complete novice can (very gratefully) understand and follow.

Any help you can offer would be very very welcome.

Many thanks

Adam.

const int button1 = 2;// permanent pin configuration:
const int button2 = 3;
const int button3 = 4;
const int button4 = 5;
const int button5 = 6;

byte combination[] = {2, 4, 6, 3, 5};  // a 5 number combination:
byte userInput[5]; // same size, will hold user input:
boolean flag = true;// boolen flag for true false check:

void setup() { // input output config - LED on pin 13, just for PoC:
  pinMode(13, OUTPUT);
  digitalWrite(13, HIGH); // to ensure locked:
  }

void loop() { // simple for loop to check flag status:
  for (byte n = 0; n < 5 ; n++)
{
   if (userInput[n] != combination[n]) // no match, stay locked:
   {
       flag = false;
       digitalWrite(13, HIGH);
   }
   {if (userInput[n] == combination[n]);// if flag true, output LOW and unlocked:
   flag = true;
   digitalWrite(13, LOW);
   }
}
}

Welcome to the Wonderful World of Arduino

I'm trying, without much success, to code a simple 5 button input sequence to change an output from HIGH to LOW if the correct sequence is entered, so that I can trigger an external event.

Let's start by defining what you want in more detail. For instance, should the program wait for 5 inputs before signalling success or failure or should it fail at the first wrong entry ? How will the user know that they have failed ? How will the user know that they are starting again ?

You have made a good start so don't get disheartened by not succeeding straight away

Helibob

many thanks for the prompt reply.

it's for an escape room puzzle, so ideally, it needs to recognise when the correct sequence has been entered and then trigger an output, such as turning a realy off to release an electromagnet.

there will be about 12 input devices, but for this example, buttons. when the correct sequence is entered, the positive trigger will alert the players to their success. there will be no negative result as i dont want them to realise the items they are touching are input devices by accident, they have to suss that out and then work out the sequence before trying to enter it.

I dont want them to be able to just do it by accident, so maybe a small delay and then reset if they take too long between inputs or too many numbers are entered. I tried to dictate the sequence length. I did have a delay after the right answer to give the output event time to trigger, but i took it out whilst debugging.

The input code will probably be more like 3422765 where each number equates to the number of the input device and pin on the board.

Does this make sense? please do let me know if I need to clarify anything.

Thanks

Adam

The input code will probably be more like 3422765 where each number equates to the number of the input device and pin on the board.

Sorry, but I can't make sense of that in the context of pressing 5 buttons in sequence

Sorry, i wasnt very clear there.

I dont want to give away the actual game, so imagine 12 bits of rope hanging from the ceiling, numbered 1 to 12 accordingly.

The players will solve a riddle, or decode something and gain a number as the answer, lets say 4563342 for instance.

If they then pull ropes 4, 5, 6, 3, 3, 4, 2 in sequence, the 'code' is corret and the appropiate reward is given, such as a drawer opens, or panel lifts up, or a light shines on the next clue, etc.

That is what I am trying to achieve. I hope that makes it clear, it's probably easier with pictures, but I'm a horrible artist...

thanks

adam

Add pinmode statements for your buttons. Use INPUT_PULLUP.

Read the button states in loop using digitalRead. If a button is pressed, note it in your user input array and increment n. That should get you closer.

Consider putting the pin numbers in an array too.

Willbill

Thanks for the reply.

I did originally have pullup set for the pins. I tried to do it with a array, but got totally muddled, so I guess in setup() I declare each pin via buttonState(INPUT_PULLUP);? Is this just to ensure that when the button is pressed the pin is set low and can be detected?

To read the buttons, can I do that with an array or do I need to read each buttong in turn, with digitalRead? Once I have the state, I don't really know how to store it in the user input array for comparison. Truth be told, I'm really struggling to get my head around this... I will get better, but it's like trying to learn to juggle, blindfold on a unicycle right now... This is why I tried to just compare the sequence with a known correct result; I knew it wouldn't be as simple as I hoped...

To set pin numbers in the array, I feel I can do that with a const int [buttons] but again, I'm not certain. I'm happy to do the research if you can point me at the right information.

Thanks

Adam

The players will solve a riddle, or decode something and gain a number as the answer, lets say 4563342 for instance.

If they then pull ropes 4, 5, 6, 3, 3, 4, 2 in sequence, the 'code' is corret and the appropiate reward is given, such as a drawer opens, or panel lifts up, or a light shines on the next clue, etc.

Thanks. that is clearer but without some way of setting the input back to a start point I foresee them getting stuck for ever

Incidentally, if rope 11 or 12 is included in the list of numbers how will they know to pull 12 and not 1 then 2 for instance ? As soon as they do that they will be out of sequence with no way of aborting the attempt. Note that I am not suggesting that they are given any clue as to the fact that they have gone wrong at any time.

I'm sorry if this sounds very pedantic but in order to program it we (and you) need to know exactly what we are aiming for

I'd suggest that you create an array for your buttons just as you did for your combination array. Then use it to set the pinMode for each button in a loop in setup. Once you've got that squared away, you should be able to do something similar in loop to read them.

That's a fair point about ropes 11 and 12. I would have to ensure that the code given to them was presented in such a way that they were in no doubt.

As for out of sequence, I dont really have an answer on that. I guess if the input takes more than 10 seconds, the system times out and they start again.

thanks

adam

wildbill:
I’d suggest that you create an array for your buttons just as you did for your combination array. Then use it to set the pinMode for each button in a loop in setup. Once you’ve got that squared away, you should be able to do something similar in loop to read them.

Bill

I’ll give it a go and post what I come out with.

Thanks

Adam

wildbill:
I’d suggest that you create an array for your buttons just as you did for your combination array. Then use it to set the pinMode for each button in a loop in setup. Once you’ve got that squared away, you should be able to do something similar in loop to read them.

Bill

Added a few lines. I think this sets the pins to buttons and sets them all to INPUT_PULLUP but I can test it as it already didn’t work so I have no way of knowing. It does compile at least…

Am I on the right track for yoru suggestion?

Cheers

Adam

const int buttons[] = {2, 3, 4, 5, 6}; // permanent pin configuration:
int buttonCount = 5;
byte combination[] = {2, 4, 6, 3, 5};  // a 5 number combination:
byte userInput[5]; // same size, will hold user input:
boolean flag = true;// boolen flag for true false check:

void setup() { // input output config - LED on pin 13, just for PoC:
  pinMode(13, OUTPUT);
  digitalWrite(13, HIGH); // to ensure locked:
}

void loop() { // simple for loop to check flag status:
  for (int thisButton = 0; thisButton < buttonCount; thisButton++)
  {
    pinMode(buttons[thisButton], INPUT_PULLUP);

    for (byte n = 0; n < 5 ; n++)
    {
      if (userInput[n] != combination[n]) // no match, stay locked:
      {
        flag = false;
        digitalWrite(13, HIGH);
      }
      { if (userInput[n] == combination[n]);// if flag true, output LOW and unlocked:
        flag = true;
        digitalWrite(13, LOW);
      }
    }
  }
}

That's close but pinMode is something you only need once, so it should be in the setup function.

wildbill:
That’s close but pinMode is something you only need once, so it should be in the setup function.

Thanks Bill.

Like this?

const int buttons[] = {2, 3, 4, 5, 6}; // permanent pin configuration:
int buttonCount = 5;
byte combination[] = {2, 4, 6, 3, 5};  // a 5 number combination:
byte userInput[5]; // same size, will hold user input:
boolean flag = true;// boolen flag for true false check:

void setup() { // input output config - LED on pin 13, just for PoC:
  pinMode(13, OUTPUT);
  digitalWrite(13, HIGH); // to ensure locked:
  for (int thisButton = 0; thisButton < buttonCount; thisButton++)
  pinMode(buttons[thisButton], INPUT_PULLUP);
}

void loop() { // simple for loop to check flag status:


  for (byte n = 0; n < 5 ; n++)
  {
    if (userInput[n] != combination[n]) // no match, stay locked:
    {
      flag = false;
      digitalWrite(13, HIGH);
    }
    { if (userInput[n] == combination[n]);// if flag true, output LOW and unlocked:
      flag = true;
      digitalWrite(13, LOW);
    }
  }
}

That's it, although you would be well advised to put some braces around the pinMode statement. They're not required, but they'll save you from a subtle bug that occurs when you want two statements to be in the loop but forget that you omitted the braces.

Tools->Autoformat would sort out your indentation.

Then add a for loop in the loop function to digitalRead your buttons and a global variable to index into your userInput array. If a button is pressed (LOW) store the value in userInput and increment the index.

Thanks Bill.

I don't totally understand but Ill go and research this and post back what I lash together.

But right now, the sun is out and the dog wants her walk, so I'm off to the woods!

Cheers

Adam

Some remarks about your last code.

If you know the valid range of variables, it's a good idea to use the smallest fitting variable type.
If something will not change while the sketch is running, make the variable const.
If something has a value that depends on other variables (like the length of an array),
let the compiler fill in the value.
Please don't comment obvious things.

In your code you use pin numbers for the combination,
you are far more flexible if you use the button index for that.

const byte buttons[] = {2, 3, 4, 5, 6}; // permanent pin configuration
const byte buttonCount = sizeof(buttons);

const byte combination[] = {0, 2, 4, 1, 3}; // was 2, 4, 6, 3, 5
const byte combinationLen = sizeof(combination);
byte userInput[combinationLen];
 { if (userInput[n] == combination[n]);// if flag true, output LOW and unlocked:

the if is ignored, because it has a ';' as the only controlled statement,
the comment is not related to the line it is on.

Your whole loop just tests whether single entries in the given code match,
but you are (or try) revealing a match/non match on a digit base via the led, is that intended?

You would better write a function that checks the code and returns match/non match if needed.

You will need some mechanism besides the current index to reset that index.
A button for "new code starts now" and "I have entered the code" would be handy and allow you to use
codes of different lengths easily.

For a beginner it is quite hard to debounce and state detect a lot of buttons,
I would suggest that you take a look at the Bounce2 library and its examples,
it hides all the nitty gritty details of button handling.

Wandall

Many thanks for the reply. I’ll try to understand what you have written and amend my code appropiately.

To use bounce2, I just enter #incude at the top of the code?

Please see below where i have got to. The LED is just constantly on. I tried removing the boolean statement to see if that was overriding the conditional flag, but still just stays on.

The purpose of the LED output is just to see if the code works. In the actual application, the output will be connected to a realy that will trigger an external function.

The buttons on the bread board are simply set with 5V + and the output to the pin. I have tried using resistors as a short to earth but the result is no different. Am i making a basic mistake with the bread board?

const byte buttons[] = {2, 3, 4, 5, 6}; 
const byte buttonCount = sizeof(buttons);

const byte combination[] = {0, 2, 4, 1, 3}; 
const byte combinationLen = sizeof(combination);
byte userInput[combinationLen];

boolean flag = true;// boolen flag for true false check:

void setup() { // input output config - LED on pin 13, just for PoC:
  pinMode(13, OUTPUT);
  digitalWrite(13, HIGH); // to ensure locked:
  for (int thisButton = 0; thisButton < buttonCount; thisButton++)
    pinMode(buttons[thisButton], INPUT_PULLUP);
}

void loop() { // simple for loop to check flag status:


  for (byte n = 0; n < 5; n++)
  {
    if (userInput[n] != combination[n]) // no match, stay locked:
    { flag = false;
      digitalWrite(13, HIGH);
    }
    { if (userInput[n] == combination[n])
      { flag = true;
        digitalWrite(13, LOW);
      }// if flag true, output LOW and unlocked:

    }
  }
}

Next I tried to make all the button pins LOW so that they can see the +5V when i press a button, still no result.

const byte buttons[] = {2, 3, 4, 5, 6}; 
const byte buttonCount = sizeof(buttons);

const byte combination[] = {0, 2, 4, 1, 3}; 
const byte combinationLen = sizeof(combination);
byte userInput[combinationLen];

boolean flag = true;// boolen flag for true false check:

void setup() { // input output config - LED on pin 13, just for PoC:
  pinMode(13, OUTPUT);
  digitalWrite(13, HIGH); // to ensure locked:
  for (int thisButton = 0; thisButton < buttonCount; thisButton++)
    pinMode(buttons[thisButton], INPUT);
    digitalWrite(buttons,LOW);
}

void loop() { // simple for loop to check flag status:


  for (byte n = 0; n < 5; n++)
  {
    if (userInput[n] != combination[n]) // no match, stay locked:
    { flag = false;
      digitalWrite(13, HIGH);
    }
    { if (userInput[n] == combination[n])
      { flag = true;
        digitalWrite(13, LOW);
      }// if flag true, output LOW and unlocked:

    }
  }
}

I’m a bit lost now. However, I have a nice big fat book on C++ to confuse me further, so that’s nice…

Cheers

Adam

sneakydog:
To use bounce2, I just enter #incude at the top of the code?

That allows you to use the library that can be installed by the library manager, yes.
I would suggest looking at some of the examples that come with the library.

Your whole loop still just tests the whole code, regardless of the number or entered buttons.

There is no cursor for the combination (number of entered buttons so far),
no buttons are read, there is no mechanism to start entering (resetting the cursor)
or to signal “enter” (which should compare the code and the number of entered buttons).

If your switches close to 5V you need pulldown resistors,
so I would rewire them to GND and use the internal pullup resistor.

Writing to INPUT pins switches the pullup, not the pin.