4×4矩阵键盘详解(stm32)_stm32矩阵键盘
目录
一 前言
二 概述
2.1 硬件准备
2.2 硬件连接
2.3 实验目标
3.1 矩阵键盘介绍
3.2 工作原理
3.3 keyboard.c
3.4 keyboard.h
四 实现目标(main.c)
五 实现效果
一 前言
大家好呀,好久没更新博客了,最近因为买的一些硬件没有到就一直迟迟没有完成博客的攥写,接下来这段时间会给大家讲stm32的矩阵键盘、由用蓝牙实现舵机云台的转动、电机步进电机等等。一些关于stm32的拓展模块,也会列入在stm32专题的介绍。
我已为大家整理好之后讲的轮询法和中断法的代码,如下,大家自行下载运行即可
【超级会员V4】通过百度网盘分享的文件:轮询法.zip等2个文件
链接:https://pan.baidu.com/s/1Jp2InrAQOFNvuQ51qzYHag
提取码:42z5
复制这段内容打开「百度网盘APP 即可获取」
二 概述
2.1 硬件准备
我们需要准备一个4*4的矩阵键盘、OLED显示屏幕、stm32f103c8t6的最小开发板以及几根杜邦线
2.2 硬件连接
(1) 矩阵键盘
(2)OLED屏幕
请大家先将硬件的设备连接好,随后我们将会进行矩阵键盘的讲解,最后再落实到项目中
2.3 实验目标
我们本次将会完成一篇关于矩阵键盘的一个实验,我们要通过oled显示输入的密码,将密码设置成‘1234’
- 如果输入密码正确,则在oled屏幕上显示“PassWord Right”;
- 如果输入密码错误,则在oled屏幕上显示“PassWord Error”;
- 如果输入密码不是四位,则在oled上显示“Input 4Num”
三 矩阵键盘
3.1 矩阵键盘介绍
矩阵键盘是一种常用的多按键输入设备,通常由多个按键按照行(Row)和列(Column)排布形成一个二维网格结构。最常见的是 4×4(16键) 或 4×3(12键),这种行列式键盘结构能够有效地提高单片机中I/O口的利用率,节约单片机的资源。我们这里讲解16键的(8个引脚控制16个按键),12键和16键的大同小异,大家可以自行写12键的代码。
3.2 工作原理
-
每个按键连接在一行一列的交点上。
-
控制器(如stm32)先设置某一行输出低电平,其它行为高电平,按下的某个按键为低电平。
-
轮流扫描每一行,并读取每一列输入状态。
-
如果某一列被检测到为低电平,说明该行该列的按键被按下。
我们也会在写代码当中将行(R1~4)设置为GPIO的输出模式,将列(C1~4)设置为GPIO的输入模式。
这里在延申一点,大家想一想,不按按键是高电平,按下去是低电平,所以我们在配置输出模式的时候,我们要选择推挽输出(GPIO_Mode_Out_PP),因为推挽输出既可以输出高电平也可以输出低电平。那每一列设置输入模式的时候,该选哪个模式呢?我们不按按键,则是高电平,用上拉输入主要是为了让输入端口有一个确定的高电平状态,避免悬空和干扰,提高可靠性,我们会默认将每一列输入模式设置为上拉输入模式(GPIO_Mode_IPU)。
3.3使用方法
在写代码的时候,我们会有两种方式来写代码,分别为:轮询法、中断法。
关于上述两种方法,我都会给大家总结好,大家进入网盘中自行领取即可~ 因为这个矩阵键盘很多时候都会用到,所以大家可以直接拿走代码直接用,相关代码原理我也会给大家讲解。我们这篇文章主要是针对于初学者,会着重讲轮询法。接下来我会给大家分板块讲解矩阵键盘的代码部分,关于本项目的轮询法和中断法,大家直接进入百度网盘中直接调用源项目即可~
3.3 keyboard.c
(1)头文件部分
#include \"stm32f10x.h\"#include \"delay.h\" #include \"keyboard.h\"//4×4矩阵键盘const char key_map[4][4] = { {\'1\', \'2\', \'3\', \'A\'}, {\'4\', \'5\', \'6\', \'B\'}, {\'7\', \'8\', \'9\', \'C\'}, {\'*\', \'0\', \'#\', \'D\'}};
(2)键盘初始化
// 初始化 PA0~PA7void Keyboard_Init(void){ GPIO_InitTypeDef GPIO_InitStructure; RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); // PA0~PA3 行:推挽输出 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_2 | GPIO_Pin_3; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOA, &GPIO_InitStructure); // PA4~PA7 列:上拉输入 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4 | GPIO_Pin_5 | GPIO_Pin_6 | GPIO_Pin_7; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; GPIO_Init(GPIOA, &GPIO_InitStructure); // 默认将所有行拉高 GPIO_SetBits(GPIOA, GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_2 | GPIO_Pin_3);}
前面这两部分还是很好理解的 大家结合代码中的注释看一看就行,下面这个返回按键值部分,不太好理解,我给大家着重讲接下来这部分。
(3)返回按键值
// 扫描键盘,返回对应字符,无按键返回0char Keyboard_Scan(void){ uint8_t row, col; for (row = 0; row < 4; row++) { // 先将所有行拉高 GPIO_SetBits(GPIOA, GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_2 | GPIO_Pin_3); // 选定当前行拉低 GPIO_ResetBits(GPIOA, (1 << row)); delay_ms(5); // 消抖 + 等待稳定 // 读取列状态 for (col = 0; col < 4; col++) { if (GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_4 << col) == 0) { while (GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_4 << col) == 0); // 等待松手 return key_map[row][col]; } } } return 0; // 无按键按下}
请大家跟紧接下来的讲解
char Keyboard_Scan(void){ uint8_t row, col; for (row = 0; row < 4; row++) { for (col = 0; col < 4; col++) { //... ... } } return 0;}
这是这个函数的外围框架,两个for 循环遍历每一行、每一列,row
, col
:分别用于行和列的索引。进行“逐行扫描”如果没检测到任何按键,最后返回 0
(表示无按键按下)。
if (GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_4 << col) == 0){ while (GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_4 << col) == 0); // 等待松手 return key_map[row][col];}
关于上面这几行代码,大家可能就不懂了,GPIOA, GPIO_Pin_4 << col这个玩意又是什么呢?为啥要左移col(列)呢?接下来给大家讲一下:
在代码中的gpio.h中提供着gpio引脚如下的代码:
我们可以清晰的看到,PIN4被宏定义为了0x0010,PIN5被宏定义为了0x0020,PIN6被宏定义为了0x0040,PIN7被宏定义为了0x0080。GPIO_PIN_4在 STM32 标准库中是一个“位掩码”,值是 0x0010
(也就是二进制 0001 0000),对应 PA4 这个引脚。
-
col取 0, 1, 2, 3,代表第几列。
-
GPIO_PIN_4
<<
col就会依次变成:-
col = 0:GPIO_PIN_4
<< 0
= GPIO_PIN_4 = 0x0010(PA4) -
col = 1:GPIO_PIN_4
<< 1
= 0x0020(PA5) -
col = 2:0x0040(PA6)
-
col = 3:0x0080(PA7)
-
其中col = 0就是硬件上的C1这一列,col = 3就是硬件的上的C4这一列,只不过在最上面定义的二位数组,计算机识别是从0开始计数的。
这个地方也是我认为轮询法很有意思的一个点,他告诉了我们GPIO_PIN_几只不过是一个位掩码。本质都不过是0和1这两个数构成的。
链接:https://pan.baidu.com/s/1Jp2InrAQOFNvuQ51qzYHag
提取码:42z5
3.4 keyboard.h
#ifndef _KEYBOARD_H_#define _KEYBOARD_H_#include \"stm32f10x.h\"void Keyboard_Init(void);char Keyboard_Scan(void);#endif
在.h中,只需要将相应的头文件给加进来即可。
那么以上就已经完成了矩阵键盘的“轮询法”底层代码编写了,关于中断法请见我给大家提供的资料中。
四 实现目标(main.c)
通过oled显示输入的密码,将密码设置成‘1234’
如果输入密码正确,则在oled屏幕上显示“PassWord Right”;
如果输入密码错误,则在oled屏幕上显示“PassWord Error”;
如果输入密码不是四位,则在oled上显示“Input 4Num”
(1)头文件
#include \"stm32f10x.h\"#include \"oled.h\"#include \"keyboard.h\"#include \"usart.h\"#include \"spi.h\"#include \"delay.h\"#include \"stdio.h\"#include \"string.h\"//全局变量char Key_Val;char input_code[7] = {0};//存放输入的密码uint8_t input_index = 0;//数组的下角标
(2)主函数
int main(void){oled_gpio_init();oled_init();Keyboard_Init();oled_fill(0xFF);delay_ms(1000);oled_fill(0x00);delay_ms(1000);while (1){//显示“Input Password”oled_show_string(0, 0, \"Input Password:\", 16);Key_Val = Keyboard_Scan();if (Key_Val){//进行输入,四位密码if (Key_Val >= \'0\' && Key_Val <= \'9\'){ if (input_index < 6) {input_code[input_index++] = Key_Val;oled_show_char(10 * input_index, 5, Key_Val, 16); // 显示输入}} /* 如果按下了#,要进行密码比对,从而清零 */else if (Key_Val == \'#\'){input_code[input_index] = \'\\0\'; // 补字符串结束符if (input_index == 4){ if (strcmp(input_code, \"1234\") == 0) { oled_fill(0x00); oled_show_string(10, 3, \"PassWord Right \", 16); delay_ms(1000); } else { oled_fill(0x00); oled_show_string(10, 3, \"PassWord Error \", 16); delay_ms(1000); } } else { oled_show_string(10, 3, \"Input 4Num\", 16); delay_ms(1000); } input_index = 0;//下角标也要重新赋值成0 memset(input_code, 0, sizeof(input_code)); //memset函数:把 input_code 这整个数组里的所有元素都设置为零,即清空了输入缓存 delay_ms(1000); oled_fill(0x00); delay_ms(500); } //如果按了*,则清零,在屏幕上显示Input Password Please Again! else if (Key_Val == \'*\') { input_index = 0; memset(input_code, 0, sizeof(input_code)); oled_fill(0x00); oled_show_string(0, 0, \"Input Password\", 16); oled_show_string(3, 3, \"Please Again!\", 16); } } }}
当然,我有个部分写的不是很好,我们可以把密码存放到ROM里面,也就是用到了原先我写的SPI应用W25Q64,可以把密码存放到W25Q64中。这次我们主要是学习关于矩阵键盘的内容,我尽量不给大家添加学习的负担,我会在未来我写单片机项目专栏中,进行多个知识点整合时,会讲解如何将密码或者数据存放到W25Q64当中。(狗头)
五 实现效果
最后实现的一些效果如下:
欢
欢迎大家在评论区发表观点~
【超级会员V4】通过百度网盘分享的文件:轮询法.zip等2个文件
链接:https://pan.baidu.com/s/1Jp2InrAQOFNvuQ51qzYHag
提取码:42z5
复制这段内容打开「百度网盘APP 即可获取」