STM32 CubeMx HAL库外部中断检测按键,定时器延时消抖

常见的单片机按键检测的方式多是在while(1)中以轮询的方式检测按键是否被按下,在进行延时消抖(10ms左右),防止误检测。这样做会长时间的占用单片机的CPU资源,不是一种高效的按键检测方式。我们可以采用外部中断加定时器的方式实现按键检测而又不会长时间占用CPU

STM32 常规的按键检测流程:

while(1)
{
    if(KEY==0)
    {
        HAL_Delay(10);  //延迟10ms再次检测,若还是低电平,代表按键被按下
        if(KEY==0)
        {
             printf("key be pressed!!!\r\n");       
        }                                 
    }
}

STM32 HAL库外部中断+定时器检测按键的基本思路:外部中断设置下降沿触发,当按键按下单片机检测到下降沿后进入外部中断回调函数→在外部中断回调函数中打开定时器中断(定时时常设置为10ms)→在定时器中断回调函数中检测外部中断IO口电平,若依旧为低电平,代表按键被按下

具体操作步骤:

1.CubeMx配置

IO口PB1设置为外部中断上升沿触发模式,上拉

使用定时器1,时钟源选择内部时钟,预分频系数199、向上计数模式,计数值2399。

这里补充一下定时器计数时间的计算公式:Tout=(arr+1)*(psc+1)/Tclk,本例程中APB1外设时钟频率为48MHZ,故Tclk=1/48000000 所以Tout=(200*2400)/48us =10ms

2.单片机程序

//当按键按下,单片机检测到下降沿后进入此外部中断回调函数
//在外部中断回调函数中开启定时器1
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
     if(GPIO_Pin==KEY_GPIO_PIN)
     {
         HAL_TIM_Base_Start_IT(&htim1);
     }     

}

//定时时间10ms到了进入此中断回调函数中
//在此回调函数中判断IO口电平状态,如果以就为低电平,代表按键被按下
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
  if(htim==(&htim1))
  {
       HAL_TIM_Base_Stop_IT(&htim1);
       if(HAL_GPIO_ReadPin(KEY_GPIO_Port,KEY_Pin)==0)
           printf("key be pressed!!!\r\n");    
  }
           
}

总结一下,实现用外部中断检测按键,定时器延时消抖的关键步骤:

  1. 设置外部中断触发方式,计算预分频系数psc、计数值大小arr来确定时时间。
  2. 在外部中断回调函数中打开定时器,让其计数。
  3. 定时器溢出回调函数中,关闭定时器,再次检测按键IO口电平值。
<think>好的,我现在要解决用户关于STM32外部中断按键的优先级处理的问题。首先,我需要回忆一下STM32的中断优先级机制。根据引用[3],STM32的中断优先级分为抢占优先级和响应优先级,通过NVIC_PriorityGroup_x来配置这两种优先级的数量。比如,如果选择NVIC_PriorityGroup_2,那么抢占优先级有4个级别,响应优先级也有4个级别。每个中断的优先级需要在这两个部分中分配。 接下来,用户提到按键,这通常涉及到硬件或软件方法。在外部中断中使用按键时,动会产生多次中断,导致误触发。所以需要处理问题。常见的软件方法是在中断服务程序(ISR)中加入延时定时器检测按键的稳定状态。但这里用户特别询问了优先级处理,所以可能需要结合中断优先级来优化处理。 首先,配置外部中断的优先级。假设用户使用的是EXTI0中断,对应的中断处理函数是EXTI0_IRQHandler,如引用[1]所述。需要设置该中断的抢占优先级和响应优先级。比如,可以将按键中断的抢占优先级设为较低,这样其他更高优先级的中断可以打断它,避免影响系统实时性。但具体配置要根据系统需求来定。 然后,考虑处理。在中断服务程序中直接进行延时可能不太合适,因为这会阻塞其他中断。更好的方法是启动一个定时器中断,在按键外部中断触发后,启动定时器,比如10ms后再次检测按键状态。这样,定时器中断的优先级需要合理设置。如果定时器中断的抢占优先级低于按键中断,那么在处理定时器中断时,按键中断无法打断它,这样可以确保的有效性。但需要根据实际应用调整优先级,避免冲突。 此外,引用[3]提到硬件,比如使用RC滤波器,这可以减少软件处理的负担。如果同时使用硬件和软件,中断优先级的配置可能更灵活,因为硬件已经减少了误触发的次数,软件部分可能只需要简单的状态检查。 总结步骤应该是:配置外部中断的优先级,处理(软件或硬件),以及在中断服务程序中合理使用定时器并设置其优先级。同时要注意,在中断服务程序中尽量减少耗时操作,确保系统响应速度。 可能还需要考虑中断标志的清除,避免重复进入中断。例如,在EXTI0的中断处理中,先清除中断标志,然后启动定时器定时器到期后再次读取GPIO状态,确认按键是否稳定按下。这样,定时器的优先级设置需要不影响其他关键任务。 用户的问题还涉及具体实现和配置步骤,可能需要给出代码示例,比如使用HAL配置NVIC,设置优先级,以及在中断服务程序中添加逻辑。同时,提醒用户注意中断处理函数中的延迟操作可能带来的影响,建议使用非阻塞的方式处理,比如状态机或定时器回调。 最后,确保回答结构清晰,分步骤说明优先级配置和处理的实现方法,并引用提供的参考资料作为支持。</think>### STM32外部中断按键的优先级处理及配置 #### 1. **中断优先级配置** STM32的中断优先级通过**抢占优先级**和**响应优先级**(子优先级)共同决定,需通过`NVIC_PriorityGroupConfig()`函数设置优先级分组。例如: - 若选择`NVIC_PriorityGroup_2`,则抢占优先级范围为`0-3`,响应优先级范围为`0-3`(共4级)。 - 配置外部中断(如EXTI0)的优先级时,需分配抢占和响应优先级值: ```c NVIC_InitTypeDef NVIC_InitStruct = {0}; NVIC_InitStruct.NVIC_IRQChannel = EXTI0_IRQn; NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 1; // 抢占优先级 NVIC_InitStruct.NVIC_IRQChannelSubPriority = 0; // 响应优先级 NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE; HAL_NVIC_Init(&NVIC_InitStruct); ``` 此处将按键中断的抢占优先级设为1,允许更高优先级(如0)的中断打断它[^3]。 #### 2. **按键实现** **软件**通常结合定时器中断实现: 1. **外部中断服务函数**中启动定时器: ```c void EXTI0_IRQHandler(void) { HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_0); // 清除中断标志 HAL_TIM_Base_Start_IT(&htim2); // 启动定时器(例如TIM2) } ``` 2. **定时器中断服务函数**中检测按键稳定状态: ```c void TIM2_IRQHandler(void) { HAL_TIM_IRQHandler(&htim2); if (HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_0) == GPIO_PIN_RESET) { // 执行按键动作 } } ``` 3. **配置定时器优先级**(需低于按键中断的抢占优先级): ```c NVIC_InitStruct.NVIC_IRQChannel = TIM2_IRQn; NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 2; // 低于EXTI0的抢占优先级 HAL_NVIC_Init(&NVIC_InitStruct); ``` #### 3. **硬件优化** 在按键电路中添加RC滤波电路(如10kΩ电阻 + 0.1μF电容),减少动信号对中断的触发次数,降低软件处理负担[^3]。 #### 4. **注意事项** - 中断服务函数应尽量简短,避免阻塞其他中断。 - 清除中断标志必须在服务函数开始处执行,防止重复触发。 - 若系统需要实时性,可提高定时器中断的响应优先级。 ---
评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值