矩阵键盘

支持的芯片[ RTL8721Dx ]

概述

矩阵键盘作为一款键盘扫描设备,其行列数可自由配置,最多支持 8 x 8 的键盘矩阵配置。

矩阵键盘支持以下功能:

  • 行数和列数可配置,适配不同大小的按键阵列

  • 支持多键检测,最多可同时按下 6 个按键

  • 支持两种工作模式:事件触发模式和常规扫描模式

  • 支持按键卡滞检测

  • 支持低功耗模式及唤醒功能

系统框图

矩阵键盘的框图如下所示:

../../_images/key_scan_block_diagram.svg

矩阵键盘主要包含 5 个功能模块:

  • 中断控制:控制和管理中断

  • 寄存器及 FIFO:配置矩阵键盘参数和 FIFO

  • 时钟模块:131KHz 时钟用于检测按键卡滞和低功耗唤醒

  • 键盘控制:扫描控制、唤醒控制、按键输入/输出控制

  • GPIO 矩阵:16 个 GPIO 实现 8x8 阵列

键盘矩阵

矩阵键盘的行列可配置,支持的最大列数或行数均为 8。

../../_images/keypad_array.svg

8x8 键盘矩阵配置

按键被按下后,完整的扫描过程如下:

  • 初始状态下,所有列输出低电平,所有行设置为内部上拉输入。

  • 当有一个或多个按键按下(列与行之间短路)时,被按下按键所在行输入电平由高到低,此时会触发内部状态机启动进行键盘扫描,以确定被按下按键所在的行列。

  • 状态机先将第一列设为输出低电平,其他列设为高阻态,然后扫描所有行来判断哪些按键被按下;接着将第二列设为输出低电平,将所有其他列置于高阻态;重复该过程,直到扫描完最后一列。

  • 经过两次全键盘扫描,最终确认哪些按键被按下。

当所有按键被释放后,矩阵键盘仍会进行两轮全键盘扫描。当确认没有按键被按下后,结束扫描,停止状态机。

下图展示了 2 x 2 键盘按下按键后的扫描时序示意图。

../../_images/keyscan_scan_timing.svg

键盘扫描时序

键盘扫描过程中有三个计时器可配置:

  • 消抖计时:两次相邻的全键盘扫描组成一次完整的扫描周期,两次全键盘扫描之间都有一次消抖计时。而第一次全键盘扫描之前有一次额外的消抖计时。

  • 扫描间隔计时:两次完整的扫描周期之间需要等待扫描间隔计时器计时结束。

  • 所有按键释放计时:当所有按键被释放,矩阵键盘仍会有一次完整的扫描周期(两轮全键盘扫描),等扫描结束后确认无按键按下,释放计时器开始计时。等计时结束,状态机才会停止。

工作模式

矩阵键盘包含两种工作模式:事件触发模式和常规扫描模式。

工作模式

描述

事件触发模式

每次按键按下和松开操作,按键按下或松开事件在 FIFO 中仅记录一次

常规扫描模式

任何按键按下事件都会记录在 FIFO 中(仅记录按键按下事件),直到按键松开

下图展示了在按键按下和松开过程中,事件触发模式和常规扫描模式下 FIFO 的差异。

../../_images/difference_FIFO_items_between_two_work_modes.svg

通常情况下,事件触发模式较为常用。该模式下,按键无须连续扫描,仅在按键状态发生改变时扫描键盘。

FIFO 机制

矩阵键盘的 FIFO 深度为 16,宽度为 12 位。其结构如下所示:

../../_images/FIFO_structure.svg

功能

参数描述

[8]

事件

  • 1:按键按下事件

  • 0:按键松开事件

[7:4]

行索引

  • 1:第 0 行

  • 2:第 1 行

  • 3:第 2 行

  • 8:第 7 行

[3:0]

列索引

  • 1:第 0 列

  • 2:第 1 列

  • 3:第 2 列

  • 8:第 7 列

按键卡滞

在实际使用过程中可能会出现按键卡滞,如果按键未被及时松开,矩阵键盘状态机将持续进行扫描,无法进入 IDLE 状态。

