
本文实现的代码基于STM32HAL库,但是也可以使用标准库,但是要调用的库函数是不同的,并且逻辑与配置相同。只需根据我的逻辑进行配置即可。
1、键盘:

原理示例:首先将F0-F7内部拉高,以便所有8个引脚都为高,然后执行列扫描。例如:如果按3按钮并扫描Y3列,先下拉F4,然后读取F0-F3的状态,它将读为1110,因此您可以知道F3行被下拉了,这现在是将Control F4下拉的程序,以便您可以知道F4列导致其更改了状态,以便可以在F4列和F3行中找到按钮。其他列也这样扫描,可以实现。
2、STM32 cubemx引脚配置图:


可以在此处使用外部晶体振荡器。时钟对此没有影响,也不需要打开中断,因此不会详细说明其他配置。让我们谈谈这8个GPIO的配置。

4个引脚配备了推挽输出,这4个带输出的引脚不需要配置为内部上拉和下拉。其他4个引脚配置为内部上拉输入。
3、生成代码后,开始编写逻辑:

在编写之前,让我们先定义头文件并定义一些要使用的宏:
#ifndef __HW_key_H__ #define __HW_key_H__ #include "main.h" #include "stm32f1xx_hal.h" #include <string.h> char KEY_SCAN(void); char KEY_ROW_SCAN(void); void HW_KEY_FUNCTION(void); #define KEY_CLO0_OUT_LOW HAL_GPIO_WritePin(GPIOE,GPIO_PIN_7,GPIO_PIN_RESET) #define KEY_CLO1_OUT_LOW HAL_GPIO_WritePin(GPIOE,GPIO_PIN_8,GPIO_PIN_RESET) #define KEY_CLO2_OUT_LOW HAL_GPIO_WritePin(GPIOE,GPIO_PIN_9,GPIO_PIN_RESET) #define KEY_CLO3_OUT_LOW HAL_GPIO_WritePin(GPIOE,GPIO_PIN_10,GPIO_PIN_RESET) #define KEY_CLO0_OUT_HIGH HAL_GPIO_WritePin(GPIOE,GPIO_PIN_7,GPIO_PIN_SET) #define KEY_CLO1_OUT_HIGH HAL_GPIO_WritePin(GPIOE,GPIO_PIN_8,GPIO_PIN_SET) #define KEY_CLO2_OUT_HIGH HAL_GPIO_WritePin(GPIOE,GPIO_PIN_9,GPIO_PIN_SET) #define KEY_CLO3_OUT_HIGH HAL_GPIO_WritePin(GPIOE,GPIO_PIN_10,GPIO_PIN_SET) #endif
然后包含头文件并定义一些要使用的变量数组:
#include "HW_key.h" uint8_t Key_row[1]={0xff}; //保存按键行扫描情况的状态数组
然后您可以编写扫描逻辑,首先编写用于水平扫描的代码:

