【STM32】HAL库开发之定时器作按键检测

目录

一、按键检测

二、定时器消抖原理

三、STM32CubeMX软件配置

四、程序设计


一、按键检测

本次是在前文《【STM32】HAL库开发之通用定时器中断》的基础上进一步开发

首先贴上板子上面的按键电路原理图

以KEY0为例,在按键没有按下的时候,GPIO的电平为高电平;当KEY0按下,此时GPIO直接与GND相连,电平变为低电平;当KEY0再次松开,GPIO的电平再次为高电平。

在按键按下或松开过程中,电平状态会出现抖动状态。在很多的例程中,都是使用延时函数来进行按键消抖。但是由于使用延时函数,占用cpu资源,会导致部分程序在延时的过程中发生暂停的情况,所以本次将使用定时器来进行按键消抖。

本次基于STM32L4VET6开发板,使用HAL库进行开发。

二、定时器消抖原理

以上述按键原理图为例,在本次实验中,一共有四个独立按键,我使用定时器每隔1ms读取一次按键的状态,然后进行判断。

如果连续8次按键都是按下状态,则判断按键确实按下了;

如果连续8次按键都是松开状态,则判断按键确实松开了;

如果连续8次内,既存在按下状态,也存在松开状态,则判断按键发生抖动,不进行处理。

原理很简单,实现起来也不难。

三、STM32CubeMX软件配置

本次是在前文《【STM32】HAL库开发之通用定时器中断》的基础上进一步开发。

在定时器的配置基础上,仅需增加按键的GPIO配置

将与几个按键相连的GPIO设置为输入模式

设置完成如下图所示

接下来将进行程序设计

四、程序设计

按键检测有关的函数将在 gpio.c 文件中添加

首先在 gpio.h 中添加几个宏定义,用于读取按键的电平状态以及操作LED

// 操作LED电平状态
#define LEDR_ON   HAL_GPIO_WritePin(LED_R_GPIO_Port, LED_R_Pin, GPIO_PIN_RESET)
#define LEDR_OFF  HAL_GPIO_WritePin(LED_R_GPIO_Port, LED_R_Pin, GPIO_PIN_SET)
#define LEDG_ON   HAL_GPIO_WritePin(LED_G_GPIO_Port, LED_G_Pin, GPIO_PIN_RESET)
#define LEDG_OFF  HAL_GPIO_WritePin(LED_G_GPIO_Port, LED_G_Pin, GPIO_PIN_SET)
#define LEDB_ON   HAL_GPIO_WritePin(LED_B_GPIO_Port, LED_B_Pin, GPIO_PIN_RESET)
#define LEDB_OFF  HAL_GPIO_WritePin(LED_B_GPIO_Port, LED_B_Pin, GPIO_PIN_SET)
#define LEDR_FLIP HAL_GPIO_TogglePin(LED_R_GPIO_Port, LED_R_Pin)
#define LEDG_FLIP HAL_GPIO_TogglePin(LED_G_GPIO_Port, LED_G_Pin)
#define LEDB_FLIP HAL_GPIO_TogglePin(LED_B_GPIO_Port, LED_B_Pin)

// 获取按键的GPIO电平状态
#define KEY0_STATE  HAL_GPIO_ReadPin(KEY0_GPIO_Port, KEY0_Pin)
#define KEY1_STATE  HAL_GPIO_ReadPin(KEY1_GPIO_Port, KEY1_Pin)
#define KEY2_STATE  HAL_GPIO_ReadPin(KEY2_GPIO_Port, KEY2_Pin)
#define WK_UP_STATE HAL_GPIO_ReadPin(WK_UP_GPIO_Port, WK_UP_Pin)

// 定义按键按下的标志位
#define NO_KEY_PRES	0
#define KEY0_PRES	1
#define KEY1_PRES 	2
#define KEY2_PRES 	3
#define WK_UP_PRES 	4

然后在 gpio.c 中的用户代码段添加

/* USER CODE BEGIN 1 */
static uint8_t KeySta[] = {1, 1, 1, 1};
/* USER CODE END 1 */
/* USER CODE BEGIN 2 */

/**
	* @Function	: Key_Scan
	* @Brief		: 按键状态扫描函数
	* @Input		: void
	* @Return		: void
	* @Others		: 放在定时器中断回调函数中调用
	*/
