Need help with 4 digit unlock code (Arduino UNO)

I need to make use of 2 buttons, 2 leds and a display to make a 4 digit code that unlocks a safe . One of the buttons as Input and the other-confirm.
When I press the input button for the first time both LEDs switch on and then off to indicate that the app is started then a new sequence starts.
1 push of the button changes the number to 1, two to 2, etc. Each time I press the button one of the pins is turned on and when confirm is pressed the other turns on and saves the number.

When all four numbers are entered the safe either switches to green LED for opened and red for Wrong code.

If possible I also want to make it so that I can manually set the code using the input. I am at the very very beginner stage and I’ve been trying for hours to get it working somehow using simple code. I read some stuff about arrays but no success so far. Here is my code, it is kind of a mess, I also tried using a for to execute the first action but then I realized it is always on.

If possible suggest solutions, fixes, optimizes for the code, advisable changed, I am also allowed to add extra stuff into the program. Thank you beforehand and much appreciated

#include "Display.h"
// constants who do not change, they specify pins:
const byte buttonConfirm = 8, buttonInput = 9;
const byte ledRed = 4, ledGreen = 5;

int counter = 0;
int lastState = 0;
int pass[4] = {1, 3, 1, 3};
int codeTyped[4] {NULL, NULL, NULL, NULL};
int startUp = 1;

void setup() {
   Serial.begin(9600);    //begin serial monitor  /  (9600) serial speed
   pinMode (buttonInput, INPUT_PULLUP);
   pinMode (buttonConfirm, INPUT_PULLUP);
   pinMode (ledRed, OUTPUT);
   pinMode (ledGreen, OUTPUT);
   Serial.println("Initialized!");    // send state
}

void loop() {
 int buttonState = digitalRead(buttonInput);
 int buttonSave = digitalRead(buttonConfirm);
   while (startUp > 0 && buttonState == LOW) {
   digitalWrite(ledRed, HIGH);
   digitalWrite(ledGreen, HIGH);
   delay(1000);
   digitalWrite(ledRed, LOW);
   digitalWrite(ledGreen, LOW);
   startUp--;
  }
  // Start of code for safe -----------------------------------------------------------------------
    if (buttonState != lastState) {
      if (buttonState == LOW) {
       digitalWrite(ledGreen, HIGH);
       delay(500);
       digitalWrite(ledGreen, LOW);
       counter = counter + 1;
       Display.show(counter);
       Serial.println(counter);  
      } 
      delay(50);
      lastState = buttonState;
    }
    if (buttonSave == LOW) {
      if (counter != pass[0]) {
      digitalWrite(ledRed, HIGH);
      delay(500);
      digitalWrite(ledRed, LOW);
      } else {
       codeTyped[0] = 1;
       digitalWrite(ledGreen, HIGH);
       delay(500);
       digitalWrite(ledGreen, LOW);
       counter = 0;
       for(int i = 0; i < 4; i++)
      {
       Serial.println(codeTyped[i]);
      }
       Display.show(codeTyped);
        }
    }
  //  constrain(counter, 1, 4);
  if(counter == 4) counter = 0;   //set max numbers to 4, incorrect because I still see 5 and a fast switch to 0
}

It would be much easier to use a keypad to enter a combination, and there are several tutorials on line to show you how.

To count button presses, carefully study the state change example.

I think I got the part of counting button presses, hard is how do I make it so that it remembers a correct digit and continues to the other one

set max numbers to 4, incorrect because I still see 5

This is because you display the number before you constrain it.

jremington:
This is because you display the number before you constrain it.

I did test it by adding constrain in the void setup and then even tried adding it at the beginning of the void loop but it still doesn't seem to limit the numbers from 1-4.

Constrain the number before displaying it. This is guaranteed to work.

If you want us to point out mistakes, post your non-working attempts, using code tags of course.

jremington:
Constrain the number before displaying it. This is guaranteed to work.

If you want us to point out mistakes, post your non-working attempts, using code tags of course.

I feel like I’m using it in a wrong way. I keep reading and trying to figure it out, pretty bad at it I guess. Also is there a way to avoid the first if after while to auto trigger? Instead of using copy/paste to finish the other 3 digits could I do another easy workaround?

//used libraries
#include "Display.h"

// constants who do not change, they specify pins:
const byte buttonConfirm = 8, buttonInput = 9;
const byte ledRed = 4, ledGreen = 5;

//integers used in the program
int counter = 0;
int lastState = 0;
int pass[4] = {1, 3, 1, 3};
int codeTyped[4] {NULL, NULL, NULL, NULL};
int startUp = 1;

