当前位置: 首页 > news >正文

【星云 Orbit • STM32F4】03g. 按键玩法七:矩阵键盘单个触发

【星云 Orbit • STM32F4】03g. 按键玩法七:矩阵键盘单个触发


引言

矩阵键盘是一种常见的输入设备,广泛应用于各种嵌入式系统中。通过矩阵键盘,用户可以通过按键输入字符或控制信号。本文将详细介绍如何使用STM32F407的GPIO引脚实现矩阵键盘的单个触发功能。通过本教程,读者将能够掌握矩阵键盘的基本原理以及如何通过HAL库实现单个触发的检测。


硬件准备

在开始编程之前,确保您已经准备好以下硬件:

  1. STM32F407开发板:板载STM32F407VGT6(Cortex-M4/168MHz)作为主控芯片。
  2. 矩阵键盘模块:4x4矩阵键盘模块。
  3. 连接线:用于连接矩阵键盘和开发板。
  4. 限流电阻:若干个220Ω至330Ω的电阻,用于保护电路。

硬件连接

将矩阵键盘连接到STM32F407的GPIO引脚:

  1. 连接矩阵键盘的行引脚

    • 将矩阵键盘的行引脚(通常标记为R0-R3)连接到STM32F407的PB0-PB3引脚。
  2. 连接矩阵键盘的列引脚

    • 将矩阵键盘的列引脚(通常标记为C0-C3)连接到STM32F407的PC0-PC3引脚。
  3. 连接地线

    • 将矩阵键盘的地线连接到STM32F407的GND引脚。

GPIO配置

在STM32F407中,GPIO引脚可以配置为多种模式,以适应不同的应用需求。以下是一些常见的GPIO模式:

  1. 输入模式

    • 浮空输入(Floating Input):引脚处于高阻态,适用于不需要上拉或下拉的情况。
    • 上拉输入(Pull-Up Input):引脚内部连接上拉电阻,适用于外部信号为低电平有效的情况。
    • 下拉输入(Pull-Down Input):引脚内部连接下拉电阻,适用于外部信号为高电平有效的情况。
  2. 输出模式

    • 推挽输出(Push-Pull Output):引脚可以输出高电平或低电平,适用于直接驱动小电流负载,如LED灯。
    • 开漏输出(Open-Drain Output):引脚输出低电平或高阻态,适用于需要外部上拉电阻的场合。

在本教程中,我们将矩阵键盘的行引脚配置为推挽输出模式,列引脚配置为上拉输入模式。

配置GPIO时钟

在使用GPIO引脚之前,需要先使能相应的GPIO时钟。对于PB0-PB3引脚,需要使能GPIOB时钟;对于PC0-PC3引脚,需要使能GPIOC时钟。

// 使能GPIOB时钟
__HAL_RCC_GPIOB_CLK_ENABLE();

// 使能GPIOC时钟
__HAL_RCC_GPIOC_CLK_ENABLE();

配置GPIO引脚

使用GPIO_InitTypeDef结构体配置GPIO引脚的模式、上下拉、速度等参数。

GPIO_InitTypeDef GPIO_InitStruct = {0};

// 配置PB0-PB3为推挽输出模式
GPIO_InitStruct.Pin = GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_2 | GPIO_PIN_3;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;

HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);

// 配置PC0-PC3为上拉输入模式
GPIO_InitStruct.Pin = GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_2 | GPIO_PIN_3;
GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
GPIO_InitStruct.Pull = GPIO_PULLUP;

HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);

按键扫描模块

为了实现模块化设计,我们将按键的扫描功能封装到bsp/KEY目录下的bsp_key.cbsp_key.h文件中。

1. 创建KEY目录

  1. 打开文件管理器

    • 导航到STM32F407项目目录下的Drivers/BSP文件夹。
  2. 创建新目录

    • 右键点击空白区域,选择新建文件夹
    • 输入目录名称KEY,并按回车键确认。

2. 创建bsp_key.cbsp_key.h文件

  • 确保bsp_key.cbsp_key.h文件当前位于Drivers/BSP/KEY目录下。

