The lcd screen doesn't show the input from the keypad

I'm doing a project for a device with a user input code and time, where the code has to be guessed. The problem is that the lcd screen doesn't show the input on the second row and shows only 0 as timer

the program should allow the user to input a code first and then a time, it then should start the timer and the user should insert the right code and the timer should stop
Here's the code, I've tried turnig the chars to ints but with the same result

#include <LiquidCrystal.h>
#include <Keypad.h>


LiquidCrystal lcd(8, 9, 10, 11, 12, 13);
const byte ROWS = 4; //four rows
const byte COLS = 4; //four columns

char timeobj;
char keys[ROWS][COLS] = {
  {'1','2','3','A'},
  {'4','5','6','B'},
  {'7','8','9','C'},
  {'*','0','#','D'}
};
byte rowPins[ROWS] = {7, 6, 5, 4}; 
byte colPins[COLS] = {3, 2, 1, 0}; 

int codiceSegreto = 0;
int tempoTimer = 0;
bool codiceInserito = false;
Keypad keypad = Keypad(makeKeymap(keys), rowPins, colPins, ROWS, COLS);
void setup() {
  lcd.begin(16, 2);
  lcd.print("Inserisci codice:");
}

void loop() {
  char key = keypad.getKey();

  if (!codiceInserito) {
    inserisciCodice(key);
  } else {
    gestisciTimer(key);
  }
}



void inserisciCodice(char key) {
  static String inputCode = "";

  if (key != NO_KEY) {
    if (key >= '0' && key <= '9') {
      inputCode += key;
      lcd.print(key);
    }

    if (key == '#') {
      codiceSegreto = inputCode.toInt();
      inputCode = "";
      lcd.clear();
      lcd.print("Inserisci tempo:");
    }

    if (key == '*') {
      tempoTimer = inputCode.toInt();
      codiceInserito = true;
      lcd.clear();
      lcd.print("Codice e tempo inseriti!");
      delay(2000);
      lcd.clear();
    }
  }
}
void gestisciTimer(char tempotimer)
{
  int time;
    time=atoi(tempotimer);
    if (tempoTimer > 0) {

    lcd.print(time);
    delay(500);
    lcd.clear();
    delay(1000);
    time--;
    }
    if (tempoTimer == 0) {
      lcd.clear();
      lcd.print("Tempo scaduto!");
    }
}

Hi @flipperstone782 ,

I ported your code to Wokwi:

and changed the wiring from Pin 0 and Pin 1 to A4 and A5 so that you can use Serial communication for debugging.

I already added a number of Serial prints.

In minimum(!) the function void gestisciTimer(char tempotimer) has to be solved differently as it blocks loop() and does not allow to read the keys in due time ...

For the timer action you should use a millis() timer function, in total it is a nice application for a state machine. See here for a comprehensive explanation.

https://forum.arduino.cc/t/yet-another-finite-state-machine-introduction/1198997

For me it's too late today for immediate further support but maybe some other members might jump in and assist you now.

1 Like

Thanks @ec2021 for the wiring.

@flipperstone782 there are some mistakes.

You pass a key to the function that expects a String of digits. Even if you did pass a String of digits, nothing in the code would ever make that go down.

Here's your code limping along a bit better. I made time a global variable for convenience, and removed the misused parameter from gestisciTimer().

Now I have fish to fry, so I just post this code which can be executed on @ec2021's hardware. Just replace all the code there with this:

More little changed code
/*
  Forum: https://forum.arduino.cc/t/the-lcd-screen-doesnt-show-the-input-from-the-keypad/1232826
  Wokwi: https://wokwi.com/projects/391735173918223361

*/

#include <LiquidCrystal.h>
#include <Keypad.h>

// RS, E, D4 ..D7
LiquidCrystal lcd(8, 9, 10, 11, 12, 13);
const byte ROWS = 4; //four rows
const byte COLS = 4; //four columns

char timeobj;
char keys[ROWS][COLS] = {
  {'1','2','3','A'},
  {'4','5','6','B'},
  {'7','8','9','C'},
  {'*','0','#','D'}
};
byte rowPins[ROWS] = {7, 6, 5, 4}; 
byte colPins[COLS] = {3, 2, A4, A5}; 