void Key_Scan(void)
{
	uint8_t i;
	static uint8_t KeyBuff[] = {0xff, 0xff, 0xff, 0xff};
	
	// 读取按键值,存入数组
	KeyBuff[0] = (KeyBuff[0] << 1 | (KEY0_STATE & 0x01));
	KeyBuff[1] = (KeyBuff[1] << 1 | (KEY1_STATE & 0x01));
	KeyBuff[2] = (KeyBuff[2] << 1 | (KEY2_STATE & 0x01));
	KeyBuff[3] = (KeyBuff[3] << 1 | (!WK_UP_STATE & 0x01));
	
	for(i = 0; i < 4; i ++)
	{
		// 连续扫描8次都是1,8ms内都是弹起状态,按键已松开
		if(KeyBuff[i] == 0xff)
		{
			KeySta[i] = 1;
		}
		// 连续扫描8次都是0,8ms内都是按下状态,按键已按下
		else if(KeyBuff[i] == 0x00)
		{
			KeySta[i] = 0;
		}
		else
		{}
	}
}

/**
	* @Function	: KeyPress
	* @Brief		: 按键检测函数
	* @Input		: void
	* @Return		: uint8_t Key_Value
	* @Others		: 放在while(1)中调用
	*/
uint8_t KeyPress(void)
{
	static uint8_t KeyBackup[] = {1, 1, 1, 1};
	uint8_t i, Key_Value = 0;
	
	for(i = 0; i < 4; i ++)
	{
		// 检测到按键状态发生变化
		if(KeySta[i] != KeyBackup[i])
		{
			// 按键按下时操作
			if(KeySta[i] == 0)
//				Key_Value = KeyDrive(i);
				Key_Value = i + 1;
			KeyBackup[i] = KeySta[i];
		}
	}
	
	return Key_Value;
}

/**
	* @Function	: KeyDrive
	* @Brief		: 读取按键键值函数
	* @Input		: uint8_t KeyValue
	* @Return		: uint8_t Key_Temp
	* @Others		: 
	*/
uint8_t KeyDrive(uint8_t KeyValue)
{
	uint8_t Key_Temp = 0;
	
	switch(KeyValue)
	{
		case 0: Key_Temp = KEY0_PRES; break;
		case 1: Key_Temp = KEY1_PRES; break;			// KEY1 开启录音
		case 2: Key_Temp = KEY2_PRES; break;			// KEY2 停止录音
		case 3: Key_Temp = WK_UP_PRES; break;
		default: Key_Temp = NO_KEY_PRES; break;
	}
	
	return Key_Temp;
}

/**
	* @Function	: KeyActivity
	* @Brief		: 按键活动函数
	* @Input		: void
	* @Return		: void
	* @Others		: 根据不同的按键,执行相应操作
	*/
void KeyActivity(void)
{
	uint8_t key;
	
	key = KeyPress();
	
	switch(key)
	{
		case KEY0_PRES: LEDR_FLIP; break;		// KEY0按下,翻转LEDR电平
		case KEY1_PRES: LEDG_FLIP; break;		// KEY1按下,翻转LEDG电平
		case KEY2_PRES: LEDB_FLIP; break;		// KEY2按下,翻转LEDB电平
		case WK_UP_PRES: LEDR_OFF; LEDG_OFF; LEDB_OFF; break;	// 关闭所有LED
		default : break;
	}
}

/* USER CODE END 2 */

在 tim.c 中编写定时器中断回调函数,并且在回调函数中调用按键扫描函数 Key_Scan();

注:默认的tim.c并没有包含gpio.h,请添加上,否则程序会报错

/* USER CODE BEGIN 1 */
// 定时器更新中断回调函数
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{

	// 判断是定时器3发生的中断
	if(htim->Instance == TIM3)
	{
		// 定时器3每中断一次执行一次按键扫描
		Key_Scan();
	}
}

/* USER CODE END 1 */

main.c 中,调用按键活动函数 KeyActivity();

while (1)
  {
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
		KeyActivity();
  }
  /* USER CODE END 3 */

至此,按键检测的全部程序编写完成,可以烧录至开发板进行验证。

所实现的功能为:

初始状态为LED_R、LED_G、LED_B全部熄灭状态;

按下KEY0,LED_R点亮,再次按下LED_R熄灭;

按下KEY1,LED_G点亮,再次按下LED_G熄灭;

按下KEY2,LED_B点亮,再次按下LED_B熄灭;

按下WK-UP,所有LED全部熄灭。

 

