找回密码
 立即注册
查看: 784|回复: 9

8 x 8 (或A x B?) 矩阵按键 按键处理 单击或长按?

[复制链接]
  • 打卡等级:以坛为家II
  • 打卡总天数:406
  • 最近打卡:2025-09-26 10:12:47
已绑定手机

32

主题

131

回帖

2029

积分

荣誉版主

Rbowlystar

积分
2029
发表于 2025-4-27 22:44:06 | 显示全部楼层 |阅读模式

8 x 8 (或A x B?) 矩阵按键 按键处理 单击&长按

目录:【虹星宝典】记录单片机学习之旅——目录

注:从本例程起,使用USB-CDC模式进行程序下载。

矩阵按键原理

image.png

以这个8x8的矩阵按键为例:

image.png

如何实现64个按键的扫描?

试想一下,当我们给KA通电时,对K1-K8的状态进行读取,如果有按键按下,那么对应的端口就会由低电平变成高电平,由此即可判断哪一个按键按下了。

如此反复对K1-KH端口置高电平,读取K1-K8端口的状态,便可以实现8x8矩阵按键的扫描,一般会对置高电平的端口配置为推挽输出模式,对读取的端口设置为高阻输入+下拉的模式。

如此便可写一个扫描按键是否按下的函数,对与N x N的矩阵按键原理也是大同小异的。

image.png

image.png

如何实现按键状态的判断?

一般的,按键分为 ”未按下“ ”消抖“ ”单击“ ”长按“等多种状态,为了更好的区分当按键按下时处于什么状态,确定一个时基便十分重要了,例如我以10ms为一次扫描时间间隔基准,即每10ms扫描一次按键状态,并保存这个按键按下的时长,通过判断按下的时长,即可推断出按键为何种状态。

案例中以按下到松开的时长在2s内时,判断为单击动作。按下超过2s时,判断为长按动作。

image.png

实例展示(仅展示部分代码)

这里以10ms作为扫描时基,如果A1为单击操作则打印“A1 Press!”,其他按键同理。

image.png

演示视频:

2 喜欢他/她就送朵鲜花吧,赠人玫瑰,手有余香!
回复

使用道具 举报 送花

  • 打卡等级:以坛为家II
  • 打卡总天数:406
  • 最近打卡:2025-09-26 10:12:47
已绑定手机

32

主题

131

回帖

2029

积分

荣誉版主

Rbowlystar

积分
2029
发表于 2025-4-27 23:12:08 | 显示全部楼层
4-Key.zip (335.5 KB, 下载次数: 74)



2025-04-29:
推出支持自定义行列引脚模式的矩阵按键扫描函数,真正实现任意AxB行列式矩阵按键扫描
欢迎小伙伴们体验测试 4-Key(AxB).zip (366.44 KB, 下载次数: 86)
截图202504292348292304.jpg

回复

使用道具 举报 送花

3

主题

1928

回帖

704

积分

等待验证会员

积分
704
发表于 2025-4-27 22:58:01 | 显示全部楼层
矩阵按键扫描与状态判断的实现

矩阵按键扫描原理

在嵌入式系统中,矩阵按键是一种常见的输入设备,通过减少I/O引脚的使用数量,实现多按键的检测。以8x8矩阵按键为例,其基本原理如下:

1. 硬件连接:矩阵按键通常由行和列组成,例如8行8列共64个按键。每一行和每一列分别连接到微控制器的I/O引脚。
  
2. 扫描方法:
行扫描:将某一行置为高电平(推挽输出模式),其余行置为低电平。
列检测:读取每一列的状态(高阻输入+下拉模式)。如果某一列检测到高电平,说明该列与当前行的交叉点有按键按下。
循环扫描:依次对每一行进行上述操作,完成整个矩阵的扫描。

3. 状态判断:
消抖处理:按键在按下和释放时可能会产生抖动,需要通过软件消抖算法来消除抖动影响。
时基确定:以10ms为扫描间隔,记录按键按下的时长。
状态分类:根据按下的时长,将按键状态分为“未按下”、“消抖”、“单击”和“长按”等。