int codiceSegreto = 0;
int tempoTimer = 0;
bool codiceInserito = false;
Keypad keypad = Keypad(makeKeymap(keys), rowPins, colPins, ROWS, COLS);
void setup() {
  Serial.begin(115200);
  Serial.println("jump on in\n");

  lcd.begin(16, 2);
  lcd.print("Inserisci codice:");
}

void loop() {
  char key = keypad.getKey();

  if (!codiceInserito) {
    inserisciCodice(key);
  } else {
    gestisciTimer();
  }
}

int time;

void inserisciCodice(char key) {
  static String inputCode = "";

  if (key != NO_KEY) {

    Serial.print(" key "); Serial.println(key);

    if (key >= '0' && key <= '9') {
      inputCode += key;
      lcd.print(key);
    }

    if (key == '#') {
      codiceSegreto = inputCode.toInt();
      inputCode = "";
      Serial.print("codiceSegreto\t");
      Serial.println(codiceSegreto);
      lcd.clear();
      lcd.print("Inserisci tempo:");
    }

    if (key == '*') {
      tempoTimer = inputCode.toInt();
      codiceInserito = true;
      lcd.clear();
      lcd.print("Codice e tempo inseriti!");
      Serial.print("tempoTimer\t");
      Serial.println(tempoTimer);

      time = tempoTimer;

      delay(2000);
      lcd.clear();
    }
  }
}

void gestisciTimer()
{
    Serial.print("timer\t");
    Serial.println(time);
    if (tempoTimer > 0) {
    lcd.print(time);
    delay(500);
    lcd.clear();
    delay(1000);
    time--;
    }
    if (time == 0) {
      lcd.clear();
      lcd.print("Tempo scaduto!");
      delay(777);
    }
}

Perhaps you could outline the larger project. This code is not a good point of departure for anything that will ever do much more, even if you did continue to fix, or let us fix, the things that make it not work very well.

a7

2 Likes

thank you both, I wasn't checking here, much and found the problem myself, it now works and I've moved on to the next feature. by the way, is there a way to clear just one line of the lcd screen?

Clear any portion of the screen by writing blanks to it.

Please post the sketch you ended up with.

Please say a bit about the big idea for this project, what is the final goal.

a7

1 Like

Here's the final code, I finally finished it after a couple of days of work

#include <LiquidCrystal.h>
#include <Keypad.h>

// initialize the library with the numbers of the interface pins
LiquidCrystal lcd(8, 9, 10, 11, 12, 13);
const byte ROWS = 4; //four rows
const byte COLS = 4; //four columns
int button=A5;
int board=A3;

//define the cymbols on the buttons of the keypads
char timeobj;
char keys[ROWS][COLS] = {
  {'1','2','3','A'},
  {'4','5','6','B'},
  {'7','8','9','C'},
  {'*','0','#','D'}
};
byte rowPins[ROWS] = {7, 6, 5, 4}; //connect to the row pinouts of the keypad
byte colPins[COLS] = {3, 2, 1, 0}; //connect to the column pinouts of the keypad

int codiceSegreto = 0;
int guess=0;
int tempoTimer = 0;
bool codiceInserito = false;
Keypad keypad = Keypad(makeKeymap(keys), rowPins, colPins, ROWS, COLS);
char key;
void setup() {
  lcd.begin(16, 2);
  pinMode(board, INPUT);
  pinMode(button, INPUT_PULLUP); 
  
  inserisciCodice();

}

void loop() {
    gestisciTimer();
}



