当前位置:首页 > 每日看点

如何按下一个矩阵键盘,松开后直到按下另个键盘之前,显示不消失?

卡卷网1年前 (2024-11-30)每日看点261

矩阵键盘本质:

矩阵键盘本质是使用8个IO口来进行16个按键的控制读取,可以减小IO口的使用,用4条I/O线作为行线,4条I/O线作为列线组成的键盘。在行线和列线的每个交叉点上,设置一个按键。而这样的按键中按键的个数是4 X 4个。

这样的行列式键盘结构能够有效地提高单片机系统中I/O口的利用率。节约单片机的资源,其本质和独立按键类似,就是进行逐行扫描和逐列扫描,然后判断是第几行的第几列的按键,进而进行整体按键值得确定。

具体实物图如下:

如何按下一个矩阵键盘,松开后直到按下另个键盘之前,显示不消失?  第1张

矩阵键盘扫描的方式有两种: 1.行列扫描,2.逐行/逐列扫描

行列扫描:适用于8个IO口接到了单片机8个连续的IO口,可以使用行列扫描

逐行/逐列扫描:适用于矩阵键盘接到了任意的IO口,则使用逐行,逐列扫描

本文主要说明逐行扫描的方式

逐行/列扫描:

逐行,逐列扫描的本质和行列扫描比较类似,本质是给某一行/某一列,低电平,其余七个全部为高电平,这时候读取电平变换,有电平变低表示按键按下,即可读取按键数据。

逐行扫描:

  1. 置第1行为低电平,其余N-1行和N列为高电平,
  2. 读取列线数据,列线有低电平表示此行有按键按下,比如按下的是1行三列(1x3),那么第三列的列线IO口就为低电平。
  3. 置第2行为低电平,其余N-1行和N列为高电平,,读取列线数据,列线有低电平表示此行有按键按下。
  4. 以此类推,进行逐行扫描。
  5. 根据行线列线的电平不同可以识别是否有按键按下,哪一个按键按下,获取按键号。(N) 根据按键号跳转至对应的按键处理程序。

如何按下一个矩阵键盘,松开后直到按下另个键盘之前,显示不消失?  第2张

硬件连接

行线与列线:在硬件上,4条行线连接到微控制器的输出引脚,而4条列线连接到微控制器的输入引脚。

按键位置:每个按键位于行线和列线的交叉点上。

如何按下一个矩阵键盘,松开后直到按下另个键盘之前,显示不消失?  第3张

GPIO初始化

行线:

通常设置为输出模式,用于向列线发送扫描信号。

扫描信号:

行线的主要功能是向列线发送扫描信号。当某一行线被设置为低电平时,与之相交的列线会被检测(若相对应的按键被按下,列线被检测为低电平)以判断是否有按键被按下。

确定按键行

通过依次将每一行线设置为低电平(可以逐行扫描键盘)。当检测到列线上有低电平时,可以确定被按下的按键位于当前选中的行上。若列线上无低电平,那么将此行线设置为高电平,下一行设置为低电平,进行新一轮按键检测。

列线

设置为输入模式,用于读取按键状态。

读取按键状态

列线的主要功能是读取按键状态。(STM32就靠列线来确认按键状态)当某一行线被选中(设置为低电平)时,微控制器会读取所有列线的电平状态,以判断是否有按键被按下。

注意事项

在实际应用中,还需要考虑去抖处理、中断处理等因素,以确保按键检测的准确性和稳定性。

Cube MX配置GPIO

使用stm32CubeMX软件配置GPIO:

PA0-PA3的配置是一样的(做行线,设置为输出模式)

如何按下一个矩阵键盘,松开后直到按下另个键盘之前,显示不消失?  第4张

PA4-PA7的配置是一样的(做列线,设置为输入模式)

如何按下一个矩阵键盘,松开后直到按下另个键盘之前,显示不消失?  第5张

有用到OLED模块,故配置SCL,SDA,做通讯线

如何按下一个矩阵键盘,松开后直到按下另个键盘之前,显示不消失?  第6张

时钟频率的话,可以选择默认的

如何按下一个矩阵键盘,松开后直到按下另个键盘之前,显示不消失?  第7张

如何按下一个矩阵键盘,松开后直到按下另个键盘之前,显示不消失?  第8张

配置完GPIO的相关资源后,就可以在Keil5软件里编写功能模块

(代码中用到的Delay模块和OLED模块是外部导入的)

(Delay也可以用HAL库自带的,OLED可以网上找找)

