STM32(二):使用标准库函数控制按键

前言

上一篇文章已经介绍了如何实现流水灯,实现了点灯的第一步。这一篇则介绍按键控制点灯的实现过程。

一、实验原理

1.GPIO输操作说明

按键的初始化与LED灯初始化不同,LED是推挽输出,而按键则是输入。而输入也分两种:上拉输入和下拉输入。若是按键为共阴极,则按键按下时,IO口输入为低电平,需要在IO口接上拉电阻,则使用上拉输入模式;若是按键为共阳极,则按键按下时,IO口输入为高电平,需要在IO口接下拉电阻,则使用下拉输入模式。

其余根据板子的实际情况选择定时器,选择IO口即可。

二、实验步骤

1.按键消抖

因为按键是机械开关,在按下的时候会产生电平的抖动。可以采用延时消抖的方法,通过延时一小段时间,消除抖动。当然除了软件消抖还有硬件消抖的方法,可以看下下面这个链接【单片机】按键消抖及原理(硬件和软件方法详解)-CSDN博客

if(GPIO_ReadInputDataBit(KEYx_GPIO, KEYx_GPIO_PIN)==KEYx_DOWN_LEVEL)
{
  /* 延时一小段时间,消除抖动 */
  Delay(10);
  /* 延时时间后再来判断按键状态,如果还是按下状态说明按键确实被按下 */
  if(GPIO_ReadInputDataBit(KEYx_GPIO, KEYx_GPIO_PIN)==KEYx_DOWN_LEVEL)
  {
    /* 等待按键弹开才退出按键扫描函数 */
    while(GPIO_ReadInputDataBit(KEYx_GPIO, KEYx_GPIO_PIN)==KEYx_DOWN_LEVEL){ }
      /* 按键扫描完毕,返回按键被按下状态 */
        return KEY_DOWN;
   }
}
  /* 按键没被按下,返回没被按下状态 */
  return KEY_UP;

2.长短按

为了检测按下时间的长短,可以采取延时计数的方法。通过引入时间计数的KeyTimeCount,在按键扫描的时候以延时多少时间,增大KeyTimeCount。最后自定义判断时间长短。

值得注意的是,要是想检测按下的时间更为精确,需要调整延时函数,且针对不同单片机的定时器有不同的频率,需要根据实际情况自行调整。

uint16_t KeyTimeCount = 0;

/* 等待按键弹开才退出按键扫描函数 */
while(GPIO_ReadInputDataBit(KEYx_GPIO, KEYx_GPIO_PIN)==KEYx_DOWN_LEVEL)
{
    /* 时间计数 */
	Delay(10);
    KeyTimeCount = KeyTimeCount + 1;  
}

   /* 按键扫描完毕,返回按键被按下状态 */
if (KeyTimeCount <= 99)   // 小于等于1s
{
	/* 计数清零 */
	KeyTimeCount = 0;  
	return KEY_DOWN;   // 短按状态
}
else if (KeyTimeCount >= 199)   // 大于等于2s
{
	/* 计数清零 */
	KeyTimeCount = 0; 
	return KEY_DOWN_LONG;   // 长按状态
}

3.联合点灯

按键部署完后,就是一个联合点灯的过程,将bsp_led.h引入到bsp_key.c便可以通过按键实现点灯了!(其实是灭灯)

void KEY_LED(void)
{
	/* 读取按键状态 */
	int key1State = KEYx_Choice(1);
	
   /* 短按按键1 */
	if (key1State == 1)
	{
		LED1_OFF;
	}
}

三、实操代码

程序分为3个文件:bsp_key.c、bsp_key.h、main.c

1.bsp_key.c

/* 包含头文件 ----------------------------------------------------------------*/
#include "bsp/key/bsp_key.h"