### 回答1: STM32 HAL库提供了许多按键处理函数,用于轻松实现按键功能,其中包括消抖处理。下面是一个简单的按键消抖处理的示例代码: ``` #include "stm32xxxx_hal.h" GPIO_TypeDef* GPIO_PORT[] = {BUTTON1_GPIO_Port, BUTTON2_GPIO_Port, BUTTON3_GPIO_Port}; const uint16_t GPIO_PIN[] = {BUTTON1_Pin, BUTTON2_Pin, BUTTON3_Pin}; uint32_t debounce_time = 50; // 定义消抖时间,单位ms uint32_t button_state = 0; // 按键状态,0表示未按下,1表示按下 uint32_t button_last_state = 0; // 上一次按键状态 uint32_t button_changed_time = 0; // 按键状态改变的时间 void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin) { // 获取按键状态 button_state = HAL_GPIO_ReadPin(GPIO_PORT[0], GPIO_PIN[0]); // 判断按键状态是否改变 if(button_state != button_last_state) { // 获取当前时间 uint32_t current_time = HAL_GetTick(); // 判断是否达到消抖时间 if((current_time - button_changed_time) > debounce_time) { button_last_state = button_state; // 更新按键状态 button_changed_time = current_time; // 更新按键状态改变的时间 } } } int main(void) { HAL_Init(); // 配置按键引脚为输入模式 GPIO_InitTypeDef GPIO_InitStruct; GPIO_InitStruct.Pin = GPIO_PIN[0]; GPIO_InitStruct.Mode = GPIO_MODE_IT_FALLING; GPIO_InitStruct.Pull = GPIO_PULLUP; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH; HAL_GPIO_Init(GPIO_PORT[0], &GPIO_InitStruct); while(1) { if(button_last_state == 1) { // 按键已经按下 } else { // 按键未按下 } } } ``` 在上述代码中,按键的引脚被配置为下降沿触发中断模式。当按键被按下时,将会调用HAL_GPIO_EXTI_Callback函数,该函数将获取按键状态并进行消抖处理。如果按键状态发生改变并且达到了消抖时间,函数将更新按键状态和状态改变时间。最后,在主循环中,可以使用button_last_state变量获取当前按键状态。 ### 回答2: 按键消抖是为了解决按键在接触和释放过程中可能出现的抖动现象,确保按键输入稳定可靠。基于STM32HAL库按键消抖代码可以按照以下步骤实现: 1. 配置按键引脚:在GPIO初始化的时候,设置按键引脚为输入模式,同时开启外部中断功能。 2. 初始化外部中断:使用HAL库提供的函数,初始化外部中断。例如,使用HAL_GPIO_Init()函数初始化GPIO引脚。 3. 编写中断处理函数:使用HAL库的外部中断处理函数,编写中断处理函数。当检测按键状态发生变化时,该中断函数会被触发。 4. 添加按键消抖功能:在中断处理函数中加入按键消抖的代码。可以通过使用延时函数或软件定时器的方式来实现按键的延时处理。 5. 读取按键状态:在主程序中通过使用HAL库提供的函数,读取按键的状态。例如,使用HAL_GPIO_ReadPin()函数读取按键引脚的状态。 6. 判断按键的有效按下:根据实际需求,判断按键是否为有效按下状态。可以使用计数器或状态机的方法进行判断。 7. 执行相应的操:如果判断按键为有效按下状态,根据实际需求,执行相应的操。 通过以上步骤,可以实现基于STM32HAL库按键消抖代码。按键消抖可以确保按键输入的准确性和稳定性,提升系统可靠性和用户体验。 ### 回答3: 按键消抖是在按下或释放按键时,为了避免产生误触发信号而采取的一种技术。基于stm32hal库按键消抖代码可以通过以下步骤实现。 首先,需要使用HAL库中的GPIO模块进行按键的初始化。通过设置GPIO引脚的模式为输入模式,同时配置GPIO的上拉或下拉电阻,以确保按键的输入可靠。 然后,我们可以利用HAL库中的外部中断模块来检测按键的状态变化。外部中断可以检测按键的按下和释放动,并且会产生中断信号,从而通知主程序进行相应的处理。 在中断服务函数中,需要进行按键的消抖处理。最常用的消抖方法是软件消抖,即通过延时一段时间来稳定按键的状态。可以使用HAL库中的延时函数进行延时操。 在延时结束后,再次读取按键的状态。如果按键的状态与延时前相同,则可以认为按键的状态没有发生变化,即按键的状态稳定。否则,需要重新进行延时。 最后,根据按键的稳定状态进行相应的处理。可以通过判断按键的按下、释放状态来实现不同功能的触发。 这是一个简单的基于stm32hal库按键消抖代码实现。具体的代码实现可以根据具体的需求进行调整和修改。
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值