void setup() {
   Serial.begin(9600);                          //Begin serial monitor  /  (9600) serial speed
   pinMode (buttonInput, INPUT_PULLUP);         //Sets the buttons as inputs
   pinMode (buttonConfirm, INPUT_PULLUP);          
   pinMode (ledRed, OUTPUT);                     //Sets LED as output
   pinMode (ledGreen, OUTPUT);
   Serial.println("Initialized!");               //Send state
}

void loop() {
 int buttonState = digitalRead(buttonInput);
 int buttonSave = digitalRead(buttonConfirm);
   while (startUp > 0 && buttonState == LOW) {
   digitalWrite(ledRed, HIGH);
   digitalWrite(ledGreen, HIGH);
   delay(1000);
   digitalWrite(ledRed, LOW);
   digitalWrite(ledGreen, LOW);
   startUp--;
  }
  // Start of code for safe -----------------------------------------------------------------------
    if (buttonState != lastState) {
      constrain(counter, 1, 4);
      Display.show(counter);
      if (buttonState == LOW) {
       greenLightOnOff();
       counter = counter + 1;
       Serial.println(counter);  
      } 
      delay(50);
      lastState = buttonState;
    }
    if (buttonSave == LOW) {
      if (counter != pass[0]) {
      redLightOnOff();
      } else {
       codeTyped[0] = 1;
       greenLightOnOff();
       counter = 0;
       Serial.println("Current code: ");
       for(int i = 0; i < 4; i++)
      {
       Serial.print(codeTyped[i]);
      }
       Display.show(codeTyped);
        }
    }
  //if(counter == 5) counter = 0;   //set max numbers to 4, incorrect because I still see 5 and a fast switch to 0
}




void redLightOnOff() {
      digitalWrite(ledRed, HIGH);
      delay(500);
      digitalWrite(ledRed, LOW);
  }

 void greenLightOnOff() {
      digitalWrite(ledGreen, HIGH);
      delay(500);
      digitalWrite(ledGreen, LOW);
  }

Right here, you increment counter, and then display it. If counter was 4 before incrementing, it will be 5 afterwards, and that value will be displayed.

       counter = counter + 1;
       Serial.println(counter);

You already have an array defined for the numbers to be entered. Rather than use only the first entry in that array, as follows, use an array index to handle the other digits.

       codeTyped[0] = 1;  //use index variable instead of "0"

If you will take the time to study the various keypad password examples, you will see this concept in action.

here is a simple way to do your task with two buttons. first button will change which number is being edited. Second button changes the value. after it gets passed the last digit, it checks what you have entered against the password and goes back to sleep.

it uses one variable i called “mode” that works as the direct index number for changing the user’s array and when it is set to 100 the code know it is “asleep”.

I used serial print to show everything in the appropriate places.
you can replace these print lines with whatever you want your lights, displays and relays to do.

an old school rule of programming is if you find your self typing the same same code block twice then there is a easier way to write it. So i couldn’t help but to put your button pin numbers in an array so i could set and check them in a loop. sorry if it confuses but it makes things neater and creates small organized sections. anyways hopefully this “system” simplifies things for you.

byte guess [] {0,0,0,0};
byte pass [] {1,3,2,1};
byte mode = 100;
int pins [] {8,9};
int last [] {0,0};
void setup() {
int i = 2;
while(i>0){i--; pinMode (pins[i], INPUT_PULLUP);}
Serial.begin(9600);
}

void loop() {

  // read both pins with a loop
 int i = 2;
 while(i>0){i--;
 int r = digitalRead(pins[i]);
 if(r!=last[i]){
  if(last[i]==HIGH){pushed(i);}last[i]=r;
  }}
}


void pushed (int b){
  if(b==1){// button one was pushed
    if(mode<4){guess[mode]++;show();}
     if(mode>99){mode=0;Serial.println("awake");}
    }
  if(b==0){// button 2 was pushed
    mode++; 
    if(mode>99){mode=0;Serial.println("good pass");}
    if(mode==4){check();}
   }}

    void check(){
    byte i = 0; while(i<4){
    if(guess[i]!=pass[i]){ i = 100; } i++;}
    if(i<100){
             Serial.println("good pass");
       }else{Serial.println("bad pass");}
        erase();
       mode=100;Serial.println("now sleeping");}

       void erase(){
         byte i = 0; while(i<4){
        guess[i]=0; i++;}
        }

        void show(){
            byte i = 0; while(i<4){
        Serial.print( String(guess[i])); i++;}
        Serial.println("");
        
        }

What would be an easy way to save my counter numbers in a second array and then compare if the two are correct?

A solution to the comparison problem is presented in reply #8, and also in the keypad-entry password tutorials.

Please post links to the ones you have looked at, and let us know what parts are giving you trouble.