STM32速成笔记—按键检测

这篇具有很好参考价值的文章主要介绍了STM32速成笔记—按键检测。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。


🎀 文章作者:二土电子

🌸 关注文末公众号获取其他资料和工程文件!

🐸 期待大家一起学习交流!


一、按键检测原理

按键检测原理比较简单,按键按下和不按下,其连接引脚的电平是不一样的,按键检测正是通过检测按键引脚的电平变化来实现的。比如按键未按下时引脚电平为高电平,按键按下后为低电平。我们在检测按键时只需要检测按键引脚是否变为低电平来确定按键是否按下。

二、硬件连接

按键的硬件连接决定了我们在配置按键IO时IO的状态。以我们使用的普中核心板为例,上面有三个按键需要硬件电路的小伙伴可以看看本人上传的资源,下载查看原理图。

按键 松手检测,STM32速成笔记,stm32,单片机,笔记
其中K1一端接VCC,另一端接单片机。K2和K3一端接地,另一端接单片机。硬件电路不同,导致他们在进行按键检测时IO的配置不同。

针对K1这种按键电路,按键按下时,单片机的引脚接到VCC,因此在未按下的情况下该引脚的默认电平为低电平,也就是要把IO设置为输入下拉模式。同理,对于K2和K3这种连接方式,对应IO应该配置为输入上拉模式,使得按键未被按下时,引脚处于高电平状态。

三、程序设计

按键检测主要有以下步骤

  • 初始化GPIO
  • 检测按下按键
  • 消抖(防误触,一般通过延时实现)
  • 松手检测
  • 执行按键功能

3.1 初始化GPIO

根据原理图,谱中的STM32核心板提供了三个按键,我们使用K1和K2来实现点亮和关闭LED的操作。K1对应的IO为PA0,K2对应的IO为PE4。
按键 松手检测,STM32速成笔记,stm32,单片机,笔记
根据上一节了解的初始化GPIO程序,初始化按键GPIO。

/*
 *==============================================================================
 *函数名称:Drv_KeyGpio_Init 
 *函数功能:初始化KEY的GPIO
 *输入参数:无
 *返回值:无
 *备  注:根据硬件电路确定GPIO模式
 *==============================================================================
 */
void Drv_KeyGpio_Init (void)
{
	GPIO_InitTypeDef GPIO_InitStructure;   // 定义结构体
	// 开启时钟
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOE,ENABLE);

	// 配置结构体 WK UP
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPD;   // 输入下拉
	GPIO_Init(GPIOA, &GPIO_InitStructure);
	
	// 配置结构体 KEY0,KEY1
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3 | GPIO_Pin_4;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;   // 输入上拉
	GPIO_Init(GPIOE, &GPIO_InitStructure);
}

3.2 按键扫描函数

按键扫描函数的功能是检测是否有按键按下,按下的按键是哪一个。检测方法上面已经叙述,通过检测按键引脚的电平。以WK UP按键为例。当WK UP被按下时,其对应的引脚PA0会变为高电平。此时检测PA0的输入电平,如果确实是低电平,则说明WK UP可能被按下。说可能是因为PA0为低电平不一定是WK UP按下造成,也可能是抖动,所以这里就需要消抖操作。这里的消抖操作比较简单粗暴,直接延时10ms看该引脚是否依旧是低电平。如果延时10ms后依旧是高电平,则认为确实是由按键按下导致的电平变化,而不是机械抖动。

确定检测到按键按下后,需要等待按键被松开在执行按键功能。为什么需要进行松手检测?举个例子,比如设置阈值时,按键按下阈值加1,如果不进行松手检测,那么按下一次按键会加很多次,因为在不停地执行按键功能。这里按键的松手检测也比较简单粗暴,用一个while死循环等待松手。比如WK UP被按下后,其引脚会一直保持高电平,也就是PAin(0)一直等于1,此时用一个while (PAin(1));来等待松手,做松手检测。

四、按键控制LED

这里做一个小练习,用普中核心板上的按键KEY0和KEY1来控制LED1的亮灭。步骤如下

  • 初始化LED和KEY的GPIO
  • 编写LED控制函数
  • 编写按键检测函数(检测按键)
  • 编写按键服务函数(实现按键功能)

4.1 初始化LED和KEY的GPIO

/*
 *==============================================================================
 *函数名称:Drv_LedGpio_Init
 *函数功能:初始化LED的GPIO
 *输入参数:无
 *返回值:无
 *备  注:无
 *==============================================================================
 */
