Set countdown time with Keypad?

Thanks for clearing it up man! I really appreciate your help!
Maybe I'm doing it the other way as you do, but your explanation of it helps me a lot.

While I was stuck with the 'true' error, I tried to code it on my way.
Everything works fine, unless the countdown:

So first off all, I need to enter the setup password, it that is correct, then I need to set the countdown time.
If I've set the countdown time(for example 120(seconds)), and I press '#' on the keypad, then the time is set and I need to enter the arm code.
If I've entered the arm code, then the countdown starts, but with problems: it wont countdown for the countdown value I set before. It just countdown from the number of keys I've pressed. So for 120 it will countdown from 3 to 0, because 120 has 3 numbers. For 1200 it will countdown from 4 to 0, because 1200 has 4 numbers, from 12 it will countdown from 2 to 0,...and so forth.

I think there is something wrong in my code, but I don't see what. Maybe you can see what's wrong?
Probably it is wrong in the arrays(TimeValue or inputTimeArray), the Countdown function or the SetTimeCode.
Again, thanks for helping me. :wink:

#include <LiquidCrystal.h>
#include <ShiftLCD.h>       // Include Library's
#include <Keypad.h> 

#define SETUP 0
#define SETTIME 1  //  case for setting time
#define ARMCODE 2       // case for arming bomb
#define ARMED 3    // case for countdown
#define DISARMED 4  // case for stopping countdown
#define DETONATED 5  // case for finished countdown

int bombState=0; // 0 = Setup, 1 = Set time, 2 = Arm Code, 3 = Armed ,4 = Disarmed, 5 = Detonated


int time;
int setTime;

const byte ROWS = 4; // Keypad has 4 rows
const byte COLS = 4; // Keypad has 4 columns
char keys[ROWS][COLS] = {
  {'1','2','3','A'},
  {'4','5','6','B'},         // define which character is on a button
  {'7','8','9','C'},
  {'*','0','#','D'}
};
byte rowPins[ROWS] = {5,6,7,8}; //connect to the row pinouts of the keypad
byte colPins[COLS] = {9,10,11,12}; //connect to the column pinouts of the keypad
Keypad keypad = Keypad( makeKeymap(keys), rowPins, colPins, ROWS, COLS );    
	 
ShiftLCD lcd(2, 4, 3); // pins connected to LCD

char clearButton[1] = {'*'};
char EnterButton[1] = {'#'};
char SetupPW[] = {'1','2','3','4'}; 
char TimeValue[4];
char ArmCode[4] = {'7','8','9','1'};   // password to arm the bomb
char inputTimeArray[4];   // array to gather user keypad presses
char inputSetupArray[4];
char inputArmArray[4];
int i = 0; // store keypresses here
int x = 0; // store the keypresses here
int a = 0;



void setup()
{
  lcd.begin(16,2);			 // open the LCD
  // bootup screen
  lcd.print("AIRSOFT BOMB V1"); // print some text
  lcd.setCursor(4,1);
  lcd.print("BY TIBO");  
  delay(2500); // display text for 2500ms
  lcd.clear(); // clear display
}
void loop()
{
  
  // cases
  switch(bombState) {
    
////////////// SET COUNTDOWN TIME//////////////////////////   

    case SETUP:
    {
      SetupCode();
    }
break;    
      
      
      
    case SETTIME: // set the countdown time
    {
      SetTimeCode();
    }
        break;
    
  
    case ARMCODE: // enter the right code to arm the bomb
  {
    TypeArmCode();
  }
break;


case ARMED:
{
Countdown();
}
break;


  }
}

////////////////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////SetupCode//////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////

