STM32-按键,内含按键的两类设计以及按键的长按短按、按键消抖、按键按下松开设计

    在我们学习STM32的过程中,按键是一个非常重要且必须要掌握的一个板块。下面小编就带大家进入按键模块吧!

一、原理说明

按键原理图

    看到上面的原理图,想必大家已经知道该块STM32开发板的按键按下后的返回值应该是0。由于该开发板的按键数量比较少,因此我们直接使用switch即可判断某一个按键是否按下 。

二、部分库函数解析

1、GPIO_ReadInputDataBit函数

在这里插入图片描述

2、GPIO_ReadInputData函数

在这里插入图片描述

三、代码解析

1、枚举变量与全局变量

//定义变量 存储上次按键按下的值
unsigned char key_old;

//枚举按键但是KEY0是无效的 为了匹配现实中开发板按键的位置而设立
enum KEY_NUM{KEY0,KEY1,KEY2,KEY3,KEY4,KEY5};

2、GPIO初始化

在GPIO初始换中,我们只需要打开GPIOE时钟,选择GPIO引脚、GPIO的频率、GPIO的模式即可。

/*
	* @brief The initialization of the button GPIO(按键GPIO的初始化)
	* @param none
	* @retval none
*/
void key_GPIO_init(void)
{
	//声明一个结构体,用于初始化GPIO
	GPIO_InitTypeDef GPIO_InitStructure;
	//开启GPIO的时钟
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOE,ENABLE);
	//选择GPIO的引脚为Pin0,Pin2,Pin3
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_All;
	//设置GPIO的速度为50MHz
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	//将GPIO引脚设置成上拉输入模式
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
	//GPIOE引脚的初始化
	GPIO_Init(GPIOE,&GPIO_InitStructure);
}

3、按键扫描函数1

小编个人认为按键扫描函数1相对于按键扫描函数2来说,更容易理解,建议大家看懂扫描函数1后再去看扫描函数2。

/*
	* @brief Determine whether the button is pressed(判断某一个按键是否按下)
	* @param KEY_NUM:one of a button(其中一个按键)
	* @retval key_num:Back to judgment status 0-pressed 1-not pressed(返回判断的状态 0-未按下 1-按下)
*/
int get_key(int KEY_NUM)
{
	//待判断按键的返回状态 0-表示按下 1-表示松开
	int key_num = 3;
	switch(KEY_NUM){
		//判断key1
		case KEY1: key_num = GPIO_ReadInputDataBit(GPIOE,GPIO_Pin_0);break;
		//判断key2
		case KEY2: key_num = GPIO_ReadInputDataBit(GPIOE,GPIO_Pin_1);break;
		//判断key3
		case KEY3: key_num = GPIO_ReadInputDataBit(GPIOE,GPIO_Pin_2);break;
		//判断key4
		case KEY4: key_num = GPIO_ReadInputDataBit(GPIOE,GPIO_Pin_3);break;
		//判断key5
		case KEY5: key_num = GPIO_ReadInputDataBit(GPIOE,GPIO_Pin_6);break;
		//屏蔽可能出现的干扰
		default: break;
	}
	return key_num;
}

4、按键服务函数1