按键状态判断的实现

1. 时基与扫描:
以10ms为时基,每隔10ms进行一次按键扫描。
记录每个按键按下的时长,通过判断时长来区分不同的按键状态。

2. 状态分类:
单击:按键按下到松开的时长在2秒内。
长按:按键按下超过2秒。

实例代码展示

以下是一个简化的按键扫描与状态判断的代码示例:
  1. c
  2. include
  3. include
  4. include
  5. define ROWS 8
  6. define COLS 8
  7. define DEBOUNCETIME 20 // 消抖时间20ms
  8. define LONGPRESSTIME 2000 // 长按时间2000ms
  9. uint8t keymatrix[ROWS][COLS] = {0}; // 按键矩阵状态
  10. uint16t keypresstime[ROWS][COLS] = {0}; // 按键按下时长
  11. void scankeys() {
  12.     static uint16t debouncecounter[ROWS][COLS] = {0};
  13.     for (uint8t row = 0; row < ROWS; row++) {
  14.         // 设置当前行为高电平
  15.         setrowhigh(row);
  16.         for (uint8t col = 0; col < COLS; col++) {
  17.             // 读取列状态
  18.             bool keystate = readcol(col);
  19.             if (keystate) {
  20.                 if (debouncecounter[row][col] < DEBOUNCETIME) {
  21.                     debouncecounter[row][col]++;
  22.                 } else {
  23.                     keypresstime[row][col]++;
  24.                 }
  25.             } else {
  26.                 if (debouncecounter[row][col] > 0) {
  27.                     debouncecounter[row][col]--;
  28.                 } else {
  29.                     if (keypresstime[row][col] > 0) {
  30.                         if (keypresstime[row][col] < LONGPRESSTIME) {
  31.                             printf("Key [%d][%d] Press!\n", row, col);
  32.                         } else {
  33.                             printf("Key [%d][%d] Long Press!\n", row, col);
  34.                         }
  35.                         keypresstime[row][col] = 0;
  36.                     }
  37.                 }
  38.             }
  39.         }
  40.         // 恢复当前行为低电平
  41.         setrowlow(row);
  42.     }
  43. }
  44. int main() {
  45.     while (1) {
  46.         scankeys();
  47.         delayms(10); // 10ms时基
  48.     }
  49.     return 0;
  50. }
复制代码

总结

通过上述方法,可以实现对8x8矩阵按键的扫描与状态判断。关键在于合理设置时基、消抖处理以及按键状态的分类。这种方法同样适用于其他规模的矩阵按键,只需调整行和列的数量即可。在实际应用中,还需根据具体硬件和需求进行优化和调整。

[本文内容由国芯人工智能辅助生成,仅供参考]
回复

使用道具 举报 送花

  • 打卡等级:偶尔看看I
  • 打卡总天数:10
  • 最近打卡:2025-09-17 09:52:11
已绑定手机

1

主题

7

回帖

57

积分

注册会员

积分
57
发表于 2025-8-15 16:43:30 | 显示全部楼层
https://www.stcaimcu.com/thread-19608-1-1.html
大佬,如果是我这种矩阵按键,我应该修改哪些部分的代码
回复

使用道具 举报 送花

  • 打卡等级:偶尔看看I
  • 打卡总天数:11
  • 最近打卡:2025-09-30 10:23:38
已绑定手机

12

主题

41

回帖

162

积分

注册会员

积分
162
发表于 2025-9-25 15:23:21 | 显示全部楼层
四*** 发表于 2025-4-27 23:12
2025-04-29:
推出支持自定义行列引脚模式的矩阵按键扫描函数,真正实现任意AxB行列式矩阵按键扫描
欢 ...

你好,请问附件 4-Key(AxB) 支持 单键短按长按,组合键最多支持3键最长5秒 的功能吗?我用的原理如图


另代码中行是下拉的,跟注释不一样