3. 更新项目包含路径

  1. 打开Keil MDK

    • 加载当前的STM32F407项目。
  2. 进入项目设置

    • 右键点击工程名称,选择Options for Target
  3. 添加新的包含路径

    • 在弹出的窗口中,选择C/C++选项卡。
    • Include Paths字段中,添加以下路径:
      Drivers/BSP/KEY
      
    • 确保路径正确无误,点击OK保存设置。

4. 更新main.c文件

  1. 打开main.c文件

    • 在Keil MDK的项目资源管理器中,找到并双击main.c文件。
  2. 包含新的头文件

    • 在文件顶部,添加以下包含语句:
      #include "bsp_key.h"
      
    • 确保路径正确,以便编译器能够找到该头文件。

5. 重新编译项目

  1. 编译工程

    • 点击工具栏中的Build按钮(或按F7键)。
    • 确保编译过程中没有错误和警告。
  2. 处理编译错误

    • 如果出现包含路径错误,请检查Include Paths设置是否正确。
    • 确保bsp_key.h文件位于Drivers/BSP/KEY目录下。

6. 更新项目分组

  1. 添加新的文件夹分组

    • 在Keil MDK的项目资源管理器中,右键点击BSP分组,选择Add Group
    • 输入分组名称KEY,点击OK
  2. 添加文件到分组

    • 右键点击新的KEY分组,选择Add New Item to Group
    • 选择Add Existing File,导航到Drivers/BSP/KEY目录,选择bsp_key.cbsp_key.h文件,点击OK
  3. 确保文件可见性

    • 确保bsp_key.cbsp_key.h文件在KEY分组下可见,并且路径正确。

按键扫描模块实现

bsp_key.h文件

#ifndef __BSP_KEY_H
#define __BSP_KEY_H

#include "stm32f4xx_hal.h"

#define ROWS 4    // 矩阵键盘的行数
#define COLS 4    // 矩阵键盘的列数

/**
 * @brief 初始化矩阵键盘
 */
void KEY_Init(void);

/**
 * @brief 扫描矩阵键盘并检测按键状态
 * @return 按键状态(0:未按下,1-16:按键编号)
 */
uint8_t KEY_Scan(void);

#endif /* __BSP_KEY_H */

bsp_key.c文件

#include "bsp_key.h"

static uint8_t key_state = 0;

/**
 * @brief 初始化矩阵键盘
 */
void KEY_Init(void) {
    GPIO_InitTypeDef GPIO_InitStruct = {0};

    // 使能GPIOB和GPIOC时钟
    __HAL_RCC_GPIOB_CLK_ENABLE();
    __HAL_RCC_GPIOC_CLK_ENABLE();

    // 配置PB0-PB3为推挽输出模式
    GPIO_InitStruct.Pin = GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_2 | GPIO_PIN_3;
    GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;

    HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);

    // 配置PC0-PC3为上拉输入模式
    GPIO_InitStruct.Pin = GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_2 | GPIO_PIN_3;
    GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
    GPIO_InitStruct.Pull = GPIO_PULLUP;

    HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);
}

/**
 * @brief 扫描矩阵键盘并检测按键状态
 * @return 按键状态(0:未按下,1-16:按键编号)
 */
