Embedded system applications usually require large number of buttons
connected (ex. calculator, cell phone). Keypad is one of the input
device that commonly used in embedded system that require large number
of buttons. 4x4 matrix keypad have 16 buttons. We can connect this buttons
directly to GPIO pin, but it will eat up precious GPIO pin (If we have
16 buttons, then we need 16 GPIO pins). To avoid this trouble, keypad
use technique that will save GPIO pin. In this technique, buttons are
connected in a matrix (row/column) style.
The internal connection of the buttons in 4x4 matrix keypad is like this:
From image above, for example if S8 is pressed, then Col 1 and Row 2 is connected. We can detect this by using a microcontroller. The microcontroller must scan every columns then on each column, read the rows value.
To connect this keypad to the microcontroller, we need 8 GPIO pins. The column pins is connected to the GPIO pins as open drain output. The row pins is connected to the GPIO pins as input with internal pull-up resistor. Every each column scan, the column pin is set to logic 0 (GND), the other column pins is in HI-Z (floating) condition. So, when no button pressed in this column, then all row pins will receive logic 1 because of pull-up resistor. When there is a button pressed on this column, then the corresponding row pin for that button will receive logic 0, because the current from pull-up resistor will flow to column pin.
This is the function for read key press:
uint8_t KeypadGetKey() { // Scan column 0 (column 0 pin is grounded, other column pins // is open drain) GPIO_ResetBits(KEYPAD_GPIO_COL, KEYPAD_PIN_COL0); GPIO_SetBits(KEYPAD_GPIO_COL, KEYPAD_PIN_COL1); GPIO_SetBits(KEYPAD_GPIO_COL, KEYPAD_PIN_COL2); GPIO_SetBits(KEYPAD_GPIO_COL, KEYPAD_PIN_COL3); DelayUs(1); // Read rows if (!GPIO_ReadInputDataBit(KEYPAD_GPIO_ROW, KEYPAD_PIN_ROW0)) return '1'; if (!GPIO_ReadInputDataBit(KEYPAD_GPIO_ROW, KEYPAD_PIN_ROW1)) return '4'; if (!GPIO_ReadInputDataBit(KEYPAD_GPIO_ROW, KEYPAD_PIN_ROW2)) return '7'; if (!GPIO_ReadInputDataBit(KEYPAD_GPIO_ROW, KEYPAD_PIN_ROW3)) return '*'; // Scan column 1 (column 1 pin is grounded, other column pins // is open drain) GPIO_SetBits(KEYPAD_GPIO_COL, KEYPAD_PIN_COL0); GPIO_ResetBits(KEYPAD_GPIO_COL, KEYPAD_PIN_COL1); GPIO_SetBits(KEYPAD_GPIO_COL, KEYPAD_PIN_COL2); GPIO_SetBits(KEYPAD_GPIO_COL, KEYPAD_PIN_COL3); DelayUs(1); // Read rows if (!GPIO_ReadInputDataBit(KEYPAD_GPIO_ROW, KEYPAD_PIN_ROW0)) return '2'; if (!GPIO_ReadInputDataBit(KEYPAD_GPIO_ROW, KEYPAD_PIN_ROW1)) return '5'; if (!GPIO_ReadInputDataBit(KEYPAD_GPIO_ROW, KEYPAD_PIN_ROW2)) return '8'; if (!GPIO_ReadInputDataBit(KEYPAD_GPIO_ROW, KEYPAD_PIN_ROW3)) return '0'; // Scan column 2 (column 2 pin is grounded, other column pins // is open drain) GPIO_SetBits(KEYPAD_GPIO_COL, KEYPAD_PIN_COL0); GPIO_SetBits(KEYPAD_GPIO_COL, KEYPAD_PIN_COL1); GPIO_ResetBits(KEYPAD_GPIO_COL, KEYPAD_PIN_COL2); GPIO_SetBits(KEYPAD_GPIO_COL, KEYPAD_PIN_COL3); DelayUs(1); // Read rows if (!GPIO_ReadInputDataBit(KEYPAD_GPIO_ROW, KEYPAD_PIN_ROW0)) return '3'; if (!GPIO_ReadInputDataBit(KEYPAD_GPIO_ROW, KEYPAD_PIN_ROW1)) return '6'; if (!GPIO_ReadInputDataBit(KEYPAD_GPIO_ROW, KEYPAD_PIN_ROW2)) return '9'; if (!GPIO_ReadInputDataBit(KEYPAD_GPIO_ROW, KEYPAD_PIN_ROW3)) return '#'; // Scan column 3 (column 3 pin is grounded, other column pins // is open drain) GPIO_SetBits(KEYPAD_GPIO_COL, KEYPAD_PIN_COL0); GPIO_SetBits(KEYPAD_GPIO_COL, KEYPAD_PIN_COL1); GPIO_SetBits(KEYPAD_GPIO_COL, KEYPAD_PIN_COL2); GPIO_ResetBits(KEYPAD_GPIO_COL, KEYPAD_PIN_COL3); DelayUs(1); // Read rows if (!GPIO_ReadInputDataBit(KEYPAD_GPIO_ROW, KEYPAD_PIN_ROW0)) return 'A'; if (!GPIO_ReadInputDataBit(KEYPAD_GPIO_ROW, KEYPAD_PIN_ROW1)) return 'B'; if (!GPIO_ReadInputDataBit(KEYPAD_GPIO_ROW, KEYPAD_PIN_ROW2)) return 'C'; if (!GPIO_ReadInputDataBit(KEYPAD_GPIO_ROW, KEYPAD_PIN_ROW3)) return 'D'; return KEYPAD_NO_PRESSED; }
The simple way to use this function is with polling method until a key is pressed. This is a simple program to get a key pressed and display that character to the LCD 16x2:
#include "stm32f10x.h" #include "stm32f10x_rcc.h" #include "stm32f10x_gpio.h" #include "delay.h" #include "lcd16x2.h" #include "keypad4x4-scanning.h" uint8_t key; int main(void) { DelayInit(); lcd16x2_init(LCD16X2_DISPLAY_ON_CURSOR_OFF_BLINK_OFF); KeypadInit(); while (1) { // Get key pressed key = KeypadGetKey(); // Display pressed char to LCD if (key != KEYPAD_NO_PRESSED) { lcd16x2_gotoxy(0, 0); lcd16x2_putc(key); DelayMs(250); } } }
Very helpful blogging. Already I’ve visited several posts about membrane keypad on the web. All the posts are very effective. I’d like to see more such beautiful posts from you.
ReplyDeleteThanks for explaining membrane keypad with coding.Sure it will helpful for a using matrix keypads.
ReplyDeleteI want to ask, how to program the stm32f4 discovery, 4x4 keypad and I2C with LCD? I tried it but there are always lots of bugs
ReplyDeleteThanks alot for the code
ReplyDeleteThanks for sharing,get an best membrane keypadfor affordable prices.
ReplyDelete