How to use keypad library to send a string per keypress

Hi I am exploring the keypad library. In many tutorial each button on the keypad send one char over to the computer. Is it possible to send over a string of two char instead? Will I simply be doing something like

char keys[2][ROW_NUM][COLUMN_NUM] = {
  {'1a','2a','3a'},
  {'4b','5b','6b'},
  {'7c','8c','9c'},
  {'*h','0h','#h'}
};

Thanks!

1 Like

The keypad is intended to return an integer for each key event…

Easy, you create an [array] of strings, and send the string that corresponds to the same position in the keypad value.

e.g. pseudocode
Press ‘1’ to send “dog”

char *messages[] = {“cat”, “dog”, etc}
keyvalue = keypad.value
send(messages[keyvalue])
1 Like

Your topic was MOVED to its current forum category which is more appropriate than the original as it is not an Introductory Tutorial

Single quotes for single characters. '1a' is 2 characters in single quotes. Not legal. "1a" is a string and that is legal.

Then you would have to modify the library to work with strings. Not easy.

What you could do is something like:

char key = keypad.getKey();
switch(key)
{
     case '1':
          Serial.println("1a");
          break;
// and so on for the strings.
// ...
}

I type too slow. Or use the method of @lastchancename.

Yes.

No. The single-quotes are for character literals, not strings. You can fit two characters in an 'int' so the compiler lets you put two in a character literal but since you store those 'int' values into a 'char' array you will lose one of the two characters. Adding another dimension to the array won't help.

Use one character per key and map them to string literals later.

char keys[ROW_NUM][COLUMN_NUM] = {
  {'a','b','c'},
  {'d','e','f'},
  {'g','h','i'},
  {'j','k','l'}
};
  cont char *messages[12] =  {"1a","2a","3a",
  "4b","5b","6b",
  "7c","8c","9c",
  "*h","0h","#h"};

Thank you all for your help.

I will try to modify the official Arduino keypad tutorial:

#include <Keypad.h>

const int ROW_NUM = 4; //four rows
const int COLUMN_NUM = 4; //four columns

char keys[ROW_NUM][COLUMN_NUM] = {
  {'1','2','3', 'A'},
  {'4','5','6', 'B'},
  {'7','8','9', 'C'},
  {'*','0','#', 'D'}
};

byte pin_rows[ROW_NUM] = {9, 8, 7, 6}; //connect to the row pinouts of the keypad
byte pin_column[COLUMN_NUM] = {5, 4, 3, 2}; //connect to the column pinouts of the keypad

Keypad keypad = Keypad( makeKeymap(keys), pin_rows, pin_column, ROW_NUM, COLUMN_NUM );

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

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

  if (key){
    Serial.println(key);
  }
}

into something like this for a two char array:

#include <Keypad.h>

const int ROW_NUM = 4; //four rows
const int COLUMN_NUM = 4; //four columns

char keys[2][ROW_NUM][COLUMN_NUM] = {
  {"1a","2a","3a", "Aa"},
  {"4a","5a","6a", "Ba"},
  {"7a","8a","9a", "Ca"},
  {"*a","0a","#a", "Da"}
};

byte pin_rows[ROW_NUM] = {9, 8, 7, 6}; //connect to the row pinouts of the keypad
byte pin_column[COLUMN_NUM] = {5, 4, 3, 2}; //connect to the column pinouts of the keypad

Keypad keypad = Keypad( makeKeymap(keys), pin_rows, pin_column, ROW_NUM, COLUMN_NUM );

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

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

  if (key){
    Serial.println(key);
  }
}

I can assure you, that is NOT going to work.

One way to modify the keypad example to do what you want is to change:

  if (key){
    Serial.println(key);
  }

