Having trouble with keypad not registering my keypress

I’m almost done with my airsoft simulated bomb and everything works great except the disarm attempt during countdown. When entering the disarm code and timer at setup there is no trouble reading the keys that are being pressed, but during countdown it very often doesn’t read every keys that are being pressed. Pretty often some of the keys on the pad doesn’t work at all, but some does with no problem at all. When restarting keys that didn’t work before could be working with no issues, but others don’t, so it doesn’t seem to be a hardware issue. I have had people telling me it is a debounce problem so I tried to debounce, with my limited knowledge, but with the new code it doesn’t read my keys at all. I would be very grateful if someone would take the time to take a look at my latest code and help me figure out how to make it work. I have only inserted the two functions that I am having trouble with. Pressing ‘*’ to enter disarming have never been a problem and still isn’t, but typing the code is.

void countdown() {
  char keypressed = myKeypad.getKey();
  unsigned long Time = millis();

  CheckWires();
  if (Time - TimeCountdown >= 90 && Time - TimeCountdown <= 110) {
    digitalWrite(Buzzer, LOW);
  }
  if (TimeRemaining[0] == 0 && TimeRemaining[1] == 0) {
    if (TimeRemaining[2] >0 && TimeRemaining[2] <= 2) {
      if (Time - TimeCountdown >= 490 && Time - TimeCountdown <= 510) {
        digitalWrite(Buzzer, HIGH);
      }
      if (Time - TimeCountdown >= 590 && Time - TimeCountdown <= 610) {
        digitalWrite(Buzzer, LOW);
      }
    }
    else if (TimeRemaining[2] < 1) {
      if (Time - TimeCountdown >= 323 && Time - TimeCountdown <= 343) {
        digitalWrite(Buzzer, HIGH);
      }
      if (Time - TimeCountdown >= 423 && Time - TimeCountdown <= 443) {
        digitalWrite(Buzzer, LOW);
      }
      if (Time - TimeCountdown >= 657 && Time - TimeCountdown <= 667) {
        digitalWrite(Buzzer, HIGH);
      }
      if (Time - TimeCountdown >= 756 && Time - TimeCountdown <= 776) {
        digitalWrite(Buzzer, LOW);
      }
    }
  }
  if (Time - TimeCountdown >= countdownSpeed) {
    if (TimeRemaining[0] == 0 && TimeRemaining[1] == 0 && TimeRemaining[2] == 0 && TimeRemaining[3] == 0) {
      bDetonated = HIGH;
    }
    else if (TimeRemaining[0] >= 1 && TimeRemaining[1] == 0 && TimeRemaining[2] == 0 && TimeRemaining[3] == 0) {
      TimeRemaining[0] = TimeRemaining[0] - 1;
      TimeRemaining[1] = 9;
      TimeRemaining[2] = 5;
      TimeRemaining[3] = 9;
    }
    else if (TimeRemaining[1] >= 1 && TimeRemaining[2] == 0 && TimeRemaining[3] == 0) {
      TimeRemaining[1] = TimeRemaining[1] - 1;
      TimeRemaining[2] = 5;
      TimeRemaining[3] = 9;
    }
    else if (TimeRemaining[2] >= 1 && TimeRemaining[3] == 0) {
      TimeRemaining[2] = TimeRemaining[2] - 1;
      TimeRemaining[3] = 9;
    }
    else {
      TimeRemaining[3] = TimeRemaining[3] - 1;
    }
    if (bDisarmAttempt == LOW) {
      lcd.clear ();
      lcd.print("DETONATION IN:");
      lcd.setCursor(0, 2);
      lcd.print(TimeRemaining[0]);
      lcd.setCursor(1, 2);
      lcd.print(TimeRemaining[1]);
      lcd.setCursor(2, 2);
      lcd.print(":");
      lcd.setCursor(3, 2);
      lcd.print(TimeRemaining[2]);
      lcd.setCursor(4, 2);
      lcd.print(TimeRemaining[3]);
    }
    digitalWrite(Buzzer, HIGH);
    TimeCountdown = Time;
  }
  if (keypressed == '*') {
    bDisarmAttempt = HIGH;
  }
  if (bDisarmAttempt == HIGH) {
    CheckKeyPressed();
    if (KeyStep == 0) {
      lcd.clear ();
      lcd.print("SET DISARM CODE:");
      lcd.setCursor(0, 2);
      lcd.print("*");
      lcd.setCursor(1, 2);
      lcd.print("*");
      lcd.setCursor(2, 2);
      lcd.print("*");
      lcd.setCursor(3, 2);
      lcd.print("*");
      KeyStep = 1;
    }
    else if (KeyStep == 1) {
      if (bKeyPressed == true) {
        Disarm[0] = keypressed;
        lcd.setCursor(0, 2);
        lcd.print(Disarm[0]);
        if (keypressed == NO_KEY){
          bKeyPressed = false;
          KeyStep = 2;
        }
      }
    }
    else if (KeyStep == 2) {
      if (bKeyPressed == true) {
        Disarm[1] = keypressed;
        lcd.setCursor(1, 2);
        lcd.print(Disarm[1]);
        if (keypressed == NO_KEY){
          bKeyPressed = false;
          KeyStep = 3;
        }
      }
    }
    else if (KeyStep == 3) {
      if (bKeyPressed == true) {
        Disarm[2] = keypressed;
        lcd.setCursor(2, 2);
        lcd.print(Disarm[2]);
        if (keypressed == NO_KEY){
          bKeyPressed = false;
          KeyStep = 4;
        }
      }
    }
    else if (KeyStep == 4) {
      if (bKeyPressed == true) {
        Disarm[3] = keypressed;
        lcd.setCursor(3, 2);
        lcd.print(Disarm[3]);
        if (keypressed == NO_KEY){
          bKeyPressed = false;
          KeyStep = 5;
        }
      }
    }
    else if (KeyStep == 5) {
      if (Disarm[0] == Code[0] && Disarm[1] == Code[1] && Disarm[2] == Code[2] && Disarm[3] == Code[3]) {
        KeyStep = 0;
        bDisarmed = HIGH;
        bBombArmed = LOW;
        bDisarmAttempt = LOW;
      }
      else {
        if (DisarmMode == 1) {
          bDisarmAttempt = LOW;
        }
        else if (DisarmMode == 2) {
          bDisarmAttempt = LOW;
          countdownSpeed = 500;
        }
        else if (DisarmMode == 3) {
          bDisarmAttempt = LOW;
          bDetonated = HIGH;
        }
        KeyStep = 0;
      }
    }
  }
}