void Drv_LedGpio_Init (void)
{
	GPIO_InitTypeDef GPIO_InitStructure;   // 定义结构体
	// 开启时钟
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB | RCC_APB2Periph_GPIOE,ENABLE);

	// 配置结构体 LED0
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;   // 推挽式输出
	GPIO_Init(GPIOB, &GPIO_InitStructure);
	GPIO_SetBits(GPIOB,GPIO_Pin_5);   // 熄灭LED
	
	// 配置结构体 LED1
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;   // 推挽式输出
	GPIO_Init(GPIOE, &GPIO_InitStructure);
	GPIO_SetBits(GPIOE,GPIO_Pin_5);   // 熄灭LED
}
/*
 *==============================================================================
 *函数名称:Drv_KeyGpio_Init 
 *函数功能:初始化KEY的GPIO
 *输入参数:无
 *返回值:无
 *备  注:根据硬件电路确定GPIO模式
 *==============================================================================
 */
void Drv_KeyGpio_Init (void)
{
	GPIO_InitTypeDef GPIO_InitStructure;   // 定义结构体
	// 开启时钟
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOE,ENABLE);

	// 配置结构体 WK UP
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPD;   // 输入下拉
	GPIO_Init(GPIOA, &GPIO_InitStructure);
	
	// 配置结构体 KEY0,KEY1
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3 | GPIO_Pin_4;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;   // 输入上拉
	GPIO_Init(GPIOE, &GPIO_InitStructure);
}

4.2 编写按键扫描函数

