본문 바로가기
DSP, MCU/STM32 (ARM Cortex-M)

STM32 ] 소프트웨어적으로 Chattering 채터링현상 Debounce 디바운스하기

by eteo 2022. 7. 13.

채터링이란 스위치의 접점이 닫히거나 열리는 순간 기계적인 진동에 의해 매우 짧은 시간 안에 스위치가 붙었다 떨어지는 것을 반복하는 현상으로 Bounce 라고도 한다.

 

디바운스는 채터링 현상을 억제하는 해결법을 말한다. 커패시터를 추가하는 등 하드웨어적인 방법이 있고 소프트웨어적으로 해결하는 방법이 있다.

 

아래에선 소프트웨어적으로 해결하는방법을 소개한다.

 

버튼은 외부 풀다운저항을 달아놨고 EXTI Rising Edge에 트리거 되도록 했다. NVIC 설정도 켜고 각각 버튼이 눌렸을 때 LED가 토글되게 소스코드를 짰다.

 

 

 

디바운스 코드 추가하지 않았을 때

void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{

	if(GPIO_Pin==GPIO_PIN_8){
		HAL_GPIO_TogglePin(LD1_GPIO_Port, LD1_Pin);
	}
	if(GPIO_Pin==GPIO_PIN_9){
		HAL_GPIO_TogglePin(LD2_GPIO_Port, LD2_Pin);
	}
	if(GPIO_Pin==GPIO_PIN_10){
		HAL_GPIO_TogglePin(LD3_GPIO_Port, LD3_Pin);
	}
}

 

 

 

 

 

 

디바운스 코드 추가했을 때

// ...
uint32_t current_tick_1;
uint32_t current_tick_2;
uint32_t current_tick_3;
uint32_t old_tick_1;
uint32_t old_tick_2;
uint32_t old_tick_3;
// ...

void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
	if(GPIO_Pin==GPIO_PIN_8){
		current_tick_1 = HAL_GetTick();
	}
	if(GPIO_Pin==GPIO_PIN_9){
		current_tick_2 = HAL_GetTick();
	}
	if(GPIO_Pin==GPIO_PIN_10){
		current_tick_3 = HAL_GetTick();
	}

	if(GPIO_Pin==GPIO_PIN_8 && (current_tick_1 - old_tick_1 > 300)){
		HAL_GPIO_TogglePin(LD1_GPIO_Port, LD1_Pin);
		old_tick_1 = current_tick_1;
	}
	if(GPIO_Pin==GPIO_PIN_9 && (current_tick_2 - old_tick_2 > 300)){
		HAL_GPIO_TogglePin(LD2_GPIO_Port, LD2_Pin);
		old_tick_2 = current_tick_2;
	}
	if(GPIO_Pin==GPIO_PIN_10 && (current_tick_3 - old_tick_3 > 300)){
		HAL_GPIO_TogglePin(LD3_GPIO_Port, LD3_Pin);
		old_tick_3 = current_tick_3;
	}
}

 

처음 또는 한동안 이벤트가 없다가 ISR에 들어왔을 땐 LED 토글작업을 한 뒤 old_tick 변수를 업데이트 하여 그 뒤 300ms 안에 들어오는 인터럽트는 처리하지 않고 무시하는 코드이다.

 

 

전역변수 대신 static 변수 사용한 버전

void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
	static uint32_t before_tick = 0;

	if(GPIO_Pin == GPIO_PIN_13)
	{
		if(HAL_GetTick() - before_tick >= 300)
		{
			before_tick = HAL_GetTick();
			HAL_GPIO_TogglePin(LD1_GPIO_Port, LD1_Pin);
		}
	}
}

 

 

 

 

 

 

비교영상

 

 

 

 

 

 

 

 

 

 

 

 

EXTI 대신 GPIO Input 사용한 버전

/* USER CODE BEGIN 2 */
uint8_t debounceState = 0;
uint32_t debounceTime = 0;
/* USER CODE END 2 */

/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
switch(debounceState)
    {
case 0:
    if(HAL_GPIO_ReadPin(BT1_GPIO_Port, BT1_Pin))
    {
        debounceState = 1;
        debounceTime = HAL_GetTick();
    }
    break;
case 1:
    if(!HAL_GPIO_ReadPin(BT1_GPIO_Port, BT1_Pin))
    {
        debounceState = 0;
        break;
    }
    if(HAL_GetTick() - debounceTime >= 100)
    {
        HAL_GPIO_TogglePin(LD1_GPIO_Port, LD1_Pin);
        debounceState = 0;
    }
    break;
    }
}