为解决此问题,矩阵键盘支持自动检测按键卡滞的功能。

  • 卡滞键检测:启用该功能后,若按键卡滞时间超过设定的阈值,该按键将被视为卡滞按键,并触发卡滞按键中断,用户可在卡滞按键中断中屏蔽卡滞按键所在行。

  • 卡滞键屏蔽:通过读取按键卡滞状态寄存器获取卡滞的按键,并设置卡滞按键所在行的默认状态,矩阵键盘在扫描到该卡滞按键所在行时,会认为没有按键被按下,从而顺利进入 IDLE 状态。

  • 卡滞键屏蔽解除:有两种方法

    • 卡滞按键被释放后,将触发卡滞按键中断,用户可在该中断中解除卡滞按键所在行的屏蔽状态

    • 非卡滞按键所在行的按键被按下,此时触发扫描状态机,产生扫描中断,用户可在中断中解除卡滞按键所在行的屏蔽状态

备注

卡滞按键被屏蔽后:

  • 卡滞按键同一行的其他按键按下,不会触发矩阵键盘的扫描状态机

  • 非卡滞按键所在行的按键按下才能触发矩阵键盘的扫描状态机。在扫描状态机唤醒后,如果卡滞按键所在行的屏蔽状态未被解除,所在行的其他按键仍然无法被识别,非卡滞行按键正常识别。

用法

正常工作模式

使用矩阵键盘的事件触发模式或常规扫描模式,需执行以下步骤:

  1. 配置矩阵键盘的引脚复用功能。

    1. 将列引脚设置为无上下拉,并配置列引脚复用功能。

      PAD_PullCtrl(pad_colx, GPIO_PuPd_NOPULL);
      Pinmux_Config(pad_colx, PINMUX_FUNCTION_KEY_COLx);
      
    2. 将行引脚设置为上拉,并配置行引脚复用功能。

      PAD_PullCtrl(pad_rowx, GPIO_PuPd_UP);
      Pinmux_Config(pad_rowx, PINMUX_FUNCTION_KEY_ROWx);
      
  2. 初始化矩阵键盘参数。

    根据键盘选择按键行数和列数(一位对应一行或一列),并将工作模式设置为事件触发模式或常规扫描模式等。

    事件触发模式:
    KeyScan_StructInit(&KeyScan_InitStruct);
    KeyScan_InitStruct.KS_ColSel = 0xFF;  //8 列
    KeyScan_InitStruct.KS_RowSel = 0xFF;  //8 行
    KeyScan_InitStruct.KS_WorkMode = KS_EVENT_TRIGGER_MODE;
    KeyScan_Init(KeyScan, &KeyScan_InitStruct);
    
  3. 使能矩阵键盘中断,并注册矩阵键盘中断处理函数。

  4. 使能矩阵键盘。

    KeyScan_Cmd(KeyScan, ENABLE);
    
  5. 等待并处理矩阵键盘中断。

按键卡滞处理

当出现按键卡滞时,执行以下步骤:

  1. 配置矩阵键盘的引脚复用功能。

    1. 将列引脚设置为无上下拉,并配置列引脚复用功能。

      PAD_PullCtrl(pad_colx, GPIO_PuPd_NOPULL);
      Pinmux_Config(pad_colx, PINMUX_FUNCTION_KEY_COLx);
      
    2. 将行引脚设置为上拉,并配置行引脚复用功能。

      PAD_PullCtrl(pad_rowx, GPIO_PuPd_UP);
      Pinmux_Config(pad_rowx, PINMUX_FUNCTION_KEY_ROWx);
      
  2. 初始化矩阵键盘参数。

    根据键盘选择按键行数和列数(一位对应一行或一列),并将工作模式设置为常规扫描模式等。

    KeyScan_StructInit(&KeyScan_InitStruct);
    KeyScan_InitStruct.KS_ColSel = 0xFF;  //8 columns
    KeyScan_InitStruct.KS_RowSel = 0xFF;  //8 rows
    KeyScan_Init(KeyScan, &KeyScan_InitStruct);
    
  3. 使能矩阵键盘按键卡滞自动检测功能。

    KeyScan_StuckAutoCmd(KeyScan, ENABLE);
    
  4. 设置卡滞时间阈值,并配置卡滞行检测时间和间隔时间。

    KeyScan_SetStuckThreshold(KeyScan, 10);  //stuck time threshold: 10ms
    KeyScan_StuckPeriodicalPull(KeyScan,2000,4000);//pull time:2000us, no pull time:4000us
    
  5. 使能矩阵键盘按键卡滞和所有默认中断,并注册矩阵键盘中断处理函数。

  6. 使能矩阵键盘。

    KeyScan_Cmd(KeyScan, ENABLE);
    
  7. 等待并处理矩阵键盘中断。

    • 在按键卡滞事件中断中,获取行状态后,设置行默认状态以指示卡滞行,然后屏蔽卡滞行的所有按键。

      row_status = KeyScan_GetStuckRow(KeyScan);
      KeyScan_SetStuckRow(KeyScan, row_status);
      
    • 在所有默认中断中,将行默认状态重置为初始值,禁用所有默认中断,启用扫描事件中断和所有松开中断,这样除卡滞按键外的其他按键可正常工作。

      KeyScan_INTConfig(KeyScan, KS_BIT_ALL_DEFAULT_INT_MASK, DISABLE);
      KeyScan_SetStuckRow(KeyScan, 0);
      KeyScan_INTConfig(KeyScan, KS_BIT_ALL_RELEASE_INT_MASK | KS_BIT_SCAN_EVENT_INT_MASK, ENABLE);
      
  8. 除卡滞按键外,其他按键的按下或松开将正常产生相应中断。

