做按键检测时,GPIO为输入操作

读取IO口输入电平调用的库函数为:

uint8_t GPIO_ReadInputDataBit(GPIO_TypeDef* GPIOx,uint16_t GPIO_Pin);

读取IO口输入电平操作的寄存器为:

GPIOx_IDR:端口输入寄存器

使用位带操作读取IO口输入电平:

PEin(4) -读取GPIOE.4口电平
PEin(n) -读取 GPIOE.n口电平

按键输入实验

1.使能按键对应IO口时钟。调用函数:RCC_APB2PeriphClockCmd();

2.初始化IO模式:上拉/下拉输入。调用函数:GPIO_lnit();

3.扫描IO口电平(库函数/寄存器/位操作)。

按键扫描(支持连续按)的实现思路

这个就是学51时最开始用的那个按键检测方法,简单

连续按意思是只要一直按住按键,按键就一直生效,比如增大音量键,按住不放,则音量会一直增加

如果要实现:按键按下,没有松开,只能算按下一次,这个函数无法实现。

u8 KEY_Scan(void)
{if(KEY被按下){delay_ms(10);       //消抖if(KEY确实被按下){return KEY_Value;}return 无效值;}
}

按键扫描(不支持连续按)的实现思路

不支持连续按意思就是,按下按键了,就算不松手,也只算按键被按下一次,必须松手后,再按下,才能算第二次按下,比如开启空调,按住电源键不放,也只是当作按下一次按键,不会说是连续按,电源开了又关,关了又开,不会这样设计

增加一个按下标志位key_up,按下后置0,只有当松手时才置1,要key_up和引脚状态同时为真才返回按键值

u8 KEY_Scan(void)
{static u8 key_up = 1;if(key_up && KEY被按下){delay_ms(10);       //消抖if(KEY确实被按下){key_up = 0;return KEY_Value;}}else if(KEY没有被按下){key_up = 1;}return 没有按下
}

支持连续按 和 不支持连续按 两者结合

在不支持连续按的代码上添加一句 if(mode == 1) key_up = 1;即可,可通过对传入的参数mode进行判断来实现两种按键方式的切换

如果mode == 1,则key_up = 1,则支持连续按;因为key_up被初始化为1,第一次按下时,if(key_up && KEY被按下)判断为真,检测KEY确实被按下后,key_up被置为0,返回 KEY_Value 然后return退出,假如是一直按着按键的,那下一次进行按键检测时,if(mode == 1) 为真,key_up = 1,所以 if(key_up && KEY被按下)判断又为真,继续进入里面执行,继续返回KEY_Value,达到连续按效果

如果mode != 1,则判断为假,key_up = 1不会执行,则这条 if 判断等于没有,代码就是上面不支持连续按的效果

u8 KEY_Scan(u8 mode)
{static u8 key_up = 1;if(mode == 1) key_up = 1; //mode == 1,则支持连续按if(key_up && KEY被按下){delay_ms(10);      //消抖if(KEY确实被按下){key_up = 0;return KEY_Value;}}else if(KEY没有被按下){key_up = 1;}return 没有被按下
}

所以要切换按键方式,在main函数while循环中调用KEY_Scan函数时,如果想支持连续按,则传入参数1,如果想不支持连续按,则传入参数不是1即可

void main()
{while(1){KEY = KEY_Scan(1);   //支持连续按KEY = KEY_Scan(0);  //不支持连续按…………}
}

程序

KEY.h

定义两个按键状态的宏定义,声明函数

#ifndef _KEY_H_
#define _KEY_H_#include "stm32f10x.h"//按键状态宏定义
#define KEY_DOWN    0
#define KEY_UP      1void KEY_Init(void);       //按键引脚初始化函数
u8   KEY_Scan(u8 mode);     //按键检测函数
#endif

KEY.c

要先对按键所接到的引脚进行初始化,配置为上拉输入,因为按键另一端接地,按键没按下时,引脚内部上拉电阻作用将引脚拉高,当按键被按下时,接GND,CPU读取引脚输入为低电平

按键扫描函数通过参数mode切换支持长按或不支持长按

#include "KEY.h"
#include "delay.h"/*** @name   KEY_Init* @brief  按键初始化* @param  None* @retval None*/
void KEY_Init(void)
{GPIO_InitTypeDef GPIO_Init_Structure;//先初始化GPIOA的时钟RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);//配置GPIOA_Pin_8GPIO_Init_Structure.GPIO_Pin = GPIO_Pin_8;          //按键接到了PA8引脚GPIO_Init_Structure.GPIO_Mode = GPIO_Mode_IPU;      //设置为上拉输入//初始化PA8GPIO_Init(GPIOA,&GPIO_Init_Structure);
}/*** @name   KEY_Scan* @brief  按键扫描* @param  mode:1:支持按键长按;其他:不支持按键长按* @retval u8*/
u8 KEY_Scan(u8 mode)
{static u8 key_up = 1;//读取PA8引脚的值u8 KEY1 = GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_8);if(mode == 1) key_up = 1;//按键检测if(key_up && (KEY1 == 0)){delay_ms(10);           //消抖//确定按键按下if(KEY1 == 0){key_up = 0;         //记录这次按下return KEY_DOWN;    //返回按下标志,0}}else if(KEY1 == 1){        //按键没按下或者松开key_up = 1;    }return KEY_UP;              //返回没按下标志,1
}

main.c

主函数while循环不断检测按键扫描函数,检测到函数返回按键按下标志后,执行亮灯操作

这里使用预编译指令,#ifndef #endif 和 #ifdef #endif,用宏定义KEY_MODE来进行支持长按和不支持长按的切换,这样就不用注释一大块的函数功能,只需注释宏定义语句就行了

当宏定义了KEY_MODE时,编译支持长按的语句;当注释掉宏定义了KEY_MODE时,编译不支持长按的语句

#include "LED.h"
#include "delay.h"
#include "KEY.h"#define KEY_MODE 1int main()
{LED_Init();        //LED初始化delay_init();   //延时初始化KEY_Init();      //按键初始化while(1){#ifndef KEY_MODE//不支持长按if(KEY_Scan(0) == KEY_DOWN){//GPIO_ResetBits(GPIOA,GPIO_Pin_1);    //点亮LEDGPIOA->ODR ^= (0x01<<1);   //对ODR1进行异或取反操作,按一次点亮,再按一次熄灭}#endif#ifdef KEY_MODE//支持长按if(KEY_Scan(1) == KEY_DOWN){GPIOA->ODR ^= (0x01<<1);  //对ODR1进行异或取反操作,按一次点亮,再按一次熄灭delay_ms(1000);}#endif}
}

想实现按一次按键亮灯,再按一次就灭灯,这个实现简单,只要把LED的引脚电平翻转即可,但查看了GPIO标准库相关函数发现好像没有让引脚电平翻转的函数,下面是各个函数的功能

然后通过对寄存器进行操作,采用异或的功能,取反某一位,达到按一次亮,再按一次熄灭的效果

GPIOA->ODR ^= (0x01<<1);   //对ODR1进行异或取反操作,按一次点亮,再按一次熄灭

复习状态机用法

KEY.h

在KEY.h头文件中添加状态机的枚举类型,定义枚举类型变量STA_KEY,并用extern声明为外部变量

#ifndef _KEY_H_
#define _KEY_H_#include "stm32f10x.h"//按键状态宏定义
#define KEY_DOWN    0
#define KEY_UP      1//状态机按键枚举类型
typedef enum
{KEY_Statues1,KEY_Statues2
}STA_KEY_t;//定义变量
extern STA_KEY_t STA_KEY;void KEY_Init(void);       //按键引脚初始化函数
u8   KEY_Scan(u8 mode);     //按键检测函数void STA_KEY1(void);        //状态机,按键状态1
void STA_KEY2(void);        //状态机,按键状态2#endif

KEY.c

源文件中添加不同状态要执行的函数,状态1按一次按键LED灯亮1秒再熄灭,然后切换到状态2,状态2中按一次按键LED灯亮1秒再熄灭,然后再亮1秒再熄灭,最后再把状态切回到状态1

/*** @name   STA_KEY1* @brief  状态机-按键状态1* @param  None* @retval None*/void STA_KEY1(){GPIO_ResetBits(GPIOA,GPIO_Pin_1);   //PA1置0,LED点亮delay_ms(1000);GPIO_SetBits(GPIOA,GPIO_Pin_1);     //延时1秒后熄灭LED灯delay_ms(1000);//切换状态STA_KEY = KEY_Statues2;} /*** @name   STA_KEY2* @brief  状态机-按键状态2* @param  None* @retval None*/void STA_KEY2(){GPIO_ResetBits(GPIOA,GPIO_Pin_1);   //PA1置0,LED点亮delay_ms(1000);GPIO_SetBits(GPIOA,GPIO_Pin_1);     //延时1秒后熄灭LED灯、delay_ms(1000);GPIO_ResetBits(GPIOA,GPIO_Pin_1);   //PA1置0,LED点亮delay_ms(1000);GPIO_SetBits(GPIOA,GPIO_Pin_1);     //延时1秒后熄灭LED灯delay_ms(1000);//切换状态STA_KEY = KEY_Statues1;}

main.c

主函数中当按键按下后,再用switch case 语句判断状态,并调用不同状态下的函数

#include "LED.h"
#include "delay.h"
#include "KEY.h"#define KEY_MODE 1
STA_KEY_t STA_KEY;  //定义状态变量int main()
{LED_Init();        //LED初始化delay_init();   //延时初始化KEY_Init();      //按键初始化while(1){#ifndef KEY_MODE//不支持长按if(KEY_Scan(0) == KEY_DOWN){//GPIO_ResetBits(GPIOA,GPIO_Pin_1);    //点亮LED//GPIOA->ODR ^= (0x01<<1); //对ODR1进行异或取反操作,按一次点亮,再按一次熄灭//状态机点灯switch (STA_KEY){case KEY_Statues1:STA_KEY1();break;case KEY_Statues2:STA_KEY2();break;default:STA_KEY = KEY_Statues1;break;}}#endif#ifdef KEY_MODE//支持长按if(KEY_Scan(1) == KEY_DOWN){GPIOA->ODR ^= (0x01<<1); //对ODR1进行异或取反操作,按一次点亮,再按一次熄灭delay_ms(1000);}#endif}
}

STM32-按键检测相关推荐

  1. STM32按键检测程序整理

    一. 在硬件连接上,按键一端连接在普通IO口上,另一端接地,IO配置为内部弱上拉. 在软件上,先配置一个5ms定时器并打开中断,每进入该定时中断则置位一次标志位"key_handle&quo ...

  2. 【STM32】GPIO输入—按键检测

    Author:AXYZdong 自动化专业 工科男 有一点思考,有一点想法,有一点理性 文章目录 2.1硬件设计 2.2软件设计 2.2.1编程要点 2.2.2代码分析 1.按键引脚宏定义 2.按键 ...

  3. stm32 工业按键检测_STM32f103按键检测程序实现长按短按

    背景本文引用地址:http://www.eepw.com.cn/article/201807/384495.htm 只要使用单片机,按键检测基本上是一定要实现的功能.按键检测要好用,最重要的是实时和去 ...

  4. STM32——GPIO输入——按键检测

    硬件介绍 当按键置空时,IO接地 按键按下之后,IO口接通3.3V高电压,电流比较大,为了避免损坏IO,这里需要加装一个限流电阻.可以看到IO口是默认低电平,按键按下后产生一个上升沿,和平常的电路设计 ...

  5. STM32速成笔记—按键检测

    如果需要本文程序工程,请评论区留邮箱或者私信. 文章目录 一.按键检测原理 二.硬件连接 三.程序设计 3.1 初始化GPIO 3.2 按键扫描函数 四.按键控制LED 4.1 初始化LED和KEY的 ...

  6. stm32实现GPIO输入按键检测

    1.硬件设计 按键机械触点断开.闭合时,由于按键触点的弹性作用,按键开关不会马上稳定接通或一下就断开,使用按键时就会产生下图中的带纹波信号,需要软件消抖处理滤波 由于用软件消抖处理滤波不方便输入检测, ...

  7. STM32学习笔记——(5)按键检测

    按键检测 一.按键检测 一.按键检测 如上图所示, 若按键KEY1未按下时检测点为低电平,按下时检测点为高电平. 若按键KEY2/3/4未按下时检测点为高电平,按下时检测点为低电平. 程序如下: /* ...

  8. 一个学妹写的按键检测函数把我秀翻了!

    摘要:今年实验室来了三个学妹,其中一个学妹以前是物联网专业的,进了实验室老师二话没说:先把STM32单片机过一遍 上来第一个例程就是使用按键点亮一个LED灯,好家伙.点灯小师弟比较在行,毕竟32.FP ...

  9. 按键检测框架单击-双击-连按

    说明 本示例用的stm32 按键是接地有效 特别设置按键拉高 按键事件循环50ms一次调用 电路图 按键检测思路 按键按下检测:检测当前本状态是否和上一次状态一致,不一致消抖完成的情况下,当前电平和按 ...

  10. linux 按键检测 防抖,GPIO输入——按键检测

    当按下一个按键时,系统是如何检测到的呢? 我们通过LED灯的亮灭状态来间接完成按键检测.当按下按键时,LED灯亮,再次按下时,LED灯灭. 要完成这个实验,我们就会用到GPIO外设的基本输入功能. 查 ...

最新文章

  1. CUDA Samples: dot product(使用零拷贝内存)
  2. SQL Server 2012入门T-SQL基础篇:(1)环境准备
  3. Solr4.7实现LBS(地理位置搜索)
  4. PM2中无法开启ES6的解决方案
  5. window创建计划自动启动服务器,Windows下搭建svn服务器端--创建自动启动的服务
  6. Vue源码解析之AST语法树(三)
  7. sqoop从mysql导入hdfs_sqoop 从mysql导入数据到hdfs、hive
  8. wget抓取网站, 模拟手机端抓取
  9. 操作mysql_MySQL 事务操作
  10. 计算机网络概念,组成,功能和分类
  11. iOS 图形处理 翻译
  12. 官宣 | iPayLinks与Shopyy达成战略合作
  13. 5G/NR: CQI 和MCS - 链路自适应,自适应编码
  14. [io_uring][自用] io_uring.pdf DeepL机翻
  15. 卡苹果6plus在线_苹果手机解决微信接收消息延时
  16. Ps导航栏的简略讲解(一)
  17. 【html】设置图片编码格式
  18. 建立一个链表,每个结点包括:学号、姓名、性别、年龄。输入一个年龄,如果链表中的结点所包含的年龄等于此年龄,则将此结点删去。(自己编程)
  19. 中国人口趋势(1990-2035)
  20. 通讯:博物馆里过大年——英国科学博物馆举办科学“春晚”

热门文章

  1. 修改ntp服务器rac,RAC时间同步的两种方法【NTP时间同步服务器】
  2. Failed to execute goal on project ...: Could not resolve dependencies for project ...
  3. 小镇5.1.1--怪物狂欢季
  4. 明日之后(C++,可复制)
  5. BZOJ 1492 [NOI2007 D1T2] 货币兑换Cash
  6. 正好股票开户股指全天冲高震荡回落
  7. uni-app 使用 webview运行到小程序,打开萤石云视频
  8. 企业即时通讯产品免费是趋势而非优势
  9. 用Office2010设计T恤
  10. 通过清华大学镜像和pip进行安装