(五)STM32 按键输入实验及 GPIO做普通 IO 的注意事项

目录

1. 按键硬件连接

2. 按键软件设计

3. 按键消抖

4. 使用 IO 口时的 注意事项(踩坑)


        上一节我们介绍了 STM32F1 的 IO 口作为输出的使用,这一章,我们将介绍如何使用 STM32F1 的 IO 口作为输入用。在本章中,我们将利用板载的 3 个按键,来控制板载的两个 LED 的亮灭和蜂鸣器的开关。通过本章的学习,你将了解到 STM32F1 的 IO 口作为输入口的使用方法。

1. 按键硬件连接

        我们将通过 正点原子 精英开发板 STM32F103 上载有的 3 个按钮(KEY_UP、KEY0 和KEY1),来控制板上的 红色个 LED 的亮灭翻转,三个按键任何一个按键,按一次,他们的状态就翻转一次。

        这里需要注意的是:KEY0 和 KEY1 是低电平有效的,而 KEY_UP 是高电平有效的,并且外部都没有上下拉电阻,所以,KEY0 和 KEY1对应的 IO 口应该设置为 上拉输入(当按键按下时候,检测 IO 口是不是低电平,是低电平则有效),KEY_UP 对应的 IO 口应该设置为 下拉输入(当按键按下时候,检测 IO 口是不是高电平,是高电平则有效),都需要在 STM32F1 内部设置上下拉。 

2. 按键软件设计

key.h 

#ifndef __KEY_H
#define __KEY_H	 
#include "sys.h"//位带操作读取IO口状态
#define KEY0  PEin(4)     //PE4
#define KEY1  PEin(3)	  //PE3 
#define WK_UP PAin(0)	  //PA0  WK_UP//库函数读取IO口状态
//#define KEY0    GPIO_ReadInputDataBit(GPIOE,GPIO_Pin_4)//读取按键0
//#define KEY1    GPIO_ReadInputDataBit(GPIOE,GPIO_Pin_3)//读取按键1
//#define WK_UP   GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_0)//读取按键3(WK_UP) #define KEY0_PRES 	1	//KEY0按下
#define KEY1_PRES	2	//KEY1按下
#define WKUP_PRES   3	//KEY_UP按下(即WK_UP/KEY_UP)void key_init(void);//IO初始化
u8 key_scan(u8);  	//按键扫描函数					    
#endif

        由以上代码可知,读取 IO 口状态,可以采用 位带操作 也可以采用 库函数读取。

key.c

#include "stm32f10x.h"
#include "key.h"
#include "sys.h"
#include "delay.h"//按键初始化函数
void key_init(void) //IO初始化
{GPIO_InitTypeDef GPIO_InitStructure;//使能PORTA,PORTE时钟RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOE, ENABLE); GPIO_InitStructure.GPIO_Pin  = GPIO_Pin_4 | GPIO_Pin_3 ; //KEY0-KEY1GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; //设置成上拉输入GPIO_Init(GPIOE, &GPIO_InitStructure);//初始化GPIOE4,3//初始化 WK_UP-->GPIOA.0      下拉输入GPIO_InitStructure.GPIO_Pin  = GPIO_Pin_0;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPD; //PA0设置成输入,默认下拉GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化GPIOA.0
}//按键处理函数
//返回按键值
//mode:0,不支持连续按;1,支持连续按; 通过改变静态变量的值来调节是否支持连续按
//0,没有任何按键按下
//1,KEY0按下
//2,KEY1按下
//3,KEY3按下 WK_UP
//注意此函数有响应优先级,KEY0>KEY1>KEY_UP!!
u8 key_scan(u8 mode)
{static u8 key_up = 1; //按键按松开标志if (mode)key_up = 1; //支持连按if (key_up && (KEY0 == 0 || KEY1 == 0 || WK_UP == 1)){delay_ms(40);//去抖动key_up = 0;if (KEY0 == 0)return KEY0_PRES;else if (KEY1 == 0)return KEY1_PRES;else if (WK_UP == 1)return WKUP_PRES;}else if (KEY0 == 1 && KEY1 == 1 && WK_UP == 0)key_up = 1;return 0;// 无按键按下
}

        这段代码包含 2 个函数,void KEY_Init(void) 和 u8 KEY_Scan(u8 mode),KEY_Init()是用来初始化按键输入的 IO 口的。首先使能 GPIOA 和 GPIOE 时钟,然后实现 PA0、PE3 和 PE4 的输入设置,这里和上一节的输出配置差不多,只是这里用来设置成的是输入而上一节是输出。
        KEY_Scan()函数,则是用来扫描这 3 个 IO 口是否有按键按下。KEY_Scan()函数,支持两种扫描方式,通过 mode 参数来设置。
        当 mode 为 0 的时候,KEY_Scan()函数将不支持连续按,扫描某个按键,该按键按下之后必须要松开,才能第二次触发,否则不会再响应这个按键,这样的好处就是可以防止按一次多次触发,而坏处就是在需要长按的时候比较不合适。
        当 mode 为 1 的时候,KEY_Scan()函数将支持连续按,如果某个按键一直按下,则会一直