Raw API

KSCAN Exported Types

struct KeyScan_InitTypeDef

KSCAN Init structure definition.

Public Members

u32 KS_ClkDiv

Specifies KeyScan clock divider. Scan_clk = Bus clock/(KS_ClkDiv+1). This parameter must be set to a value in the 0x0-0xfff range.

u32 KS_WorkMode

Specifies the KeyScan operating mode. This parameter can be a value of KSCAN Work Mode Definitions

u32 KS_RowSel

Specifies which rows are active. This parameter must be set to a value in the 0x1-0xff range.

u32 KS_ColSel

Specifies which columns are active. This parameter must be set to a value in the 0x1-0xff range.

u32 KS_DebounceCnt

Specifies the debounce counter value. Debounce timer = (KS_DebounceCnt + 1) * Scan_clk. This parameter must be set to a value in the 0x0-0xfff range.

u32 KS_IntervalCnt

Specifies the scan interval counter value. Interval timer = (KS_IntervalCnt + 1) * Scan_clk. This parameter must be set to a value in the 0x0-0xfff range.

u32 KS_ReleaseCnt

Specifies the all-release counter value. Release timer = (KS_ReleaseCnt + 1) * Scan_clk. This parameter must be set to a value in the 0x0-0xfff range.

u32 KS_LimitLevel

Specifies the maximum number of keys that can be pressed simultaneously. This parameter can be a value of KSCAN FIFO Limit Level Control

u32 KS_ThreholdLevel

Specifies the KeyScan FIFO threshold level for the KS_FIFO_FULL interrupt. This parameter can be a value of KSCAN FIFO Threshold Level Control

u32 KS_OverCtrl

Specifies KeyScan FIFO over control. This parameter can be a value of KSCAN FIFO Overflow Control

KSCAN Exported Constants

KSCAN All Interrupt Clear

/* Clear bits for all KSCAN interrupts. */
#define KS_BIT_ALL_INT_CLR (KS_BIT_ALL_DEFAULT_INT_CLR | \
    KS_BIT_STUCK_INT_CLR | \
    KS_BIT_FIFO_LIMIT_INT_CLR | \
    KS_BIT_FIFO_OV_INT_CLR | \
    KS_BIT_SCAN_FINISH_INT_CLR | \
    KS_BIT_ALL_RELEASE_INT_CLR)

KSCAN All Interrupt Mask

/* Mask bits for all KSCAN interrupts. */
#define KS_BIT_ALL_INT_MSK (KS_BIT_ALL_DEFAULT_INT_MASK | \
    KS_BIT_STUCK_EVENT_INT_MASK | \
    KS_BIT_SCAN_EVENT_INT_MASK | \
    KS_BIT_FIFO_LIMIT_INT_MASK | \
    KS_BIT_FIFO_OV_INT_MASK | \
    KS_BIT_FIFO_FULL_INT_MASK | \
    KS_BIT_SCAN_FINISH_INT_MASK | \
    KS_BIT_FIFO_NOTEMPTY_INT_MASK | \
    KS_BIT_ALL_RELEASE_INT_MASK)

KSCAN FIFO Limit Level Control

/* Check if FIFO limit level value is valid. */
#define IS_KS_FIFO_LIMIT_LEVEL ((DATA_NUM) <= 6)

KSCAN FIFO Overflow Control

/* Reject new data when FIFO full. */
#define KS_FIFO_OVER_CTRL_DIS_NEW ((u32)0x00000000)

/* Discard oldest data when FIFO full. */
#define KS_FIFO_OVER_CTRL_DIS_LAST ((u32)0x00000001)

/* Check if FIFO overflow control value is valid. */
#define IS_KS_FIFO_OVER_CTRL (((CTRL) == KS_FIFO_OVER_CTRL_DIS_NEW) || \
    ((CTRL) == KS_FIFO_OVER_CTRL_DIS_LAST))

