STM32学习7 按键扫描

STM32学习7 按键扫描

  • 一、实验电路介绍
  • 二、按键GPIO初始化
  • 三、扫描原理
    • 1. GPIO引脚配置
    • 2. 状态轮询
    • 3. 按键状态检测
    • 4. 循环扫描的优缺点
      • 优点:
      • 缺点:
  • 四、一次扫描与持续扫描
  • 五、代码实现
    • 1. 头文件定义
    • 2. 函数实现
    • 3. 主体函数

一、实验电路介绍

本实验使用普中STM32-F1开发板,芯片型号是STM32F103ZET6。
其按键电路如下:
在这里插入图片描述
对应的芯片引脚:
在这里插入图片描述
从电路可以看出,键盘的 KEY_UP 键如果接通,会连接高电平 。
其它几个按键在按下的时候连接低电平,对应的GPIO口:

  • KEY_UP:GPIOA GPIO_Pin0 引脚
  • KEY_LEFT:GPIOE GPIO_Pin2 引脚
  • KEY_RIGHT:GPIOE_GPIO_Pin4 引脚
  • KEY_DOWN:GPIOE_GPIO_Pin3 引脚

二、按键GPIO初始化

按键 KEY_UP 和其它三个按键的接法不同,需要不同的配置方式。
其中 KEY_UP 按下后接高电平,在默认情况下需要置低,初始化时设置为输入下拉,代码如下:

    // 开启GPIOA的时钟RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);// 设置上引脚GPIO_InitStructure.GPIO_Pin = KEY_UP_PIN;// 设置输入下拉模式GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPD;GPIO_Init(KEY_UP_PORT, &GPIO_InitStructure); // 初始化GPIOA

其它三个按键,按下时接低电平,默认置高,初始化设置为输入上拉,代码如下:

    // 开 E 时钟RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOE, ENABLE);// 设置下、左、右引脚GPIO_InitStructure.GPIO_Pin = KEY_DOWN_PIN | KEY_LEFT_PIN | KEY_RIGHT_PIN;// 设置输入上拉模式GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;GPIO_Init(KEY_DOWN_PORT, &GPIO_InitStructure); // 初始化GPIOE

三、扫描原理

1. GPIO引脚配置

首先,需要将用于连接按键的GPIO引脚配置为输入模式。

2. 状态轮询

然后轮询每个按键的状态,以确定按键是否被按下或释放。轮询扫描可以通过在主循环中定期检查每个按键的状态来实现。例如,在每次主循环迭代中,都检查一次按键的状态。

3. 按键状态检测

一般来说,按键有两种状态:按下和释放。在检测按键状态时,需要注意去除按键的抖动干扰。抖动是指在按键被按下或释放时,由于机械接触或物理特性导致的瞬间状态变化。为了应对抖动,可以采用软件方法或硬件滤波器。

本示例采用延时10ms读取值的方法来去抖,示例:

if(key_up_value == 1 || key_down_value ==0 || key_left_value ==0 || key_right_value ==0){delay_ms(10);
}

硬件方法去抖可以参考实现:SR触发器去抖

4. 循环扫描的优缺点

优点:

  1. 简单直观: 在循环中进行按键扫描的方法简单易懂,逻辑清晰,易于理解和实现。

  2. 灵活性: 可以根据具体需求灵活调整扫描的频率和方式,满足不同场景下的要求。

  3. 适用性广: 适用于小型嵌入式系统或者对按键响应速度要求不高的场景,适用性广泛。

  4. 资源消耗低: 相比于中断方式,循环扫描不需要额外的中断处理函数,减少了系统资源的占用。

缺点:

  1. 效率低下: 在循环中进行按键扫描会占用 CPU 的时间片,降低了系统的处理效率,特别是当系统有其他紧急任务需要处理时,会影响响应速度和实时性。

  2. 实时性差: 循环扫描需要不断地遍历所有按键状态,导致按键的检测周期相对较长,实时性差,无法满足对按键响应速度要求较高的场景。

  3. 占用 CPU 资源: 循环扫描需要持续占用 CPU 资源,特别是在大型系统中,可能会影响其他任务的执行,降低系统的整体性能。

  4. 功耗高: 循环扫描需要 CPU 不断地处于工作状态,会增加系统的功耗,对于对功耗要求较高的场景不太适用。

后面学习中会采用中断的方式来读取键盘。

四、一次扫描与持续扫描

