# Keypad numericals ok, now letters: how to?

**URL:** <https://forum.arduino.cc/t/keypad-numericals-ok-now-letters-how-to/1128871>\
**Category:** Programming\
**Created:** [May 19, 2023, 5:33pm UTC](https://forum.arduino.cc/t/keypad-numericals-ok-now-letters-how-to/1128871 "2023-05-19T17:33:06Z")\
**Posts on this page:** 10\
**Page:** 1

<div class="post-metadata">

**Author:** ![brice3010](https://dub1.discourse-cdn.com/arduino/user_avatar/forum.arduino.cc/brice3010/32/912680_2.png) [@brice3010](https://forum.arduino.cc/u/brice3010)\
**Post date:** [May 19, 2023, 5:33pm UTC](https://forum.arduino.cc/t/keypad-numericals-ok-now-letters-how-to/1128871/1 "2023-05-19T17:33:06Z")

</div>

The program below nicely returns two digit numbers.  
Serial output for pressing for example '1' and then '2':

```arduino
DCCpp_turntable_controller_v3
myValue = 1
i = 1
myValue = 12
i = 2
full value of two digits obtained : 12

```

Now I would like letters (A, B, C or D, as well as \* and #), individually, to be output to a separate variable, different from where the number is stored.  
Each letter is to be pressed just once, and stored as an idividual letter. Not two subsequent letters.

I am hitting a dead-end right now, so any usefull pointer or indication would be most appreciated.

Here is the current working code for return of two-digit numbers:

```arduino
#include "Wire.h"
#include "I2CKeyPad.h" // https://github.com/RobTillaart/I2CKeyPad
const uint8_t KEYPAD_ADDRESS = 0x38; // PCF8574 = 0x20 PCF8574AP = 0x38
char keys[] = "123A456B789C*0#DNF"; // N = NoKey, F = Fail (e.g. >1 keys pressed)
uint8_t i;
I2CKeyPad keyPad(KEYPAD_ADDRESS);

void setup() {
  Serial.begin(9600);
  Serial.println("DCCpp_turntable_controller_v3");
  Wire.begin();
  if (keyPad.begin() == false)
  {
    Serial.println("\nERROR: cannot communicate to keypad.\nPlease reboot.\n");
    while (1);
  }
}

void loop() {
  uint8_t inputInt = 0;
  static bool keyPress = 0;
  static bool secNum = 0;
  static int myValue = 0;
  static uint8_t caseValue = 0;

  if (!keyPad.isPressed()) keyPress = true; // set flag keyPress: keypad released

  if (keyPad.isPressed () && keyPress == true) // execute only once
  {

    keyPress = false;
    myValue = getKeypadInteger(myValue);
    Serial.print("myValue = ");
    Serial.println(myValue);
    Serial.print("i = ");
    Serial.println(i);

  }
  if (i == 2) // 2 valid digits have been entered on keypad
  {
    i = 0;
    Serial.print("full value of two digits obtained : ");
    Serial.println(myValue);
    caseValue = myValue; // convert myValue to character
    myValue = 0;

    stepperAction(caseValue); // activate stepper use keypad keystroke to select corresponding new position
  }
}

int getKeypadInteger(int value)
{
  char keyVal = 0; // the key press
  bool isNum = 0;
  bool isLetter = 0;
  static int index = 0;
  do
  {
    index = keyPad.getKey(); // input the key
    keyVal = keys[index];
    isNum = (keyVal >= '0' && keyVal <= '9'); // is it a digit?
    if (isNum)
    {
      i = i + 1;
      //Serial.print(keyVal - '0');
      value = value * 10 + keyVal - '0'; // accumulate the input number
    }
  }
  while ( !keyVal); // until not a digit or while no key pressed
  return value;
}

void stepperAction(char keyStroke)
{
  switch (keyStroke)
  {
    case 01:
      {
      }
  }
}

```

---

<div class="post-metadata">

**Author:** ![kolaha](https://dub1.discourse-cdn.com/arduino/user_avatar/forum.arduino.cc/kolaha/32/966427_2.png) [@kolaha](https://forum.arduino.cc/u/kolaha)\
**Post date:** [May 19, 2023, 10:22pm UTC](https://forum.arduino.cc/t/keypad-numericals-ok-now-letters-how-to/1128871/3 "2023-05-19T22:22:14Z")

</div>

you can use Serial.parseInt() to get whole integer

---

<div class="post-metadata">

**Author:** ![gcjr](https://dub1.discourse-cdn.com/arduino/user_avatar/forum.arduino.cc/gcjr/32/314015_2.png) [@gcjr](https://forum.arduino.cc/u/gcjr)\
**Post date:** [May 19, 2023, 10:50pm UTC](https://forum.arduino.cc/t/keypad-numericals-ok-now-letters-how-to/1128871/4 "2023-05-19T22:50:38Z")

</div>

here's code i put into and customize in almost all programs to help debug, exercise sub-functions or execute commands based on the value accumulated from numeric characters

```arduino
// pcRead - debugging using serial monitor

const char version [] = "PcRead 201114a";

int debug = 0;

// ---------------------------------------------------------
// toggle output bit
int
readString (
    char *s,
    int maxChar )
{
    int n = 0;

    Serial.print ("> ");
    do {
        if (Serial.available()) {
            int c = Serial.read ();

            if ('\n' == c)
                break;

            s [n++] = c;
            if (maxChar == n)
                break;
        }
    } while (true);

    return n;
}

// -----------------------------------------------------------------------------
// process single character commands from the PC
#define MAX_CHAR 10
char s [MAX_CHAR] = {};

int analogPin = 0;

void
pcRead (void)
{

    static int val = 0;

    if (Serial.available()) {
        int c = Serial.read ();

        switch (c) {
        case '0':
        case '1':
        case '2':
        case '3':
        case '4':
        case '5':
        case '6':
        case '7':
        case '8':
        case '9':
            val = c - '0' + (10 * val);
            break;

        case 'A':
            analogPin = val;
            Serial.print ("analogPin = ");
            Serial.println (val);
            val = 0;
            break;

        case 'D':
            debug ^= 1;
            break;

        case 'I':
            pinMode (val, INPUT);
            Serial.print ("pinMode ");
            Serial.print (val);
            Serial.println (" INPUT");
            val = 0;
            break;

        case 'O':
            pinMode (val, OUTPUT);
            Serial.print ("pinMode ");
            Serial.print (val);
            Serial.println (" OUTPUT");
            val = 0;
            break;

        case 'P':
            pinMode (val, INPUT_PULLUP);
            Serial.print ("pinMode ");
            Serial.print (val);
            Serial.println (" INPUT_PULLUP");
            val = 0;
            break;

        case 'a':
            Serial.print ("analogRead: ");
            Serial.println (analogRead (val));
            val = 0;
            break;

        case 'c':
            digitalWrite (val, LOW);
            Serial.print ("digitalWrite: LOW ");
            Serial.println (val);
            val = 0;
            break;

        case 'p':
#if !defined(ARDUINO_ARCH_ESP32)
            analogWrite (analogPin, val);
            Serial.print ("analogWrite: pin ");
            Serial.print (analogPin);
            Serial.print (", ");
            Serial.println (val);
            val = 0;
#endif
            break;

        case 'r':
            Serial.print ("digitalRead: pin ");
            Serial.print (val);
            Serial.print (", ");
            Serial.println (digitalRead (val));
            val = 0;
            break;

        case 's':
            digitalWrite (val, HIGH);
            Serial.print ("digitalWrite: HIGH ");
            Serial.println (val);
            val = 0;
            break;

        case 't':
            Serial.print ("pinToggle ");
            Serial.println (val);
            digitalWrite (val, ! digitalRead (val));
            val = 0;
            break;

        case 'v':
            Serial.print ("\nversion: ");
            Serial.println (version);
            break;

        case '\n': // ignore
            break;

        case '"':
            while ('\n' != Serial.read ()) // discard linefeed
                ;

            readString (s, MAX_CHAR-1);
            Serial.println (s);
            break;

        case '?':
            Serial.println ("\npcRead:\n");
            Serial.println (" [0-9] append to #");
            Serial.println (" A # - set analog pin #");
            Serial.println (" D # - set debug to #");
            Serial.println (" I # - set pin # to INPUT");
            Serial.println (" O # - set pin # to OUTPUT");
            Serial.println (" P # - set pin # to INPUT_PULLUP");
            Serial.println (" a # - analogRead (pin #)");
            Serial.println (" c # - digitalWrite (pin #, LOW)");
            Serial.println (" p # -- analogWrite (analogPin, #)");
            Serial.println (" r # - digitalRead (pin #)");
            Serial.println (" s - digitalWrite (pin #, HIGH)");
            Serial.println (" t -- toggle pin # output");
            Serial.println (" v - print version");
            Serial.println (" \" - read string");
            Serial.println (" ? - list of commands");
            break;

        default:
            Serial.print ("unknown char ");
            Serial.println (c,HEX);
            break;
        }
    }
}

// -----------------------------------------------------------------------------
void
loop (void)
{
    pcRead ();
}

// -----------------------------------------------------------------------------
void
setup (void)
{
    Serial.begin(115200);

    Serial.println (version);
#if defined(ARDUINO_ARCH_ESP32)
    Serial.println ("esp32");
#endif
}

```

---

<div class="post-metadata">

**Author:** ![brice3010](https://dub1.discourse-cdn.com/arduino/user_avatar/forum.arduino.cc/brice3010/32/912680_2.png) [@brice3010](https://forum.arduino.cc/u/brice3010)\
**Post date:** [May 20, 2023, 5:05am UTC](https://forum.arduino.cc/t/keypad-numericals-ok-now-letters-how-to/1128871/6 "2023-05-20T05:05:45Z")

</div>

@Delta_G : thank you for that suggestion;  
"else" will allow the processing for other keypad strokes than numerical ones.

However, I still need to store this non-numerical value into a different variable than the numerical.  
For that I use the fact that a numerical requires two strokes. Hence an additional if condition after the function call: if two strokes were made then store in numerical variable; if just one stroke was needed then another storage variable.

I add the resulting program below; if you would want to look over it to see whether a different approach would be better?

One error I cannot seem to get rid of is that either the value for i = 2 hence a numerical entry was made, or i = 5 hence a character entry was made. But whenever the first of two numericals was entered the display shows "no valid keypad entry".

1. how to get rid of that display after a correct numerical entry
2. would it be necessary at all to have this display to be shown in case of an invalid character?

```arduino
/*
  Read keypad: if number pressed then two keypad strokes required; else just one stroke
  Store keypad numerical entry for
     1. either turntable index position (moveTo)
     2. or store in EEPROM after 'A' is pressed
  Store character entry for:
     A = Assign current position eeprom for index position (to be entered)
     B = not assigned yet
     C = calibration of '0' index position
     D = not assigned yet
     # = no assigned yet
     * = not assigned yet

  How to input 2 digit numbers on keypad https://forum.arduino.cc/t/keypad-input-2-digit-numbers/604861

*/
#include "Wire.h"
#include "I2CKeyPad.h" // https://github.com/RobTillaart/I2CKeyPad
const uint8_t KEYPAD_ADDRESS = 0x38; // PCF8574 = 0x20 PCF8574AP = 0x38
char keys[] = "123A456B789C*0#DNF"; // N = NoKey, F = Fail (e.g. >1 keys pressed)
uint8_t i;
uint8_t ttMaxPos = 15; // maximum number of indexed turntable positions
I2CKeyPad keyPad(KEYPAD_ADDRESS);

///|||||||||||||||||||||||||||||||||||||||||||||||||||///
/// setup ///
///|||||||||||||||||||||||||||||||||||||||||||||||||||///

void setup() {
  Serial.begin(9600);
  Serial.println("DCCpp_turntable_controller_v3");
  Wire.begin();
  if (keyPad.begin() == false)
  {
    Serial.println("\nERROR: cannot communicate to keypad.\nPlease reboot.\n");
    while (1);
  }
}

///|||||||||||||||||||||||||||||||||||||||||||||||||||///
/// loop ///
///|||||||||||||||||||||||||||||||||||||||||||||||||||///

void loop() {
  uint8_t inputInt = 0;
  static bool keyPress = 0;
  static bool secNum = 0;
  static int myValue = 0;
  static uint8_t caseValue = 0;

  if (!keyPad.isPressed()) keyPress = true; // set flag keyPress: keypad released
  if (keyPad.isPressed () && keyPress == true) // execute only once
  {
    keyPress = false;
    myValue = getKeypadInteger(myValue); // read keypad being pressed
    Serial.print("myValue = ");
    Serial.println(myValue);
    Serial.print("i = ");
    Serial.println(i);
    if (i == 2) // 2 valid digits have been entered on keypad
    {
      i = 0;
      Serial.print("full value of two digits obtained : ");
      Serial.println(myValue);
      caseValue = myValue; // convert myValue to character
      myValue = 0;
      stepperAction(caseValue); // activate stepper use keypad keystroke to select corresponding new position
    }
    else if (i == 5) // a character or # or * was pressed
    {
      i = 0;
      char str = myValue; // convert number to character
      myValue = 0;
      Serial.print("letter obtained : ");
      Serial.println(str);
      stepperAction(str);
    }
    else
    {
      Serial.println("no valid keypad entry");
    }
  }
}

///|||||||||||||||||||||||||||||||||||||||||||||||||||///
/// get integer from keypad, 2 values ///
///|||||||||||||||||||||||||||||||||||||||||||||||||||///

int getKeypadInteger(int value)
{
  char keyVal = 0; // the key press
  bool isNum = 0;
  bool isLetter = 0;
  static int index = 0;
  do
  {
    index = keyPad.getKey(); // input the key
    keyVal = keys[index];
    isNum = (keyVal >= '0' && keyVal <= '9'); // is it a digit?
    if (isNum)
    {
      i = i + 1;
      //Serial.print(keyVal - '0');
      value = value * 10 + keyVal - '0'; // accumulate the input number
    }
    if (keyVal == 'A' || keyVal == 'B' || keyVal == 'C' || keyVal == 'D' || keyVal == '*' || keyVal == '#')
    {
      i = 5;
      value = keyVal;
    }
  }
  while ( !keyVal); // until not a digit or while no key pressed
  return value;
}

///|||||||||||||||||||||||||||||||||||||||||||||||||||///
/// keypad activated stepper ///
///|||||||||||||||||||||||||||||||||||||||||||||||||||///

void stepperAction(char keyStroke)
{
  // i = 0;
  switch (keyStroke)
  {
    case 01:
      {
      }
  }
}

```

---

<div class="post-metadata">

**Author:** ![gcjr](https://dub1.discourse-cdn.com/arduino/user_avatar/forum.arduino.cc/gcjr/32/314015_2.png) [@gcjr](https://forum.arduino.cc/u/gcjr)\
**Post date:** [May 20, 2023, 11:05am UTC](https://forum.arduino.cc/t/keypad-numericals-ok-now-letters-how-to/1128871/7 "2023-05-20T11:05:59Z")

</div>

shouldn't you have a function that returns the keypad character, not integer and then separate process values that '0'...'9', 'A'...'F' and '\*' and '#'.

the numeric characters can be used to accumulate a value -- `val = 10*val + c-'0'`, the '\*'/'#' either reset or process `val` and the non-digits are commands processed independently of one another

---

<div class="post-metadata">

**Author:** ![brice3010](https://dub1.discourse-cdn.com/arduino/user_avatar/forum.arduino.cc/brice3010/32/912680_2.png) [@brice3010](https://forum.arduino.cc/u/brice3010)\
**Post date:** [May 20, 2023, 11:25am UTC](https://forum.arduino.cc/t/keypad-numericals-ok-now-letters-how-to/1128871/8 "2023-05-20T11:25:20Z")

</div>

Do you mean that getKeypadInteger() should be used to return whatever is typed, and a separate process to separate integers from A...D and \* and # characters?

---

<div class="post-metadata">

**Author:** ![gcjr](https://dub1.discourse-cdn.com/arduino/user_avatar/forum.arduino.cc/gcjr/32/314015_2.png) [@gcjr](https://forum.arduino.cc/u/gcjr)\
**Post date:** [May 20, 2023, 11:45am UTC](https://forum.arduino.cc/t/keypad-numericals-ok-now-letters-how-to/1128871/9 "2023-05-20T11:45:30Z")

</div>

look this over

```arduino
#define MyHW
#ifdef MyHW
# include "sim.hh"
struct I2CKeyPad {
    I2CKeyPad (int x) { }
    bool begin (void) { return true; }
    int isPressed (void) { return Serial.available (); }
    char getKey (void) { return Serial.read (); }
};

#else
# include "Wire.h"
# include "I2CKeyPad.h" // https://github.com/RobTillaart/I2CKeyPad
#endif

const uint8_t KEYPAD_ADDRESS = 0x38; // PCF8574 = 0x20 PCF8574AP = 0x38
char keys[] = "123A456B789C*0#DNF"; // N = NoKey, F = Fail (e.g. >1 keys pressed)
I2CKeyPad keyPad (KEYPAD_ADDRESS);

int val;

// -----------------------------------------------------------------------------
void funcA (void) { Serial.println ( __func__ ); }
void funcB (void) { Serial.println ( __func__ ); }
void funcC (void) { Serial.println ( __func__ ); }
void funcD (void) { Serial.println ( __func__ ); }
void funcE (void) { Serial.println ( __func__ ); }

void funcMoveTT (
    int pos ) {
    Serial.print ( __func__ );
    Serial.print (": move TT to position ");
    Serial.println (pos);
}

// -----------------------------------------------------------------------------
char
getKeyChar (void)
{
    char cLst;
    if (! keyPad.isPressed ())
        return cLst = 0;

    char c = keyPad.getKey ();
 // c = keys [index];
    if (cLst == c)
        return 0;

    return cLst = c;
}

// -----------------------------------------------------------------------------
void loop ()
{
    char c = getKeyChar ();
    if (c) {
        Serial.println (c);

        switch (c) {
        case '0'...'9':
            val += 10*val + c-'0';
            break;

        case 'A':
            funcA();
            break;

        case 'B':
            funcB();
            break;

        case 'C':
            funcC();
            break;

        case 'D':
            funcD();
            break;

        case '#':
            funcMoveTT (val);
            val = 0;
            break;

        case '*':
            val = 0;
            break;
        }
    }
}

// -----------------------------------------------------------------------------
void setup ()
{
    Serial.begin (9600);
    Serial.println ("DCCpp_turntable_controller_v3");
    Wire.begin ();
    if (keyPad.begin () == false)
    {
        Serial.println ("\nERROR: cannot communicate to keypad.\nPlease reboot.\n");
        while (1)
            ;
    }
}

```

---

<div class="post-metadata">

**Author:** ![brice3010](https://dub1.discourse-cdn.com/arduino/user_avatar/forum.arduino.cc/brice3010/32/912680_2.png) [@brice3010](https://forum.arduino.cc/u/brice3010)\
**Post date:** [May 20, 2023, 12:30pm UTC](https://forum.arduino.cc/t/keypad-numericals-ok-now-letters-how-to/1128871/10 "2023-05-20T12:30:52Z")

</div>

Thanks greg... I knew it, one day I would have to deal with struct... LOL. That day has come..

---

<div class="post-metadata">

**Author:** ![gcjr](https://dub1.discourse-cdn.com/arduino/user_avatar/forum.arduino.cc/gcjr/32/314015_2.png) [@gcjr](https://forum.arduino.cc/u/gcjr)\
**Post date:** [May 20, 2023, 12:51pm UTC](https://forum.arduino.cc/t/keypad-numericals-ok-now-letters-how-to/1128871/11 "2023-05-20T12:51:02Z")

</div>

> [@brice3010](#):
>
> one day I would have to deal with struct... LOL.

sorry, you should change

> [@gcjr](#):
>
> `#define MyHW`

to

```arduino
#undef MyHW

```

i used a struct to simulate your keypad.

and

> [@gcjr](#):
>
> ` // c = keys [index];`

should be

```arduino
    c = keys [c];

```

---

<div class="post-metadata">

**Author:** ![system](https://dub1.discourse-cdn.com/arduino/user_avatar/forum.arduino.cc/system/32/1140315_2.png) [@system](https://forum.arduino.cc/u/system)\
**Post date:** [November 16, 2023, 12:51pm UTC](https://forum.arduino.cc/t/keypad-numericals-ok-now-letters-how-to/1128871/12 "2023-11-16T12:51:25Z")

</div>

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.
