Keypad integration

Hello,
I am trying to feed digits through a keypad and intending to get a combination of digit.
For example: I pressed 123 then, integer num = 123.
For some reason, my code is not working.
I will very appreciate if you could help me solve this issue.

Thanks.

int key_loop(){
 // if (count > 100) count = 0;
 char key[100] = {keypad.waitForKey()};
 key[100] = {keypad.getKey()};
 
 TFTscreen.text(key,count,60);
 if (key != NO_KEY){
    Serial.println(key);
    if (count > 1000) count = 0;
    delay(150);
  }  

int key1 = atoi(key);
//Serial.println(key1);
  while ((key1 >= 0) && (key1 <= 9)) {
    int keyValue = key1 - 0;
    num = (num * 10) + keyValue;
    key[100] = {keypad.waitForKey()};
}

count=count + 12;
Serial.print("Got the number: ");
Serial.println(num); 

  //resetFunc();
  return(count);
}
 char key[100] = {keypad.waitForKey()};
 key[100] = {keypad.getKey()};

do you think there is actually such a thing as key[[color=red]100[/color]] given the declaration?
and what is that supposed to do in your mind?

which keypad library are you using? is that all your code?

suggest you write a small example totally outside your current project to do just this. then integrate in your whole code.

  1. atoi () works on nul terminated character arrays, not on single characters.
  2. Subtracting 0 from any variable is quite useless.
  3. key[100] in line 4 of the code you presented is an element outside the key array that is declared in line 3.

Please explain what you think that every line in your code does and we will explain where you go wrong.

