stm32按键 长按 短按 函数 一

 

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


   
   
  1. #define KEY_ON 1
  2. #define KEY_OFF 0
  3. #define KEY_NULL 0
  4. #define KEY_SHORT 1
  5. #define KEY_LONG 10
  6. #define SHORT_TIME 200

   
   
  1. uint8_t Key_state(GPIO_TypeDef* GPIOx,uint16_t GPIO_Pin)
  2. {
  3. static uint8_t key_value = KEY_NULL;
  4. static uint16_t longtime;
  5. if( (longtime == 0) && (key_value != KEY_NULL)) //当按键状态为长按或者短按时,而longtime 不为零,则按键状态清零
  6. {
  7. key_value = KEY_NULL;
  8. }
  9. if ( time == 5 ) /* 5 * 1 ms = 5ms 定时时间到 */
  10. {
  11. time = 0;
  12. if( KEY_PRESS(GPIOx,GPIO_Pin)) //按键按下
  13. {
  14. longtime++;
  15. }
  16. else //按键松开
  17. {
  18. if((longtime >= 3) && (longtime <= SHORT_TIME)) //短按
  19. {
  20. key_value = KEY_SHORT;
  21. }
  22. else if( longtime > SHORT_TIME ) //长按
  23. {
  24. key_value = KEY_LONG;
  25. }
  26. else //去抖动
  27. {
  28. key_value = KEY_NULL;
  29. }
  30. longtime = 0; //清零
  31. }
  32. }
  33. return key_value;
  34. }

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


   
   
  1. #define KEY_PRESS(GPIOx,GPIO_Pin) GPIO_ReadInputDataBit(GPIOx,GPIO_Pin)
  2. #define KEY_INPUT KEY_PRESS(GPIOx,GPIO_Pin) //读取按键状态
  3. #define KEY_STATE_0 0 // 按键状态位
  4. #define KEY_STATE_1 1
  5. #define KEY_STATE_2 2
  6. #define KEY_STATE_3 3
  7. #define LONG_KEY_TIME 300 //长按的3秒时间
  8. #define SINGLE_KEY_TIME 3 // 短按的消抖时间
  9. #define N_KEY 0 // 无状态
  10. #define S_KEY 1 // 单击
  11. #define L_KEY 10 // 长按

 

 

 

 

 

 

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


   
   
  1. unsigned char key_driver(GPIO_TypeDef* GPIOx,uint16_t GPIO_Pin))
  2. {
  3. static unsigned char key_state = 0; // 按键状态变量
  4. static unsigned int key_time = 0; // 按键计时变量
  5. unsigned char key_press, key_return;
  6. key_return = N_KEY; // 清除 返回按键值
  7. key_press = KEY_INPUT; // 读取当前键值
  8. switch (key_state)
  9. {
  10. case KEY_STATE_0: // 按键状态0:判断有无按键按下
  11. if (key_press == KEY_ON) // 有按键按下
  12. {
  13. key_time = 0; // 清零时间间隔计数
  14. key_state = KEY_STATE_1; // 然后进入 按键状态1
  15. }
  16. break;
  17. case KEY_STATE_1: // 按键状态1:软件消抖(确定按键是否有效,而不是误触)。按键有效的定义:按键持续按下超过设定的消抖时间。
  18. if (key_press == KEY_ON)
  19. {
  20. key_time++; // 一次10ms
  21. if(key_time>=SINGLE_KEY_TIME) // 消抖时间为:SINGLE_KEY_TIME*10ms = 30ms;
  22. {
  23. key_state = KEY_STATE_2; // 如果按键时间超过 消抖时间,即判定为按下的按键有效。按键有效包括两种:单击或者长按,进入 按键状态2, 继续判定到底是那种有效按键
  24. }
  25. }
  26. else key_state = KEY_STATE_0; // 如果按键时间没有超过,判定为误触,按键无效,返回 按键状态0,继续等待按键
  27. break;
  28. case KEY_STATE_2: // 按键状态2:判定按键有效的种类:是单击,还是长按
  29. if(key_press == KEY_OFF) // 如果按键在 设定的长按时间 内释放,则判定为单击
  30. {
  31. key_return = S_KEY; // 返回 有效按键值:单击
  32. key_state = KEY_STATE_0; // 返回 按键状态0,继续等待按键
  33. }
  34. else
  35. {
  36. key_time++;
  37. if(key_time >= LONG_KEY_TIME) // 如果按键时间超过 设定的长按时间(LONG_KEY_TIME*10ms=200*10ms=2000ms), 则判定为 长按
  38. {
  39. key_return = L_KEY; // 返回 有效键值值:长按
  40. key_state = KEY_STATE_3; // 去状态3,等待按键释放
  41. }
  42. }
  43. break;
  44. case KEY_STATE_3: // 等待按键释放
  45. if (key_press == KEY_OFF)
  46. {
  47. key_state = KEY_STATE_0; // 按键释放后,进入 按键状态0 ,进行下一次按键的判定
  48. }
  49. break;
  50. default: // 特殊情况:key_state是其他值得情况,清零key_state。这种情况一般出现在 没有初始化key_state,第一次执行这个函数的时候
  51. key_state = KEY_STATE_0;
  52. break;
  53. }
  54. return key_return; // 返回 按键值
  55. }

   
   
  1. unsigned char key_handle(GPIO_TypeDef* GPIOx,uint16_t GPIO_Pin)
  2. {
  3. unsigned char key_value;
  4. if ( time >= 10 ) /* 10 * 1 ms = 10ms 定时器 */
  5. {
  6. time = 0;
  7. key_value = key_driver(GPIOx,GPIO_Pin);
  8. }
  9. return key_value;
  10. }

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

 在main.c中调用


   
   
  1. int main(void)
  2. {
  3. int8_t key_value;
  4. /* led 初始化*/
  5. LED_GPIO_Config();
  6. BASIC_TIM_Init();
  7. Key_GPIO_Config();
  8. while( 1)
  9. {
  10. // key_value = Key_state(KEY1_GPIO_PORT,KEY1_GPIO_PIN);
  11. key_value = key_handle(KEY1_GPIO_PORT,KEY1_GPIO_PIN);
  12. if(key_value == KEY_SHORT)
  13. {
  14. LED1_TOGGLE;
  15. }
  16. else if(key_value == KEY_LONG)
  17. {
  18. LED2_TOGGLE;
  19. }
  20. }
  21. }

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

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

链接    提取码:66zh

 

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

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

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
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开发板编写按键按和短按程序的方法。你可以根据自己的需求进行修改和扩展。希望对你有所帮助!
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值