返回这个按键的键值,这样可以方便的实现长按检测。

        这里有个 C语言小知识点:静态局部变量,只会被初始化一次,后续调用该函数,其值都是保留上次运行状态的值。
        有了 mode 这个参数,大家就可以根据自己的需要,选择不同的方式同时还有一点要注意的就是,该函数的按键扫描是有优先级的,最优先的是 KEY0,第二优先的是 KEY1,最后是WK_UP 按键。该函数有返回值,如果有按键按下,则返回非 0值,如果没有或者按键不正确,则返回 0。

3. 按键消抖

        这里还有一个消抖操作,通过延时进行按键消抖,其实还有其他方式进行消抖,定时器消抖和硬件消抖,这里是延时消抖,定时器消抖,可以以后来讲解,下面看下硬件上的按键消抖:

        利用电容充放电的延时,消除了波纹,从而简化软件的处理,软件只需要直接检测引脚的电平即可。

        从按键的原理图可知,这些按键在没有被按下的时候,GPIO 引脚的输入状态为低电平 (按键所在的电路不通,引脚接地);当按键按下时,GPIO 引脚的输入状态为高电平 (按键所在的电路导通,引脚接到电源)。只要我们检测引脚的输入电平,即可判断按键是否被按下。 这是在硬件上对按键的抖动做了处理。

4. 使用 IO 口时的 注意事项(踩坑)

        注意:PB3/PB4/PA13/PA14/PA15 这五个引脚不是普通的IO口,这是用作 JTAG/SWD 仿真器的调试接口,用作普通的IO口时,需要重定义功能后才能作为普通的IO口使用。情非得已,尽量不要使用这个 IO 口做为 普通的 IO 口来使用。这几个 IO 口默认是我插上仿真器来用的,一般不动他们。 

如果非要用做 普通的 IO 的话:

// PB3/PB4/PA13/PA14/PA15这五个引脚用作普通IO口的初始化:
{GPIO_InitTypeDef GPIO_InitStructure;  RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB | RCC_APB2Periph_GPIOA | RCC_APB2Periph_AFIO, ENABLE);// 使能复用时钟和引脚GPIO时钟  DBGMCU->CR = DBGMCU->CR & ~((uint32_t)1<<5); // 不分配跟踪引脚,释放PB3      GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable, ENABLE);  // 切换到SWJ调试,释放PA15,PB4, PB3GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4;  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;  GPIO_Init(GPIOB, &GPIO_InitStructure);  GPIO_SetBits(GPIOB,GPIO_Pin_4);  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3;  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;  GPIO_Init(GPIOB, &GPIO_InitStructure);  GPIO_SetBits(GPIOB,GPIO_Pin_3);  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_15;  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;  GPIO_Init(GPIOA, &GPIO_InitStructure);  GPIO_ResetBits(GPIOA,GPIO_Pin_15);  
}

        当把 PB3 PB4 PA15 初始化好之后,如果再次调用GPIOA GPIOB接口的时钟代码的话,会使得PB3 PA15引脚变回JTAG的引脚

        即初始化完之后不能再执行如下代码,否则PB3 PA15引脚会变回 JTAG 的引脚,而无法作为普通IO使用:

RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB | RCC_APB2Periph_GPIOA | RCC_APB2Periph_AFIO, ENABLE);  

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

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

相关文章

modbus 通信协议介绍与我的测试经验分享

1、简介 Modbus 协议是一种通信协议&#xff0c;用于工业自动化系统中的设备间通信。该协议最初由 Modicon 公司开发&#xff0c;并于 1979 年发布。 Modbus 协议通过串行通信格式进行通信&#xff0c;在物理层上支持 RS-232、RS-422 和 RS-485 等多种通信方式。在协议层面&am…

Guardrails for Amazon Bedrock 基于具体使用案例与负责任 AI 政策实现定制式安全保障(预览版)

作为负责任的人工智能&#xff08;AI&#xff09;战略的一部分&#xff0c;您现在可以使用 Guardrails for Amazon Bedrock&#xff08;预览版&#xff09;&#xff0c;实施专为您的用例和负责任的人工智能政策而定制的保障措施&#xff0c;以此促进用户与生成式人工智能应用程…

redis未授权漏洞复现

什么是redis redis就是个数据库&#xff0c;跟mysql不同的地方在于redis主要将数据存在内存中&#xff0c;读写速度非常快 redis未授权 其原因很简单&#xff0c;就是redis服务器在默认安装好不配置的情况下可以直接免密码登录&#xff0c;登录后在web目录写入一句话木马&am…

【Spark精讲】RDD特性之数据本地化

目录 首选运行位置 数据的本地化级别 谁来负责数据本地化 数据本地化执行流程 调优 代码中的设置方法 首选运行位置 上图红框为RDD的特性五&#xff1a;每个RDD的每个分区都有一组首选运行位置&#xff0c;用于标识RDD的这个分区数据最好能够在哪台主机上运行。通过RDD的…

亚信科技AntDB数据库——深入了解AntDB-M元数据锁的相关概念

AntDB-M在架构上分为两层&#xff0c;服务层和存储引擎层。元数据的并发管理集中在服务层&#xff0c;数据的存储访问在存储引擎层。为了保证DDL操作与DML操作之间的一致性&#xff0c;引入了元数据锁&#xff08;MDL&#xff09;。 AntDB-M提供了丰富的元数据锁功能&#xff…

leetcode 236. 二叉树的最近公共祖先

leetcode 236. 二叉树的最近公共祖先 题目 给定一个二叉树, 找到该树中两个指定节点的最近公共祖先。 百度百科中最近公共祖先的定义为&#xff1a;“对于有根树 T 的两个节点 p、q&#xff0c;最近公共祖先表示为一个节点 x&#xff0c;满足 x 是 p、q 的祖先且 x 的深度尽…

4G无线工业级路由器在智能制造设备互联互通中的角色

随着工业技术的不断发展和进步&#xff0c;智能制造已经成为了现代制造业的重要趋势和发展方向。而在智能制造过程中&#xff0c;设备之间的互联互通是至关重要的一环。在这个过程中&#xff0c;4G无线工业级路由器扮演着重要的角色&#xff0c;它提供了稳定可靠的网络连接&…

Vue3项目中集成mars3D简单三部曲

Vue3项目中集成mars3D简单三部曲 这里是参考网址&#xff0c;大佬可以点击一件跳转 1.安装依赖 npm install vite-plugin-mars3d --save-dev2.修改 vite.config.ts 配置文件 import { defineConfig } from vite; import { mars3dPlugin } from vite-plugin-mars3d;export d…

Go开发运维:Go服务发布到K8S集群

目录 一、实验 1.Go服务发布到k8s集群 二、问题 1.如何从Harbor拉取镜像 一、实验 1.Go服务发布到k8s集群 &#xff08;1&#xff09;linux机器安装go(基于CentOS 7系统) yum install go -y &#xff08;2&#xff09;查看版本 go version &#xff08;3&#xff09;创…

vue3 setup语法糖写法基本教程

