HD44780 + 4x3 Keypad Matrix

Hello! I have a 4x3 alphanumeric keypad matrix that has 7pins on in and a 16x2 HD44780 LCD. I want the keypad to act as a cellphone keypad. I got a keypad library installed already and used one of the example which is the Dynamic Keypad wherein you can swap the keymaps between numbers and letters. I got it working but not the way that I want. When in letter mode, say in key '2', this has 3 characters, 'abc'... pressing this key will first display 'a', if you press again it will display 'b'..then 'c'...then it will go back to 'a'.. all of these characters will be displayed ('abcabc')! What I want is if I pressed twice, it will only display 'b' and not 'ab' and if pressed thrice only 'c' and therefore I can select which character to be displayed on the LCD.

Here's the code:

// Define the keymaps.
char alphaKeys[4][3] = {
    { '.','a','d' },
    { 'g','j','m' },
    { 'p','t','w' },
    { 'C',' ','#' }
};
char numberKeys[4][3] = {
    { '1','2','3' },
    { '4','5','6' },
    { '7','8','9' },
    { ' ','0','#' }
};
boolean alpha = false;   // Start with the numeric keypad.

char* keypadMap = (alpha == true) ? makeKeymap(alphaKeys) : makeKeymap(numberKeys);

// Connect keypad ROW0, ROW1, ROW2 and ROW3 to these pins, eg. ROW0 = Arduino pin2.
byte rowPins[] = { 11,6,7,9};
// Connect keypad COL0, COL1 and COL2 to these pins, eg. COL0 = Arduino pin6.
byte colPins[] = { 10,12,8 };

//create a new Keypad
Keypad keypad = Keypad(keypadMap, rowPins, colPins, sizeof(rowPins), sizeof(colPins));

const byte ledPin = 13;                                                  // Use the LED on pin 13.

void setup() {
    //Serial.begin(9600);
    digitalWrite(ledPin, HIGH);                                                // Turns the LED on.
    keypad.addEventListener(keypadEvent);                                      // Add an event listener.
    keypad.setHoldTime(500);                                                   // Default is 1000mS
    keypad.setDebounceTime(50);                                               // Default is 50mS
    
    lcd.begin(16,2);
}

void loop() {
    char key = keypad.getKey();
   
    if (alpha) {                      // Flash the LED if we are using the letter keymap.
        digitalWrite(ledPin,!digitalRead(ledPin));
        delay(100);
    }
}

// Take care of some special events.
void keypadEvent(KeypadEvent key) {
    static char virtKey = NO_KEY;      // Stores the last virtual key press. (Alpha keys only)
    static char physKey = NO_KEY;      // Stores the last physical key press. (Alpha keys only)
    static char buildStr[12];
    static byte buildCount;
    static byte pressCount;

    switch (keypad.getState())
    {
    case PRESSED:
        if (isalpha(key)) {              // This is a letter key so we're using the letter keymap.
            if (physKey != key) {        // New key so start with the first of 3 characters.
                pressCount = 0;
                virtKey = key;
                physKey = key;
            }
            else {                       // Pressed the same key again...
                virtKey++;               // so select the next character on that key.
                pressCount++;            // Tracks how many times we press the same key.
            }           
            if (key == 'p' || key == 'w') {                 
              if (pressCount >3) {
                pressCount=0;
                virtKey=key;
              }              
            }
            else {              
              if (pressCount > 2) {        // Last character reached so cycle back to start.
                pressCount = 0;
                virtKey = key;
              }
            } 
            //Serial.print(virtKey);       // Used for testing.
            lcd.setCursor(0,1);
            lcd.print(virtKey);
        }
        if (isdigit(key) || key == ' ' || key == '.')  
          //Serial.print(key); 
          lcd.print(key);
        if (key == '#')  //Serial.println();
        break;

    case HOLD:
        if (key == '#')  {                   // Toggle between keymaps.
            if (alpha == true)  {            // We are currently using a keymap with letters
                keypad.begin(*numberKeys);   // and want to change to numbers.
                alpha = false;
            }
            else  {                          // Or, we are currently using a keymap with numbers
                keypad.begin(*alphaKeys);    // and want to change to letters.
                alpha = true;
            }
        }
        else  {                             // Some key other than '#' was pressed.
            buildStr[buildCount++] = (isalpha(key)) ? virtKey : key;
            buildStr[buildCount] = '\0';
            //Serial.println();
            //Serial.println(buildStr);
        }
        break;

    case RELEASED:
        if (buildCount >= sizeof(buildStr))  buildCount = 0;    // Our string is full. Start fresh.
        break;

    }  // end switch-case
}  // end keypad events

What I want is if I pressed twice, it will only display 'b' and not 'ab' and if pressed thrice only 'c' and therefore I can select which character to be displayed on the LCD.

So, don't print the value every time a key is pressed.

Putting each { on a new line, and indenting all the code between the { and } would help you see the structure of the keypadEvent code.

What I want is if I pressed twice, it will only display 'b' and not 'ab' and if pressed thrice only 'c' and therefore I can select which character to be displayed on the LCD.

Isn't what you really want is that when pressed once it will display an 'a', if pressed twice it will display a 'b' where the 'a' used to be, and if pressed three times it will display a 'c' where the 'a' and 'b' used to be? If so then you will have to reposition the cursor before displaying each new character.

Don

Do a search for "multitap", liudr has that cellphone type code running with an LCD display all worked out.

brutal_magnet:

floresta: ...

Isn't what you really want is that when pressed once it will display an 'a', if pressed twice it will display a 'b' where the 'a' used to be, and if pressed three times it will display a 'c' where the 'a' and 'b' used to be? If so then you will have to reposition the cursor before displaying each new character.

Exactly, just like the behavior of a cellphone keypad when you're creating sms. I just don't know how to do that.

Well you set the cursor in the sketch:

            lcd.setCursor(0,1);

Just do something like: if I get the same keypress in a row, reposition the cursor to where it was, and display (the new character) over the previous character.

I got another problem. How am I going to store 5 inputs from the keypad to a char array? Say typing '12345' will be stored in a char number[5], so if I do lcd.print(number), it will display '12345'

Typically you would decide the maximum amount you need (say, 20 digits). So make an array:

char number [20];

To print a variable-length string you normally have it "null-terminated" which means after the final character is a zero.

(Note: because of this the above array would actually only hold 19 digits. Change the 20 to 21, to hold 20 digits, plus the terminator).

To "empty" the string you put zero at the start, eg.

number [0] = 0;

Then to add numbers you do strcat, eg.

strcat (number, "2");

Be careful not to add more than you have room for. The strcat function "moves" the terminator along.

If you get the same digit twice in a row, you could replace the last character. Eg. to find how much you have there:

int i = strlen (number);  // find length of number

This is 1-relative, but arrays are zero-relative. So to replace the last digit you would do:

number [i - 1] = 'a';

That's the general idea. There are other ways of doing it. Read up on C and strings, including null terminators, strcat, strcpy, zero-relative, that sort of thing.