这里的一次扫描,是指按下按键后,如果不松开,键盘的扫描函数不会继续输出所按键值。
而持续扫描,在按下按键后,如果手不松开,键盘的扫描函数仍会持续输出按键值。

五、代码实现

为方便看到演示效果,示例的代码在获取到扫描的按键后,会在数码管显示不同的数值。

  • 上:显示0
  • 下:显示1
  • 左:显示2
  • 右:显示3

1. 头文件定义

key_utils.h

#ifndef __KEY_UTILS_H__
#define __KEY_UTILS_H__
#include "stm32f10x.h"// 引脚和端口
#define KEY_UP_PIN GPIO_Pin_0
#define KEY_UP_PORT GPIOA
#define KEY_LEFT_PIN GPIO_Pin_2
#define KEY_LEFT_PORT GPIOE
#define KEY_DOWN_PIN GPIO_Pin_3
#define KEY_DOWN_PORT GPIOE
#define KEY_RIGHT_PIN GPIO_Pin_4
#define KEY_RIGHT_PORT GPIOE// 读取引脚状态
#define key_up_value  GPIO_ReadInputDataBit(KEY_UP_PORT, KEY_UP_PIN)
#define key_down_value  GPIO_ReadInputDataBit(KEY_DOWN_PORT, KEY_DOWN_PIN)
#define key_left_value  GPIO_ReadInputDataBit(KEY_LEFT_PORT, KEY_LEFT_PIN)
#define key_right_value  GPIO_ReadInputDataBit(KEY_RIGHT_PORT, KEY_RIGHT_PIN)// 按键
#define KEY_UP 0
#define KEY_DOWN 1
#define KEY_LEFT 2
#define KEY_RIGHT 3
#define KEY_NONE 4void key_init(void);
u8 key_scan(u8 mode);
#endif

2. 函数实现

