Manual Mode
该示例通过使用Keyscan的手动扫描模式,实现矩阵键盘的扫描。
示例中Key press debounce及key release debounce使用软件定时器实现。
当单次扫描完成时,进入Keyscan单次扫描完成中断,在中断处理函数内进行按键信息读取。
环境需求
该示例支持以下开发套件:
Hardware Platforms |
Board Name |
---|---|
RTL87x2G HDK |
RTL87x2G EVB |
更多信息请参考快速入门。
硬件连线
EVB外接矩阵键盘,连接P2_3和ROW0,P2_4和ROW1,P4_0和COLUMN0,P4_1和COLUMN1。
外接矩阵键盘的原理图如下图所示:
编译和下载
该示例的工程路径如下:
Project file: samples\peripheral\keyscan\keyscan_manual\proj\rtl87x2g\mdk
Project file: samples\peripheral\keyscan\keyscan_manual\proj\rtl87x2g\gcc
请按照以下步骤操作构建并运行该示例:
打开工程文件。
按照 快速入门 中 编译APP Image 给出的步骤构建目标文件。
编译成功后,在路径
mdk\bin
或gcc\bin
下会生成 app binapp_MP_xxx.bin
文件。按下复位按键,开始运行。
测试验证
EVB启动后,在Debug Analyzer工具内观察log。
Start keyscan manual test!
初始化软件定时器,打印log。
[io_keyscan] timer_keyscan_init: keyscan timer init
当检测到按键按下后,打印按键信息。
若检测到单个按键按下,打印如下log。
[io_keyscan] io_keyscan_handle_keys: Single key press. key: (x, x)
若检测到两个按键按下,打印如下log。
[io_keyscan] io_keyscan_handle_keys: Two key press. key0: (x, x), key1: (x, x)
当按键全部松开后,打印如下log。
[io_keyscan] io_keyscan_handle_keys: All keys release.
代码介绍
该章节分为以下几个部分:
源码路径
工程路径:
sdk\samples\peripheral\keyscan\keyscan_manual\proj
源码路径:
sdk\samples\peripheral\keyscan\keyscan_manual\src
该工程的工程文件代码结构如下:
└── Project: keyscan_manual
└── secure_only_app
└── Device includes startup code
├── startup_rtl.c
└── system_rtl.c
├── CMSIS includes CMSIS header files
├── CMSE Library Non-secure callable lib
├── Lib includes all binary symbol files that user application is built on
└── rtl87x2g_io.lib
├── Peripheral includes all peripheral drivers and module code used by the application
├── rtl_rcc.c
├── rtl_pinmux.c
├── rtl_nvic.c
└── rtl_keyscan.c
└── APP includes the ble_peripheral user application implementation
├── main_ns.c
└── io_keyscan.c
初始化
初始化流程包括了 global_data_keyscan_init
board_keyboard_init
driver_keyboard_init
和 timer_keyscan_init
。
global_data_keyscan_init
中包含了对Keyscan按键信息存储数组的初始化。
board_keyboard_init
中包含了PAD与PINMIX设置。
配置PAD:设置引脚、PINMUX模式、PowerOn、内部上拉或无上拉。
配置PINMUX:分配引脚分别为KEY_ROW_0、KEY_ROW_1、KEY_COL_0、KEY_COL_1功能。
driver_keyboard_init
包含了对Keyscan外设的初始化。
使能PCC时钟。
配置Keyscan的rowSize和colSize为(2*2)。
配置扫描模式为Manual Mode。
使能Keyscan的硬件去抖功能。
配置Keyscan单次扫描结束中断
KEYSCAN_INT_SCAN_END
。
RCC_PeriphClockCmd(APBPeriph_KEYSCAN, APBPeriph_KEYSCAN_CLOCK, ENABLE);
...
KEYSCAN_InitStruct.rowSize = KEYBOARD_ROW_SIZE;
KEYSCAN_InitStruct.colSize = KEYBOARD_COLUMN_SIZE;
KEYSCAN_InitStruct.scanmode = KeyScan_Manual_Scan_Mode;
KEYSCAN_InitStruct.debounceEn = ENABLE;
...
KeyScan_INTConfig(KEYSCAN, KEYSCAN_INT_SCAN_END, ENABLE);
...
timer_keyscan_init
包含了对软件定时器的初始化。
执行
os_timer_create
函数,创建软件定时器,定时时间为200ms,定时结束后执行timer_keyscan_callback
回调函数,用于模拟Keyscan按键按下的Debounce。
os_timer_create(&KeyScan_Timer_Handle, "keyscan_timer", 1, KEYSCAN_SW_INTERVAL, false, timer_keyscan_callback);
功能实现
程序开始会启动一个200ms的软件定时器并使能Keyscan外设进行一次手动扫描。扫描结束后会进入单次扫描结束中断。如果检测到有按键按下,则将Key_Pressed_Flag置1,重启200ms定时器,重新使能Keyscan开始下一次扫描。
重复上述过程,当200ms定时器到期后,重新启动10ms的软件定时器用于模拟按键松开去抖。10ms定时器到期后判断Key_Pressed_Flag,如果为0代表扫描到所有按键松开,反之则仍有按键按下。
初始化完毕之后,执行
os_sched_start
函数,开始任务调度。当有按键按下时,开启手动扫描模式。当单次扫描完成后,进入Keyscan中断函数。
屏蔽Keyscan单次扫描结束中断。
执行
KeyScan_GetFifoDataNum()
,读取Keyscan FIFO中的数据长度。执行
KeyScan_Read()
,读取Keyscan FIFO中的数据内容。将
Key_Pressed_Flag
置为true
,表明当前有按键按下。重启软件定时器,定时时间为200ms,继续检测按键按下信息,模拟按下Debounce功能。
打印Keyscan按键信息。
开启Keyscan单次扫描结束中断。
KeyScan_INTMask(KEYSCAN, KEYSCAN_INT_SCAN_END, ENABLE);
fifo_length = (uint32_t)KeyScan_GetFifoDataNum(KEYSCAN);
KeyScan_Read(KEYSCAN, (uint16_t *)&Current_Key_Data.key[0], fifo_length);
Key_Pressed_Flag = true;
if (!os_timer_restart(&KeyScan_Timer_Handle, KEYSCAN_SW_INTERVAL))
{
...
}
...
KeyScan_INTMask(KEYSCAN, KEYSCAN_INT_SCAN_END, DISABLE);
当200ms定时结束时,进入回调函数
timer_keyscan_callback
,检测flag标志位Key_Pressed_Flag
。如果flag位为true,表明当前有按键按下。
将flag位置为false。
执行
driver_keyboard_init
,重新初始化Keyscan,使能Keyscan功能,重新启动键盘扫描。重启软件定时器,修改定时时间为10ms,模拟按键松开的debounce。
如果flag位为false,表明当前没有按键按下。
打印按键全部松开信息。
执行
global_data_keyscan_init
,初始化按键信息。执行
driver_keyboard_init
,重新初始化Keyscan。
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
{
/* Keyscan release event detected */
DBG_DIRECT("[io_keyscan] io_keyscan_handle_keys: All keys release.");
global_data_keyscan_init();
driver_keyboard_init(ENABLE);
}