当前位置: 首页 > news >正文

【星闪】Hi2821 | KEYSCAN矩阵按键扫描

1. 简介

        在键盘相关的应用中,通常需要驱动数十个按键,如果每个按键使用一个管脚来驱动那就太浪费了,而且一般也没有那么多管脚可用,因此使用矩阵按键会是一个不错的选择。

        上面是一个 2×4 的键盘矩阵,一共 8 个按键,但仅需 6 根管脚即可驱动。

        一般来说,矩阵键盘采用行扫描的方式,即行方向的管脚配置为输出,列方向的管脚配置为输入。空闲时,行输出高电平。扫描时,行依次拉低电平,每次拉低后读取列管脚的值,如果某一列的按键被按下,那么该按键列管脚将会读到低电平;没按下即保持高电平。

        根据管脚模式和上下拉电阻的配置,矩阵键盘会有 4 种驱动方式:

行扫描列扫描
上拉电阻行输出,空闲高电平,列输入接上拉,按下时低电平列输出,空闲高电平,行输入接上拉,按下时低电平
下拉电阻行输出,空闲低电平,列输入接上拉,按下时高电平列输出,空闲低电平,行输入接下拉,按下时高电平

2. 硬件特性

        Hi2821 在硬件上原生支持矩阵键盘,最大支持 16×8 的矩阵键盘,支持芯片算法防鬼键,支持 IO 端口可旁路的防抖设计

3. 例程

        例程将以上面的 2×4 矩阵键盘为例进行驱动。

3.1 Kconfig

        比较重点的配置,第一行这个用来设置同时能上报多少个按键,默认为 6 个。KEYSCAN use software to detect ghost key:软件防鬼键。KEYSCAN avoids the tiny jitter:软件防抖。Select keyscan type:一般选择最后一个用户自定义。number of columns to start:列数。number of rows to start:行数。

3.2 代码

#include "key_scan.h"#include <stdint.h>
#include <string.h>#include "keyscan.h"
#include "soc_osal.h"/* 键位映射(先行再列) */
static uint8_t g_key_gpio_map[CONFIG_KEYSCAN_ENABLE_ROW + CONFIG_KEYSCAN_ENABLE_COL] = {11, 12, 13, 14
};
static uint8_t g_key_map[CONFIG_KEYSCAN_ENABLE_ROW][CONFIG_KEYSCAN_ENABLE_COL] = {{ 0x01, 0x02 },{ 0x03, 0x04 }
};static int key_scan_report_callback(int key_nums, uint8_t key_values[])
{osal_printk("keys: ");for (int i = 0; i < key_nums; i++) {osal_printk("%02X ", key_values[i]);}osal_printk("\r\n");return 0;
}int key_scan_init(void)
{int ret = ERRCODE_SUCC;ret = keyscan_porting_set_gpio(g_key_gpio_map);if (ret) {osal_printk("set key gpio failed\r\n");return ret;}ret = uapi_set_keyscan_value_map((uint8_t **) g_key_map, CONFIG_KEYSCAN_ENABLE_ROW, CONFIG_KEYSCAN_ENABLE_COL);if (ret != ERRCODE_SUCC) {osal_printk("set key map failed\r\n");return ret;}uapi_keyscan_init(EVERY_ROW_PULSE_40_US, HAL_KEYSCAN_MODE_0, KEYSCAN_INT_VALUE_RDY);ret = uapi_keyscan_register_callback(key_scan_report_callback);if (ret != ERRCODE_SUCC) {osal_printk("set irq callback failed\r\n");return ret;}if (uapi_keyscan_enable() != ERRCODE_KEYSCAN_POWER_ON) {osal_printk("key scan enable start failed\r\n");return -1;}return ret;
}

1. 注册按键管脚

        如果使用的是用户自定义按键模式,那么就需要先调用 keyscan_porting_set_gpio 函数去注册管脚,传入一个数组,行管脚在前,列管脚在后

2. 注册按键映射

        调用 uapi_set_keyscan_value_map 函数,传入一个二维数组、行数和列数,按键上报时会根据该数组的键值进行上报。

