STM32/STM32_RTOS

STM32 RTOS 알아보기 8편(버튼동작-one tap/double tap/triple tap)

원원 2025. 8. 16. 23:01

안녕하세요. 오늘은 버튼동작 one tap/double tap/triple tap을 추가해보겠습니다.
(구현  방식은 해당 유튜브를 참고했습니다.
https://www.youtube.com/watch?v=QEGN9-44WVY&list=PLvFHFPM09alJrzYz45gcErBnc-YXEJ9ch&index=26)


테스트하는 회로는 풀업상태이고 rising edge에서 외부인터럽트가 발생합니다. (버튼클릭시 LOW, 버튼릴리즈시 HIGH)
테스트했을때 버튼클릭시는 채터링이 발생안했고 버튼릴리즈할때 발생했습니다.


One tap시 감지 방법입니다.
버튼을 클릭하고 릴리즈했을때 인터럽트가 발생하고 50ms동안 발생하는 신호는 무시합니다. 그리고 250ms후에 One tap을 확정합니다.

Double tap시 감지 방법입니다.
버튼을 한번 click->release 이후 250ms이내에 버튼을 한번 더 누르고 250ms후에 Double tap으로 확정합니다.

Triple tap시 감지방법은 Double tap 확정방법과 같습니다.



외부인터럽트 함수에서 Debounce 처리를 했습니다.
buttonObjectProcess에서 One tap/Double tap/Tripple tap/error tap 판단을 합니다.
Quadruple tap이상 추가하려면 case만 하나 더 추가하면 됩니다.

#include <stdio.h>
#include <stdbool.h>
#include "cmsis_os.h"
#include "main.h"
#include "FreeRTOS.h"
#include "task.h"
#include "queue.h"
#include "semphr.h"

#define DEBOUNCE_TIME_MS       50
#define TAP_THRESHOLD_MS       250

void btnTask(void *pvParameters);


typedef struct
{
  uint8_t ch;
  uint32_t pre_time;
  uint8_t tap_count;
  uint32_t last_tap_time;
} button_obj_t;

button_obj_t buttonObj[3];

void buttonObjectCreate(button_obj_t *p_obj, uint8_t ch)
{
  p_obj->ch = ch;
  p_obj->pre_time = HAL_GetTick();
  p_obj->tap_count = 0;
  p_obj->last_tap_time = 0;
}

void myTask()
{
  buttonObjectCreate(&buttonObj[0], 0); // button 1
  buttonObjectCreate(&buttonObj[1], 1); // button 2
  buttonObjectCreate(&buttonObj[2], 2); // button 3
  xTaskCreate(btnTask, "btnTask", 256, NULL, 3, NULL);
}

void buttonObjectProcess(button_obj_t *p_obj)
{
  uint32_t now = HAL_GetTick();

  if (p_obj->tap_count > 0)
  {
    if (now - p_obj->last_tap_time > TAP_THRESHOLD_MS)
    {
      switch (p_obj->tap_count)
      {
        case 1:
          printf("ONE TAP ch:%d\n", p_obj->ch);
          break;
        case 2:
          printf("DOUBLE TAP ch:%d\n", p_obj->ch);
          break;
        case 3:
          printf("TRIPLE TAP ch:%d\n", p_obj->ch);
          break;
        default:
          printf("TAP COUNT ERROR : %d \n",p_obj->tap_count);
          break;
      }
      p_obj->tap_count = 0;
    }
  }
}

void btnTask(void *pvParameters)
{
  printf("btn task start\n");

  while(1)
  {
    for(int i=0; i<3; i++)
    {
      buttonObjectProcess(&buttonObj[i]);
    }
    vTaskDelay(pdMS_TO_TICKS(10));
  }
}

void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
  uint32_t now = HAL_GetTick();
  uint16_t btn_ID;

  if(GPIO_Pin == BTN1_Pin)
  {
    btn_ID = 0;
  }
  else if(GPIO_Pin == BTN2_Pin)
  {
    btn_ID = 1;
  }
  else if(GPIO_Pin == BTN3_Pin)
  {
    btn_ID = 2;
  }
  else
    return;
  
  // Debounce check
  if (now - buttonObj[btn_ID].pre_time < DEBOUNCE_TIME_MS)
    return;
  buttonObj[btn_ID].pre_time = now;
  //
  
  buttonObj[btn_ID].tap_count++;
  buttonObj[btn_ID].last_tap_time = now;
}


소스코드(Commits: Button taps) 
https://github.com/yhunterr/STM32_RTOS_STUDY/commits/main/