打印
[其他ST产品]

使用TIM内部计数器(CNT)实现按键长、短按

[复制链接]
114|6
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
STM32使用TIM内部计数器(CNT)实现按键长、短按
1.工具
STM32CUBE、IAR
STM32F411VET6
2.实现
2.1案例说明
按键:本案例使用PA0,高电平有效(按下引脚电平为1,未按下为0)
长按: 按键从按下到释放时间 > 2s
短按: 按键从按下到释放时间 < 1s
长按功能:LED15翻转1次,调用HAL_GPIO_TogglePin( GPIOD, GPIO_PIN_15);
短按功能:LED12翻转1次,调用HAL_GPIO_TogglePin( GPIOD, GPIO_PIN_12);
2.2 方法
一般按键短按一次用时100ms,因此对TIM进行预分频,使其内部CNT每计一个数用时为1ms。当按键按下时将TIM内部的CNT进行保存,释放时再保存一次,计算2次CNT的差值,从而进行长按、短按判定

F411VET6定时器TIM3内部CNT是32bit的,可以计时达到us级别,这里设置溢出值为60000即60ms,(没有打开中断,只是利用CNT计1个数用时1ms),另外也可利用定时器+中断+计数器实现长、短按,大概思路这样,设置TIM短长时间进入中断1次,进入中断后计数器累加,判断计数器从而实现长短按(文章后边有该方法实现的结果(5ms进入1次中断))


使用特权

评论回复
沙发
有何不可0365|  楼主 | 2024-1-30 16:07 | 只看该作者
main

#include "main.h"
#include "tim.h"
#include "gpio.h"

uint8_t tim_flag = 0;
uint8_t key_flag = 0;
#define key_null     0
#define key_long     1
#define key_short    2

void SystemClock_Config(void);

void KeyScan(void);

uint32_t tmpbuf[4] = {0, 0, 0, 0};

int main(void)
{
  HAL_Init();
  SystemClock_Config();
  MX_GPIO_Init();
  MX_TIM3_Init();
  HAL_TIM_Base_Start(&htim3);//在按键扫描之前开启定时器

  while (1)
  {
   
     KeyScan();
     switch(tim_flag)
     {
      
     case key_null:
           break;

     case key_short:
          HAL_GPIO_TogglePin( GPIOD, GPIO_PIN_12);
         break;
         
     case key_long:
          HAL_GPIO_TogglePin( GPIOD, GPIO_PIN_15);
         break;
         
     default:
         break;
     
     }
  }

}

使用特权

评论回复
板凳
有何不可0365|  楼主 | 2024-1-30 16:08 | 只看该作者
keyscan

void KeyScan(void)
{

     uint8_t key_states = 0;
     key_states = HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_0);

     if(key_flag == 0)
     {
         
         tmpbuf[0] = TIM3->CNT;
         key_flag = 1;
         tim_flag = key_null;
     }
      else
    {
         if( 0 == key_states)
         {
             tmpbuf[1] = TIM3->CNT;
             key_flag = 0;
            
             if( tmpbuf[1] < tmpbuf[0] )//CNT判断
             {
            
                  tmpbuf[2] = (60000 + tmpbuf[1])  - tmpbuf[0];
            
             }
             else if(tmpbuf[1] > tmpbuf[0])
             {
            
                  tmpbuf[2] =  tmpbuf[1]  - tmpbuf[0];
            
             }
            
             if(tmpbuf[2] > 2000 )
             {
                  tim_flag = key_long;
               
                  tmpbuf[2] = 0;
             }
             else if((tmpbuf[2] > 20 ) && (tmpbuf[2] < 1000))
             {
                   tim_flag = key_short;
                 
                   tmpbuf[2] = 0;
             }
   
         }
            
      }
         
}

使用特权

评论回复
地板
有何不可0365|  楼主 | 2024-1-30 16:08 | 只看该作者
TIM配置

  htim3.Instance = TIM3;
  htim3.Init.Prescaler = 15999;//CNT计一个数1ms
  htim3.Init.CounterMode = TIM_COUNTERMODE_UP;
  htim3.Init.Period = 60000;//溢出值
  htim3.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
  htim3.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;

使用特权

评论回复
5
有何不可0365|  楼主 | 2024-1-30 16:08 | 只看该作者
利用CNT实现长短按的结果:

使用特权

评论回复
6
有何不可0365|  楼主 | 2024-1-30 16:08 | 只看该作者
定时器+中断+计数器实现结果:

使用特权

评论回复
7
有何不可0365|  楼主 | 2024-1-30 16:09 | 只看该作者
可见利用CNT实现的长短按效果更高些,按键抖动处理的时间相对较少,当然定时器+中断+计数器的方法还可以在优化

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

31

主题

445

帖子

0

粉丝