Manual Mode
This sample application note describes KeyScan manual scan mode to implement matrix keyboard scanning.
Key press debounce and key release debounce are realized by a software timer.
When the single scan is completed, the Keyscan scan end interrupt is entered and the key information is read within the interrupt handler function.

KeyScan Manual Mode Diagram
Requirements
For requirements, please refer to the Requirements.
Wiring
The EVB is connected to a matrix keyboard module, connect P2_3 to ROW0, P2_4 to ROW1, P4_0 to COLUMN0, and P4_1 to COLUMN1.
External matrix keyboard is shown below:

External Matrix keyboard
Configurations
The following macro can be configured to modify the pin definitions.
#define KEYBOARD_ROW_0 P2_3 #define KEYBOARD_ROW_1 P2_4 #define KEYBOARD_COLUMN_0 P4_0 #define KEYBOARD_COLUMN_1 P4_1
The following macros can be configured to modify the timing duration of the software timer.
#define KEYSCAN_SW_INTERVAL (200)/* 200ms */ #define KEYSCAN_SW_RELEASE_TIMEOUT (10)/* 10ms */
Building and Downloading
For building and downloading, please refer to the Building and Downloading.
Experimental Verification
When the EVB starts, observe the following log within the Debug Analyzer.
Start keyscan manual test!
Initialize the keyscan software timer, print log.
[io_keyscan] timer_keyscan_init: keyscan timer init
When a key is pressed, Keyscan starts scan. After the scan ends, it enters the Keyscan interrupt and prints the key information. If a key remains pressed continuously, it will keep printing the key information.
If a single key press is detected, print the following log.
[io_keyscan] io_keyscan_handle_keys: Single key press. key: (x, x)
If two key presses are detected, print the following log.
[io_keyscan] io_keyscan_handle_keys: Two key press. key0: (x, x), key1: (x, x)
After all the keys are released, print the following log within the callback function of the software timer.
[io_keyscan] io_keyscan_handle_keys: All keys released.
Code Overview
This section introduces the code and process description for initialization and corresponding function implementation in the sample.
Source Code Directory
The directory for project file and source code are as follows:
Project directory:
sdk\samples\peripheral\keyscan\keyscan_manual\proj
Source code directory:
sdk\samples\peripheral\keyscan\keyscan_manual\src
Initialization
The initialization flow for peripherals can refer to Initialization Flow in General Introduction.
Call
Pad_Config()
andPinmux_Config()
to configure the PAD and PINMUX of the corresponding pins.void board_keyboard_init(void) { /* Keypad pad config */ Pad_Config(KEYBOARD_ROW_0, PAD_PINMUX_MODE, PAD_IS_PWRON, PAD_PULL_UP, PAD_OUT_DISABLE, PAD_OUT_LOW); Pad_Config(KEYBOARD_ROW_1, PAD_PINMUX_MODE, PAD_IS_PWRON, PAD_PULL_UP, PAD_OUT_DISABLE, PAD_OUT_LOW); Pad_Config(KEYBOARD_COLUMN_0, PAD_PINMUX_MODE, PAD_IS_PWRON, PAD_PULL_NONE, PAD_OUT_ENABLE, PAD_OUT_LOW); Pad_Config(KEYBOARD_COLUMN_1, PAD_PINMUX_MODE, PAD_IS_PWRON, PAD_PULL_NONE, PAD_OUT_ENABLE, PAD_OUT_LOW); /* keypad pinmux config */ Pinmux_Config(KEYBOARD_ROW_0, KEY_ROW_0); Pinmux_Config(KEYBOARD_ROW_1, KEY_ROW_1); Pinmux_Config(KEYBOARD_COLUMN_0, KEY_COL_0); Pinmux_Config(KEYBOARD_COLUMN_1, KEY_COL_1); }
Call
RCC_PeriphClockCmd()
to enable the KeyScan clock.Initialize the KeyScan peripheral:
Define the
KEYSCAN_InitTypeDef
typeKEYSCAN_InitStruct
, and callKEYSCAN_StructInit
to pre-fillKEYSCAN_InitStruct
with default values.Modify the
KEYSCAN_InitStruct
parameters as needed. The KeyScan initialization parameter configuration is shown in the table below.Call
KeyScan_Init()
to initialize the KeyScan peripheral.
KeyScan Hardware Parameters |
Setting in the |
KeyScan |
---|---|---|
Row Size |
2 |
|
Column Size |
2 |
|
Scan Mode |
||
Debounce Enable |
Configure the KeyScan scan end interrupt:
KEYSCAN_INT_SCAN_END
, and configure the NVIC. For NVIC-related configuration, refer to Interrupt Configuration.Call
KeyScan_Cmd()
to enable KeyScan scanning.Call the
os_timer_create
function to create a software timer with a timing interval ofKEYSCAN_SW_INTERVAL
to simulate the interval between two scans.os_timer_create(&KeyScan_Timer_Handle, "keyscan_timer", 1, KEYSCAN_SW_INTERVAL, false, timer_keyscan_callback);
Functional Implementation
The KeyScan scanning flow in this sample is shown in the figure:

KeyScan scanning flow
In this sample, KeyScan is configured in manual scan mode. The interval time and release time are simulated using a software timer to mimic the process of KeyScan automatic scan mode.
After initialization is complete, the
os_sched_start
function is executed to begin task scheduling.When a key is pressed, KeyScan triggers a manual scan. After a single scan is completed, it triggers a KeyScan single scan completion interrupt.
In the KeyScan interrupt function, during KeyScan interrupt handling, the
KeyScan_GetFifoDataNum()
andKeyScan_Read()
functions are called to read data from the KeyScan FIFO, and theKey_Pressed_Flag
is set totrue
to indicate that a key has been pressed.The
os_timer_restart
function is called to start the software timer, with the timer set toKEYSCAN_SW_INTERVAL
to simulate the interval time in the KeyScan automatic scan process.void KEYSCAN_Handler(void) { uint32_t fifo_length; if (KeyScan_GetFlagState(KEYSCAN, KEYSCAN_INT_FLAG_SCAN_END) == SET) { /* Read current keyscan interrupt status and mask interrupt */ KeyScan_INTMask(KEYSCAN, KEYSCAN_INT_SCAN_END, ENABLE); memset(&Current_Key_Data, 0, sizeof(KeyScan_Data_TypeDef)); /* KeyScan fifo not empty */ if (KeyScan_GetFlagState(KEYSCAN, KEYSCAN_FLAG_EMPTY) != SET) { fifo_length = (uint32_t)KeyScan_GetFifoDataNum(KEYSCAN); KeyScan_Read(KEYSCAN, (uint16_t *)&Current_Key_Data.key[0], fifo_length); Current_Key_Data.length = fifo_length; Key_Pressed_Flag = true; /* Start sw timer to check press status */ if (!os_timer_restart(&KeyScan_Timer_Handle, KEYSCAN_SW_INTERVAL)) { APP_PRINT_ERROR0("[io_keyscan] Keyscan_Handler: Restart keyscan_timer failed!"); /* Set flag to default status and reinit keyscan module with debounce enabled */ global_data_keyscan_init(); driver_keyboard_init(ENABLE); return; } ... } KeyScan_ClearINTPendingBit(KEYSCAN, KEYSCAN_INT_SCAN_END); KeyScan_INTMask(KEYSCAN, KEYSCAN_INT_SCAN_END, DISABLE); } }
When the software timer reaches the set time (
KEYSCAN_SW_INTERVAL
time), check the status ofKey_Pressed_Flag
in the callback function.If
Key_Pressed_Flag
istrue
, it indicates that a key was pressed during the last scan and the scan interval time has elapsed. In the callback function, setKey_Pressed_Flag
tofalse
, reinitialize KeyScan for scanning, and start the timer forKEYSCAN_SW_RELEASE_TIMEOUT
to simulate the all release time.If
Key_Pressed_Flag
isfalse
, it indicates that after theKEYSCAN_SW_RELEASE_TIMEOUT
time has passed, the callback function is entered again, and no keys are pressed, meaning all keys have been released. Clear the key information, reinitialize KeyScan, and start a new round of scanning.
void timer_keyscan_callback(void *p_xTimer) { if (true == Key_Pressed_Flag) { Key_Pressed_Flag = false; driver_keyboard_init(ENABLE); /* Start timer to check key status */ os_timer_restart(&p_xTimer, KEYSCAN_SW_RELEASE_TIMEOUT); } else { global_data_keyscan_init(); driver_keyboard_init(ENABLE); } }
After the
KEYSCAN_SW_RELEASE_TIMEOUT
timer is activated, if a key state is detected during this period, the KeyScan interrupt function will be triggered again. Within the interrupt function, theKEYSCAN_SW_INTERVAL
timer will be restarted to override theKEYSCAN_SW_RELEASE_TIMEOUT
timing. During theKEYSCAN_SW_INTERVAL
timer period, since KeyScan is not reinitialized, a key press will not trigger a scan.