3. 初始化矩阵键盘

        调用 uapi_keyscan_init 函数,参数一为扫描时长,可选值如下:

typedef enum {EVERY_ROW_PULSE_10_US,               /*!< KEYSCAN every row pulse 10 us */EVERY_ROW_PULSE_20_US,               /*!< KEYSCAN every row pulse 20 us */EVERY_ROW_PULSE_30_US,               /*!< KEYSCAN every row pulse 30 us */EVERY_ROW_PULSE_40_US                /*!< KEYSCAN every row pulse 40 us */
} keyscan_pulse_time_t;

        参数二为扫描模式,可选值如下:

typedef enum {HAL_KEYSCAN_MODE_0,                 /*!< Input=0 Output=1 Pull down Output while scanning, scan high level */HAL_KEYSCAN_MODE_1,                 /*!< Input=1 Output=0 Pull up Output while scanning, scan low level */HAL_KEYSCAN_MODE_2,                 /*!< Input=0 Output=1 Pull up Input while scanning, scan low level */HAL_KEYSCAN_MODE_3                  /*!< Input=1 Output=0 Pull down Input while scanning, scan high level */
} keyscan_mode_t;

        参数三为回调触发事件,可选值如下:

typedef enum {KEYSCAN_INT_FIFO_FULL,             /*!< Fifo full interrupt */KEYSCAN_INT_PRESS,                 /*!< Button press interrupt */KEYSCAN_INT_RELEASE,               /*!< Key release interrupt */KEYSCAN_INT_VALUE_RDY,             /*!< Key value report interrupt */KEYSCAN_INT_STOPPED,               /*!< Stop interrupt interrupt */KEYSCAN_INT_SCAN_ONE,              /*!< Completes a scan interrupt */KEYSCAN_INT_AFIFO_FULL,            /*!< Fifo will be full interrupt */KEYSCAN_INT_PRESS_AON,             /*!< Keyboard matrix key interrupt */KEYSCAN_INT_MAX_NUM,               /*!< KEYSCAN num */
} keyscan_int_t;

4. 注册回调函数

        调用 uapi_keyscan_register_callback 函数注册,回调中会返回扫描到的键值。

5. 使能键值按键

        调用 uapi_keyscan_enable 函数使能。

3.3 测试

    http://www.dtcms.com/a/393223.html

    相关文章:

  • ​​[硬件电路-282]:PWM信号通用解读、应用场景及在步进电机中的应用详解
  • 给链表装上“后视镜”:深入理解双向链表的自由与高效
  • Off-Grid Direction of Arrival Estimation Using Sparse Bayesian Inference (II)
  • Unity中的渲染管线
  • PyMuPDF 库
  • 【故障】windows7开机后能出现windows启动界面,但停在黑屏很久才进入系统界面
  • tqdm 库
  • 模块化编程规范与分层设计指南
  • Photoshop - Photoshop 调整照片的颜色强度
  • 【ROS2】通讯机制 Topic 常用命令行
  • DeepSeek的GPU优化秘籍:解锁大规模AI训练的底层效率
  • Gemini in Chrome深度解析:反垄断胜诉后,Chrome开启AI智能浏览时代!
  • 如何修复 Google Chrome 上的白屏问题
  • Camera2原生api级 Demo答
  • 【Redis】Redis缓存与数据库DB数据如何保持同步?
  • 考研408---C语言复习
  • 批量抓取图片
  • WinDivert学习文档之五-————编程API(十一)
  • 【打印菱形】
  • XC7Z100-2FFG900I Xilinx AMD Zynq-7000 FPGA SoC
  • 成本价的SEO优化服务供应链
  • dock生命周期体验-生到死的命令
  • 软件测试方案-模板一
  • 防火墙WEB方式登录配置【HCL模拟】-学习篇(1)
  • Ceph用户管理与cephFS分布式存储实战
  • AgenticSeek:重新定义AI助手的边界 - 100%本地化智能代理系统深度解析
  • 701. 二叉搜索树中的插入操作
  • Spring AI(六)Tool Calling本地回调方法
  • 《2511系统分析师第二遍阅读总结3》
  • 【Linux】系统部分——线程同步与生产者消费者模型