KSCAN FIFO Threshold Level Control

/* Check if FIFO threshold level value is valid. */
#define IS_KS_FIFO_TH_LEVEL (((DATA_NUM) > 0) && ((DATA_NUM) < 16))

KSCAN Peripheral Definitions

/* Check if KSCAN peripheral is valid. */
#define IS_KEYSCAN_ALL_PERIPH ((PERIPH) == KEYSCAN_DEV || (PERIPH) == KEYSCAN_DEV_S)

KSCAN Work Mode Definitions

/* Regular scan mode selection. */
#define KS_REGULAR_SCAN_MODE ((u32)0x00000000)

/* Event trigger mode selection. */
#define KS_EVENT_TRIGGER_MODE ((u32)0x00000001)

/* Check if KSCAN work mode is valid. */
#define IS_KS_WORK_MODE (((MODE) == KS_REGULAR_SCAN_MODE) || \
    ((MODE) == KS_EVENT_TRIGGER_MODE))

KSCAN Exported Functions

void KeyScan_ClearFIFOData(KSCAN_TypeDef *KeyScan)

Clear the FIFO data.

参数:
  • KeyScan -- selected KeyScan peripheral.

void KeyScan_ClearINT(KSCAN_TypeDef *KeyScan, u32 KeyScan_IT)

Clear the specified KeyScan interrupt pending bits.

参数:
  • KeyScan -- selected KeyScan peripheral.

  • KeyScan_IT --

    specifies the KeyScan interrupt to be cleared. This parameter can be one or combinations of the following values:

    • KS_BIT_ALL_DEFAULT_INT_CLR: all default flag

    • KS_BIT_STUCK_INT_CLR: Stuck event interrupt flag

    • KS_BIT_FIFO_LIMIT_INT_CLR: FIFO limit interrupt flag

    • KS_BIT_FIFO_OV_INT_CLR: FIFO overflow interrupt flag

    • KS_BIT_SCAN_FINISH_INT_CLR: Scan finish interrupt flag

    • KS_BIT_ALL_RELEASE_INT_CLR: All Release interrupt flag

备注

  • KS_BIT_SCAN_EVENT_INT_STATUS is automatically cleared by hardware when the data is read.

  • KS_BIT_FIFO_FULL_INT_STATUS is automatically cleared by hardware when the buffer level goes below the KS_FIFO_TH_LEVEL threshold.

  • KS_BIT_FIFO_NOTEMPTY_INT_STATUS is automatically cleared by hardware when the FIFO is empty.

void KeyScan_Cmd(KSCAN_TypeDef *KeyScan, u8 NewState)

Enable or disable the specified KeyScan peripheral.

参数:
  • KeyScan -- selected KeyScan peripheral.

  • NewState -- new state of the KeyScan peripheral. This parameter can be: ENABLE or DISABLE.

u8 KeyScan_GetDataNum(KSCAN_TypeDef *KeyScan)

Get the number of entries in the KeyScan FIFO.

参数:
  • KeyScan -- selected KeyScan peripheral.

返回:

Number of entries currently in the KeyScan FIFO.

bool KeyScan_GetFIFOState(KSCAN_TypeDef *KeyScan, u32 KeyScan_Flag)

Get the status of the KeyScan FIFO.

参数:
  • KeyScan -- selected KeyScan peripheral.

  • KeyScan_Flag --

    specifies the flag to check. This parameter can be one of the following values:

    • KS_BIT_FIFO_FULL

    • KS_BIT_FIFO_EMPTY

返回:

The new state of the specified flag:

  • TRUE: flag is set

  • FALSE: flag is not set

u32 KeyScan_GetINT(KSCAN_TypeDef *KeyScan)

Get KeyScan interrupt status.

参数:
  • KeyScan -- selected KeyScan peripheral.

返回:

Interrupt status.

u32 KeyScan_GetRawINT(KSCAN_TypeDef *KeyScan)

Get KeyScan Raw Interrupt Status.

参数:
  • KeyScan -- selected KeyScan peripheral.

返回:

Raw interrupt status.

u32 KeyScan_GetStuckRow(KSCAN_TypeDef *KeyScan)

Get the stuck-row default status.

参数:
  • KeyScan -- selected KeyScan peripheral.

返回:

Default status of row0 to row7:

  • 1: row stuck

  • 0: row not stuck

void KeyScan_INTConfig(KSCAN_TypeDef *KeyScan, u32 KeyScan_IT, u8 newState)