Ideally (from what I have seen in the examples:

char key = keypad.waitForKey();
 key = keypad.getKey();

should work. But I get an error

TFTscreen.text(key,count,60);
invalid conversion from 'char' to 'const char*' [-fpermissive]

To solve this, I had to define waitforkey and getkey as array.

To solve this, I had to define waitforkey and getkey as array.

no you are receiving characters one by one and you need to build an array of char which then you can pass to your TFTscreen for display and analysis. (there are other way to do that on the fly)

a char is something like 'H', just one symbol taking one byte of memory. if you do char letter = 'H'; then your variable name letter is the address of a byte in memory which will be filled with the ASCII value of the symbol 'H'

a string is composed of multiple chars and is stored in memory as consecutive bytes. usually one allocate an array for that such as char message[100];. This reserves 100 bytes in memory for your message (from message[0]to message[99]) and message is actually the pointer to that memory space, so a char *, a pointer (the *) to somewhere there are a bunch of char stored.

makes sense?

Thanks for explanation. Yes it is clear to me but what doesn't make sense is TFTscreen.text(key,count,60); Why can't I print a character? If I pressed 1 which is '1' in character format, I should be able to see this on the screen, but I don't. If I define as array, TFT works great.

look at the doc...

screen.text([color=blue]text[/color], xPos, yPos);
[color=blue]text[/color] : [color=red]char array[/color], the text you want to write on the screen

so you need to pass an array (null terminated sequence of characters) - that is from my explanation above a pointer to a set of character, not just one character as this is not what the function expects. if you want to print only 1 character, you still need to put it into a buffer of 2 chars, the first one being your character you want to show and the second one being the '\0' null character so that you do have a well formed string array.

So again - you need to read the input on the keypad as they come in and build up the string.

Why can’t I print a character? If I pressed 1 which is ‘1’ in character format, I should be able to see this on the screen, but I don’t.

Because the library does not provide such a method. You have the source code, though, so YOU could add such a method.

J-M-L:
look at the doc

screen.text([color=blue]text[/color], xPos, yPos);

text : char array, the text you want to write on the screen




so you need to pass an array (null terminated sequence of characters) - that is from my explanation above a pointer to a set of character, not just one character as this is not what the function expects. if you want to print only 1 character, you still need to put it into a buffer of 2 chars, the first one being your character you want to show and the second one being the '\0' null character so that you do have a well formed string array.

So again - you need to read the input on the keypad as they come in and build up the string.

Thanks.

I have now

void loop(){
  char key[2] = {keypad.waitForKey()};
  key[2] = {keypad.getKey()};
  const char *key1 = &key[0];
  TFTscreen.text(key1,count,60);
 if (key != NO_KEY){
    Serial.println(key);
    if (count > 100) count = 0;

  }  
//int key2 = atoi(key);
Serial.println(key);
  while ((key1 >= '0') && (key1 <= '9')) {
    int keyValue = key1 - '0';
    num = (num * 10) + keyValue;
char key[2] = {keypad.waitForKey()};
}

count=count + 12;
Serial.print("Got the number: ");
Serial.println(num); 


}

But while statement is still failing. :frowning:

  char key[2] = {keypad.waitForKey()};

Create an array with 2 elements, populating the 0th element.

  key[2] = {keypad.getKey()};

Then, write to the 3rd position in a 2 element array, thereby stomping on memory you don't own. The curly braces here are useless. The value that you are writing may well be NO_KEY, by the way.

No wonder things are not going well.

  const char *key1 = &key[0];

This is useless. Anywhere you (try to) use key1, you can use key[0], instead.

 if (key != NO_KEY){

Since key is the address of an array, it will never equal NO_KEY, so this test is worthless, even if it were correct.

char key[2] = {keypad.waitForKey()};

Why are you defining ANOTHER array?

PaulS:   key[2] = {keypad.getKey()};

Then, write to the 3rd position in a 2 element array, thereby stomping on memory you don't own. The curly braces here are useless. The value that you are writing may well be NO_KEY, by the way.

I am not sure I understood.

Can you give an example?

Thanks.

Array indices go from 0 to size -1' So if you declare an array key[2], you can access the elements using the indices 0 and 1. If you access element 2 (key[2]) you are overwriting (bad) or reading (not so bad but still bad) something that does not belong to the array.

sterretje: Array indices go from 0 to size -1' So if you declare an array key[2], you can access the elements using the indices 0 and 1. If you access element 2 (key[2]) you are overwriting (bad) or reading (not so bad but still bad) something that does not belong to the array.

Sure, I am using key[0]. On TFT, I do see all the digits but in serial monitor "Got the number: 0"

zeus2kx:
I am not sure I understood.
Can you give an example?
Thanks.

Assuming you have a simple standard keypad, try this code. I did not try it so hopefully it works, even if there is a bug, you’ll probably get the idea. I just copied the header part from the examples just wrote the loop part to show some of the things discussed above.

don’t forget to put your serial console at 115200

#include <Keypad.h>

const byte ROWS = 4; //four rows
const byte COLS = 3; //three columns

char keys[ROWS][COLS] = {
  {'1', '2', '3'},
  {'4', '5', '6'},
  {'7', '8', '9'},
  {'*', '0', '#'}
};

byte rowPins[ROWS] = {5, 4, 3, 2}; //connect to the row pinouts of the keypad
byte colPins[COLS] = {8, 7, 6}; //connect to the column pinouts of the keypad

Keypad keypad = Keypad( makeKeymap(keys), rowPins, colPins, ROWS, COLS );

char message[10];     // ten memory slots, from 0 to 9
int nbCharacters = 0; // will count how many we get
unsigned long value = 0;

void setup() {
  Serial.begin(115200);
}

void loop() {
  // we read something from the keypad. this returns the null character ('\0') if nothing is available
  char key = keypad.getKey();

  if (key) { // if the key is not null, we've got something to handle

    // build up a string of character
    message[nbCharacters++] = key; // store the key at position nbCharacters, then increase nbCharacters (this is what ++ does)
    message[nbCharacters] = '\0'; // put end of string in the next position to have a well formed string. 

    // if this is a digit we typed, then build up our value
    if ((key >= '0') && (key <= '9')) {
      value = 10 * value + key - '0'; // build up decimal representation of the number
    }

    // let's display where we are so far:
    Serial.print("key entered\t= '"); Serial.print(key); Serial.println("'");
    Serial.print("Value\t= "); Serial.println(value);
    Serial.print("Message\t= \""); Serial.print(message); Serial.println("\"");

    // make sure we don't overflow the buffer. after 9 chars + the trailing '\0' we add, we reset
    if (nbCharacters >= 9) {
      nbCharacters = 0; // will restart next time
      value = 0;
      Serial.println("message buffer full, reset everything");
    }
  }
}
void loop()
{
  // an array to hold two characters
  char key[2];
  // initialize to zero
  memset(key, 0, sizeof(key));

  // read key
  key[0] = keypad.getKey();

  // you now have an array with one key that you can convert to integer
  int x = atoi(key);

}

Do you really want to read 100 characters from the keypad? You do conversion to int so the max will be 5 plus possibly a sign

Define a maximum number of digits that you want to read. If possible, use ‘#’ or ‘*’ as the key; this make life easier.

/*
  read characters from keypad till '#' is pressed
  returns:
    NULL if input not complete (no '#') else pointer to nul terminated input
*/
char * readKeypad()
{
  // array to store keypad input; 6 characters plus terminating nul character
  static char kpBuffer[7];
  // index into above array to indicate where keypress must be stored
  static byte index = 0;
  
  if(index == sizeof(kpBuffer))
  {
    Serial.println("Buffer overflow; data discarded");
    index = 0;
    return NULL;
  }  

  // read keypad
  kpBuffer[index] = keypad.getKey();

  // if '#', it's end of input
  if(kpBuffer[index] == '#')
  {
    // create nul terminated string
    kpBuffer[index] = '\0';
    // reset the index so next time we read we fill kpBuffer from beginning
    index = 0;
    // and return the user input
    return kpBuffer;
  }

  // if a key was pressed, increment the index
  if(kpBuffer[index]!= NO_KEY)
  {
    index++;
  }

  // indicate input not yet complete
  return NULL;
}

void loop()
{
  char *kpString = readKeypad();

  if(kpString != NULL)
  {
    Serial.println(atoi(kpString));
  }
}

loop() will continuously call readKeypad(). readKeypad() will return NULL as long as the input is not complete; once the input is complete (’#’ pressed), it will return the text that the user entered.

You can also create a readKeypadWithEcho() that will echo a keypress to the TFT

Code not compiled.

J-M-L: Assuming you have a simple standard keypad, try this code. I did not try it so hopefully it works, even if there is a bug, you'll probably get the idea. I just copied the header part from the examples just wrote the loop part to show some of the things discussed above.

Super!!! Thanks a bunch.

key entered = '1'
Value = 1
Message = "1"
key entered = '2'
Value = 12
Message = "12"
key entered = '3'
Value = 123
Message = "123"
key entered = '#'
Value = 123
Message = "123#"

Two things: 1. How do I stop adding digits to message? 2. How do I set # to behave as "enter"? Should I define as a case?

  1. How do I stop adding digits to message?

Stop pressing keys. More realistically, you want some event to cause the contents of message to be converted to a value, stored somewhere, and for message to get a \0 in position 0.

  1. How do I set # to behave as "enter"? Should I define as a case?

Since there are no switch statements, a case seems pointless. An else if statement, on the other hand, seems reasonable.

Thanks to J-M-L, sterretje and PaulS for helping me out.
Now I should be able to move ahead.

Two things:

  1. How do I stop adding digits to message?
  2. How do I set # to behave as “enter”? Should I define as a case?

look at my code. there is a test where I reset value to zero.

→ Try to understand what the condition is.
→ Try to write your condition to stop adding to the buffer