STM32 实现 4*4 矩阵键盘扫描(HAL库标准库 都适用)

Posted xingboy

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了STM32 实现 4*4 矩阵键盘扫描(HAL库标准库 都适用)相关的知识,希望对你有一定的参考价值。

  本文实现的代码是基于STM32HAL库的基础上的,不过标准库也可以用,只是调用的库函数不同,逻辑跟配置是一样的,按我这里的逻辑来配置即可。

 

1、键盘原理图:

 技术图片

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
",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;
}

  这个函数,可以判断哪一行有按键按下,并返回有按键按下的行数。

  接着编写列扫描的代码,这里的思想是,先扫描第一列,接着判断第一列有没有行被按下,有的话就可以直接定位到这一列的哪一行,其他4列逻辑一样,这样就可以定位到哪个按键按下了。

/***
 *函数名: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;    //第1列扫描    
    if( (key_row_num=KEY_ROW_SCAN()) != 0 )
    { 
        Key_Num = 0 + KEY_ROW_SCAN();
        //printf("Key_Clo_1
");
    }
    KEY_CLO0_OUT_HIGH;
    
    KEY_CLO1_OUT_LOW;    //第2列扫描    
    if( (key_row_num=KEY_ROW_SCAN()) != 0 )
    { 
        Key_Num = 4 + key_row_num;
        //printf("Key_Clo_2
");
    }
    KEY_CLO1_OUT_HIGH;
    
    KEY_CLO2_OUT_LOW;   //第3列扫描
    if( (key_row_num=KEY_ROW_SCAN()) != 0 )
    { 
      Key_Num = 8 + key_row_num;
        //printf("Key_Clo_3
");
    }
    KEY_CLO2_OUT_HIGH;
    
    KEY_CLO3_OUT_LOW;   //第4列扫描 
    if( (key_row_num=KEY_ROW_SCAN()) != 0 )
    { 
        Key_Num = 12 + key_row_num;
        //printf("Key_Clo_4
");
    }
    KEY_CLO3_OUT_HIGH;
    
    return Key_Num;
}

  这个函数就可以直接返回1-16个按键的按键数了,按下第一个按键就返回1,第2个就返回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 
",key_confirm); //按下1-16个按键的操作
        printf("= = = = = = = = = = = 
");
    }
}

  我这里就是用串口助手打印出来查看哪个按键按下的,实测可用。

4、总结:

(1)先配置8个引脚,4个配置输入,上拉;4个配置成推挽(PP)输出,不用上下拉,输出高电平;

(2)软件逻辑:

  a. 先说一下行扫描的原理,因为如果有按键按下的话,某一个输入的引脚就会跟对应的输出引脚连接,因为输出为高电平,所以对应的输入引脚会被拉高,读取引脚的状态,判断哪个引脚被拉高就可以知道哪一行有按键按下了;总的来说是通过高四位输出高电平来对矩阵键盘进行逐行扫描,当低四位接收到的数据不全为1的时候,说明有按键按下,然后通过接收到的数据是哪一位为0来判断是哪一行按键被按下

  b. 列扫描原理:思路是先把第一列输出低电平,接着读取高4位的电平转态,单不全为1时,说明这一列有按键按下,同时结合行扫描判断出来的行数定位到按下的按键。程序里是扫描第一列的时候第一列给低电平,接着进行行扫描判断,因为输入输出引脚都是高电平了,只有第一列的引脚是低电平,所以当第一列有按键按下的时候,行扫描读到的4个引脚就不全为1,这时因为第一列的电平是我们自己给的,所以就可以直接判断这一列有按键按下;接着利用行扫描原理定位哪一行有按键按下,这样就可以判断出第一列的某一行的按键被按下了,其他3列同理,然后轮流扫描4列就可以判断16个按键了。

 

以上是关于STM32 实现 4*4 矩阵键盘扫描(HAL库标准库 都适用)的主要内容,如果未能解决你的问题,请参考以下文章

STM32使用HAL库实现串口通讯——实战操作

4*4矩阵键盘FPGA扫描实现

STM32学习(31)STM32通过ADC实现多按键功能(标准库和HAL库实现)

带有 HAL 库的 STM32F4-Discovery (STM32F429ZIT6) 上的 RS232 (UART)?

基于STM32F103+AS608指纹模块+RFID-RC522射频模块+OLED显示模块+4x4矩阵键盘+HC-05蓝牙模块发验证码----智能门禁系统

stm32hal库rtc设置出错