void KEY_GPIO_Init(void)
{
   /* 定义IO硬件初始化结构体变量 */
  GPIO_InitTypeDef GPIO_InitStructure;
        
   /* 使能(开启)KEY引脚对应IO端口时钟 */   
  RCC_APB2PeriphClockCmd(KEY1_RCC_CLOCKGPIO|KEY2_RCC_CLOCKGPIO|KEY3_RCC_CLOCKGPIO, ENABLE);
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;

  /* 设定KEY对应引脚IO编号 */
  GPIO_InitStructure.GPIO_Pin = KEY1_GPIO_PIN |KEY2_GPIO_PIN | KEY3_GPIO_PIN;
  /* 配置KEY GPIO:输入上拉模式 */
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
  GPIO_Init(KEY3_GPIO, &GPIO_InitStructure);
  GPIO_Init(KEY1_GPIO, &GPIO_InitStructure);
  GPIO_Init(KEY2_GPIO, &GPIO_InitStructure);

}

/**
  * 函数功能: 读取按键KEYx的状态
  * 输入参数:无
  * 返 回 值: KEY_UP  :按键没被按下;
  *           KEY_DOWN:按键被按下;
  *           KEY_DOWN_LONG  :按键被长按下
  * 说    明:无。
  */
	
KEYState_TypeDef KEYx_StateSet(GPIO_TypeDef* KEYx_GPIO, uint16_t KEYx_GPIO_PIN, uint8_t KEYx_DOWN_LEVEL)
{	
  uint16_t KeyTimeCount = 0;  
  if(GPIO_ReadInputDataBit(KEYx_GPIO, KEYx_GPIO_PIN)==KEYx_DOWN_LEVEL)
  {
    /* 延时一小段时间,消除抖动 */
    Delay(10);
    /* 延时时间后再来判断按键状态,如果还是按下状态说明按键确实被按下 */
    if(GPIO_ReadInputDataBit(KEYx_GPIO, KEYx_GPIO_PIN)==KEYx_DOWN_LEVEL)
    {
      /* 等待按键弹开才退出按键扫描函数 */
      while(GPIO_ReadInputDataBit(KEYx_GPIO, KEYx_GPIO_PIN)==KEYx_DOWN_LEVEL)
	  {
		  /* 时间计数 */
		  Delay(10);
		  KeyTimeCount = KeyTimeCount + 1;  
	  }
	 }
       /* 按键扫描完毕,返回按键被按下状态 */
		if (KeyTimeCount <= 99)   // 小于等于1s
		{
			 /* 计数清零 */
			KeyTimeCount = 0;  
			return KEY_DOWN;   // 短按状态
		}
		else if (KeyTimeCount >= 199)   // 大于等于2s
		{
			 /* 计数清零 */
			KeyTimeCount = 0; 
			return KEY_DOWN_LONG;   // 长按状态
		}
    
  }
  /* 按键没被按下,返回没被按下状态 */
  return KEY_UP;
}

/**
  * 函数功能: 选取按键KEYx
  * 输入参数:1 :按键1;
  *          2 :按键2;
  *          3 :按键3
  * 返 回 值: KEYx_StateSet(KEYx_GPIO, KEYx_GPIO_PIN, KEYx_DOWN_LEVEL)
  * 说    明:无。
  */
KEYState_TypeDef KEYx_Choice(int KEYIndex)
{
    switch(KEYIndex)
    {
        case 1:
            return KEYx_StateSet(KEY1_GPIO, KEY1_GPIO_PIN, KEY1_DOWN_LEVEL);
        case 2:
            return KEYx_StateSet(KEY2_GPIO, KEY2_GPIO_PIN, KEY2_DOWN_LEVEL);
		  case 3:
            return KEYx_StateSet(KEY3_GPIO, KEY3_GPIO_PIN, KEY3_DOWN_LEVEL);
        default:
            return KEY_UP; 
    }
}

/**
  * 函数功能: 按键KEYx控制LED
  * 输入参数:无
  * 返 回 值:LED1_OFF:1灯灭;
  *          LED2_OFF:2灯灭;
  *          LED3_OFF:3灯灭
  * 说    明:无。
  */
void KEY_LED(void)
{
	/* 读取按键状态 */
	int key1State = KEYx_Choice(1);
	int key2State = KEYx_Choice(2);
	int key3State = KEYx_Choice(3);
	
   /* 短按按键1 */
	if (key1State == 1)
	{
		LED1_OFF;
	}
	 /* 长按按键1 */
	else if (key1State == 2)
	{
		LED3_OFF;
	}

	else if (key2State == 1)
	{
		LED2_OFF;
	}
	else if (key2State == 2)
	{
		LED3_OFF;
	}

	else if (key3State == 1)
	{
		LED3_OFF;
	}
	else
	{
		LED1_ON;
		LED2_ON;
		LED3_ON;
	}
}