这里的按键服务函数小编以点亮开发板上的LED灯为例。(想看小编的点亮LED函数可通过链接前往——STM32-八位流水灯

/*
	* @brief scan the button and perform the corresponding function which is Press and light up or loosen and go out
	*				(扫描按键并且执行相应的功能)
	* @param none
	* @retval none
*/
void scan_key(void)
{
	if(get_key(KEY1) == 0){//按下key1点亮LED1
		LED_ctrl(LED1,LED_ON);
	}else{//松开key1熄灭LED1
		LED_ctrl(LED1,LED_OFF);
	}
	
	if(get_key(KEY2) == 0){//按下key2点亮LED2
		LED_ctrl(LED2,LED_ON);
	}else{//松开key2熄灭LED2
		LED_ctrl(LED2,LED_OFF);
	}
	
	if(get_key(KEY3) == 0){//按下key3点亮LED3
		LED_ctrl(LED3,LED_ON);
	}else{//松开key3熄灭LED3
		LED_ctrl(LED3,LED_OFF);
	}
	
	if(get_key(KEY4) == 0){//按下key4点亮LED4
		LED_ctrl(LED4,LED_ON);
	}else{//松开key4熄灭LED4
		LED_ctrl(LED4,LED_OFF);
	}
	
	if(get_key(KEY5) == 0){//按下key5点亮LED5
		LED_ctrl(LED5,LED_ON);
	}else{//松开key5熄灭LED5
		LED_ctrl(LED5,LED_OFF);
	}
	
	//熄灭无关的LED6、LED7、LED8
	LED_ctrl(LED6,LED_OFF);
	LED_ctrl(LED7,LED_OFF);
	LED_ctrl(LED8,LED_OFF);
}

5、按键扫描函数2

小编个人认为,尽管扫描函数2比扫描函数1跟不容易理解,但是小编更加青睐它。

/*
	* @brief  scan the button and back to the value
	* @param  none
	* @retval key_val:Back to key number which was pressed(返回被按下按键的值)
*/
unsigned char scan_kbd(void)
{
	//定义一个返回值
	unsigned char key_val = 0;
	//扫描按键的引脚
	unsigned int key_press = GPIO_ReadInputData(GPIOE);
	//排除其他引脚的影响
	key_press = key_press|0xffb0;
	//判断按键是否按下
	switch(key_press)
	{
		//KEY1按下
		case 0xfffe: key_val = 1;break;
		//KEY2按下
		case 0xfffd: key_val = 2;break;
		//KEY3按下
		case 0xfffb: key_val = 3;break;
		//KEY4按下
		case 0xfff7: key_val = 4;break;
		//KEY5按下
		case 0xffbf: key_val = 5;break;
		//所有按键都没按下或者其他可能出现的干扰
		default: key_val = 0;break;
	}
	return key_val;
}

6、按键服务函数2

这里小编是以数码管显示数值为实例的。相对于服务函数1而言,小编在服务函数2中加上了按键消抖、按键松开、按键按下这三个功能。其实这里的按键扫描函数使用函数1应该也是能够达到该效果的,不过小编没有尝试。(小编这里有数码管刷新的具体函数,可前往链接——STM32-刷新数码管

/*
	* @brief perform the corresponding function which is Press(执行按键按下后的执行相应的函数)
	* @param none
	* @retval none
*/
void key_por(void)
{
	static unsigned int number = 0;
	//定义变量 存储案件是否松开、按下的值
	unsigned char key_up,key_down;
	//按键扫描
	unsigned int key_num = scan_kbd();
	//获取按键是否按下
	key_down = key_num & (key_old ^ key_num);
	//获取按键是否松开
	key_up = ~key_num & (key_old ^ key_num);
	//保存本次按键的值
	key_old = key_num;
	
	if(key_down){//按键消抖 每次只有按键按下后number的值才会加1
		number++;
	}
	
	segbuff[0] = key_num;
	segbuff[1] = key_down;
	segbuff[2] = key_up;
	segbuff[3] = key_old;
	segbuff[5] = number;
}

四、总结

    STM32F103ZET6开发板的按键数量相对较少,实现按键扫描函数相对简单。
    在我们写按键扫描函数时,第一步需要查阅原理图,观察按键的排列方式;第二步,判断扫描按键使用的方法,即是否需要使用行列扫描法扫描函数,若不需要(也就是按键数量较少、排列简单的前提下)我们可以直接使用switch判断按键是否按下;第三步,若有需要,可以完善按键的功能。

  • 2
    点赞
  • 40
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
好的,下面是一个简单的STM32f103按键检测程序实现短按的例子: 首先需要定义按键的GPIO引脚和模式,比如我们使用PA0作为按键输入,设置为下拉输入模式: ```c GPIO_InitTypeDef GPIO_InitStructure; RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; GPIO_Init(GPIOA, &GPIO_InitStructure); ``` 然后在主循环中检测按键状态,可以使用一个计数器来实现按和短按的区分,比如按下后计数器从0开始计数,当计数器达到一定值时判断为按,否则为短按: ```c uint8_t key_state = 0; //0表示未按下,1表示短按,2表示按 uint8_t key_down_cnt = 0; //按键按下计数器 uint8_t key_up_cnt = 0; //按键松开计数器 while(1) { if(GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_0) == 0) //检测按键是否按下 { key_down_cnt++; //按键按下计数器加1 key_up_cnt = 0; //按键松开计数器清零 if(key_down_cnt >= 50) //按键按下计数器达到一定值时判断为按 { if(key_state == 0 || key_state == 1) //如果之前状态为未按下短按,则判断为按 { key_state = 2; //设置状态为按 printf("key long press\r\n"); } } else //按键按下计数器未达到一定值时判断为短按 { if(key_state == 0) //如果之前状态为未按下,则判断为短按 { key_state = 1; //设置状态为短按 printf("key short press\r\n"); } } } else //按键按下 { key_up_cnt++; //按键松开计数器加1 key_down_cnt = 0; //按键按下计数器清零 if(key_up_cnt >= 50) //按键松开计数器达到一定值时判断为按键已经松开 { key_state = 0; //设置状态为未按下 } } delay_ms(10); //延时10ms } ``` 需要注意的是,计数器的值需要根据实际情况调整,这里的50只是一个参考值。另外,还需要实现一个延时函数delay_ms,可以使用定时器或者软件延时来实现。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值