stm32按键 长按 短按 函数 一

13 篇文章 0 订阅
8 篇文章 1 订阅

 

在stm32工程中,长按和短按的代码书写, 调用的读取按键状态的底层函数。封装成的按键函数代码。下面是函数的头文件,和.c文件的代码。使用定时器来扫描按键。

#define KEY_ON	1
#define KEY_OFF	0
#define KEY_NULL 0
#define KEY_SHORT 1
#define KEY_LONG  10
#define SHORT_TIME 200
uint8_t Key_state(GPIO_TypeDef* GPIOx,uint16_t GPIO_Pin)
{
	 static uint8_t key_value = KEY_NULL;
	 static uint16_t longtime;
	 if( (longtime == 0) && (key_value != KEY_NULL))  //当按键状态为长按或者短按时,而longtime 不为零,则按键状态清零
	 { 
	     key_value = KEY_NULL;
	 }
	 if ( time == 5 ) /* 5 * 1 ms = 5ms 定时时间到 */
     {
        time = 0;
		if(KEY_PRESS(GPIOx,GPIO_Pin))  //按键按下
	    {
	         longtime++;
        }
        else  //按键松开
		{
		    if((longtime >= 3) && (longtime <= SHORT_TIME))  //短按
			{
				key_value = KEY_SHORT;
			}
			else if( longtime > SHORT_TIME ) //长按
			{
			    key_value = KEY_LONG;
			}
			else  //去抖动
			{
			    key_value = KEY_NULL;
			}
				longtime = 0; //清零
		}					
     }  
 return key_value;
}

上面的代码,是按键松开才能判断按键的状态,是长按还是短按。在实际项目中我需要,按键按下一段时间后,判断为按键长按,不用松开,返回按键长按。参考网上的代码,使用状态机写了如下代码

#define    KEY_PRESS(GPIOx,GPIO_Pin)      GPIO_ReadInputDataBit(GPIOx,GPIO_Pin)
#define KEY_INPUT           KEY_PRESS(GPIOx,GPIO_Pin)    //读取按键状态

#define KEY_STATE_0         0       // 按键状态位
#define KEY_STATE_1         1
#define KEY_STATE_2         2
#define KEY_STATE_3         3

#define LONG_KEY_TIME       300     //长按的3秒时间
#define SINGLE_KEY_TIME     3       // 短按的消抖时间

#define N_KEY    0                  // 无状态
#define S_KEY    1                  // 单击
#define L_KEY    10                 // 长按

 

 

 

 

 

 

函数的主体部分,代码中按下按键读取到高电平。

unsigned char key_driver(GPIO_TypeDef* GPIOx,uint16_t GPIO_Pin)) 
{     
    static unsigned char key_state = 0;         // 按键状态变量
    static unsigned int key_time = 0;           // 按键计时变量
    unsigned char key_press, key_return; 

    key_return = N_KEY;                         // 清除 返回按键值

    key_press = KEY_INPUT;                      // 读取当前键值

    switch (key_state)     
    {       
        case KEY_STATE_0:                       // 按键状态0:判断有无按键按下
            if (key_press == KEY_ON)                     // 有按键按下
            {
                key_time = 0;                   // 清零时间间隔计数
                key_state = KEY_STATE_1;        // 然后进入 按键状态1
            }        
            break;

        case KEY_STATE_1:                       // 按键状态1:软件消抖(确定按键是否有效,而不是误触)。按键有效的定义:按键持续按下超过设定的消抖时间。
            if (key_press == KEY_ON)                     
            {
                key_time++;                     // 一次10ms
                if(key_time>=SINGLE_KEY_TIME)   // 消抖时间为:SINGLE_KEY_TIME*10ms = 30ms;
                {
                    key_state = KEY_STATE_2;    // 如果按键时间超过 消抖时间,即判定为按下的按键有效。按键有效包括两种:单击或者长按,进入 按键状态2, 继续判定到底是那种有效按键
                }
            }         
            else key_state = KEY_STATE_0;       // 如果按键时间没有超过,判定为误触,按键无效,返回 按键状态0,继续等待按键
            break; 

        case KEY_STATE_2:                       // 按键状态2:判定按键有效的种类:是单击,还是长按
            if(key_press == KEY_OFF)                       // 如果按键在 设定的长按时间 内释放,则判定为单击
            { 
                 key_return = S_KEY;            // 返回 有效按键值:单击
                 key_state = KEY_STATE_0;       // 返回 按键状态0,继续等待按键
            } 
            else
            {
                key_time++;                     

                if(key_time >= LONG_KEY_TIME)   // 如果按键时间超过 设定的长按时间(LONG_KEY_TIME*10ms=200*10ms=2000ms), 则判定为 长按
                {
                    key_return = L_KEY;         // 返回 有效键值值:长按
                    key_state = KEY_STATE_3;    // 去状态3,等待按键释放
                }
            }
            break;

      case KEY_STATE_3:                         // 等待按键释放
          if (key_press == KEY_OFF) 
          {
              key_state = KEY_STATE_0;          // 按键释放后,进入 按键状态0 ,进行下一次按键的判定
          }         
          break; 

        default:                                // 特殊情况:key_state是其他值得情况,清零key_state。这种情况一般出现在 没有初始化key_state,第一次执行这个函数的时候
            key_state = KEY_STATE_0;
            break;
    }

    return key_return;                          // 返回 按键值
} 
unsigned char key_handle(GPIO_TypeDef* GPIOx,uint16_t GPIO_Pin)
{
	unsigned char key_value;
  if ( time >= 10 ) /* 10 * 1 ms = 10ms 定时器 */
   {
        time = 0;
		    key_value = key_driver(GPIOx,GPIO_Pin); 
	 }
	 return key_value;
}

