Set countdown time with Keypad?

I can make a key do something like this:

Not without errors, you can't. The value in the [] on the declaration statement is the number of elements. Element indices start at 0.

But it was a mess and I didn't save the code.

Try something (that, preferably, isn't a mess) and show what you have.

Getting a key press is easy. Getting the key that was pressed is easy. Storing the character that corresponds to the key is easy. Incrementing the index after storing the character is easy. Adding a NULL after adding each character is easy. Converting the stored data to a number is easy. Doing all these things at the right place in the code, in the right order is the only challenging part.

PaulS:

I can make a key do something like this:

Not without errors, you can't. The value in the [] on the declaration statement is the number of elements. Element indices start at 0.

It did work, here is the full code:
(I was trying to set the time value with a potentiometer, and it worked but it was difficult to get the right value.)

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


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

int bombState=0; // 0 = Set time, 1 = On, 2 = Armed ,3 = Disarmed, 4 = Detonated

int potPin = 0;
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 SetTimeButton[1] = {'*'};
char ArmCode[4] = {'7','8','9','1'};   // password to arm the bomb
char inputArray[4];   // array to gather user keypad presses
int i = 0; // store keypresses here



void setup()
{
  lcd.begin(16,2);			 // open the LCD
  // bootup screen
  lcd.print("AIRSOFT BOMB V1"); // print some text    
  delay(2500); // display text for 2500ms
  lcd.clear(); // clear display
}
void loop()
{
  
  // cases
  switch(bombState) {
    
////////////// SET COUNTDOWN TIME//////////////////////////   
    case SETTIME: // set the countdown time
    {
      
      
      time = analogRead(potPin);
      setTime = (time / 1.024) * 3.6;
      lcd.setCursor(0,0);
      lcd.print("Set Time(s)");
      lcd.setCursor(0,1);
      lcd.print(setTime);
 
       char key = keypad.getKey();
//if a key is pressed
if(key)
{
  

    if(SetTimeButton[1]) {
      
      lcd.clear();
      bombState = ON;
      
      
      
    }
      
}
    }
        break;
    
    
///////////////////////////////////////////////////////////
//////////////////////ENTER ARM CODE/////////////////////////
    case ON: // enter the right code to arm the bomb
  {

    lcd.setCursor(0,0);
  lcd.print("Enter Code:");

 char key = keypad.getKey();
//if a key is pressed
if(key)
{
  inputArray[i] = key; //store entry into array
  i++;
  lcd.setCursor(0,1); // set cursor at column 0 and row 1
lcd.print(key); // print keypad character entry to lcd
if (i == 4) // if 4 presses on the keypad have been made
 {
   if (inputArray[0] == ArmCode[0] && // if first character pressed on keypad = first character in password for arming bomb
inputArray[1] == ArmCode[1] &&  // and if second character pressed on keypad = second character in password for arming bomb
inputArray[2] == ArmCode[2] && // and if third character pressed on keypad = third character in password for arming bomb
inputArray[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
  bombState = ARMED; // switch to ARMED case
  lcd.clear();
}
}
}
  }
break;

////////////////////////////////////////////////////////////////////////

case ARMED:
{

while(setTime > 0) {
lcd.setCursor(0,0);
   lcd.print("Time remaining:");
   setTime -= 1;
   delay(1000);
   lcd.clear();
   lcd.setCursor(7,1);
   lcd.print(setTime);
 
}

}
break;


  }
}

Try something (that, preferably, isn't a mess) and show what you have.

Getting a key press is easy. Getting the key that was pressed is easy. Storing the character that corresponds to the key is easy. Incrementing the index after storing the character is easy. Adding a NULL after adding each character is easy. Converting the stored data to a number is easy. Doing all these things at the right place in the code, in the right order is the only challenging part.

I will try it again.

    if(SetTimeButton[1]) {

This references the second element in a one element array. It is NOT correct.

PaulS:

    if(SetTimeButton[1]) {

This references the second element in a one element array. It is NOT correct.

That's strange, it really works...
If I press the '*' button, then the lcd clears and switches to the countdown.
If I enter a '0' like you said, then I get this error:
too many initializers for 'char [0]'

If I enter a '0' like you said, then I get this error:
too many initializers for 'char

'

You don't change the declaration to declare a smaller array. You need to change the reference to refer to a valid element in the array.

Okay, here is what I've tried:
(I've leaved the ARMED case as it is)

-First attempt:

Errors:
If the 'Set Time' menu appears and I enter the time I want, then it redirects to the ARMED case when I press 1 number on the keypad.
It needs to have the possibility to enter more then 1 number.

char SetTimeButton[1] = {'*'};
int x = 0; // store the keypresses here

case SETTIME: // set the countdown time
    {
      
char TimeCode[4];

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

  TimeCode[x] = key;
  x++;
  x = setTime;
  lcd.setCursor(0,1); // set cursor at column 0 and row 1
lcd.print(setTime); // print keypad character entry to lcd
if(key)
{
    if(SetTimeButton[0]) {
      
      lcd.clear();
      bombState = ON;

    }
      
}
    }
}
    
        break;

-Second attempt:

Errors: - I can enter the time with 4 numbers this time, but I can't enter a time value with less then 4 numbers.

  • If the 4 numbers are entered, then the countdown won't start >> just an empty screen.
char TimeCode[4];
int x = 0; // store the keypresses here

if(key)
{

  TimeCode[x] = key;
  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
 {
      x = setTime;
      lcd.clear();
      bombState = ON;

    }
      
}
    }
        break;

How should I create an array that doesn't have a minium of keys to be entered?

How should I create an array that doesn't have a minium of keys to be entered?

It's not a matter of creating the array. It is a matter of how you populate the array.

What do you do when you come to the end of a sentence when typing a post? What do you do when you come to the end of a statement in the sketch? You use a special character to say "Hey, this sentence/statement is complete. Do something with it".

You need to do the same in your code. Allow up to 4 characters, with one of the special keys meaning backspace (oops, didn't want that number there) and one meaning enter/done/use this value, regardless of how many digits have been entered.

You need to do the same in your code. Allow up to 4 characters, with one of the special keys meaning backspace (oops, didn't want that number there) and one meaning enter/done/use this value, regardless of how many digits have been entered.

Do you mean something like this?:
(backspace key is not included)

////////////// SET COUNTDOWN TIME//////////////////////////   

char TimeCode[4];
char enterButton[1] = {'#'};

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

  TimeCode[x] = key;
  x++;
  lcd.setCursor(0,1); // set cursor at column 0 and row 1
lcd.print(key); // print keypad character entry to lcd
if(enterButton['#']); 

 {
      x = setTime;
      lcd.clear();
      bombState = ON;
      
    
}
      
}
    }
        break;

If I upload this code, then I get the error from my first attempt:

If the 'Set Time' menu appears and I enter the time I want, then it redirects to the ARMED case when I press 1 number on the keypad.

So maybe I'm understanding you wrong?

You have obviously used the example for the keypad so why not use the rest of the example:

if(key)
{
 if (bombstate > 0)    //As long as you are not in settime mode, the following runs
 {
   switch(key)
    {
      case '#':
        x = setTime;
        lcd.clear();
        bombState = ON;
        break;
      case '*':
        bombstate = 0;    //Use the * Key to put you in time set mode
        break;
      default:
        appendentry(key);    //Pass the key press to append it to your char[]
        break;
      }
  }
  else        //If you are in time set mode, you want to handle your button presses differently
  {
    switch(key)
    {
      case '#':
        //use this to accept your time entry once you have entered 4 numbers. I would pass this to a function that handles that.
        break;
      case 'A':
        break;    //Don't do anything on the Letters unless you want to
      case 'B':
        break;
      case 'C':
        break;
      case 'D':
        break;
      default:
        settime(key);    //Pass the key press to a settime function
        break;
    }
  }
}

This is not the only way but it will get you well on your way.

Since you are using single digits, it is simple to convert a byte to an int by subtracting '0'.

In other words:

int tempvalue = key - '0';

So everytime you call your settime function, you can use simple math to convert it to seconds for your counter and minutes and seconds for display. You want to limit your time entry to 4 digits (two for minutes, and two for seconds) so use an index counter each time you call you settime function. If you try to call it again before they have hit the '#' ignore it. You will have to stipulate the the time be entered as 4 digits. Otherwise someone will try to enter 3 minutes and 2 seconds as only 2 digits and it won't work. Another option is to use the '*' key as your colon and capture its input as well and format accordingly.

There is still a LOT of work to do even with this starting point. I just happen to be working with a keypad for the first time myself and it is fresh.

Thanks for helping.

But were do I need to put this code?
Does it need to be inside the 'switch(bombState)' block?

And I assume that the following code has to be in the 'else' block because it's not possible to set the time if I'm not in the SETTIME case? :

 if (bombstate > 0)    //As long as you are not in settime mode, the following runs
 {
   switch(key)
    {
      case '#':
        x = setTime;
        lcd.clear();
        bombState = ON;
        break;

Try to think of it this way.

When you turn the device on. It will do nothing until you enter a code that allows you to set it up. So accept a 4 digit input and once you press the "#" it will check that entered code against a setup code like 9999. If it is right then set your mode to setup that way the next entries you make will be for your time. If it is wrong, it will reset the entry index and clear your entered code allowing them to try again. Add a boolean variable that is false when your turn it on. Once you have set your time you turn it to true. Also add a second boolean that you can set if the code entered matches the setup password. Then you can check those in your loop. If setuppass == true then the next buttons you press will be for setting time. Once your time is completely set, set your setup to true.

After you have performed that, you will now accept input to arm and disarm. The code I included above doesn't quite handle that but it is close. You have to think about what you are trying to do. Use functions to handle tasks to keep your loop clean.

For example, you would have a function that handles a '#' call so you can check what code was entered. Only call that function if they have entered enough digits to satisfy your passcode. Use your incremented index to check for that. So if they enter 3 digits and press '#' it ignores it but if they enter 4 digits it calls it. Use a function to handle your time entry.

I am doing something that is similar but doesn't include setting time. If I posted the code as it exists, it would be way too difficult to walk you through step by step since it is about 200 lines of code. I just tackled it one step at a time. For example, make sure you can check an entered code against a saved code. Make sure that you can only press 4 keys (if that is the number of digits for your code) and any further presses are ignored. Make sure that the '#' calls your function to check the code but only after you have entered enough digits. Use Serial to debug print. This will be a life saver. I have an RGB LED that I change to different colors as well to make sure the codes I am entering do the right thing.

If you work your way through methodically it will make a lot more sense than if you simply copy and paste code. That's what Paul is trying to get you to do and why I didn't include everything in the code above. What you are trying to do, like Paul has said is easy in its individual parts but much more difficult in making sure they happen when you want them to. This is where boolean flags, if statements and switch cases are your friends and are ultimately the heart and soul of any program you write.

One last note about the last thing you posted. Are you going to arm just by pressing the # key or is there an arming code? A lot of what I just typed assumes that you would be using a code to arm as well. Not necessary but what if you accidentally hit that # key when you aren't ready for it? The code you posted basically does that but I would encourage you to reconsider.

You made your work of it, man. :astonished: :smiley: Thank you!

For example, you would have a function that handles a '#' call so you can check what code was entered. Only call that function if they have entered enough digits to satisfy your passcode. Use your incremented index to check for that. So if they enter 3 digits and press '#' it ignores it but if they enter 4 digits it calls it. Use a function to handle your time entry.

I also want the possibility to enter the time with less then 4 numbers. Otherwise I cannot enter 60 seconds for example.

One last note about the last thing you posted. Are you going to arm just by pressing the # key or is there an arming code? A lot of what I just typed assumes that you would be using a code to arm as well. Not necessary but what if you accidentally hit that # key when you aren't ready for it? The code you posted basically does that but I would encourage you to reconsider.

The user needs to type a code to arm the bomb, as in my code.

Use Serial to debug print.

What do you mean?

I will try to type the code like you said now. If I'm stuck again, then I'll post a message here.

Big thanks for help guys!

If your setuppass is true, then you can enter numbers and accept any number of digits. That way when you press the '#' while setuppass is true but setup is false, then you can handle the time anyway you want. If they have only entered 2 digits, treat it as seconds etc...

if ((setuppass == true) && (setup == false))
{

}

And then to handle everything once your setup is done:

If (setup == true) //you don't have to include the setuppass boolean in this since it must be true before you can ever set you setup to true.
{

}

I would put everything inside the if(key) loop.

I used only 1 switch case in my loop. I handle any checks for boolean in the sub functions. I do have a setup as well in order to assign the device an ID. It doesn't set time but it functions sort of the same.

The only thing I check in my switch case is to see if I have exceed the number of digits. But I always require 4 so this works for me.

switch(key)
{
  case '#':
    if(entryindex == 4)    //This is the count of how many digits I have entered if it equals 4 then move on, if not then ignore it. Since you 
                                    //may be accepting less than four you will need to do this a little different and include a look at your booleans here
                                    //if (setuppass == true)    //I have entered the passcode for setup time
                                    //{
                                    //   if  (entryindex >0)      //Make sure at least one number has been pressed.
                                    //   }
                                    //  setuptime();
                                    //   }
                                    //}
                                    //else         //in every other case you are going to look for 4 digits before you move on 
                                    //{
                                    //  if (entryindex == 4)
                                    //   {
                                    //    checkpassword();
                                    //   }   
                                    //}
    {
      checkpassword();   //Call to a subfunction that checks the password against all passwords, I have three.
    {
    break;                     //Don't forget the breaks. Switch will not work correctly without these.
  case '*':
    break;                 //I don't use this key so I ignore it. If you are not going to use your letters, you will have to do the same for those.
                                 //If you are going to use them aas part of the password it will get more complicated since you will need to ignore
                                 //them when you are entering time 
   default:
     if(entryindex + 1 == 5)
     {
     //I flash my RGB led red here to let them know they have tried to enter more than 4 digits
     }
     else
     {
     appendentry(key)     //I pass the key presssed to a function that adds it to the array. You could do it here since it is simple code
     //entry[entryindex] = key;
     //entryindex ++;
     //entry[entryindex] = '/0';       //Adds string terminator at the end of the string each time a new char is added.

     }

That check password function is where everything happens.

I do not really understand what the setuppass function is?
This is the part I do not really understand:

Add a boolean variable that is false when your turn it on. Once you have set your time you turn it to true. Also add a second boolean that you can set if the code entered matches the setup password. Then you can check those in your loop. If setuppass == true then the next buttons you press will be for setting time. Once your time is completely set, set your setup to true.

I'm a bit confused that you have a setup and a setuppass function:

if ((setuppass == true) && (setup == false))

Thanks again for the help :wink:

setuppass and setup are boolean variables.

When you first start up these are both false. Until you enter the setup password, nothing else should work.

So you enter 4 numbers and hit '#'.

This sends control to the checkpassword() function that looks like this:

void checkpassword()
{
char tempentry;
char temppass;

 for(int i = 0;i <5; i++)
 {
  tempentry = entry[i];                         //These next two lines just give you something that is comparable. The first one takes each of your 
                                                           //entered digits.
  temppass = setuppassword[i];            //This one takes each digit of your password used for setup. 
  if ((tempentry ==  '/0') && (temppass == '/0')     //If you have reached the end of your two strings this is what you should get
  {
   setuppass = true;            //Since your entered code = setuppass, set your setuppass boolean to true. 
                                        //Now that setuppass = true, the next time through your loop it will behave differently
  if (tempentry != temppass)      //If at any time your entered code does not equal your setuppassword durng the 5 iterations through the 
                                                //for loop
  {
   entryindex = 0;                      //Reset your entryindex so that it effectively clears your entry.
   entry[entryindex] = '/0';         //Always add the null
   //Since you have a display, use this opportunity to print something to the display saying that the two did not match.
  }
  }

 }
}

This code will not handle multiple passwords. It will only look for the setuppassword. What you will need to do is add more levels to it to look for the arm/disarm codes if setup = true. You will set setup to true after you have entered your time and pressed the '#' again. Once setup is true, when you check your password, you will want to ignore this check and check instead for an arm password. You can use a boolean that tells you if it is armed. When it is false, check for an arming password. If it is true check for the disarm passoword. The code above will work for all three you just have to reconfigure it for each.

Thank you for explaining.
Here is my code at this time:

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

#define SETUP 0
#define SETTIME 1  //  case for setting time
#define ON 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 = On, 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[4] = {
  '1','2','3','4'}; 
char TimeCode[4];
char ArmCode[4] = {
  '7','8','9','1'};   // password to arm the bomb
char inputArray[4];   // array to gather user keypad presses
char inputSetupArray[4];
int i = 0; // store keypresses here
int x = 0; // store the keypresses here



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
    {

    }
    break;


    ///////////////////////////////////////////////////////////
    //////////////////////ENTER ARM CODE/////////////////////////
  case ON: // enter the right code to arm the bomb
    {

    }
    break;

    ////////////////////////////////////////////////////////////////////////

  case ARMED:
    {

    }
    break;


  }
}

////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////getArmCode////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////

boolean getArmCode() 
{

}

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

boolean SetupCode() {

  
  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 && EnterButton['#']) // 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

      {
       checkpassword();
      }
    }
  }
}

//////////////////////////////////////////////////////

void checkpassword()
{
  char tempentry;
  char temppass;
  int entryindex;

  for(int x = 0;x <5; x++)
  {
    tempentry = inputSetupArray[x];                         //These next two lines just give you something that is comparable. The first one takes each of your         
    //entered digits.
    temppass = SetupPW[x];      //This one takes each digit of your password used for setup. 
  }
  if ((tempentry ==  '/0') && (temppass == '/0'))  //If you have reached the end of your two strings this is what you should get
  {
      SetupCode() = true;         //Since your entered code = setuppass, set your setuppass boolean to true. 
  }                                //Now that setuppass = true, the next time through your loop it will behave differently
  if (tempentry != temppass)      //If at any time your entered code does not equal your setuppassword durng the 5 iterations through the 
    //for loop
  {
    entryindex = 0;                      //Reset your entryindex so that it effectively clears your entry.
    inputSetupArray[entryindex] = '/0';         //Always add the null
    //Since you have a display, use this opportunity to print something to the display saying that the two did not match.
  }
}

Am I doing it right?

I get this error with the SetupCode() = true; :
lvalue required as left operand of assignment

I've only got a minute but a couple of things. You have done this differently than I did but in theory most of it will work.

First where you start your setupcode function you call it a boolean function. The way you are using it, you want it to be a void. You are not returning a value so instead of:

boolean setupcode() {

you want

void setupcode(){

Second, you have already verified your password in the setupcode function. Again doing it a different way but it should work fine. So if it is true, you don't need to call checkpassword. In fact the way you have handled it, you can delete the whole checkpassword function.

The reason you get that error is that you are trying to set a function to true. You can't do that. Your setupcode is a function not a boolean variable. I can see where that got confusing over my last few posts. When I said declare a boolean called setupcode, I meant at the top of you code in the declarations section you should declare it as such:

boolean setupcode;

To be used later in the program. The way you are managing your code you don't need this.

Don't forget to handle a situation where they have entered the wrong password. The way your code is written right now you can't do this. Where you check for 4 digits and the '#' key, you will need to nest those two if loops. First check that the '#' key is pressed, then check if you have 4 digits. Then you inner loop can handle any situation where either you don't have 4 digits or your matching the codes returns false.

Do these couple of things and here you have called checkpassword. Just print something to the LCD to show you it worked. You are on a different track than I was but it should work.

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.