to

  switch (key)
  {
  case '1': Serial.write("1a"); break;
  case '2': Serial.write("2a"); break;
  case '3': Serial.write("3a"); break;
  case 'A': Serial.write("Aa"); break;
  case '4': Serial.write("4a"); break;
  case '5': Serial.write("5a"); break;
  case '6': Serial.write("6a"); break;
  case 'B': Serial.write("Ba"); break;
  case '7': Serial.write("7a"); break;
  case '8': Serial.write("8a"); break;
  case '9': Serial.write("9a"); break;
  case 'C': Serial.write("Ca"); break;
  case '*': Serial.write("*a"); break;
  case '0': Serial.write("0a"); break;
  case '#': Serial.write("#a"); break;
  case 'D': Serial.write("Da"); break;
  }

That's unfortunate. Probably need to read more C++. What I want to eventually do is not just a 4 by 4 matrix but a 19 by 19 matrix. It would be great if I don't need to use an if / switch to check through them. Having two character matrix is probably the easiest if that's possible.

Warning: The Keypad library only supports 16 columns and has to be modified to support more than 10 rows. You will need to use 16 columns and 23 rows or modify the library for more columns (24 or 32 should not be hard).

Warning: 361 keys can't all be uniquely identified by single characters. You will need to modify the library to use 16-bit integers instead of characters. Then you can use two-character constants like your original attempt.

Thanks for the heads-up. I will try to modify the library so that it can do 19 by 19.

Will the process be something like:

  • download the source code of keypad
  • include the source code in the same arduino project folder
  • modify the library and include the modified library in the main source file
  • flashing everything to arduino

Another question I have is that why do I need to use 16-bit integers first? is it because the keypad library takes a primitive type as the content of the matrix? You also said that after using 16-bit integers, I will be able to use two-character constants. Why are these two sentences relevant?

I'm sorry I am not very familiar with coding for arduino. I apologize for any silly or trivial questions.

The [2] should be after row and column, and should be 3 to allow for the terminating null, unless you want to code two individual characters (that will reduce memory usage).

The Keypad library uses one 'char' per key to identify the keys. You can only use the values 1 through 255 in a 'char' (the value 0 is reserved to mean "no key was pressed"). You can't identify 361 (19x19) separate keys with 255 values.

It would be much easier to do something like I have below rather than modify the library:

#include <Keypad.h>
const int ROW_NUM = 4; //four rows
const int COL_NUM = 4; //four columns
char keys[ROW_NUM][COL_NUM] = {
  {'1', '2', '3', 'A'},
  {'4', '5', '6', 'B'},
  {'7', '8', '9', 'C'},
  {'E', '0', 'F', 'D'}
};
byte pin_rows[ROW_NUM] = {7, 6, 5, 4}; //connect to the row pinouts of the keypad
byte pin_column[COL_NUM] = {A3, A2, A1, A0}; //connect to the column pinouts of the keypad
Keypad keypad = Keypad( makeKeymap(keys), pin_rows, pin_column, ROW_NUM, COL_NUM );

char* keyString[ROW_NUM*COL_NUM] =
{
  "String0",
  "String1",
  "String2",
  "String3",
  "String4",
  "String5",
  "String6",
  "String7",
  "String8",
  "String9",
  "StringA",
  "StringB",
  "StringC",
  "StringD",
  "String*",
  "String#"
};

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

void loop()
{
  char key = keypad.getKey();
  
  if (key)
  {
    if (isdigit(key))
    {
      Serial.println(keyString[key - '0']);
    }
    else
    {
      Serial.println(keyString[10 + key - 'A']);
    } 
  }
}

How will that help with a 19x19 keypad?

True. Forgot about that. Still needs to be modified. That's a lot of keys!

Over 4.1 grand pianos!

1 Like

As long as you are going to modify the library, why not have the library just return the index of the key (1 through 361 in your case), then you can use that to access an array of whatever type data you desire.

I am not sure if I understand what you mean by having the library return the number. What I want to achieve is for the keypad library to send data through the serial port to a computer when I press any one of the 361 keys..

That's true. Other data types have more range. If I modify the source code so that the keypad library takes 19 rows and 19 columns and accept array of two chars, maybe my previous method will work?

Yes. I think it will. It shouldn't be too hard. The keypad library isn't very large. If you like, I could make the changes for you, just for fun.