Enable or disable the specified KeyScan interrupt sources.

参数:
  • KeyScan -- selected KeyScan peripheral.

  • KeyScan_IT --

    specifies the KeyScan interrupt sources to be enabled or masked. This parameter can be one or combinations of the following values:

    • KS_BIT_ALL_DEFAULT_INT_MASK: Unmask all default interrupt

    • KS_BIT_STUCK_EVENT_INT_MASK: Unmask Stuck event interrupt

    • KS_BIT_SCAN_EVENT_INT_MASK: Unmask Scan event interrupt

    • KS_BIT_FIFO_LIMIT_INT_MASK: Unmask FIFO limit interrupt

    • KS_BIT_FIFO_OV_INT_MASK: Unmask FIFO overflow interrupt

    • KS_BIT_FIFO_FULL_INT_MASK: Unmask FIFO full interrupt

    • KS_BIT_SCAN_FINISH_INT_MASK: Unmask scan finish interrupt

    • KS_BIT_FIFO_NOTEMPTY_INT_MASK: Unmask FIFO nonempty interrupt

    • KS_BIT_ALL_RELEASE_INT_MASK: Unmask All Release interrupt

  • newState -- new state of the specified KeyScan interrupt sources. This parameter can be: ENABLE or DISABLE.

void KeyScan_Init(KSCAN_TypeDef *KeyScan, KeyScan_InitTypeDef *KeyScan_InitStruct)

Initialize the KeyScan peripheral according to the specified parameters in the KeyScan_InitStruct.

参数:
  • KeyScan -- selected KeyScan peripheral.

  • KeyScan_InitStruct -- pointer to a KeyScan_InitTypeDef structure that contains the configuration information for the specified KeyScan peripheral.

void KeyScan_Read(KSCAN_TypeDef *KeyScan, u32 *outBuf, u8 count)

Read data from KeyScan FIFO.

参数:
  • KeyScan -- selected KeyScan peripheral.

  • outBuf -- buffer to save data read from KeyScan FIFO.

  • count -- number of entries to read.

void KeyScan_SetColRow(KSCAN_TypeDef *KeyScan, u32 column_sel, u32 row_sel)

Set the active columns and rows for KeyScan.

参数:
  • KeyScan -- selected KeyScan peripheral.

  • column_sel -- Specifies which columns are active. This parameter must be set to a value in the 0x1-0xff range.

  • row_sel -- Specifies which rows are active. This parameter must be set to a value in the 0x1-0xff range.

void KeyScan_SetStuckRow(KSCAN_TypeDef *KeyScan, u32 Status)

Set the stuck-row default status.

参数:
  • KeyScan -- selected KeyScan peripheral.

  • Status -- row default status. one bit one row, bit 0 means row0, bit 7 means row7. 1: row stuck 0: row not stuck

void KeyScan_SetStuckThreshold(KSCAN_TypeDef *KeyScan, u32 ThresholdMs)

Set the stuck key detection time threshold.

参数:
  • KeyScan -- selected KeyScan peripheral.

  • ThresholdMs -- stuck key detection time threshold in milliseconds. ThresholdMs = (Threshold +1)* Scan_clk(ms). Threshold must be set to a value in the 0x0-0x7fffffff range.

void KeyScan_StructInit(KeyScan_InitTypeDef *KeyScan_InitStruct)

Fill each KeyScan_InitStruct member with its default value.

参数:
void KeyScan_StuckAutoCmd(KSCAN_TypeDef *KeyScan, u8 NewState)

Enable or disable the KeyScan stuck auto check function.

参数:
  • KeyScan -- selected KeyScan peripheral.

  • NewState -- new state of the KeyScan stuck auto check function. This parameter can be: ENABLE or DISABLE.

void KeyScan_StuckPeriodicalPull(KSCAN_TypeDef *KeyScan, u32 PullUpUs, u32 NoPullUs)

Set the stuck-row periodic detection timing.

参数:
  • KeyScan -- selected KeyScan peripheral.

  • PullUpUs -- stuck-row detection pull-up time in microseconds. PullUpUs = (PullUpCnt +1)* clk_131k(us), max value is 15625us. PullUpCnt must be set to a value in the 0x0-0x7ff range.

  • NoPullUs -- stuck-row detection no-pull time in microseconds. When NoPullUs is 0, disable stuck-row detection. When NoPullUs is not 0, NoPullUs = (NoPullCnt +1)* clk_131k(us), max value is 31250us. NoPullUs can be set to a value in the 0x0-0xfff range.