/*** *函数名:KEY_ROW_SCAN *功 能:按键行扫描 *返回值:1~4,对应1~4行按键位置 */ char KEY_ROW_SCAN(void) { //读出行扫描状态 Key_row[0] = HAL_GPIO_ReadPin(GPIOE,KEY_row0_Pin)<<3; Key_row[0] = Key_row[0] | (HAL_GPIO_ReadPin(GPIOE,KEY_row1_Pin)<<2); Key_row[0] = Key_row[0] | (HAL_GPIO_ReadPin(GPIOE,KEY_row2_Pin)<<1); Key_row[0] = Key_row[0] | (HAL_GPIO_ReadPin(GPIOE,KEY_row3_Pin)); if(Key_row[0] != 0x0f) //行扫描有变化,判断该列有按键按下 { HAL_Delay(10); //消抖 if(Key_row[0] != 0x0f) { //printf("Key_Row_DATA = 0x%x\r\n",Key_row[0]); switch(Key_row[0]) { case 0x07: //0111 判断为该列第1行的按键按下 return 1; case 0x0b: //1011 判断为该列第2行的按键按下 return 2; case 0x0d: //1101 判断为该列第3行的按键按下 return 3; case 0x0e: //1110 判断为该列第4行的按键按下 return 4; default : return 0; } } else return 0; } else return 0; }
此功能可以确定按下了按钮的行,并按下了按钮即可返回行数。
接下来,编写用于列扫描的代码。这里的想法是先扫描第一列,然后确定第一列中是否有行被按下,如果这样,您可以直接找到该列中的哪一行,其他四列的逻辑相同,因此您可以找到按下了哪个按钮。
/*** *函数名:KEY_SCAN *功 能:4*4按键扫描 *返回值:0~16,对应16个按键 */ char KEY_SCAN(void) { char Key_Num=0; //1-16对应的按键数 char key_row_num=0; //行扫描结果记录 KEY_CLO0_OUT_LOW; if( (key_row_num=KEY_ROW_SCAN()) != 0 ) { while(KEY_ROW_SCAN() != 0); //消抖 Key_Num = 0 + key_row_num; //printf("Key_Clo_1\r\n"); } KEY_CLO0_OUT_HIGH; KEY_CLO1_OUT_LOW; if( (key_row_num=KEY_ROW_SCAN()) != 0 ) { while(KEY_ROW_SCAN() != 0); Key_Num = 4 + key_row_num; //printf("Key_Clo_2\r\n"); } KEY_CLO1_OUT_HIGH; KEY_CLO2_OUT_LOW; if( (key_row_num=KEY_ROW_SCAN()) != 0 ) { while(KEY_ROW_SCAN() != 0); Key_Num = 8 + key_row_num; //printf("Key_Clo_3\r\n"); } KEY_CLO2_OUT_HIGH; KEY_CLO3_OUT_LOW; if( (key_row_num=KEY_ROW_SCAN()) != 0 ) { // Key_row[0] = HAL_GPIO_ReadPin(GPIOE,KEY_col0_Pin)<<3; // Key_row[0] = Key_row[0] | (HAL_GPIO_ReadPin(GPIOE,KEY_col1_Pin)<<2); // Key_row[0] = Key_row[0] | (HAL_GPIO_ReadPin(GPIOE,KEY_col2_Pin)<<1); // Key_row[0] = Key_row[0] | (HAL_GPIO_ReadPin(GPIOE,KEY_col3_Pin)); // printf("Key_Clo4_DATA = 0x%x\r\n",Key_row[0]); while(KEY_ROW_SCAN() != 0); Key_Num = 12 + key_row_num; //printf("Key_Clo_4\r\n"); } KEY_CLO3_OUT_HIGH; return Key_Num; }
此功能可以直接从1-16键返回键数。按第一个键返回1,第二个键返回2,依此类推。现在,您可以调用此函数执行按键操作:
/*** *函数名:KEY_ROW_SCAN *功 能:执行按下按键后的操作 *返回值:无 */ void HW_KEY_FUNCTION(void) { char key_confirm; key_confirm = KEY_SCAN(); if( 0 < key_confirm && key_confirm < 17 ) { printf("Key_NUM = %d \r\n",key_confirm); //按下1-16个按键的操作 printf("= = = = = = = = = = = \r\n"); } }
我使用串行端口助手将其打印出来,以查看按下了哪个按钮。可以进行实际测量。

4、摘要:
([1)首先配置8个引脚,4个配置输入,上拉; 4个配置为推挽(PP)输出,无上拉和下拉,输出高电平;
([2)软件逻辑:
a。我先说说行扫描的原理,因为如果按下一个按钮,一个输入引脚将被连接到相应的输出引脚,因为输出为高电平,所以相应的输入引脚将被拉高,读取状态该引脚,判断哪个引脚被拉高,您可以知道哪一行已按下按钮;通常,矩阵键盘是通过输出高四位的高电平逐行扫描的,当接收到的数据的低四位不是全部为1时,表示按下了按钮,然后确定哪一行按下的按钮,接收到的数据的哪一位为0;
b。列扫描原理:想法是首先在第一列中输出低电平,然后读取高4位的电平转换。当单个数字不是全为1时,表示此列中有一个按钮按下,并且该行同时合并。通过扫描确定的行数位于按下的键上。在程序中,当扫描第一列时,将第一列设置为低电平,然后执行行扫描判断。由于输入和输出引脚均为高电平,因此仅第一列中的引脚为低电平,因此当按下一列时,行扫描读取的4个引脚并非全部为1。第一栏的水平由我们自己给定,我们可以直接判断该栏是否已按下按钮;然后使用行扫描原理来定位哪个行被按下了一个按钮,从而可以判断出第一列的一行中的一个按钮被按下了,其他三列是相同的,然后可以判断出16个按钮依次扫描4列。
用外行的话来说,如果我给该列设置一个较低的级别,从而导致行扫描发生变化,那么我知道此列中有一个按键,然后检查行更改的级别变化,并计算出哪个行已更改。 ,您可以知道该列中的哪个按钮被按下。
本文来自电脑杂谈,转载请注明本文网址:
https://www.pc-fly.com/a/bofangqi/article-325496-1.html
热血丹心