void inserisciCodice() {

  static String inputCode = "";
  int code;
  int i=0;
    lcd.print("Inserisci codice:");
    lcd.setCursor(0,1);
    do { 
      key=keypad.getKey();
      if(key)
      {
        inputCode += key;
      i++;
      code=inputCode.toInt();
      lcd.clear();
      lcd.print("Inserisci codice:");
      lcd.setCursor(0,1);
      lcd.print(code);
      }
    }while (key != '#');
      codiceSegreto = inputCode.toInt();
      inputCode = "";
      code=0;
      lcd.clear();
      lcd.print("Inserisci tempo:");
      do { 
      key=keypad.getKey();
      if(key)
      {
        inputCode += key;
        i++;
        code=inputCode.toInt();
        lcd.clear();
        lcd.print("Inserisci tempo:");
        lcd.setCursor(0,1);
        lcd.print(code);
      }
    }while (key != '*');
    tempoTimer = inputCode.toInt();
      codiceInserito = true;
      lcd.clear();
      lcd.print("Codice e tempo inseriti!");
      delay(2000);
      lcd.clear();
}

void gestisciTimer()
{
  bool hacked=false;
  static String inputCode = "";
  int code;
  lcd.setCursor(0,1);
    while (tempoTimer > 0 && key!='C'&& !hacked) {
    key=keypad.getKey();
    if(key)
    {
      inputCode += key;
      code=inputCode.toInt();
    }
    lcd.setCursor(0,1);
    lcd.print(code);
    lcd.setCursor(1,0);
    lcd.print(tempoTimer);
    delay(500);
    lcd.clear();
    delay(1000);
    tempoTimer--;
    if (digitalRead(button) == LOW)
    {
      lcd.print("hacking...");
      delay(500);
      solved();
    }
    if (digitalRead(board) == HIGH)
    {
      lcd.print("hacking...");
      delay(500);
      solved();
    }
    if(key=='C')
    {
      break;
    }
    }
    guess=inputCode.toInt();
    if(guess==codiceSegreto)
    {
      solved();
    }
    else
    {
      lcd.setCursor(1,0);
      lcd.clear();
      lcd.print("Ordigno detonato");
    }
}
void solved()
{
  lcd.clear();
  lcd.print("ordigno");
  lcd.setCursor(0,1);
  lcd.print("disinnescato");
  delay(20000000);
}