/**
* @name GPIO_Key_Init
* @brief 矩阵按键GPIO口初始化
* @version 版本:v1.0
* @date 日期:2025-04-22
* @author 作者:四汐
* @note 注释:行设置为上拉,列设置为下拉。行置1时,读列
*/
void GPIO_Key_Init(void)
{
    // P2 列 ABCDEFGH 推挽输出
    P2M0 = 0xff; P2M1 = 0x00;
    // P2PU = 0xff;
    P2PD = 0xff;

    // P0 行 12345678 高阻输入 下拉
    P0M0 = 0x00; P0M1 = 0xff;
    P0PD = 0xff;
}
我移植试了下,好像不能组合键




key_matrix.png

点评

我的代码中有两种方案,一种是8*8的使用一整个端口作为【读取】或【扫描】。另一种是任意独立IO口作为【读取】或【扫描】的,这个电路推荐使用任意IO口的方案。   发表于 7 天前
你的程序无法下载。 这个注释应该是忘记改了。按照实际代码来。 行和列的定义其实不重要,重要是明白哪些是【读取】口,哪些是【扫描】口。 【读取】设置为高阻输入,配置成下拉,默认为低电平,即没有按下。 【扫描  详情 回复 发表于 7 天前
回复

使用道具 举报 送花

  • 打卡等级:以坛为家II
  • 打卡总天数:406
  • 最近打卡:2025-09-26 10:12:47
已绑定手机

32

主题

131

回帖

2029

积分

荣誉版主

Rbowlystar

积分
2029
发表于 7 天前 | 显示全部楼层
mfsl*** 发表于 2025-9-25 15:23
你好,请问附件 4-Key(AxB) 支持 单键短按长按,组合键最多支持3键最长5秒 的功能吗?我用的原理如图

你的程序无法下载。
这个注释应该是忘记改了。按照实际代码来。
行和列的定义其实不重要,重要是明白哪些是【读取】口,哪些是【扫描】口。
【读取】设置为高阻输入,配置成下拉,默认为低电平,即没有按下。
【扫描】设置为推挽输出,配置成下拉,按下按键时,两个下拉电阻相当于并联,影响不大;配置成上拉,按下按键时,上拉和下拉电阻相当于串联在电源两端,【读取】口的电平就是VCC的一半左右。我之前应该是做了测试,认为配置下拉更稳定。

矩阵按键的原理就是:
在一个时刻内,【扫描A】输出高电平,其余【扫描X】输出低电平,同时检测【读取1-Y】的电平,如果检测【读取1】是高电平,那么认为A1按下,再通过算法实现“消抖”、“单击”等。

你的串口数据,看起来像是【读取】口配置成上拉了,就会判断按键一直按着,然后判断成“长按”了。
回复

使用道具 举报 送花

  • 打卡等级:偶尔看看I
  • 打卡总天数:11
  • 最近打卡:2025-09-30 10:23:38
已绑定手机

12

主题

41

回帖

162

积分

注册会员

积分
162
发表于 7 天前 | 显示全部楼层
四*** 发表于 2025-9-26 10:12
你的程序无法下载。
这个注释应该是忘记改了。按照实际代码来。
行和列的定义其实不重要,重要是明白哪些 ...
昨天打印错误是因为一个口配置错了,更改后可以单键短按和长按了。

用你的软硬件支持最大3个键组合键最长5秒的功能吗?

点评

用的是u16的,理论上最大是65536*10ms,我限制了60000为最大值,也就是600s。 至于组合键,矩阵按键理论上是不支持多键组合,这个算法也没有专门去处理这个事件。   发表于 7 天前
回复

使用道具 举报 送花

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|手机版|深圳国芯人工智能有限公司 ( 粤ICP备2022108929号-2 )

GMT+8, 2025-10-3 13:04 , Processed in 0.138488 second(s), 90 queries .

Powered by Discuz! X3.5

© 2001-2025 Discuz! Team.

快速回复 返回顶部 返回列表