终极:STM32实现4 * 4矩阵键盘扫描(适用HAL库和标准库)

电脑杂谈  发布时间:2020-10-12 05:07:26  来源:网络整理

stm32 矩阵键盘 程序_stm32 矩阵键盘程序_stm32矩阵键盘程序

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

1、键盘:

stm32矩阵键盘程序

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

2、STM32 cubemx引脚配置图:

stm32矩阵键盘程序_stm32 矩阵键盘程序_stm32 矩阵键盘 程序

stm32矩阵键盘程序

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

stm32矩阵键盘程序

4个引脚配备了推挽输出,这4个带输出的引脚不需要配置为内部上拉和下拉。其他4个引脚配置为内部上拉输入。

3、生成代码后,开始编写逻辑:

stm32 矩阵键盘 程序_stm32 矩阵键盘程序_stm32矩阵键盘程序

在编写之前,让我们先定义头文件并定义一些要使用的宏:

#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};   //保存按键行扫描情况的状态数组

然后您可以编写扫描逻辑,首先编写用于水平扫描的代码:

stm32 矩阵键盘 程序_stm32矩阵键盘程序_stm32 矩阵键盘程序

/***
 *函数名: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,依此类推。现在,您可以调用此函数执行按键操作:

stm32 矩阵键盘 程序_stm32 矩阵键盘程序_stm32矩阵键盘程序

/***
 *函数名: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");
    }
}

我使用串行端口助手将其打印出来,以查看按下了哪个按钮。可以进行实际测量。

stm32矩阵键盘程序

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

    相关阅读
      发表评论  请自觉遵守互联网相关的政策法规,严禁发布、暴力、反动的言论

      热点图片
      拼命载入中...