void CheckKeyPressed() {
  char keypressed = myKeypad.getKey();
  
  if (keypressed != NO_KEY && keypressed >='0' && keypressed <='9'){
    lastDebounceTime = millis();
  }
  if ((millis() - lastDebounceTime) > debounceDelay){
    if (keypressed != NO_KEY && keypressed >='0' && keypressed <='9'){
      bKeyPressed = true;
    }
  }
}

I cannot get your sketch to compile. Is that the entire sketch?

No, it is only the two functions that handles the disarming. When I try to submit the whole sketch I only get a message that I have exceeded the limit of 9000 characters. I have tried both reply and quick-reply.

In that case, you may need to attach the .ino file.

Ok, thanks. Didn’t realize that was possible. :slight_smile:

Bomb_mega_V3.ino (17.4 KB)

The problem appears in the “Countdown” function when “bDisarmAttempt” goes high. I am also uploading the original sketch with no debouncing (or whatever my attempt could be called).

Bomb_mega.ino (16.7 KB)

Add Serial.println statements in strategic places for debugging and use serial monitor to observer what your code is doing.

You can also make your code a lot simpler. Just part of it

E.g. If you look closer at your timerConvention functionality, 48 → 0, 49->1 etc; this is basically a subtraction of ‘0’ (48decimal) from the key that is stored in the timer array. The below does the same in a few lines.

void timerConvertion()
{
  for (int i = 0; i <= 3; i++)
  {
    TimeRemaining[i] = timer[i] - '0';
  }
}

Next you have 2 places where you display the TimeRemaining; make that a function like

void displayTimeRemaining()
{
  lcd.clear ();
  lcd.print("DETONATION IN:");
  lcd.setCursor(0, 2);
  lcd.print(TimeRemaining[0]);
  lcd.setCursor(1, 2);
  lcd.print(TimeRemaining[1]);
  lcd.setCursor(2, 2);
  lcd.print(":");
  lcd.setCursor(3, 2);
  lcd.print(TimeRemaining[2]);
  lcd.setCursor(4, 2);
  lcd.print(TimeRemaining[3]);
}

