支持的芯片

Ameba SoC

RTL8721Dx

RTL8720E

RTL8726E

RTL8713E

RTL8730E

RTL8721F

支持状态

Y

N

N

N

N

N

概述

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

Key-Scan 支持以下功能:

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

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

  • 支持按键卡滞检测

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

系统框图

Key-Scan 的框图如下所示:

../../../rst_peripherals/rtos/8_key_scan/figures/key_scan_block_diagram.svg

Key-Scan 主要包含 6 个功能模块:

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

  • 寄存器及 FIFO:配置 Key-Scan 参数和 FIFO

  • 时钟模块:131KHz 时钟用于检测行键卡滞的情况

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

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

键盘矩阵

Key-Scan 的行列可配置,支持的最大列数或行数均为 8。

../../../rst_peripherals/rtos/8_key_scan/figures/keypad_array.svg

8x8 键盘矩阵配置

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

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

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

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

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

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

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

../../../rst_peripherals/rtos/8_key_scan/figures/keyscan_scan_timing.svg

键盘扫描时序

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

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

  • 扫描间隔计时:两次 full scan 之间需要等待扫描间隔计时器计时结束。

  • 所有按键释放计时:当所有按键被释放,Key-Scan 仍会有一次 full scan(两轮全键盘扫描),等扫描结束后确认无按键按下,释放计时器开始计时。等计时结束,状态机才会停止。

工作模式

Key-Scan 包含两种工作模式:事件触发模式和常规扫描模式。

工作模式

描述

事件触发模式

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

常规扫描模式

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

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

../../../rst_peripherals/rtos/8_key_scan/figures/difference_FIFO_items_between_two_work_modes.svg

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

FIFO 机制

Key-Scan 的 FIFO 深度为 16,宽度为 12 位。其结构如下所示:

../../../rst_peripherals/rtos/8_key_scan/figures/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 列

按键卡滞

在实际使用过程中可能会出现按键卡滞,如果按键未被及时松开,Key-Scan 状态机将持续进行扫描,无法进入 ILDE 状态。CPU 也将保持活动状态持续进行键盘扫描,无法进入低功耗模式,进而产生高功耗。

  • 屏蔽卡滞按键所在行 :为解决此问题,Key-Scan 支持自动检测按键卡滞的功能。启用该功能后,若按键卡滞时间超过设定的阈值,该按键将被视为卡滞按键。通过读取按键卡滞状态寄存器获取卡滞的按键,并设置卡滞按键所在行的默认状态,Key-Scan 在扫描到

该卡滞按键所在行时,会认为没有按键被按下,从而顺利进入 IDLE 状态。

  • 重置卡滞按键所在行 :按键卡滞后,有两种方法可以重置卡滞按键所在行的状态。

    • 一是按下其他非卡滞按键所在行的按键,将 Key-Scan 状态机唤醒,重置卡滞状态寄存器,以唤醒 Key-Scan 的扫描电路;

    • 二是松开卡滞按键,Key-Scan 检测到默认状态寄存器和卡滞状态寄存器的值不匹配,唤醒 Key-Scan 的扫描检测电路。

用法

正常工作模式

使用 Key-Scan 的事件触发模式或常规扫描模式,需执行以下步骤:

  1. 配置 Key-Scan 的引脚复用功能。

    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. 初始化 Key-Scan 参数。

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

    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. 使能 Key-Scan 中断,并注册 Key-Scan 中断处理函数。

  4. 使能 Key-Scan。

    KeyScan_Cmd(KeyScan, ENABLE);
    
  5. 等待并处理 Key-Scan 中断。

按键卡滞处理

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

  1. 配置 Key-Scan 的引脚复用功能。

    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. 初始化 Key-Scan 参数。

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

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

    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. 使能 Key-Scan 按键卡滞和所有默认中断,并注册 Key-Scan 中断处理函数。

  6. 使能 Key-Scan。

    KeyScan_Cmd(KeyScan, ENABLE);
    
  7. 等待并处理 Key-Scan 中断。

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

      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. 除卡滞按键外,其他按键的按下或松开将正常产生相应中断。