```c
/*
 *==============================================================================
 *函数名称:Med_KeyScan
 *函数功能:检测按下按键
 *输入参数:无
 *返回值:按键键值 0:按键WK UP,1:KEY0,2:KEY1
 *备  注:无
 *==============================================================================
 */
u8 Med_KeyScan (void)
{
	// 按键WK UP
	if (KEY_UP == 1)
	{
		delay_ms (10);   // 延时10ms消抖
		if (KEY_UP == 1)
		{
			while (KEY_UP);   // 松手检测
			return 1;
		}
	}
	
	// 按键KEY0
	else if (KEY0 == 0)
	{
		delay_ms (10);   // 延时10ms消抖
		if (KEY0 == 0)
		{
			while (!KEY0);   // 松手检测
			return 2;
		}
	}
	
	// 按键KEY1
	else if (KEY1 == 0)
	{
		delay_ms (10);   // 延时10ms消抖
		if (KEY1 == 0)
		{
			while (!KEY1);   // 松手检测
			return 3;
		}
	}
	
	// 没有按键按下
	return 0xff;   // 用0xff表示没有按键按下
}

4.2 编写LED控制函数

/*
 *==============================================================================
 *函数名称:Med_Led_StateCtrl
 *函数功能:控制LED亮灭
 *输入参数:
           LEDx:可选择的LED(0~1)
					 State:LED亮灭状态(LED_ON,LED_OFF)
 *返回值:无
 *备  注:无
 *==============================================================================
 */
void Med_Led_StateCtrl (LED_TypeDef LEDx,u8 State)
{
	switch (LEDx)
	{
		case 0:
			PBout(5) = State;
		break;
		
		case 1:
			PEout(5) = State;
		break;
		
		default:
			break;
	}
}

下面是.h文件中的一些结构体和宏定义。

// 可选择的LED
typedef enum
{
	LED1 = 0,
	LED2
}LED_TypeDef;

// 亮灭电平需要根据硬件电路确定
#define LED_ON   0
#define LED_OFF  1

4.3 编写按键服务函数

这里没有再单独编写按键服务函数,直接在main函数中编写。KETY0按下点亮LED1,KEY1按下,熄灭LED1。

u8 gKeyValue = 0;   // 记录按键键值变量

int main(void)
{
	Med_Mcu_Iint();   // 系统初始化
	
	while(1)
  {
		gKeyValue = Med_KeyScan();   // 获取按键键值
		
		// 按键KEY0按下
		if (gKeyValue == 2)
		{
			Med_Led_StateCtrl(LED1,LED_ON);   // 点亮LED1
		}
		
		// 按键KEY1按下
		if (gKeyValue == 3)
		{
			Med_Led_StateCtrl(LED1,LED_OFF);   // 熄灭LED1
		}
	}
}

至此,实现了利用KEY0和KEY1控制LED的亮灭状态。

五、拓展

5.1 一个按键单独控制一个LED亮灭

单片机的IO资源是比较珍贵的,在实际用用时很少会用两个IO资源来控制一个外设的开关,这里介绍一下方法并给出例程。比如使用普中核心板上的WK UP按键来控制LED2的亮灭状态。基本思路是在上面学会按键检测的基础上,增加一个按键按下计次变量。按键按下一次,该变量加1。如果检测到变量为1,那么点亮LED,如果检测到变量为2,那么熄灭LED,同时将计数变量清零。程序设计如下

u8 gKeyValue = 0;   // 记录按键键值变量
u8 gKeyWkUpCunt = 0;   // WK UP按下次数计数变量

int main(void)
{
	Med_Mcu_Iint();   // 系统初始化
	
	while(1)
  {
		gKeyValue = Med_KeyScan();   // 获取按键键值
		
		// 按键WK UP按下
		if (gKeyValue == 1)
		{
			gKeyWkUpCunt = gKeyWkUpCunt + 1;   // 按键按下次数计数变量加1
			
			// 第一次被按下
			if (gKeyWkUpCunt <= 1)
			{
				Med_Led_StateCtrl(LED2,LED_ON);   // 点亮LED2
			}
			// 不是第一次被按下
			else if (gKeyWkUpCunt > 1)
			{
				gKeyWkUpCunt = 0;   // 清空计数变量
				Med_Led_StateCtrl(LED2,LED_OFF);   // 熄灭LED2
			}
		}
	}
}

5.2 按键长短按

除了上面介绍的一些常规操作外,有时还会用到一个按键分长按和短按。这里给出一种简单粗暴的实现思路。需要检测按键长短按时,修改一下松手检测的逻辑。延时10ms后如果按键IO依旧保持按下状态,那么确定不是机械抖动,此时在之前的松手检测while中进行粗略地计时。定义一个计数变量,每隔10ms加1。直到按键被松开。根据计数变量的值来判断按键被按下的时间,从而来区别长短按。

这里给出一个例程,KEY1短按功能为熄灭LED1,长按功能为LED1和LED2交替闪烁两轮后熄灭。按下持续时间在1s内,认为是短按,按下超过2s认为是长按。短按返回3,长按返回4。程序设计如下

u8 gKeyValue = 0;   // 记录按键键值变量
u16 gKey1TimeCunt = 0;   // 按键KEY1的计时变量
/*
 *==============================================================================
 *函数名称:Med_KeyScan
 *函数功能:检测按下按键
 *输入参数:无
 *返回值:按键键值 0:按键WK UP,1:KEY0,2:KEY1
 *备  注:无
 *==============================================================================
 */
u8 Med_KeyScan (void)
{
	// 按键WK UP
	if (KEY_UP == 1)
	{
		delay_ms (10);   // 延时10ms消抖
		if (KEY_UP == 1)
		{
			while (KEY_UP);   // 松手检测
			return 1;
		}
	}
	
	// 按键KEY0
	else if (KEY0 == 0)
	{
		delay_ms (10);   // 延时10ms消抖
		if (KEY0 == 0)
		{
			while (!KEY0);   // 松手检测
			return 2;
		}
	}
	
	// 按键KEY1
	// 按下1s内认为是短按,返回3
	// 按下超过2s认为是长按,返回4
	else if (KEY1 == 0)
	{
		delay_ms (10);   // 延时10ms消抖
		if (KEY1 == 0)
		{
			// 等待松手
			while (!KEY1)
			{
				delay_ms (10);
				gKey1TimeCunt = gKey1TimeCunt + 1;   // 计时变量加1
			}
		}
		
		// 判断长短按
		if (gKey1TimeCunt <= 99)   // 小于等于1s
		{
			gKey1TimeCunt = 0;   // 清零计时变量
			return 3;   // 短按
		}
		else if (gKey1TimeCunt >= 199)   // 大于1s,等于2s
		{
			gKey1TimeCunt = 0;   // 清零计时变量
			return 4;   // 长按
		}
	}
	
	// 没有按键按下
	return 0xff;   // 用0xff表示没有按键按下
}

main函数中添加下述程序文章来源地址https://www.toymoban.com/news/detail-714312.html

// 长按KEY1
		if (gKeyValue == 4)
		{
			Med_Led_StateCtrl(LED1,LED_ON);   // 点亮LED1
			delay_ms (500);
			Med_Led_StateCtrl(LED1,LED_OFF);   // 熄灭LED1
			Med_Led_StateCtrl(LED2,LED_ON);   // 点亮LED2
			delay_ms (500);
			Med_Led_StateCtrl(LED2,LED_OFF);   // 熄灭LED2
			Med_Led_StateCtrl(LED1,LED_ON);   // 点亮LED1
			delay_ms (500);
			Med_Led_StateCtrl(LED1,LED_OFF);   // 熄灭LED1
			Med_Led_StateCtrl(LED2,LED_ON);   // 点亮LED2
			delay_ms (500);
			Med_Led_StateCtrl(LED1,LED_OFF);   // 熄灭LED1
			Med_Led_StateCtrl(LED2,LED_OFF);   // 熄灭LED1
		}

到了这里,关于STM32速成笔记—按键检测的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 毕业设计 单片机心率检测器设计与实现 - stm32

    Hi,大家好,今天向大家介绍一个学长做的单片机项目 基于STM32的心率检测器的设计与实现 大家可用于 课程设计 或 毕业设计 主控:STM32F103C8T6 MAX30102传感器 OLED屏幕:用于显示实时心率波形 未测试时的状态:心率波形显为平稳直线,即0 将手指放上进行心率测试: 还可以把

    2024年02月07日
    浏览(32)
  • 基于stm32单片机甲醛烟雾温湿度检测仪设计

    目录 第1章 绪论 1.1 引言 1.1.1甲醛的特性及危害 1.1.2甲醛的来源 1.2甲醛检测仪的种类 第2章  概述 2.1系统总概述 2.2总体方案设计 2.3硬件设计 2.4软件设计 第3章  硬件设计 3.1  硬件设计主电路图 3.2  硬件选择 3.2.1  MCU的选择与简介 3.2.3  数据采集系统 3.2.4  数据采集简介

    2023年04月08日
    浏览(33)
  • 单片机设计基于STM32的心率检测仪设计与实现

      现代科学的发展,导致越来越多人开始重视自己的身体健康,他们往往会想在能力之余使用健身运动等方式来锻炼自身。你会发现,在健身房,健身达人或者是教练都会叮嘱新手去关注自己的心率节奏。一般来说,人的激烈的锻炼会造成心脏血压的上升,心率变化从而加

    2024年02月04日
    浏览(41)
  • 毕业设计 STM32空气质量检测仪 - 单片机 嵌入式

    Hi,大家好,学长今天向大家介绍一个 单片机项目 基于STM32的空气质量检测仪 大家可用于 课程设计 或 毕业设计 如今人们大约 80%的时间是在室内度过的, 室内空气质量与我们每个人的工作和生活都息息相关, 因此对生活环境的空气质量提出了更高的要求。 针对雾霾、 室内

    2024年01月17日
    浏览(36)
  • 单片机课程设计:基于STM32的心率血氧检测报警系统

      本文使用搭载STM32F103VET6主控芯片的野火指南者、野火3.2寸LCD屏幕和MAX30102心率血氧传感器实现心率血氧采集并显示的效果。 (文末附完整程序下载链接)   1.可以通过MAX30102心率血氧传感器对用户的心率血氧进行采集,并用实时显示在LCD液晶屏上;   2.可以设定一个固

    2024年02月14日
    浏览(31)
  • 单片机项目分享 基于Stm32的家庭智能监控系统 - 单片机 图像识别 人体检测 AI

    hr style=\\\" border:solid; width:100px; height:1px;\\\" color=#000000 size=1\\\" 🔥 这两年开始毕业设计和毕业答辩的要求和难度不断提升,传统的毕设题目缺少创新和亮点,往往达不到毕业答辩的要求,这两年不断有学弟学妹告诉学长自己做的项目系统达不到老师的要求。 为了大家能够顺利以及最

    2024年01月16日
    浏览(54)
  • 单片机项目分享 stm32机器视觉的口罩佩戴检测系统 - 单片机 物联网 嵌入式

    🔥 这两年开始毕业设计和毕业答辩的要求和难度不断提升,传统的毕设题目缺少创新和亮点,往往达不到毕业答辩的要求,这两年不断有学弟学妹告诉学长自己做的项目系统达不到老师的要求。 为了大家能够顺利以及最少的精力通过毕设,学长分享优质毕业设计项目,今天

    2024年02月22日
    浏览(54)
  • stm32毕设分享 Stm32 WIFI智能家居温湿度和烟雾检测系统 - 单片机 物联网 嵌入式

    🔥 这两年开始毕业设计和毕业答辩的要求和难度不断提升,传统的毕设题目缺少创新和亮点,往往达不到毕业答辩的要求,这两年不断有学弟学妹告诉学长自己做的项目系统达不到老师的要求。 为了大家能够顺利以及最少的精力通过毕设,学长分享优质毕业设计项目,今天

    2024年02月02日
    浏览(34)
  • STM32单片机入门学习笔记——MPU6050

    笔记整理自B站UP主江科大自化协教程《[10-2] MPU6050简介_哔哩哔哩_bilibili》,所用单片机也为教程推荐单片机。 如果芯片里再集成一个3轴的磁场传感器,测量XYZ轴的磁场强度,那就叫做9轴姿态传感器,如果再集成一个气压传感器,测量气压大小,那就叫做10轴姿态传感器,一

    2024年02月08日
    浏览(38)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包