uint8_t KEY_Scan(void) {
    static uint8_t row = 0;
    static uint8_t col = 0;
    static uint8_t key_pressed = 0;

    if (key_pressed) {
        // 检测按键是否释放
        if (HAL_GPIO_ReadPin(GPIOC, C0_Pin) == GPIO_PIN_SET &&
            HAL_GPIO_ReadPin(GPIOC, C1_Pin) == GPIO_PIN_SET &&
            HAL_GPIO_ReadPin(GPIOC, C2_Pin) == GPIO_PIN_SET &&
            HAL_GPIO_ReadPin(GPIOC, C3_Pin) == GPIO_PIN_SET) {
            key_pressed = 0;
        }
        return 0;
    }

    // 扫描行
    for (row = 0; row < ROWS; row++) {
        // 激活当前行
        switch (row) {
            case 0:
                HAL_GPIO_WritePin(GPIOB, GPIO_PIN_0, GPIO_PIN_RESET);
                break;
            case 1:
                HAL_GPIO_WritePin(GPIOB, GPIO_PIN_1, GPIO_PIN_RESET);
                break;
            case 2:
                HAL_GPIO_WritePin(GPIOB, GPIO_PIN_2, GPIO_PIN_RESET);
                break;
            case 3:
                HAL_GPIO_WritePin(GPIOB, GPIO_PIN_3, GPIO_PIN_RESET);
                break;
        }

        // 检测列
        for (col = 0; col < COLS; col++) {
            if (HAL_GPIO_ReadPin(GPIOC, (GPIO_PinTypeDef)(GPIO_PIN_0 << col)) == GPIO_PIN_RESET) {
                // 按键按下
                key_pressed = 1;
                return (row * COLS) + col + 1;
            }
        }

        // 禁用当前行
        switch (row) {
            case 0:
                HAL_GPIO_WritePin(GPIOB, GPIO_PIN_0, GPIO_PIN_SET);
                break;
            case 1:
                HAL_GPIO_WritePin(GPIOB, GPIO_PIN_1, GPIO_PIN_SET);
                break;
            case 2:
                HAL_GPIO_WritePin(GPIOB, GPIO_PIN_2, GPIO_PIN_SET);
                break;
            case 3:
                HAL_GPIO_WritePin(GPIOB, GPIO_PIN_3, GPIO_PIN_SET);
                break;
        }
    }

    return 0;
}

主程序实现

#include "stm32f4xx_hal.h"
#include "bsp_key.h"

int main(void) {
    // 系统初始化
    HAL_Init();
    SystemClock_Config();

    // 按键初始化
    KEY_Init();

    while (1) {
        // 扫描按键状态
        uint8_t key = KEY_Scan();

        if (key != 0) {
            // 按键按下,执行相应操作
            // 在此处添加按键处理代码
            // 例如,控制LED灯或播放声音
        }
    }
}

测试与验证

  1. 编译与下载

    • 将代码编译并下载到STM32F407开发板中。
  2. 观察按键状态

    • 连接好硬件后,按下矩阵键盘上的按键,观察是否能够正确检测按键按下事件。如果按键状态没有正确检测,请检查硬件连接和代码配置是否正确。
  3. 验证单个触发

    • 按下按键,确保每次按下只触发一次响应。如果触发不正常,请检查按键扫描逻辑以及相关处理代码。

总结

通过本教程,您已经掌握了如何使用STM32F407的GPIO引脚实现矩阵键盘的单个触发功能。矩阵键盘的扫描逻辑是关键步骤,选择合适的行和列配置以及扫描逻辑可以确保按键的稳定工作。模块化设计使代码更加清晰和易于维护,为后续的项目扩展奠定了良好的基础。希望本教程对您有所帮助,祝您在嵌入式开发的道路上取得更大的成功!

相关文章:

  • 迷你世界脚本方块接口:Block
  • 力扣hot 100之矩阵四题解法总结
  • 博客系统--测试报告
  • 基于SpringBoot和PostGIS的各省与地级市空间距离分析
  • 17、什么是智能指针,C++有哪几种智能指针【高频】
  • C#使用技巧
  • Deepseek+RAGFLOW部署教程
  • 计算机毕业设计SpringBoot+Vue.js在线课程管理系统(源码+文档+PPT+讲解)
  • JVM常用概念之垃圾回收设计与停顿
  • 学习C++常用词汇词组及缩写汇总
  • Node.js二:第一个Node.js应用
  • 蓝桥备赛(六)- C/C++输入输出
  • 在Spring Boot项目中将中文转换为拼音:从入门到实践
  • Hive之正则表达式
  • flink web ui未授权漏洞处理
  • 【行政区划获取】
  • 专业工具,杜绝一切垃圾残留!
  • surfaceflinger对INVALIDATE和REFRESH消息的处理
  • 解锁网络防御新思维:D3FEND 五大策略如何对抗 ATTCK
  • 突破Ajax跨域困境,解锁前端通信新姿势
  • 商务部:中方敦促美方尽快停止232关税措施
  • 中央军委决定调整组建3所军队院校
  • 杨文庄当选中国人口学会会长,曾任国家卫健委人口家庭司司长
  • 多条跨境铁路加速推进,谁是下一个“超级枢纽”?
  • 优化营商环境,服务上海“五个中心”建设,北外滩有何举措?
  • 走进“双遗之城”,领略文武风采:沧州何以成文旅新贵