2.bsp_key.h

#ifndef __BSP_KEY_H__
#define __BSP_KEY_H__

/* 包含头文件 ----------------------------------------------------------------*/
#include <stm32f10x.h>
#include "bsp/delay/delay.h"
#include "bsp/led/bsp_led.h"

/* 类型定义 --------------------------------------------------------------*/
typedef enum
{
  KEY_UP   = 0,
  KEY_DOWN = 1,
  KEY_DOWN_LONG   = 2,
}KEYState_TypeDef;

/* 宏定义 --------------------------------------------------------------------*/
#define KEY1                          (uint8_t)0x01
#define KEY2                          (uint8_t)0x02
#define KEY3                          (uint8_t)0x04
#define IS_KEY_TYPEDEF(KEY)           (((KEY) == KEY1) || ((KEY) == KEY2) || ((KEY) == KEY3))

/* 宏定义 --------------------------------------------------------------------*/
#define KEY1_RCC_CLOCKGPIO            RCC_APB2Periph_GPIOE
#define KEY1_GPIO_PIN                 GPIO_Pin_7
#define KEY1_GPIO                     GPIOE
#define KEY1_DOWN_LEVEL               0  /* 根据原理图设计,KEY1按下时引脚为低电平,所以这里设置为0 */


#define KEY2_RCC_CLOCKGPIO            RCC_APB2Periph_GPIOE
#define KEY2_GPIO_PIN                 GPIO_Pin_8
#define KEY2_GPIO                     GPIOE
#define KEY2_DOWN_LEVEL               0  /* 根据原理图设计,KEY2按下时引脚为低电平,所以这里设置为0 */


#define KEY3_RCC_CLOCKGPIO            RCC_APB2Periph_GPIOE
#define KEY3_GPIO_PIN                 GPIO_Pin_9
#define KEY3_GPIO                     GPIOE
#define KEY3_DOWN_LEVEL               0  /* 根据原理图设计,KEY3按下时引脚为低电平,所以这里设置为0 */

/* 扩展变量 ------------------------------------------------------------------*/
/* 函数声明 ------------------------------------------------------------------*/
void KEY_GPIO_Init(void);
KEYState_TypeDef KEYx_StateSet(GPIO_TypeDef* KEYx_GPIO, uint16_t KEYx_GPIO_PIN, uint8_t KEYx_DOWN_LEVEL);
KEYState_TypeDef KEYx_Choice(int KEYIndex);
void KEY_LED(void);

#endif  // __BSP_KEY_H__

3.main.c

这边值得注意的是延时函数需要配置文件,也可以将上一篇的延时函数直接放入main.c和bsp_key.c中

STM32(一):流水灯 (标准库函数)-CSDN博客

/* 包含头文件 ----------------------------------------------------------------*/
#include "stm32f10x.h"
#include "bsp/led/bsp_led.h"
#include "bsp/key/bsp_key.h"
#include "bsp/delay/delay.h"


/* 函数体 --------------------------------------------------------------------*/

/**
  * 函数功能: 主函数.
  * 输入参数: 无
  * 返 回 值: 无
  * 说    明: 无
  */
int main(void)
{

    /* 初始化 */
	LED_GPIO_Init();
	KEY_GPIO_Init();
  while (1)
  {
//	/* 流水灯 */
//   LED_Turn();
//   Delay(100);
	  
	/* 按键控制LED */
	KEY_LED();
	Delay(100);

  }
}

四、实验效果

按键点灯

结束语

本文以STM32VET6为例讲解了一种按键长按和短按点灯的实现方法,当然,这只是其中一种方法,实现的方式其实还是很多。
如果还有什么问题,欢迎评论区留言,谢谢!

作者:是覆盖对于变化

物联沃分享整理
物联沃-IOTWORD物联网 » STM32(二):使用标准库函数控制按键

发表评论