basically the goal was to create a device that could have a timer and code set by the user so that another user on the opposing team (it's for a softair obj) can try a few methods to deactivate the device, one is getting the code from another player, another is a button on a separate small breadboard that deactivates the device, while the last is similar but instead of a button on a breadboard is an Arduino uno wifi rev2 that can be planted on analog pin 3 and accessed through a browser where the user can select anhyperlink to deactivate the device
Now that I think about it the part that handles the guess input doesn't work that well, it does what it's supposed to but after a couple of presses, what could the problem be?
Edit: I just noticed that the part for the wifi board doesn't work is there a way to do it in a similar way? If not I'll just won't include it. Also for some reason the program shows 97 on the second row before entering the code

I must admit that I'm not a fan of programming a microcontroller in the same sequential way like a PET2001 or CBM64 back in the good old 70/80th ... :wink:

If you are interested in a different way to handle your application feel free to have a look here:

https://wokwi.com/projects/391797529307245569

Sketch:

/*
  Forum: https://forum.arduino.cc/t/the-lcd-screen-doesnt-show-the-input-from-the-keypad/1232826
  Wokwi: https://wokwi.com/projects/391797529307245569

*/

#include <LiquidCrystal.h>
#include <Keypad.h>

// initialize the library with the numbers of the interface pins
LiquidCrystal lcd(8, 9, 10, 11, 12, 13);
const byte ROWS = 4; //four rows
const byte COLS = 4; //four columns
int button = A5;
int board = A3;

//define the symbols on the buttons of the keypads
char timeobj;
char keys[ROWS][COLS] = {
  {'1', '2', '3', 'A'},
  {'4', '5', '6', 'B'},
  {'7', '8', '9', 'C'},
  {'*', '0', '#', 'D'}
};
byte rowPins[ROWS] = {7, 6, 5, 4}; //connect to the row pinouts of the keypad
byte colPins[COLS] = {3, 2, 1, 0}; //connect to the column pinouts of the keypad


enum StatusType  { INPUTCODE, INPUTTEMPO, GUESSCODE, SOLVED, HACKED, FAILED, WAIT};

StatusType status;

unsigned long codiceSegreto = 0;
String inputString;
int tempoTimer = 0;
int countDown = 0;
bool codiceInserito = false;
unsigned long startTime;
unsigned long countDownTime;
Keypad keypad = Keypad(makeKeymap(keys), rowPins, colPins, ROWS, COLS);
char key;
void setup() {
  lcd.begin(16, 2);
  pinMode(board, INPUT);
  pinMode(button, INPUT_PULLUP);
  setNewStatus(INPUTCODE);
}

void loop() {
  handleKeypad();
  handleTimer();
  handleHacking();
  StateMachine();
}

void handleKeypad() {
  key = keypad.getKey();
}

void StateMachine() {
  switch (status) {
    case INPUTCODE:
      handleCodeInput();
      break;
    case INPUTTEMPO:
      handleTempoInput();
      break;
    case  GUESSCODE:
      guessCode();
      break;
    case  SOLVED:
      solved();
      break;
    case  HACKED:
      handleHacked();
      break;
    case  FAILED:
      failed();
      break;
    case  WAIT:
      handleWait();
      break;
  }
}

void handleWait() {
  if (key == 'A') {
    setNewStatus(GUESSCODE);
  }
  if (key == 'D') {
    setNewStatus(INPUTCODE);
  }
}

void setNewStatus(StatusType newStatus) {
  inputString = "";
  switch (newStatus) {
    case INPUTCODE:
      clearLCD("Inserisci codice:");
      break;
    case SOLVED:
      codiceInserito = false;
      break;
    case FAILED:
      codiceInserito = false;
      startTime = millis();
      break;
    case GUESSCODE:
      lcd.clear();
      codiceInserito = true;
      countDownTime = millis();
      countDown     = tempoTimer + 1;
      break;
    case WAIT:
      clearLCD("Again with 'A'", "New with 'D'");
      break;
  }
  status = newStatus;
}

void clearLCD(String line) {
  lcd.clear();
  lcd.print(line);
}

void clearLCD(String line0, String line1) {
  clearLCD(line0);
  lcd.setCursor(0, 1);
  lcd.print(line1);
}


boolean keyIsNumber() {
  return (key >= '0' && key <= '9');
}

void addNumberToInputString(int maxLen) {
  if (keyIsNumber() && inputString.length() < maxLen) {
    inputString += key;
    lcd.setCursor(0, 1);
    lcd.print(inputString);
  }
}

void handleCodeInput() {
  addNumberToInputString(8);
  if (key == '#' && inputString.length() >= 3) {  // Use in minimum three numbers
    codiceSegreto = inputString.toInt();
    clearLCD("Inserisci tempo:");
    setNewStatus(INPUTTEMPO);
  }
}

void handleTempoInput() {
  addNumberToInputString(2);
  if (key == '*' && inputString.toInt() >= 5) { // Give in minimum five seconds
    tempoTimer = inputString.toInt();
    clearLCD("Codice e tempo", "inseriti!");
    delay(2000);
    setNewStatus(GUESSCODE);
  }
}

void guessCode() {
  addNumberToInputString(8);
  if (key == 'C') {
    unsigned long guess = inputString.toInt();
    codiceInserito = false;
    if (guess == codiceSegreto) {
      setNewStatus(SOLVED);
    } else {
      setNewStatus(FAILED);
    }
  }
}

void failed() {
  lcd.clear();
  lcd.print("Ordigno detonato");
  if (millis() - startTime > 3000 ) {
    clearLCD("Out of business ...");
    delay(10000);
    setNewStatus(WAIT);
  }
}

void solved() {
  clearLCD("ordigno","disinnescato");
  delay(3000);
  setNewStatus(WAIT);
}

void handleHacked() {
  clearLCD("Hacking ....");
  delay(1000);
  setNewStatus(SOLVED);
}

void handleTimer() {
  static unsigned long lastCountDown = 0;
  if (codiceInserito && countDown > 0) {
    if (lastCountDown == 0) {
      lastCountDown = millis();
    }
    if (millis() - lastCountDown > 1000) {
      lastCountDown = millis();
      countDown--;
      lcd.setCursor(0, 0);
      lcd.print("Count Down:     ");
      lcd.setCursor(12, 0);
      lcd.print(countDown);
    }
    if (countDown == 0) {
      setNewStatus(FAILED);
    }
  } else {
    lastCountDown = 0;
  }
}

void handleHacking() {
  if (!codiceInserito) {
    return;
  }
  if (digitalRead(button) == LOW ||
      digitalRead(board) == HIGH) {
    setNewStatus(HACKED);
  }
}

The sketch uses your original wiring but a state machine to switch between different states of your application:

  • INPUTCODE

  • INPUTTEMPO

  • GUESSCODE

  • SOLVED

  • HACKED

  • FAILED

  • WAIT

  • Some states can only be left by a given key input, some change state after a certain time.

  • The secret code requires in minimum three numbers,

  • The tempoTimer requires in minimum five seconds,

  • Hacking is only possible while a valid secret code is active. There are two buttons in Wokwi (the red one "simulates" the external Arduino board pin).

  • A handleTimer() routine takes care of the count down after input of a valid secret code and tempoTimer value.

  • In WAIT state you can choose whether you go for another turn with the same or if you want to input new data.

As each state has its own routine and the preparation before entering a certain state is done in the function setNewStatus().

If you are not happy with one or the other function do not hesitate to change its behaviour.

Be aware that I changed the secret code variables (e.g. codiceSegreto) to unsigned long to handle 8 digits ...

Hope it is of assistance ...
Good luck and have fun!

ec2021

1 Like

Thank you so much, I really appreciate your help,but I've just tried it and right after the time (which for some reason is limited to two digits) automatically hacks the device
still thanks alot
FS782

Not quite clear what you mean with "automatically hacks the device".

If you test the sketch on Wokwi it doesn't...

Are you talking about your real application? If yes, then I would assume that there is a difference to the Wokwi wiring.

Good luck!

Yeah I tested it on the real project and also tried to remove the wifi board altogether so that only the external button can hack the device but it still goes directly to the hacked state. Still thank you so much

When you removed the UNO WiFi Board, did you also change the function

void handleHacking() {
  if (!codiceInserito) {
    return;
  }
  if (digitalRead(button) == LOW ||
      digitalRead(board) == HIGH) {
    setNewStatus(HACKED);
  }
}

to this

void handleHacking() {
  if (!codiceInserito) {
    return;
  }
  if (digitalRead(button) == LOW) {
    setNewStatus(HACKED);
  }
}

???

Otherwise "hacking" reacts on the pin "board" which floats due to pinMode(board, INPUT); (it is not like with pinMode(board, INPUT_PULLUP) where the pin state is kept HIGH by an internal resistor even if not connected).

Have a look at the Wokwi wiring where I consider this type of pinMode by using a resistor to GND (you can call that an external "pulldown resistor"):

image

If your UNO is connected to the pin board without this external resistor it should draw the pin to GND (LOW) otherwise "hacking" will be active as soon as you have input the tempoTimer value ...

Yep I did that but it didn't change anything, I considered putting a resistor in there but Ai wasn't sure if it would work, thank you

That sounds weird ... :wink:

Just a last check:

If you comment handleHacking() in loop()

void loop() {
  handleKeypad();
  handleTimer();
  // handleHacking();
  StateMachine();
}

does it still behave as you mentioned?

When you typed "Ai", were you going for"AI" or "I"?

a7

For some reason the autocorrect changed I to Ai

I'll try it once I get home in a couple of minutes

Uh oh… it's starting to take over. :wink:

a7

1 Like

Question: “Are you afraid of the increasing spread of artificial intelligence?”

Answer: "No, I'm more worried about the decline in natural intelligence..."

:wink:

2 Likes

Ok, so by commenting handle Hacking it works just fine but of course it can't hack, do you need my wiring? Maybe that's the issue

OK, I managed to solve the issue completely it now hacks fine and most importantly when needed, I don't really know how to thank you both for the help you've given me. One last question, why is the time limited to two digits?
FS782