boolean SetupCode() {

  lcd.setCursor(0,0);
  lcd.print("Enter Password:");
char key = keypad.getKey();
//if a key is pressed
if(key)
{
  inputSetupArray[x] = key; //store entry into array
  x++;
  lcd.setCursor(0,1); // set cursor at column 0 and row 1
lcd.print(key); // print keypad character entry to lcd
if (x == 4) // if 4 presses on the keypad have been made
 {
   if (inputSetupArray[0] == SetupPW[0] && // if first character pressed on keypad = first character in password for arming bomb
inputSetupArray[1] == SetupPW[1] &&  // and if second character pressed on keypad = second character in password for arming bomb
inputSetupArray[2] == SetupPW[2] && // and if third character pressed on keypad = third character in password for arming bomb
inputSetupArray[3] == SetupPW[3] ) // and if fourth charactet pressed on keypad = fourth character in password for arming bomb

{
  lcd.clear(); // clear display
  lcd.setCursor(0,0);
  lcd.print("Pass Correct"); // display some text
  delay(1000); // display text for 1000ms
  lcd.clear();
  bombState = SETTIME; // switch to ARMED case
  
}
else {
    lcd.clear(); // clear display
  lcd.setCursor(0,0);
  lcd.print("Pass Incorrect"); // display some text
  delay(1000); // display text for 1000ms
  x = 0;                      //Reset your entryindex so that it effectively clears your entry.
  inputSetupArray[x] = '/0';         //Always add the null
  lcd.clear();
  
}

  }
}
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////SetTimeCode//////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

boolean SetTimeCode() {
  

lcd.setCursor(0,0);
lcd.print("Enter Time:");
char key = keypad.getKey();
//if a key is pressed
if(key)
{

  inputTimeArray[i] = key; //store entry into array
 i++;
 inputTimeArray[i] = '/0';
  lcd.setCursor(0,1); // set cursor at column 0 and row 1
lcd.print(key); // print keypad character entry to lcd
  
 if (key == '#') {
 inputTimeArray[i] = TimeValue[i];
  lcd.clear(); // clear display
  lcd.setCursor(0,0);
  lcd.print("Time Set"); // display some text
  delay(1000); // display text for 1000ms
  bombState = ARMCODE; // switch to ARMED case
  lcd.clear();
 }
}
}


  
  
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////  
/////////////////////////////////////////////////////TypeArmCode////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

boolean TypeArmCode() {
  
    lcd.setCursor(0,0);
  lcd.print("Enter ArmCode:");
char key = keypad.getKey();
//if a key is pressed
if(key)
{
  inputArmArray[a] = key; //store entry into array
  a++;
  lcd.setCursor(0,1); // set cursor at column 0 and row 1
lcd.print(key); // print keypad character entry to lcd
if (a == 4) // if 4 presses on the keypad have been made
 {
   if (inputArmArray[0] == ArmCode[0] && // if first character pressed on keypad = first character in password for arming bomb
inputArmArray[1] == ArmCode[1] &&  // and if second character pressed on keypad = second character in password for arming bomb
inputArmArray[2] == ArmCode[2] && // and if third character pressed on keypad = third character in password for arming bomb
inputArmArray[3] == ArmCode[3] ) // and if fourth charactet pressed on keypad = fourth character in password for arming bomb

{
  lcd.clear(); // clear display
  lcd.setCursor(0,0);
  lcd.print("Bomb Armed!"); // display some text
  delay(1000); // display text for 1000ms
  lcd.clear();
  bombState = ARMED; // switch to ARMED case
}

else {
    lcd.clear(); // clear display
  lcd.setCursor(0,0);
  lcd.print("Code Incorrect"); // display some text
  delay(1000); // display text for 1000ms
  a = 0;                      //Reset your entryindex so that it effectively clears your entry.
  inputSetupArray[a] = '/0';         //Always add the null
  lcd.clear();
  
}

  }
}
}
  
  
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////Countdown/////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

boolean Countdown() {
  
  while(i > 0) {
lcd.setCursor(0,0);
   lcd.print("Time remaining:");
   i -= 1;
   delay(1000);
   lcd.clear();
   lcd.setCursor(7,1);
   lcd.print(i);
  if (i == 0) {
    lcd.clear();
   lcd.setCursor(0,0); 
   lcd.print("Bomb Exploded");
  }
}
}

Okay. So sounds like you are really close.

First you are storing your time data as a char array. This might be how you need to use it for printing to the LCD but you need this data in int form to do math on it. Since you are using unique arrays for each of your inputs, you don't need your timevalue[4] at all. It doesn't serve any purpose.

Also, in your code, you are setting it backwards anyway. You are actually setting your inputtimearray = to your timevalue array which is declared as '0','0','0','0'. This means that no matter what you entered, you were setting it back to all 0.

So what you need now is a way to increment the time you entered. It looks like you assume that you are not forcing a colon so if you enter one or two numbers, you get only seconds, if you enter 3 or 4 numbers, you get minutes and seconds. This will work you just have to account for it.

So first you have to convert your char to ints. Then you have to put them together in an order that makes sense.

First, in your declarations, you need to declare two integers:

int timemin;
int timesec;

Then in you timesetcode function after you have pressed the '#' key:

timesec = ((inputtimecode[0] - '0') * 10) + (inputtimecode[1] - '0');    //This places the first digit you entered into the tens spot on the     
                                                                                                     //seconds and adds to it the second digit.  The -'0' is an easy way to
                                                                                                     // convert a char number into an integer. 
 timemin = ((inputtimecode[2] - '0') * 10) + (inputtimecode[3] - '0');  // this does the same for the minutes. 

//It doesn't matter how many digits you press since if the value is 0 it will give you 0.

So now the next bit is to decrement those. Decrement the seconds first. If seconds = 0, reset seconds to 59 unless minutes = 0. If minutes does not = 0 then you will decrement minutes at that point:

Although Delay(1000) is not the best way to countdown, since your code doesn't need to do anything else, it will probably work.

So in your countdown() function:

delay(1000)

If (timesec == 0) && (timemin == 0)
{
// Bomb blew up set the appropriate mode. The next time you hit your loop it will see that instead of countdown mode.
}
If (timesec > 0)
{
 timesec -= 1;
}
else if (timesec == 0) && (timemin > 0)
{
timesec = 59;
timemin -=1;
}

//this will decrement your time appropriately. Not the challenge is that you can't write those values back to the display unless I am wrong.
//I have never used the 16x2 but I assume you must write the values in char format so you use that timevalue you declared and I told you 
//was useless. Leave it alone, we can use it here although I think you might have to make it bigger. Make it timevalue[10] just to have 
//some room to move. You are not critical on RAM so it should be fine.

//First lets convert the integers back to a char. This assumes that you cannot print the integers directly. I really don't know if that is the case.

sprintf(timevalue, "%2d:%02d, timemin, timesec);
lcd.setcursor(7,1);
lcd.print(timevalue);

//If you can print the integers directly then you don't need the timevalue[10] or the sprintf statement. Just print them out in the format
//that you want.

This is interesting to watch. Everything you have done is completely different from the way I have done it yet it still seems to function like it should.

Just remember that people will do weird things and enter things that don't make any sense. You always need to idiot proof. Think of every way that they could break your code. What happens if I press 5 keys for my password. Does it ignore the 5th? What if I press the '*' key? What happens if I press one of the letters while I am entering time. It will work but give you a really messed up value. You have to trap these kinds of errors and make sure you have handled them in code. The worst thing is to have this thing all boxed up and have to remove the battery or do a hard reset because someone did something that you should have accounted for.

Thank you!!!! This helped me very much!

It counts down now, but there is a little bug:

If I want to countdown from 20 seconds, then I enter '2000' and press enter.
That all works fine, until it eaches 9 seconds, then it shows 90>80>70>60>50>40>30>20>10>00 instead of 9>8>7>6>5>4>3>2>1>0.

If I want to countdown from 20 seconds, and I enter '20', then it counts down from 20 to 00, and the minutes are -130.

The bug happens not only with number 20, but also with other numbers.

Here is the code:

#include <LiquidCrystal.h>
#include <ShiftLCD.h>       // Include Library's
#include <Keypad.h> 

#define SETUP 0
#define SETTIME 1  //  case for setting time
#define ARMCODE 2       // case for arming bomb
#define ARMED 3    // case for countdown
#define DISARMED 4  // case for stopping countdown
#define DETONATED 5  // case for finished countdown

int bombState=0; // 0 = Setup, 1 = Set time, 2 = Arm Code, 3 = Armed ,4 = Disarmed, 5 = Detonated


int time;
int setTime;

const byte ROWS = 4; // Keypad has 4 rows
const byte COLS = 4; // Keypad has 4 columns
char keys[ROWS][COLS] = {
  {'1','2','3','A'},
  {'4','5','6','B'},         // define which character is on a button
  {'7','8','9','C'},
  {'*','0','#','D'}
};
byte rowPins[ROWS] = {5,6,7,8}; //connect to the row pinouts of the keypad
byte colPins[COLS] = {9,10,11,12}; //connect to the column pinouts of the keypad
Keypad keypad = Keypad( makeKeymap(keys), rowPins, colPins, ROWS, COLS );    
	 
ShiftLCD lcd(2, 4, 3); // pins connected to LCD

char clearButton[1] = {'*'};
char EnterButton[1] = {'#'};
char SetupPW[] = {'1','2','3','4'}; 
char ArmCode[4] = {'7','8','9','1'};   // password to arm the bomb
char inputTimeArray[4];   // array to gather user keypad presses
char inputSetupArray[4];
char inputArmArray[4];
int i = 0; // store keypresses here
int x = 0; // store the keypresses here
int a = 0;



void setup()
{
  lcd.begin(16,2);			 // open the LCD
  // bootup screen
  lcd.print("AIRSOFT BOMB V1"); // print some text
  lcd.setCursor(4,1);
  lcd.print("BY TIBO");  
  delay(2500); // display text for 2500ms
  lcd.clear(); // clear display
}
void loop()
{
  
  // cases
  switch(bombState) {
    


    case SETUP:
    {
      SetupCode();
    }
break;    
      
      
      
    case SETTIME: // set the countdown time
    {
      SetTimeCode();
    }
        break;
    
  
    case ARMCODE: // enter the right code to arm the bomb
  {
    TypeArmCode();
  }
break;


case ARMED:
{
Countdown();
}
break;


  }
}

////////////////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////SetupCode//////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////

boolean SetupCode() {

  lcd.setCursor(0,0);
  lcd.print("Enter Password:");
char key = keypad.getKey();
//if a key is pressed
if(key)
{
  inputSetupArray[x] = key; //store entry into array
  x++;
  lcd.setCursor(0,1); // set cursor at column 0 and row 1
lcd.print(key); // print keypad character entry to lcd
if (x == 4) // if 4 presses on the keypad have been made
 {
   if (inputSetupArray[0] == SetupPW[0] && // if first character pressed on keypad = first character in password for arming bomb
inputSetupArray[1] == SetupPW[1] &&  // and if second character pressed on keypad = second character in password for arming bomb
inputSetupArray[2] == SetupPW[2] && // and if third character pressed on keypad = third character in password for arming bomb
inputSetupArray[3] == SetupPW[3] ) // and if fourth charactet pressed on keypad = fourth character in password for arming bomb

{
  lcd.clear(); // clear display
  lcd.setCursor(0,0);
  lcd.print("Pass Correct"); // display some text
  delay(1000); // display text for 1000ms
  lcd.clear();
  bombState = SETTIME; // switch to ARMED case
  
}
else {
    lcd.clear(); // clear display
  lcd.setCursor(0,0);
  lcd.print("Pass Incorrect"); // display some text
  delay(1000); // display text for 1000ms
  x = 0;                      //Reset your entryindex so that it effectively clears your entry.
  inputSetupArray[x] = '/0';         //Always add the null
  lcd.clear();
  
}

  }
}
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////SetTimeCode//////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

boolean SetTimeCode() {
  

lcd.setCursor(0,0);
lcd.print("Enter Time:");
char key = keypad.getKey();
//if a key is pressed
if(key)
{

  inputTimeArray[i] = key; //store entry into array
 i++;
 inputTimeArray[i] = '/0';
  lcd.setCursor(0,1); // set cursor at column 0 and row 1
lcd.print(key); // print keypad character entry to lcd
  
 if (key == '#') {
 inputTimeArray[i] = TimeValue[i];
  lcd.clear(); // clear display
  lcd.setCursor(0,0);
  lcd.print("Time Set"); // display some text
  delay(1000); // display text for 1000ms
  bombState = ARMCODE; // switch to ARMED case
  lcd.clear();
 }
}
}


  
  
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////  
/////////////////////////////////////////////////////TypeArmCode////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

boolean TypeArmCode() {
  
    lcd.setCursor(0,0);
  lcd.print("Enter ArmCode:");
char key = keypad.getKey();
//if a key is pressed
if(key)
{
  inputArmArray[a] = key; //store entry into array
  a++;
  lcd.setCursor(0,1); // set cursor at column 0 and row 1
lcd.print(key); // print keypad character entry to lcd
if (a == 4) // if 4 presses on the keypad have been made
 {
   if (inputArmArray[0] == ArmCode[0] && // if first character pressed on keypad = first character in password for arming bomb
inputArmArray[1] == ArmCode[1] &&  // and if second character pressed on keypad = second character in password for arming bomb
inputArmArray[2] == ArmCode[2] && // and if third character pressed on keypad = third character in password for arming bomb
inputArmArray[3] == ArmCode[3] ) // and if fourth charactet pressed on keypad = fourth character in password for arming bomb

{
  lcd.clear(); // clear display
  lcd.setCursor(0,0);
  lcd.print("Bomb Armed!"); // display some text
  delay(1000); // display text for 1000ms
  lcd.clear();
  bombState = ARMED; // switch to ARMED case
}

else {
    lcd.clear(); // clear display
  lcd.setCursor(0,0);
  lcd.print("Code Incorrect"); // display some text
  delay(1000); // display text for 1000ms
  a = 0;                      //Reset your entryindex so that it effectively clears your entry.
  inputSetupArray[a] = '/0';         //Always add the null
  lcd.clear();
  
}

  }
}
}
  
  
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////Countdown/////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

boolean Countdown() {
  
  while(i > 0) {
lcd.setCursor(0,0);
   lcd.print("Time remaining:");
   i -= 1;
   delay(1000);
   lcd.clear();
   lcd.setCursor(7,1);
   lcd.print(i);
  if (i == 0) {
    lcd.clear();
   lcd.setCursor(0,0); 
   lcd.print("Bomb Exploded");
  }
}
}

Do you know why it shows the numbers wrong?
I'll also take a look at it now.

This is the to-do-list:

  • Fix the bug
    -Change boolean to void where possible
    -Make disarm function
    -Make it idiot proof

This is interesting to watch. Everything you have done is completely different from the way I have done it yet it still seems to function like it should.

Yes it is, that's something of the cool things of Arduino.

btw: it can print the integers directly.

That all works fine, until it eaches 9 seconds, then it shows 90>80>70>60>50>40>30>20>10>00 instead of 9>8>7>6>5>4>3>2>1>0.

It looks like your lcd.clear is not working.

 inputTimeArray[i] = '/0';

That is not a NULL. For a NULL, the slash goes the other way.

 if (key == '#') {
 inputTimeArray[i] = TimeValue[i];

Where did TimeValue get a value?

Figuring out the minutes issue is not something I want to do, after seeing that the time to count down is stored in i. One letter variables are generally used only for loop indices. Global variables should never have one letter names.

It appears as though i is used for many purposes, so it really shouldn't be global. Another variable with a meaningful name SHOULD be added to hold the time to count down.

I don't see where you characters entered to a time in minutes and seconds, anyway.

Removing the superfluous braces and blank lines from your code, and using Tools + Auto Format to neaten it up would make the code a lot easier to read, too.

When a function has a return type of other than void, there is supposed to be a return statement to actually return a value. None of your functions return anything.

It looks like your lcd.clear is not working.

Adding lcd.clear fixed the bug, thank you!

Where did TimeValue get a value?

That's from the old code, it's removed now.

For the rest, thank you for the tips :wink:

For some reason I can't enter the TypeDisarmCode function.
If I press # nothing happens, it just keeps counting down.

Here is the code:

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////Countdown/////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

void Countdown() {

  delay(1000);
  
  char key = keypad.getKey();
  //if a key is pressed
  if (key == '#') {
    TypeDisarmCode();
  }

  if ((timesec == 0) && (timemin == 0))
  {
    bombState = DETONATED;
  }
  if (timesec > 0)
  {
    timesec -= 1;
    lcd.clear();
  }
  else if ((timesec == 0) && (timemin > 0))
  {
    timesec = 59;
    timemin -=1;
  }
  lcd.setCursor(0,0);
  lcd.print("Time Remaining:");
  lcd.setCursor(3,1);
  lcd.print(timesec);
  lcd.setCursor(0,1);
  lcd.print(timemin);
}

/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////TypeDisarmCode////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

void TypeDisarmCode() {

  char key = keypad.getKey();
  //if a key is pressed
  if(key)
  {

    inputTimeArray[b] = key; //store entry into array
    b++;
    inputTimeArray[b] = '\0';
    lcd.setCursor(6,1); // set cursor at column 0 and row 1
    lcd.print(key); // print keypad character entry to lcd

    if (inputDisarmArray[0] == DisarmCode[0] && // if first character pressed on keypad = first character in password for arming bomb
    inputDisarmArray[1] == DisarmCode[1] &&  // and if second character pressed on keypad = second character in password for arming bomb
    inputDisarmArray[2] == DisarmCode[2] && // and if third character pressed on keypad = third character in password for arming bomb
    inputDisarmArray[3] == DisarmCode[3] ) // and if fourth charactet pressed on keypad = fourth character in password for arming bomb
    {
      lcd.clear(); // clear display
      lcd.setCursor(0,0);
      lcd.print("Bomb Disarmed!"); // display some text
      delay(1000); // display text for 1000ms
      lcd.clear();
    }
    //It doesn't matter how many digits you press since if the value is 0 it will give you 0.
  }
}

If I press # nothing happens, it just keeps counting down.

If you press the # key, the function gets called. It is not a blocking function, so it doesn't wait for a key press. If no key is being pressed when it looks, it simply returns.

Okay, how can I make it work?

Does it print Bomb Disarmed to the screen for a flash and then go back to counting?

In your disarm function you need to change the bomb state. You status is still in Armed so when it goes through the loop again it goes back to the armed function.

If you want to be able to re-arm it you will need to add another case in your void loop to handle that.

If the # button is pressed during the countdown, then the user is able to enter the disarm code.
If the code is right, then the countdown stops and the lcd prints 'bomb disarmed".
If the code is wrong, then the lcd prints 'code wrong' and it just keeps counting down.

Sorry about the backward slash. I am typing this all here and not in the IDE and copy and pasting so no compile for errors.

I think you have a bit of a conceptual error on how the processor functions.

The void setup() runs once when it first powers up.

The void loop() runs over and over and over and forever. It is the only thing that is consistent through the whole process. Your custom functions like typedisarmcode() only runs when they are called.

So I guess you have been a bit lucky so far in the way you have called the functions but your misunderstanding has caused it to crash on you here.

when you press the '#' while counting down, it does not go to your typedisarmcode and stay there. It runs that code once and then it returns to finish your countdown code then it returns to the loop again.

So instead of calling your typedisarmcode from the countdown function, you will need to do something like set a variable to some value so that when it goes back to the loop it needs to go look for disarm key presses first, then go to the countdown since you want it to keep counting while you are entering the countdown code.

So if you add an additional state to your bomb and call it disarming, when you press the '#' key in the time code, set the state to disarming. Add a new case to your loop called disarming and call your disarm code each time and then call your countdown.

Once the disarm password is entered correctly, set the state to disarmed. Add another case to your loop to handle the disarmed state.

Whew! This is tough because as Paul has pointed out, there are some pretty glaring flaws in the approach you have used to code this. It works but it is not pretty. In my code which does a lot of the same things, I check for the key in the loop every time and then handle what to do with the key from there passing it to the various functions as needed. This makes for much safer code (and cleaner) since you should never miss a key press. The way you have done this, since you are using the delay for your countdown instead of millis(), you have a very narrow window of opportunity to capture those key presses. By switching to millis() you just check every loop to see if 1000 milliseconds have passed since you last updated your counter. If it hasn't them it just keeps looping looking for other key presses until it does. However, in order to change to this method you will have to drastically change the rest of the code. I will just be surprised if you can capture your disarm key presses. You will likely have to hold each of them down until you know you got it.

Thanks for explaining!
I will try to do the disarm code today.

I did a little test, and this won't even work, it just keeps counting down.

case DISARMCODE:
  {
    lcd.clear();
    lcd.setCursor(0,0);
    lcd.print("test");
  }
  break;


///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////Countdown/////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

void Countdown() {

  delay(1000);
  
  char key = keypad.getKey();
  if (key == '#') {
    bombState = DISARMCODE;
  }

  if ((timesec == 0) && (timemin == 0))
  {
    bombState = DETONATED;
  }
  if (timesec > 0)
  {
    timesec -= 1;
    lcd.clear();
  }
  else if ((timesec == 0) && (timemin > 0))
  {
    timesec = 59;
    timemin -=1;
  }
  lcd.setCursor(0,0);
  lcd.print("Time Remaining:");
  lcd.setCursor(3,1);
  lcd.print(timesec);
  lcd.setCursor(0,1);
  lcd.print(timemin);
}

I just noticed where your breaks; are.

Move them inside the brackets for each case. I really don't know if this will cause a problem but they are in a weird spot and should go inside the case code. You have them actually inside the switch brackets.

Hold down the '#' key for more than a second (about 2 seconds depending on exactly when you press it) and see if it works. This is the only other thing that I can see that is wrong. Because of the way it is coded, it should count one more second and then stop.

If that doesn't work, then I'm not sure what the problem is. If that does work then you might want to take a look at the blink without delay example in the IDE. This will show you how to use the millis() function to replace your delay and still count down.

To get around some of your issues, it would be better if you moved all of your key capture activity to the loop. This would take a major overhaul of your code but would be a much better way to do it. That way every time through the loop you would look for a key press. If you don't have one then it looks at the state to see if it needs to do the countdown. If it does see one, then it performs the appropriate action depending on the state.

void loop();


char key = keypad.getKey();

if (key)
{
  switch(key)
  {
  //Look at the key pressed ignore the ones you want to ignore first
  //If they press a number, look at your state and the number of presses. This can be in the default after you have looked at all a the other potential key presses.
  //That way you don't have to have different cases for all of the numbers. 
  //Depending on these factors you can either add it to the input char array or ignore it if they have already pressed enough buttons.
  //If they press the '#' look at the state and the number of digits pressed. For example, if they have pressed 4 digits and the state is Arm Code, then go to the armcode function only to compare the password.
  }
}

//After the if(key) loop, check to see if you are in the armed state, if you are, check millis() and compare it to the last time you set the time.
//If state is armed and it has been 1000 millis, do your countdown code. Otherwise do nothing and wait until either you get a key press or 
//1000 millis has elapsed. 

if ((bombstate == ARMED) && (millis() - lastmillis() >= 1000))
  {
   countdown();  //Remove the delay(1000); from your countdown code.
   lastmillis = millis(); //this sets your last millis() to your current millis() to be ready to use in the next loop
  }

}

Thanks for help! Your solution did it again!

It works nice now!

This are the only things that could be 'better', but it's not that important:

  1. The enter button for disarming the code must be entered at the right timing, it only works when all the numbers don't move. So the moment when there is no countdown.

  2. Is it possible to let the fakebomb keep counting down when someone is entering the disarm code? So it doesn't pause and continue from the last time if the disarm code is wrong.

I will also take a look at it tomorrow.

I think I'm on the right way now, and that would never be possible without your guys help! THANK YOU!
I'm learning very much here.

To-do-list:

-Fix the bug
-Change boolean to void where possible
-Make disarm function
-Cleaning up
-Tweaking and extra's
-Make it idiot proof

The code at this time(the comments are not right and the DISARMED function is not fully set up):

Does someone know why the piezo disc won't beep faster and the red led won't blink faster, when there is less then 10 seconds countdown left?

If there is more than 10 seconds left, there is no Beep(), and the FastBeep() starts after 8 seconds left, instead of 10 seconds left. The led just keeps doing the RedLedBlink() function, but no RedLedBlinkFast() function if there is less than 10 seconds left.

Here's my code(The functions are Beep, FastBeep, RedLedBlink, RedLedBlinkFast and Countdown):

If there is more than 10 seconds left, there is no Beep(), and the FastBeep() starts after 8 seconds left, instead of 10 seconds left.

Apparently you do know how to use millis() to make things happen at the correct time. So, the delay(1000) in Countdown() is amazing.

I think you really need to work on getting rid of that.

I think that having GreenLedBlink() call RedLedBlink() is confusing. There is nothing in the name GreenLedBlink() that implies that it will also blink the red LED.

I will try to use millis instead of delay tomorrow.
Thanks for helping.

The millis() fixed it. Thanks!

Now there are two things I want to do:

  1. When someone presses the '*' button, the text entered will be cleared.

  2. At this time, when someone presses numbers on the keypad, the pressed numbers get displayed on each other on the lcd.
    So for example, it doesn't display 5461 if I enter 5461. It only displays the numbers on 1 row of the lcd.
    How can I fix that?

I"ll try to do the clear button now.

Here is the code:

The clear button does also work.

I still don't find how to do this:

  1. At this time, when someone presses numbers on the keypad, the pressed numbers get displayed on each other on the lcd.
    So for example, it doesn't display 5461 if I enter 5461. It only displays the numbers on 1 row of the lcd.
    How can I fix that?

Anyone know how to do this?