time 这个变量,定义在了定时器文件中

 在main.c中调用

int main(void)
{
	int8_t key_value;
	/* led 初始化*/ 
	LED_GPIO_Config();
	
	BASIC_TIM_Init();
	
	Key_GPIO_Config();
	
  while(1)
  {

//		key_value = Key_state(KEY1_GPIO_PORT,KEY1_GPIO_PIN);
		key_value = key_handle(KEY1_GPIO_PORT,KEY1_GPIO_PIN);

		if(key_value == KEY_SHORT)
		{
			  
		    LED1_TOGGLE;
		}
		else if(key_value == KEY_LONG)
		{
		    LED2_TOGGLE; 
		}
		
  }
}

这样可以实现长按不松手,执行长按的代码。以后遇到好的思想会继续学习,总结下来。

代码风格不是特别好,很早之前写的了,放在这里了,仅供参考

链接    提取码:66zh

 

https://blog.csdn.net/xiaohu1996/article/details/103236089

这个是我写的按键二的博客,一些思想可以提供学习

  • 27
    点赞
  • 153
    收藏
    觉得还不错? 一键收藏
  • 20
    评论
Arduino和STM32都是常用的单片机开发板,用于各种电子项目和嵌入式系统的开发。下面我将用300字介绍如何使用这两种开发板编写按键按和短按的程序。 对于Arduino开发板,可以使用内置的库函数来实现按键按和短按的功能。首先,需要通过数字IO口连接一个机械按键并设置为输入模式。然后,在程序中设置一个计时器,用来检测按键的按下时间。通过判断按键按下的持续时间来确定是按还是短按。 以下是Arduino的示例代码: ```Arduino const int buttonPin = 2; // 连接按键的数字IO口 int buttonState = 0; // 按键状态 unsigned long buttonTimer = 0; // 按键计时器 bool isLongPress = false; // 是否按 void setup() { pinMode(buttonPin, INPUT); Serial.begin(9600); } void loop() { buttonState = digitalRead(buttonPin); if (buttonState == HIGH) { if (buttonTimer == 0) { buttonTimer = millis(); // 记录按下的起始时间 } } else { if (buttonTimer != 0) { if (millis() - buttonTimer > 1000) { isLongPress = true; } else { isLongPress = false; } buttonTimer = 0; // 清空计时器 } } if (isLongPress) { Serial.println("Button long press"); } else { Serial.println("Button short press"); } delay(100); // 延时100毫秒 } ``` 对于STM32开发板,可以使用CubeMX和HAL库来实现按键按和短按的功能。首先,在CubeMX中配置按键对应的GPIO口,并设置为输入模式。然后,在程序中使用HAL库提供的函数来检测按键的状态和按下时间。通过判断按键按下的持续时间来确定是按还是短按。 以下是STM32的示例代码: ```C #include "main.h" #include "stdio.h" #include "stm32f1xx_hal.h" GPIO_TypeDef* BUTTON_GPIO_Port = GPIOA; uint16_t BUTTON_Pin = GPIO_PIN_0; uint32_t buttonTimer = 0; _Bool isLongPress = 0; void SystemClock_Config(void); static void MX_GPIO_Init(void); int main(void) { HAL_Init(); SystemClock_Config(); MX_GPIO_Init(); while (1) { if (HAL_GPIO_ReadPin(BUTTON_GPIO_Port, BUTTON_Pin) == GPIO_PIN_SET) { if (buttonTimer == 0) { buttonTimer = HAL_GetTick(); } } else { if (buttonTimer != 0) { if (HAL_GetTick() - buttonTimer > 1000) { isLongPress = 1; } else { isLongPress = 0; } buttonTimer = 0; } } if (isLongPress) { printf("Button long press\n"); } else { printf("Button short press\n"); } HAL_Delay(100); } } void SystemClock_Config(void) { RCC_OscInitTypeDef RCC_OscInitStruct = {0}; RCC_ClkInitTypeDef RCC_ClkInitStruct = {0}; /**Configure the main internal regulator output voltage */ __HAL_RCC_PWR_CLK_ENABLE(); __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1); RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI; RCC_OscInitStruct.HSIState = RCC_HSI_ON; RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT; RCC_OscInitStruct.PLL.PLLState = RCC_PLL_NONE; if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK) { Error_Handler(); } /**Configure the SYSCLKSource, HCLK, PCLK1 and PCLK2 clocks dividers */ RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2; RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_HSI; RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1; RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1; RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1; if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_0) != HAL_OK) { Error_Handler(); } } static void MX_GPIO_Init(void) { GPIO_InitTypeDef GPIO_InitStruct = {0}; __HAL_RCC_GPIOA_CLK_ENABLE(); __HAL_RCC_AFIO_CLK_ENABLE(); HAL_GPIO_WritePin(GPIOA, GPIO_PIN_0, GPIO_PIN_RESET); GPIO_InitStruct.Pin = GPIO_PIN_0; GPIO_InitStruct.Mode = GPIO_MODE_INPUT; GPIO_InitStruct.Pull = GPIO_NOPULL; HAL_GPIO_Init(GPIOA, &GPIO_InitStruct); } ``` 以上就是使用Arduino和STM32开发板编写按键按和短按程序的方法。你可以根据自己的需求进行修改和扩展。希望对你有所帮助!

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 20
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值