之前我一直使用阻塞式的按键消抖,虽然用在实时性不强的裸机系统问题不大,但感觉一直很膈应,因为我的宗旨是能不用delay就不用delay(笑),所以我写了这样一个程序来记录一下。

        我的思路是利用按键外部中断,在中断中记录当前按键值,唤醒一个20ms的定时器中断,当定时器产生中断事件时,在中断事件里再次读取按键值,如果两次按键值一致则判定按键触发。

        这里我只提供思路,就不放完整代码了(因为我代码写的太烂了)

        我的设备是STM32F411CEU6,使用HAL库,利用CUBEMX生成代码,开启TIM4设置单次触发20ms定时中断,然后KEY4_Pin是我定义的外部中断引脚。

这里是外部中断函数里的处理:

volatile uint8_t button_pressed_flag = 0;//定义按键按下标志
volatile uint8_t debounce_timer_enabled = 0;//定义定时器启动标志
volatile uint8_t Keyx_input = 0;//定义是哪一个按键按下

//外部中断回调函数
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
  if(GPIO_Pin == KEY4_Pin)//KEY4_Pin为用户标签
	{
		// 如果定时器没有在运行,就启动它
		if (debounce_timer_enabled == 0)
		{
			// 设置互斥锁,防止重复启动
			debounce_timer_enabled = 1;
            //按键4按下
			Keyx_input = 4;
            //读取按键值
			button_pressed_flag = HAL_GPIO_ReadPin(KEY4_GPIO_Port, KEY4_Pin);
			// 启动定时器,单次模式
			HAL_TIM_Base_Start_IT(&htim4); // 启动tim4
				
		}
	}
}

然后下面是定时器中断中的按键事件处理:

//定时器事件更新回调函数
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
  if (htim->Instance == TIM4) // 如果是TIM4触发了更新事件
	{
		// 停止定时器并清除标志位
		HAL_TIM_Base_Stop_IT(&htim4);
		//如果是按键4触发了外部中断
		if(Keyx_input == 4)
		{
			// 再次读取按键电平,进行判断
			if (HAL_GPIO_ReadPin(KEY4_GPIO_Port, KEY4_Pin) == button_pressed_flag)
			{
				// 两次电平相同,判定按键按下
				if (button_pressed_flag == GPIO_PIN_RESET) // 按下是低电平
				{
					// 切换LED状态
					HAL_GPIO_TogglePin(DEBUG_LED_GPIO_Port, DEBUG_LED_Pin);
				}
			}
		}
}

        这里我为了测试就只写了翻转电平。

        思路就提供到这了,还有非常多的功能不完善,我也不知道该如何改进了,欢迎各路大佬来指导/(ㄒoㄒ)/~~

 

Logo

智能硬件社区聚焦AI智能硬件技术生态,汇聚嵌入式AI、物联网硬件开发者,打造交流分享平台,同步全国赛事资讯、开展 OPC 核心人才招募,助力技术落地与开发者成长。

更多推荐