#include "key_utils.h"
#include "sys_tick_utils.h"void key_init(void)
{GPIO_InitTypeDef GPIO_InitStructure; // 定义GPIO初始化结构体// 开启GPIOA的时钟RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);// 设置上引脚GPIO_InitStructure.GPIO_Pin = KEY_UP_PIN;// 设置输入下拉模式GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPD;GPIO_Init(KEY_UP_PORT, &GPIO_InitStructure); // 初始化GPIOA// 开 E 时钟RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOE, ENABLE);// 设置下、左、右引脚GPIO_InitStructure.GPIO_Pin = KEY_DOWN_PIN | KEY_LEFT_PIN | KEY_RIGHT_PIN;// 设置输入上拉模式GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;GPIO_Init(KEY_DOWN_PORT, &GPIO_InitStructure); // 初始化GPIOE}
static u8 key_read(void){if(key_up_value == 1 || key_down_value ==0 || key_left_value ==0 || key_right_value ==0){delay_ms(10);if(key_up_value == 1){return KEY_UP;}else if(key_down_value == 0){return KEY_DOWN;}else if(key_left_value == 0){return KEY_LEFT;}else if(key_right_value == 0){return KEY_RIGHT;}}return KEY_NONE;
}
u8 last_key;
/*** @brief  按键扫描函数* @param  mode: 0 单次扫描 1: 连续扫描*/
u8 key_scan(u8 mode)
{if(mode==0){u8 key = key_read();if(key != KEY_NONE){if(key == last_key){return KEY_NONE;}else{last_key = key;return key;}}else{last_key = KEY_NONE;}}else{return key_read();}return KEY_NONE;
}

3. 主体函数

#include "gpio_utils.h"
#include "rcc_utils.h"
#include "stm32f10x.h"
#include "sys_tick_utils.h"
#include "led_utils.h"
#include "key_utils.h"// 主函数
int main(void)
{GPIO_Configuration(); //调用GPIO配置函数sys_tick_init(72);led_all_off();key_init();while (1) //无限循环{delay_ms(10);u8 key = key_scan(0);if(key==KEY_UP){led_lightn(0);}else if(key==KEY_DOWN){led_lightn(1);}else if(key==KEY_LEFT){led_lightn(2);}else if(key==KEY_RIGHT){led_lightn(3);}else{led_all_off();}}
}

本文源码地址:
https://gitee.com/xundh/stm32_arm_learn/tree/master/lesson7_key

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/521279.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

广播

1.什么是广播 2.标准广播 BroadStandardActivity.java package com.tiger.chapter09;import androidx.appcompat.app.AppCompatActivity;import android.content.Intent; import android.content.IntentFilter; import android.os.Bundle; import android.view.View;…

为什么不用 index 做 key?

“在 Vue 中,我们在使用 v-for 渲染列表的时候,为什么要绑定一个 key?能不能用 index 做 key?” 在聊这个问题之前我们还得需要知道 Vue 是如何操作 DOM 结构的。 虚拟DOM 我们知道,Vue 不可以直接操作 DOM 结构&am…

js小案例-表格隔行变色

运行效果: 代码演示: <!DOCTYPE html> <html><head><meta charset="utf-8" /><title>18-案例-表格隔行变色</title></head><body><table id="tab1" border="1" width="800" al…

北斗卫星引领智能油气管线革新

北斗卫星引领智能油气管线革新 现代化的油气管线系统已成为国家经济发展的重要基础设施&#xff0c;而北斗卫星则为这些管线注入了新的活力。北斗卫星作为中国自主研发的卫星导航定位系统&#xff0c;其准确度和稳定性在全球范围内享有盛誉。在智能化时代的背景下&#xff0c;…

【OpenGL实践02】glDrawElements的使用案例

目录 一、说明二、顶点顺序渲染和选择渲染2.1 基本方法函数2.2.顶点数据管理2.3 层级关系 三、测试EBO的代码四、总结五、后记 一、说明 我们常用的着色器绘制函数是glDrawArray和glDrawElements&#xff0c;glDrawArray我们已经使用的很熟练&#xff0c;不需要重提&#xff…

深入了解Python的eval函数:基础用法与潜在危险【第118篇—eval函数】

深入了解Python的eval函数&#xff1a;基础用法与潜在危险 在Python中&#xff0c;eval函数是一个强大而灵活的工具&#xff0c;它允许将字符串作为代码来执行。然而&#xff0c;虽然eval在某些情况下非常方便&#xff0c;但它也潜藏着一些潜在的危险&#xff0c;如果不小心使…

小火星露谷管理器 如何禁用管理器下载?

错误操作 当你在N网点击下载时&#xff0c;你可能会点击左边第一个按钮进行下载&#xff0c;如图&#xff1a; 然后你可能会看到这样的一个提示&#xff1a; 很多用户看着这个提示误以为小火星露谷管理器禁用了N网的下载。 正确操作 N网网页上的按钮MOD MANAGER DOWNLOAD翻…

海外IP代理应用:亚马逊使用什么代理IP?

代理IP作为网络活动的有力工具&#xff0c;同时也是跨境电商的必备神器。亚马逊作为跨境电商的头部平台&#xff0c;吸引了大量的跨境电商玩家入驻&#xff0c;想要做好亚马逊&#xff0c;养号、测评都需要代理IP的帮助。那么应该使用什么代理IP呢&#xff1f;如何使用&#xf…

这6个国产办公软件凭什么被推荐?是真的好用

在数字化时代&#xff0c;办公软件已经成为我们日常生活和工作中不可或缺的工具。近年来&#xff0c;国产办公软件凭借其高效、便捷的特点受到了广泛的好评。今天给大家分享6款备受推荐的国产办公软件&#xff0c;让你了解它们的优势和使用场景。 一、Listary&#xff1a;强大的…

Python数据分析库之pandera使用详解

概要 在数据科学和数据分析中,数据的质量至关重要。不良的数据质量可能导致不准确的分析和决策。为了确保数据的质量,Python Pandera 库应运而生。本文将深入介绍 Python Pandera,这是一个用于数据验证和清洗的库,并提供丰富的示例代码,帮助大家充分利用它来提高数据质量…

学生课程参与度的一些情况

喊口号 日常校园中不乏各式各样的口号和标语。 但是能否落实到实处&#xff0c;非常难以评定的。 以学生为中心 实际上&#xff0c;学生对于课程几乎没有任何选择权和掌控权。 1&#xff0c;课程并非是学生自己选择的&#xff0c;还是培养方案安排的。 2&#xff0c;课程教…

Python与Go代码转换库之grumpy使用详解

概要 在软件开发领域,Python 和 Go 是两种备受欢迎的编程语言,它们各自拥有独特的优势和特点。Python 以其简洁、易学和强大的生态系统而闻名,而 Go 则以其高效、并发和简洁的语法而受到广泛青睐。然而,在某些情况下,开发人员可能会希望将 Python 代码转换为 Go 代码,以…