按键扫描(KEYSCAN)¶
主要特性¶
支持最大的矩阵式按键为
12 X 20,支持最大的行列式按键为31 X 31,模式可配置按键扫描时钟可配置(10kzh - 128khz)按键扫描时间间隔可配置按键消抖时间可配置按键结束超时时间可配置按键FIFO阈值可配置按键中断类型使能可配置按键行列的使用数量可配置
功能设计¶
功能说明¶
KEYSCAN 设备数据结构¶
/**
* @brief KEYSCAN设备句柄
*/
typedef struct {
uint32_t regs; /*!< 基地址 */
uint32_t frequency; /*!< keyscan时钟频率 */
uint16_t wait_time; /*!< 扫描时间间隔, 单位(ms) */
uint16_t deb_time; /*!< 消除抖动时间, 单位(ms) */
uint32_t time_out; /*!< 超时时间, 单位(ms) */
uint8_t fifo_threshold; /*!< fifo 阈值 */
uint16_t fifo_th_timeout; /*!< fifo 阈值超时时间 , 单位(ms) */
uint8_t empty_frm_flag; /*!< 空帧不触发中断 , 如果设置不上报,在timeout时会一起上报,会影响按键单击和双击事件的延时触发 */
GX_HAL_KEYSCAN_SCAN_MODE ksc_mode; /*!< 扫描模式 */
uint8_t row_num; /*!< 按键行数 */
uint8_t col_num; /*!< 按键列数 */
GX_HAL_KEYSCAN_CALLBACK cb; /*!< 按键中断回调函数 >*/
} GX_HAL_KEYSCAN;
KEYSCAN 驱动配置初始化¶
矩阵式配置初始化¶
配置模式为矩阵模式 \ref GX_HAL_KEYSCAN_SCAN_MODE,配置基本按键时间参数,使用的行列数量等;
配置按键中断回调函数;
调用驱动初始化接口 \ref gx_hal_keyscan_init;
注册中断服务函数接口 \ref gx_request_irq;
使能模块驱动 gx_hal_keyscan_enable;
代码配置示例:
static GX_HAL_KEYSCAN dev = {
.regs = GX_REG_BASE_KEYSCAN,
.frequency = 32000,
.wait_time = 50,
.deb_time = 10,
.time_out = 1000,
.fifo_th_timeout = 200,
.empty_frm_flag = 1,
.fifo_threshold = 3,
.ksc_mode = GX_HAL_KEYSCAN_SCAN_MODE_MATRIX,
.row_num = 4,
.col_num = 4,
.cb = keyscan_process_keycode_callback;
};
static int keyscan_process_keycode_callback(void *pdata, unsigned int int_type)
{
uint32_t fifo_off = 0;
uint32_t key_value = 0, end_flag = 0;
GX_HAL_KEYSCAN *dev = (GX_HAL_KEYSCAN*)pdata;
if(dev == NULL)
return -1;
if(int_type == GX_HAL_KEYSCAN_INT_STATUS_FIFO_NOT_EMPTY ||
int_type == GX_HAL_KEYSCAN_INT_STATUS_FIFO_TH_OVERFLOW ||
int_type == GX_HAL_KEYSCAN_INT_STATUS_FIFO_TH_TIME_OUT ||
int_type == GX_HAL_KEYSCAN_INT_STATUS_TIMEOUT) {
fifo_off = gx_hal_keyscan_get_fifo_data_num(dev);
for(int i=0; i<fifo_off; i++) {
key_value = gx_hal_keyscan_read_fifo_data(dev);
}
}
}
static int keyscan_isr(int irq, void *pdata)
{
gx_hal_keyscan_irq_handler(irq, &dev);
return 0;
}
gx_hal_keyscan_init(&dev);
gx_request_irq(IRQ_NUM_KEYSCAN, keyscan_isr, NULL);
gx_hal_keyscan_enable(&dev);
行列式配置初始化¶
配置模式为行列模式 \ref GX_HAL_KEYSCAN_SCAN_MODE,配置基本按键时间参数,使用的行列数量等;
配置按键中断回调函数;
调用驱动初始化接口 \ref gx_hal_keyscan_init;
注册中断服务函数接口 \ref gx_request_irq;
使能模块驱动 gx_hal_keyscan_enable;
代码配置示例:
static GX_HAL_KEYSCAN dev = {
.regs = GX_REG_BASE_KEYSCAN,
.frequency = 32000,
.wait_time = 50,
.deb_time = 10,
.time_out = 1000,
.fifo_th_timeout = 200,
.empty_frm_flag = 1,
.fifo_threshold = 3,
.ksc_mode = GX_HAL_KEYSCAN_SCAN_MODE_DETERMINANT,
.row_num = 7,
.col_num = 7,
.cb = keyscan_process_keycode_callback;
};
static int keyscan_process_keycode_callback(void *pdata, unsigned int int_type)
{
uint32_t fifo_off = 0;
uint32_t key_value = 0, end_flag = 0;
GX_HAL_KEYSCAN *dev = (GX_HAL_KEYSCAN*)pdata;
if(dev == NULL)
return -1;
if(int_type == GX_HAL_KEYSCAN_INT_STATUS_FIFO_NOT_EMPTY ||
int_type == GX_HAL_KEYSCAN_INT_STATUS_FIFO_TH_OVERFLOW ||
int_type == GX_HAL_KEYSCAN_INT_STATUS_FIFO_TH_TIME_OUT ||
int_type == GX_HAL_KEYSCAN_INT_STATUS_TIMEOUT) {
fifo_off = gx_hal_keyscan_get_fifo_data_num(dev);
for(int i=0; i<fifo_off; i++) {
key_value = gx_hal_keyscan_read_fifo_data(dev);
}
}
}
static int keyscan_isr(int irq, void *pdata)
{
gx_hal_keyscan_irq_handler(&dev);
return 0;
}
gx_hal_keyscan_init(&dev);
gx_request_irq(IRQ_NUM_KEYSCAN, keyscan_isr, NULL);
gx_hal_keyscan_enable(&dev);
按键使用¶
配置完成后,可以进行按键操作,查看按键功能回调是否有对应键值上报。
接口使用说明¶
设置按键扫描时间间隔¶
通过 gx_hal_keyscan_set_wait_time 函数设置每轮按键扫描的时间间隔。代码使用示例:
static GX_HAL_KEYSCAN dev = {
.regs = GX_REG_BASE_KEYSCAN,
};
int time_ms = 50;
gx_hal_keyscan_set_wait_time(&dev, time_ms);
备注
间隔越短,扫描键值越灵敏。
设置按键消抖时间¶
通过 gx_hal_keyscan_set_deb_time 函数设置每轮按键扫描的消抖时间,消除在按键按下和抬起瞬间产生的毛刺。代码使用示例:
static GX_HAL_KEYSCAN dev = {
.regs = GX_REG_BASE_KEYSCAN,
};
int time_ms = 10;
gx_hal_keyscan_set_deb_time(&dev, time_ms);
重要
为避免被识别成键值,消抖时间要小于扫描时间间隔。
设置按键扫描结束超时时间¶
通过 gx_hal_keyscan_set_timeout 函数设置每轮按键扫描结束后的无键按下的超时时间,超时后认为一轮按键的结束。代码使用示例:
static GX_HAL_KEYSCAN dev = {
.regs = GX_REG_BASE_KEYSCAN,
};
int time_ms = 1000;
gx_hal_keyscan_set_timeout(&dev, time_ms);
设置按键 FIFO 阈值¶
通过 gx_hal_keyscan_set_fifo_threshold 函数设置按键 FIFO 阈值,当按键键值数量超过阈值时会上报按键阈值中断。代码使用示例:
static GX_HAL_KEYSCAN dev = {
.regs = GX_REG_BASE_KEYSCAN,
};
int fifo_th = 8;
gx_hal_keyscan_set_fifo_threshold(&dev, fifo_th);
设置按键 FIFO 阈值超时时间¶
通过 gx_hal_keyscan_set_fifo_th_timeout 函数设置按键 FIFO 阈值中断响应超时时间,当在该时间内按键阈值中断没有被响应时上报阈值超时中断。代码使用示例:
static GX_HAL_KEYSCAN dev = {
.regs = GX_REG_BASE_KEYSCAN,
};
int time_ms = 1000;
gx_hal_keyscan_set_fifo_th_timeout(&dev, time_ms);
设置按键管脚使能¶
通过 gx_hal_keyscan_pin_enable 函数设置启用按键的 row 和 col 管脚数。代码使用示例:
static GX_HAL_KEYSCAN dev = {
.regs = GX_REG_BASE_KEYSCAN,
};
int row = 4; // 表示使用 row1 - row4
int col = 4; // 表示使用 col1 - col4
gx_hal_keyscan_pin_enable(&dev, row, col);
设置按键管脚失能¶
通过 gx_hal_keyscan_pin_disable 函数设置关闭按键的 row 和 col 管脚数。代码使用示例:
static GX_HAL_KEYSCAN dev = {
.regs = GX_REG_BASE_KEYSCAN,
};
int row = 4; // 表示使用 row1 - row4
int col = 4; // 表示使用 col1 - col4
gx_hal_keyscan_pin_disable(&dev, row, col);
设置按键中断使能¶
通过 gx_hal_keyscan_interrupt_enable 函数使能按键中断。有 5 种类型的中断 \ref GX_HAL_KEYSCAN_INT_TYPE:
按键 FIFO 有值中断 1
按键 FIFO 阈值中断 2
按键 FIFO 阈值超时中断 3
按键 FIFO 溢出中断 4
按键超时中断 5
代码使用示例:
static GX_HAL_KEYSCAN dev = {
.regs = GX_REG_BASE_KEYSCAN,
};
GX_HAL_KEYSCAN_INT_TYPE type = GX_HAL_KEYSCAN_INT_STATUS_FIFO_NOT_EMPTY; /*!< FIFO 有值中断 1 */
gx_hal_keyscan_interrupt_enable(&dev, type);
设置按键中断失能¶
通过 gx_hal_keyscan_interrupt_disable 函数失能按键中断。代码使用示例:
static GX_HAL_KEYSCAN dev = {
.regs = GX_REG_BASE_KEYSCAN,
};
GX_HAL_KEYSCAN_INT_TYPE type = GX_HAL_KEYSCAN_INT_STATUS_FIFO_NOT_EMPTY; /*!< FIFO 有值中断 1 */
gx_hal_keyscan_interrupt_disable(&dev, type);
读取按键 FIFO 中存储的数据个数¶
通过 gx_hal_keyscan_get_fifo_data_num 函数读取 FIFO 中数据个数。
代码使用示例:
static GX_HAL_KEYSCAN dev = {
.regs = GX_REG_BASE_KEYSCAN,
};
int num = gx_hal_keyscan_get_fifo_data_num(&dev);
每次读取按键 FIFO 中一个位宽的数据¶
通过 \ref gx_hal_keyscan_get_fifo_data 函数每次读取 FIFO 中一个位宽的数据。
代码使用示例:
static GX_HAL_KEYSCAN dev = {
.regs = GX_REG_BASE_KEYSCAN,
};
unsigned int data = gx_hal_keyscan_get_fifo_data(&dev);
清除按键 FIFO 中所有数据¶
通过 gx_hal_keyscan_clear_fifo 函数来清空 FIFO 。
代码使用示例:
static GX_HAL_KEYSCAN dev = {
.regs = GX_REG_BASE_KEYSCAN,
};
gx_hal_keyscan_clear_fifo(&dev);
按键卡键时屏蔽该行按键响应¶
通过 gx_hal_keyscan_set_stuck_flag 函数来设置需要屏蔽按键的行号。
备注
设置后,该行上所有的按键将都不会响应。
该行的按键扫描唤醒会继续触发,只是不会产生该行键值;如果需要屏蔽该行的按键扫描唤醒,则需要通过 PMU 来屏蔽掉该行的 IO 唤醒功能;
row 表示卡键的行号(行索引)
代码使用示例:
static GX_HAL_KEYSCAN dev = {
.regs = GX_REG_BASE_KEYSCAN,
};
int row = 1;
gx_hal_keyscan_set_stuck_flag(&dev, row);
设置按键空帧上报模式¶
通过 gx_hal_keyscan_set_empty_frm_flag 函数设置按键空帧上报模式,是否触发中断 1 来上报。
1 表示不触发中断 1 上报
0 表示会触发中断 1 上报
代码使用示例:
static GX_HAL_KEYSCAN dev = {
.regs = GX_REG_BASE_KEYSCAN,
};
int flag = 1; // 表示空帧键值不会触发中断1进行上报
gx_hal_keyscan_set_empty_frm_flag(&dev, flag);
设置按键模块使能¶
通过 gx_hal_keyscan_enable 函数使能按键模块。代码使用示例:
static GX_HAL_KEYSCAN dev = {
.regs = GX_REG_BASE_KEYSCAN,
};
gx_hal_keyscan_enable(&dev);
设置按键模块失能¶
通过 gx_hal_keyscan_disable 函数失能按键模块。代码使用示例:
static GX_HAL_KEYSCAN dev = {
.regs = GX_REG_BASE_KEYSCAN,
};
gx_hal_keyscan_disable(&dev);
参考代码¶
示例代码参考 keyscan.c