前言 官网地址&#xff1a;Vue.js - 渐进式 JavaScript 框架 | Vue.js (vuejs.org)下面只讲Vue3与Vue2有差异的地方&#xff0c;一些相同的地方我会忽略或者一笔带过与Vue3一同出来的还有Vite&#xff0c;但是现在不使用它&#xff0c;等以后会有单独的教程使用。目前仍旧使用v…

GZ015 机器人系统集成应用技术样题3-学生赛

2023年全国职业院校技能大赛 高职组“机器人系统集成应用技术”赛项 竞赛任务书&#xff08;学生赛&#xff09; 样题3 选手须知&#xff1a; 本任务书共 26页&#xff0c;如出现任务书缺页、字迹不清等问题&#xff0c;请及时向裁判示意&#xff0c;并进行任务书的更换。参赛队…

自定义日志打印功能--C++

一、介绍 日志是计算机程序中用于记录运行时事件和状态的重要工具。通过记录关键信息和错误情况&#xff0c;日志可以帮助程序开发人员和维护人员追踪程序的执行过程&#xff0c;排查问题和改进性能。 在软件开发中&#xff0c;日志通常记录如下类型的信息&#xff1a; 事件信…

Go delve调试工具的简单应用

Delve是个啥 Delve is a debugger for the Go programming language. The goal of the project is to provide a simple, full featured debugging tool for Go. Delve should be easy to invoke and easy to use. Chances are if you’re using a debugger, things aren’t go…

openmediavault debian linux安装配置企业私有网盘(三 )——raid5与btrfs文件系统无损原数据扩容

一、适用环境 1、企业自有物理专业服务器&#xff0c;一些敏感数据不外流时&#xff0c;使用openmediavault自建NAS系统&#xff1b; 2、在虚拟化环境中自建NAS系统&#xff0c;用于内网办公&#xff0c;或出差外网办公时&#xff0c;企业内的文件共享&#xff1b; 3、虚拟化环…

数据结构-迷宫问题

文章目录 1、题目描述2、题目分析3、代码实现 1、题目描述 题目链接&#xff1a;迷宫问题 、 注意不能斜着走&#xff01; 2、题目分析 &#xff08;1&#xff09;0为可以走&#xff0c;1不能走且只有唯一一条通路 &#xff08;2&#xff09;我们可以通过判断上下左右来确定…

AI智能化办公:ChatGPT使用方法与技巧

文章目录 ChatGPT简介✨ChatGPT的使用方法✨登录与访问发送请求调整参数 ChatGPT技巧分享✨清晰的提问实验不同的温度值多轮对话 图书推荐✨AI智能化办公内容简介获取方式 AI短视频内容简介获取方式 随着人工智能技术的不断发展&#xff0c;AI助手在办公场景中扮演着越来越重要…

基于Python自动化测试框架之接口测试

上一篇阐述了关于web UI相关的内容&#xff0c;这篇谈谈关于接口测试及自动化测试框架。 接口测试是测试系统组件间数据交互的一种方式&#xff0c;通过不同情况下的输入参数和与之对应的输出结果来判断接口是否符合或满足相应的功能性、安全性要求。简单来说&#xff0c;接口…

UE5 - ArchvizExplorer与Map Border Collection结合 - 实现电子围栏效果

插件地址&#xff1a; https://www.unrealengine.com/marketplace/zh-CN/product/archviz-explorer https://www.unrealengine.com/marketplace/zh-CN/product/map-border-collection ArchvizExplorer扩展&#xff1a; https://download.csdn.net/download/qq_17523181/8843305…

Power BI - 5分钟学习增加索引列

每天5分钟&#xff0c;今天介绍Power BI增加索引列。 什么是增加索引列&#xff1f; 增加索引列就是向表中添加一个具有显式位置值的新列&#xff0c;一般从0或者从1开始。 举例&#xff1a; 首先&#xff0c;导入一张【Sales】样例表(Excel数据源导入请参考每天5分钟第一天)…

消除非受检警告

在Java中&#xff0c;有一些情况下编译器会生成非受检警告&#xff08;Unchecked Warnings&#xff09;。这些警告通常与泛型、类型转换或原始类型相关。消除这些警告可以提高代码的可读性和安全性。以下是一些常见的非受检警告以及如何消除它们的例子&#xff1a; 1. 泛型类型…