卡卷网
当前位置:卡卷网 / 每日看点 / 正文

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

作者:卡卷网发布时间:2024-11-30 16:08浏览数量:111次评论数量:0次

矩阵键盘本质:

矩阵键盘本质是使用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张

END

免责声明:本文由卡卷网编辑并发布,但不代表本站的观点和立场,只提供分享给大家。

卡卷网

卡卷网 主页 联系他吧

请记住:卡卷网 Www.Kajuan.Net

欢迎 发表评论:

请填写验证码