#include <main.h> #include "Delay.h" /** * @brief 矩阵键盘读取按键键码 * @param 无 * @retval KeyNumber 按下按键的键码值 如果按键按下不放,程序会停留在此函数,松手的一瞬间,返回按键键码,没有按键按下时,返回0 */ void GPIOAallset() { HAL_GPIO_WritePin(GPIOA, GPIO_PIN_0, GPIO_PIN_SET); HAL_GPIO_WritePin(GPIOA, GPIO_PIN_1, GPIO_PIN_SET); HAL_GPIO_WritePin(GPIOA, GPIO_PIN_2, GPIO_PIN_SET); HAL_GPIO_WritePin(GPIOA, GPIO_PIN_3, GPIO_PIN_SET); HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_SET); HAL_GPIO_WritePin(GPIOA, GPIO_PIN_5, GPIO_PIN_SET); HAL_GPIO_WritePin(GPIOA, GPIO_PIN_6, GPIO_PIN_SET); HAL_GPIO_WritePin(GPIOA, GPIO_PIN_7, GPIO_PIN_SET); } uint8_t MatrixKey(void) { uint8_t KeyNumber=0; GPIOAallset(); //把PA0-PA7全置为高电平 HAL_GPIO_WritePin(GPIOA, GPIO_PIN_0, GPIO_PIN_RESET); //PA0置0,开始检测第一行 if(HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_4)==0) { Delay_ms(10); while(!HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_4)); //当按钮处于被按下的状态的时候,程序一直卡在循环读取按钮的状态,避免多按钮同时按下时读取错误 Delay_ms(10); KeyNumber=1; } if(HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_5)==0) { Delay_ms(10); while(!HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_5)); Delay_ms(10); KeyNumber=2; } if(HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_6)==0) { Delay_ms(10); while(!HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_6)); Delay_ms(10); KeyNumber=3; } if(HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_7)==0) { Delay_ms(10); while(!HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_7)); Delay_ms(10); KeyNumber=4; } GPIOAallset(); //把PA0-PA7全置为高电平 HAL_GPIO_WritePin(GPIOA, GPIO_PIN_1, GPIO_PIN_RESET); //PA1置0,开始检测第二行 if(HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_4)==0) { Delay_ms(10); while(!HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_4)); //当按钮处于被按下的状态的时候,程序一直卡在循环读取按钮的状态,避免多按钮同时按下时读取错误 Delay_ms(10); KeyNumber=5; } if(HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_5)==0) { Delay_ms(10); while(!HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_5)); Delay_ms(10); KeyNumber=6; } if(HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_6)==0) { Delay_ms(10); while(!HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_6)); Delay_ms(10); KeyNumber=7; } if(HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_7)==0) { Delay_ms(10); while(!HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_7)); Delay_ms(10); KeyNumber=8; } GPIOAallset(); //把PA0-PA7全置为高电平 HAL_GPIO_WritePin(GPIOA, GPIO_PIN_2, GPIO_PIN_RESET); //PA2置0,开始检测第三行 if(HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_4)==0) { Delay_ms(10); while(!HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_4)); //当按钮处于被按下的状态的时候,程序一直卡在循环读取按钮的状态,避免多按钮同时按下时读取错误 Delay_ms(10); KeyNumber=9; } if(HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_5)==0) { Delay_ms(10); while(!HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_5)); Delay_ms(10); KeyNumber=10; } if(HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_6)==0) { Delay_ms(10); while(!HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_6)); Delay_ms(10); KeyNumber=11; } if(HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_7)==0) { Delay_ms(10); while(!HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_7)); Delay_ms(10); KeyNumber=12; } GPIOAallset(); //把PA0-PA7全置为高电平 HAL_GPIO_WritePin(GPIOA, GPIO_PIN_3, GPIO_PIN_RESET); //PA3置0,开始检测第四行 if(HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_4)==0) { Delay_ms(10); while(!HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_4)); //当按钮处于被按下的状态的时候,程序一直卡在循环读取按钮的状态,避免多按钮同时按下时读取错误 Delay_ms(10); KeyNumber=13; } if(HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_5)==0) { Delay_ms(10); while(!HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_5)); Delay_ms(10); KeyNumber=14; } if(HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_6)==0) { Delay_ms(10); while(!HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_6)); Delay_ms(10); KeyNumber=15; } if(HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_7)==0) { Delay_ms(10); while(!HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_7)); Delay_ms(10); KeyNumber=16; } return KeyNumber; }

主函数部分:

while (1) { OLED_ShowString(2, 1,"NUM:"); num = MatrixKey(); if(num) { OLED_ShowNum(2, 5, num, 2); } }

仿真图片:

如何按下一个矩阵键盘,松开后直到按下另个键盘之前,显示不消失?  第9张

扫描二维码推送至手机访问。

版权声明:本文由卡卷网发布,如需转载请注明出处。

本文链接:https://www.kajuan.net/ttnews/2024/11/2236.html

分享给朋友:

相关文章

创业值得吗?

许多企业主会说,是的。企业所有权可能意味着利润以及一定程度的财务稳定性。此外,对于小企业主来说,它提供了摆脱朝九晚五工作限制的机会,这些工作可能不会给您带来快乐或成就感。也就是说,创业并非没有挑战——从提出一个有利可图的想法,到获得资金,再…

怎么用游戏搬砖挣钱呢?

怎么用游戏搬砖挣钱呢?

今天,我把我多年操作的经验分享出来,以供各位老板们学习借鉴,胆小的老板就离开吧,心里承受能力太弱了,会刷新你的认知的。 有些新人在计算收益的时候,会以机器数来计算,其实是有误区的, 比如,一台机器一个月搞400元,平均每天搞13元钱,搞上1…

B 站上有哪些很好的学习资源?

B 站上有哪些很好的学习资源?

前!方!高!能!精选了多位学习Up主,不乏百万粉丝的大V,还有超多珍贵的学习资源推荐。 进了小破站,完全不用担心学完了该怎么办?因为根本学不完啊!!!B站的学习干货实在太多了! 语言学习葉子先生酱 https://space.bilib…

为什么我感受不到 1500 元的手机比四五千的差?

我长期使用两千元左右的安卓机,一天接近8小时的重度手机使用者。 某天我突然想试试看传说中非常赛艇的苹果。狠了心,砸了钱。七千大样买了爱疯。 就这?什么辣鸡玩意。而且因为我一直更新软件,用了两年爱疯就卡了。并没有传说中的用四五年不卡。 用了这…

发表评论

访客

看不清,换一张

◎欢迎参与讨论,请在这里发表您的看法和观点。