And call that function when needed

  1. In settimer()
        delay(900);
        timerConvertion();
        Time = millis();
        TimeCountdown = Time;
        displayTimeRemaining();
        bBombArmed = HIGH;
  1. In countdown()
    if (bDisarmAttempt == LOW)
    {
        displayTimeRemaining();
    }

Next, instead of having an array for TimeRemaining, consider the use of a struct. Assuming the format is minutes and seconds

struct TIMEREMAINING
{
  int8_t minutes;
  int8_t seconds;
};

TIMEREMAINING TimeRemaining = {0, 0};

Now your timerConvertion() can be like

void timerConvertion()
{
  TimeRemaining.minutes = timer[0] - '0';
  TimeRemaining.minutes *=10;
  TimeRemaining.minutes += timer[1] - '0';

  TimeRemaining.seconds = timer[2] - '0';
  TimeRemaining.seconds *=10;
  TimeRemaining.seconds += timer[3] - '0';
}

And your displayTimeRemaining() changes a little

void displayTimeRemaining()
{
  lcd.clear ();
  lcd.print("DETONATION IN:");
  lcd.setCursor(0, 2);

  if (TimeRemaining.minutes < 10)
  {
    lcd.print("0");
  }
  lcd.print(TimeRemaining.minutes);
  lcd.print(":");
  if (TimeRemaining.seconds < 10)
  {
    lcd.print("0");
  }
  lcd.print(TimeRemaining.seconds);
}

Now you have to change everywhere where you use the array; I think it’s only in countdown

  //if (TimeRemaining[0] == 0 && TimeRemaining[1] == 0)
  if (TimeRemaining.minutes == 0)
  {
    //if (TimeRemaining[2] > 0 && TimeRemaining[2] <= 2)
    if (TimeRemaining.seconds > 0 && TimeRemaining.seconds <= 29)
    {
      ...
      ...
    }
    //else if (TimeRemaining[2] < 1)
    else if (TimeRemaining.seconds < 10)
    {
      ...
      ...
    }
  }

and

  if (Time - TimeCountdown >= countdownSpeed)
  {
    //if (TimeRemaining[0] == 0 && TimeRemaining[1] == 0 && TimeRemaining[2] == 0 && TimeRemaining[3] == 0)
    if (TimeRemaining.minutes == 0 && TimeRemaining.seconds == 0)
    {
      bDetonated = HIGH;
    }
    else
    {
      TimeRemaining.seconds--;
      if (TimeRemaining.seconds < 0)
      {
        TimeRemaining.seconds = 59;
        TimeRemaining.minutes--;
      }
    }

    ...
    ...

The else block replaces your complicated way to decrement the time.

Note that the above suggestions will not solve your problems. It’s just more my style and I think it’s easier to understand.

Thanks! I'm still a novice programmer of Arduino so I'm not yet fully familiar with it all. Your example sure makes the code a lot simpler. Entering the code and time at setup was originally a for statement, but for some reason I couldn't get it to work properly.

I will bring your example to the IDE so that I fully understand what I'm doing. I need to solve the issues first, though, since it is supposed to be used in a game in two weeks.

veritas: I need to solve the issues first, though, since it is supposed to be used in a game in two weeks.

See my first comment ;) Use Serial.println for debugging.

I will!

Seems as the boolean never goes high so the conditions are never met to store the key pressed. :/

Thank you, sterretje!

I took your suggestions and implemented it into my code and now it works. I guess the arduinos memory doesn't get filled up with my complicated code anymore and therefor has time to register the keys that are getting pressed. Every once and a while it misses a key, but then you just need to press it again and it will accept it.

Like the perfectionist I am, I am a little reluctant to implement code that I don't understand, but I have read it through a couple of times and now I understand what the hell it really does. When I need it in upcoming projects I will probably have forgotten it, but then I will read it all over again. ;)

If you post your updated code, somebody might be willing to have a look at it and try to find the cause that you occasionally miss a key.

Sure. :slight_smile:

Bomb_mega.ino (15.1 KB)