单片机
返回首页

stm32f1按键检测使用外部中断以及定时器延时方式去抖

2018-12-27 来源:eefocus

本来一个按键检测是很简单的功能,在大学的时候做的51单片机矩阵键盘更要复杂,但是如果要在操作系统中使用按键并且很好的去除抖动,不影响整个rtos系统的运行,保证中断不会长时间占用CPU,达到快进快出的目的。就需要另外启动一个定时器来完成计时功能(比如去抖20ms)后,产生定时器中断后再次检测按键电平。


    一般51或stm32按键检测流程:


#define key1 GPIOC_11

 

void delay(uint32_t n )

{

while(n--);

}

 

void key_detected()

{

    if (key1 == 0)

    {

        delay(20);

  if (ke1 == 0)

            printf('key1 be pressed!!!\r\n');

        else

      return ;

    }

}

 

while(1)

{

    key_detected();

}

    这样的delay()可以达到去抖的目的,但是实现方式太过暴力,在延时的时候一直占用cpu的资源,如果在延时的时候,有其他外部中断或者抢占事件,系统完全没有响应的。所以我们CPU需要一个独立的定时装置,来完成这个计时工作,而且需要在计时时间到达时再检测一次按键的电平值。


    我的r8t6资源有限,所以使用TIM1和它的定时溢出(update)中断。


    首先初始化管脚,打开管脚的外部中断:


/*Configure GPIO pins : KEY_1_Pin KEY_2_Pin */

GPIO_InitStruct.Pin = KEY_1_Pin|KEY_2_Pin;

GPIO_InitStruct.Mode = GPIO_MODE_IT_FALLING;

GPIO_InitStruct.Pull = GPIO_NOPULL;

HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);


/* EXTI interrupt init*/

HAL_NVIC_SetPriority(EXTI15_10_IRQn, 5, 0);

HAL_NVIC_EnableIRQ(EXTI15_10_IRQn);

    初始化TIM1,打开其update中断:


static void MX_TIM1_Init(void)

{

htim1.Instance = TIM1;

htim1.Init.Prescaler = 7200 - 1;                // 72000000 / 7200 = 10000 hz  0.01ms

htim1.Init.CounterMode = TIM_COUNTERMODE_UP;

htim1.Init.Period = 200 - 1;                    // 200 * 0.01 = 20ms

htim1.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;

htim1.Init.RepetitionCounter = 0;

htim1.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;


if (HAL_TIM_Base_Init(&htim1) != HAL_OK)

{

_Error_Handler(__FILE__, __LINE__);

}


}

这个在stm32f1xx_hal_msp.c中

void HAL_TIM_Base_MspInit(TIM_HandleTypeDef* htim_base){ if(htim_base->Instance==TIM1) {/* Peripheral clock enable */ __HAL_RCC_TIM1_CLK_ENABLE();/* USER CODE BEGIN TIM1_MspInit 1 */HAL_NVIC_SetPriority(TIM1_UP_IRQn,1,3); HAL_NVIC_EnableIRQ(TIM1_UP_IRQn); }}

在stm32f1xx_hal_it.c中去注册中断回调函数(关键的步骤,需要在按键中断处理函数中打开定时器,开始计时):


void EXTI15_10_IRQHandler(void)            // 按键的中断处理函数

{

 

HAL_TIM_Base_Start_IT(&htim1);    //  开启定时器1,开始计时

 

printf('key down\r\n');

 

__HAL_GPIO_EXTI_CLEAR_IT(GPIO_PIN_11);

__HAL_GPIO_EXTI_CLEAR_IT(GPIO_PIN_12);

}

定时器的中断处理函数:


void TIM1_UP_IRQHandler(void)

{


HAL_TIM_IRQHandler(&htim1);   //这个是所有定时器处理回调的入口,在这个函数里对应定时器多种中断情况的中断回调,需要找到update的回调函数

printf('TIM IRQ\r\n');

 

}

void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)        // 定时器update中断处理回调函数

{

/* USER CODE BEGIN Callback 0 */

 

/* USER CODE END Callback 0 */

if (htim->Instance == TIM2) {

   HAL_IncTick();

}

 

if (htim->Instance == TIM1) {            // 在这里选择tim1 

 

printf('TIM1 updata\r\n');

 

HAL_TIM_Base_Stop_IT(&htim1);       //    关闭tim1 及清除中断

 

if (GPIO_PIN_RESET == HAL_GPIO_ReadPin(GPIOC,GPIO_PIN_11) )    //再次判断管脚的电平

{

printf('KEY1 be pressed!!!\r\n');

}


if (GPIO_PIN_RESET == HAL_GPIO_ReadPin(GPIOC,GPIO_PIN_12) )//再次判断管脚的电平

{

printf('KEY2 be pressed!!!\r\n');

}

}

/* USER CODE BEGIN Callback 1 */

 

/* USER CODE END Callback 1 */

}


总结一下,实现用定时器中断来完成按键延时去抖的关键步骤:


1. 初始化GPIO管脚,初始化TIM ,算好时间,填入分频值。


2. 打开GPIO中断,在中断处理函数中打开定时器,让其计数。


3. 定时器溢出中断函数中,再次判断按键电平值。关闭定时器,清除pending。



进入单片机查看更多内容>>
相关视频
  • RISC-V嵌入式系统开发

  • SOC系统级芯片设计实验

  • 云龙51单片机实训视频教程(王云,字幕版)

  • 2022 Digi-Key KOL 系列: 你见过1GHz主频的单片机吗?Teensy 4.1开发板介绍

  • TI 新一代 C2000™ 微控制器:全方位助力伺服及马达驱动应用

  • MSP430电容触摸技术 - 防水Demo演示

精选电路图
  • 家用电源无载自动断电装置的设计与制作

  • 用数字电路CD4069制作的万能遥控轻触开关

  • 使用ESP8266从NTP服务器获取时间并在OLED显示器上显示

  • 开关电源的基本组成及工作原理

  • 用NE555制作定时器

  • 带有短路保护系统的5V直流稳压电源电路图

    相关电子头条文章