cancel
Showing results for 
Search instead for 
Did you mean: 

how can ı solve debounce problem? If I hit the button once, it sends an extra signal

newlearner
Associate II

#include "main.h"

/* Private includes ----------------------------------------------------------*/

/* USER CODE BEGIN Includes */

TIM_HandleTypeDef htim2;

static uint8_t count=0;

/* USER CODE END Includes */

/* Private typedef -----------------------------------------------------------*/

/* USER CODE BEGIN PTD */

/* USER CODE END PTD */

/* Private define ------------------------------------------------------------*/

/* USER CODE BEGIN PD */

/* USER CODE END PD */

/* Private macro -------------------------------------------------------------*/

/* USER CODE BEGIN PM */

void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef* htim)

{

HAL_GPIO_TogglePin(GPIOC, GPIO_PIN_13);

}

/* USER CODE END PM */

/* Private variables ---------------------------------------------------------*/

TIM_HandleTypeDef htim2;

/* USER CODE BEGIN PV */

/* USER CODE END PV */

/* Private function prototypes -----------------------------------------------*/

void SystemClock_Config(void);

static void MX_GPIO_Init(void);

static void MX_TIM2_Init(void);

/* USER CODE BEGIN PFP */

/* USER CODE END PFP */

/* Private user code ---------------------------------------------------------*/

/* USER CODE BEGIN 0 */

/* USER CODE END 0 */

/**

 * @brief The application entry point.

 * @retval int

 */

int main(void)

{

 /* USER CODE BEGIN 1 */

 /* USER CODE END 1 */

 /* MCU Configuration--------------------------------------------------------*/

 /* Reset of all peripherals, Initializes the Flash interface and the Systick. */

 HAL_Init();

 /* USER CODE BEGIN Init */

 /* USER CODE END Init */

 /* Configure the system clock */

 SystemClock_Config();

 /* USER CODE BEGIN SysInit */

 /* USER CODE END SysInit */

 /* Initialize all configured peripherals */

 MX_GPIO_Init();

 MX_TIM2_Init();

 /* USER CODE BEGIN 2 */

 /* USER CODE END 2 */

 /* Infinite loop */

 /* USER CODE BEGIN WHILE */

 while (1)

 {

 if (count % 5== 0 && count %10!=0)

 {

 HAL_TIM_Base_Start_IT(&htim2);

 }

 else if (count %10==0)

 {

 HAL_TIM_Base_Stop_IT(&htim2);

 }

  /* USER CODE END WHILE */

  /* USER CODE BEGIN 3 */

 }

 /* USER CODE END 3 */

}

/**

 * @brief System Clock Configuration

 * @retval None

 */

void SystemClock_Config(void)

{

 RCC_OscInitTypeDef RCC_OscInitStruct = {0};

 RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};

 /** Initializes the RCC Oscillators according to the specified parameters

 * in the RCC_OscInitTypeDef structure.

 */

 RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;

 RCC_OscInitStruct.HSEState = RCC_HSE_ON;

 RCC_OscInitStruct.HSEPredivValue = RCC_HSE_PREDIV_DIV1;

 RCC_OscInitStruct.HSIState = RCC_HSI_ON;

 RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;

 RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;

 RCC_OscInitStruct.PLL.PLLMUL = RCC_PLL_MUL9;

 if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)

 {

  Error_Handler();

 }

 /** Initializes the CPU, AHB and APB buses clocks

 */

 RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK

               |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;

 RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;

 RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;

 RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2;

 RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;

 if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2) != HAL_OK)

 {

  Error_Handler();

 }

}

/**

 * @brief TIM2 Initialization Function

 * @param None

 * @retval None

 */

static void MX_TIM2_Init(void)

{

 /* USER CODE BEGIN TIM2_Init 0 */

 /* USER CODE END TIM2_Init 0 */

 TIM_ClockConfigTypeDef sClockSourceConfig = {0};

 TIM_MasterConfigTypeDef sMasterConfig = {0};

 /* USER CODE BEGIN TIM2_Init 1 */

 /* USER CODE END TIM2_Init 1 */

 htim2.Instance = TIM2;

 htim2.Init.Prescaler = 1000;

 htim2.Init.CounterMode = TIM_COUNTERMODE_UP;

 htim2.Init.Period = 65535;

 htim2.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;

 htim2.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;

 if (HAL_TIM_Base_Init(&htim2) != HAL_OK)

 {

  Error_Handler();

 }

 sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;

 if (HAL_TIM_ConfigClockSource(&htim2, &sClockSourceConfig) != HAL_OK)

 {

  Error_Handler();

 }

 sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;

 sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;

 if (HAL_TIMEx_MasterConfigSynchronization(&htim2, &sMasterConfig) != HAL_OK)

 {

  Error_Handler();

 }

 /* USER CODE BEGIN TIM2_Init 2 */

 /* USER CODE END TIM2_Init 2 */

}

/**

 * @brief GPIO Initialization Function

 * @param None

 * @retval None

 */

static void MX_GPIO_Init(void)

{

 GPIO_InitTypeDef GPIO_InitStruct = {0};

 /* GPIO Ports Clock Enable */

 __HAL_RCC_GPIOC_CLK_ENABLE();

 __HAL_RCC_GPIOD_CLK_ENABLE();

 __HAL_RCC_GPIOA_CLK_ENABLE();

 /*Configure GPIO pin Output Level */

 HAL_GPIO_WritePin(GPIOC, GPIO_PIN_13, GPIO_PIN_RESET);

 /*Configure GPIO pin : PC13 */

 GPIO_InitStruct.Pin = GPIO_PIN_13;

 GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;

 GPIO_InitStruct.Pull = GPIO_NOPULL;

 GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;

 HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);

 /*Configure GPIO pin : PA10 */

 GPIO_InitStruct.Pin = GPIO_PIN_10;

 GPIO_InitStruct.Mode = GPIO_MODE_IT_RISING;

 GPIO_InitStruct.Pull = GPIO_NOPULL;

 HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

 /* EXTI interrupt init*/

 HAL_NVIC_SetPriority(EXTI15_10_IRQn, 0, 0);

 HAL_NVIC_EnableIRQ(EXTI15_10_IRQn);

}

/* USER CODE BEGIN 4 */

void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)

{

 if (GPIO_Pin == GPIO_PIN_10)

 {

count++;

 }

}

/* USER CODE END 4 */

/**

 * @brief This function is executed in case of error occurrence.

 * @retval None

 */

void Error_Handler(void)

{

 /* USER CODE BEGIN Error_Handler_Debug */

 /* User can add his own implementation to report the HAL error return state */

 __disable_irq();

 while (1)

 {

 }

 /* USER CODE END Error_Handler_Debug */

}

#ifdef USE_FULL_ASSERT

/**

 * @brief Reports the name of the source file and the source line number

 *     where the assert_param error has occurred.

 * @param file: pointer to the source file name

 * @param line: assert_param error line source number

 * @retval None

 */

void assert_failed(uint8_t *file, uint32_t line)

{

 /* USER CODE BEGIN 6 */

 /* User can add his own implementation to report the file name and line number,

   ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */

 /* USER CODE END 6 */

}

#endif /* USE_FULL_ASSERT */

/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/

5 REPLIES 5
KiptonM
Lead

Key bounce is a common problem. Physically when you press a mechanical switch the switch can bounce. For something like a light you do not notice it because it happens so fast. But modern microcontrollers are so fast they can detect signals as fast as a microsecond or less. Depending on your switch the bounce can occur for as much as 50 ms. (1/20 of a second) so that is the signal. It is not the fault of the micro-controller to accurately detect the bounce, it is up to you to de-bounce it.

There are many ways to do it. A hardware guy would put a resistor between the switch and the microcontroller and a small capacitor between the resistor and the microcontroller, creating a low pass filter so the micro-controller does not see the short signal drop. that makes it multiple signals.

Software people prefer to read the signal multiple times. First you need to see how how long the shortest press is that you want to register. Can someone press it for 50 ms? Probably not, but it depends on the switch. measure it. How fast can you press the switch and let it up? Or what is a normal press? It is probably at least 1/4 second. or 250 ms. But check it yourself. Then set up the polling so you can get 2 or 3 reads in that time. And to prevent the debounce you need to see three presses in a row to be called a press, and three not presses in a row to be a release.

Some people do not like the overhead of polling. Especially when the switch is not used very often, So they set it up with an interrupt. When the interrupt fires, you can set a timer interrupt to fire in say 50-100 ms and check the pin again. and set the timer for another 50-100 ms and check again. three in a row means it was a real single key press.

All of a sudden the resistor and capacitor does not seem like such a bad idea. Welcome to the real world.

So what can I use in the code? I am very new and open to your suggestions

I had been using 50ms for a commercial project.

Poll e.g. every 10ms, and set to "pressed" after the change is stable, i.e. 5 periods in this example.

The timing (bouncing) depends on the mechanical characteristics of the switch.

how is the content of the code so sorry but i'm so new. I have trouble understanding

Piranha
Chief II

Put one of these RC circuits on button inputs:

https://i.stack.imgur.com/VZKDf.png

http://www.ganssle.com/images/debouncerrc.jpg

The values of 10kOhm and 100nF are OK and will deal with 98% of bounces.

For a total reliability I've found a proper combination of hardware and software to be the best. For that in addition to the RC circuit configure an interrupt on both signal edges and on an interrupt event restart a timer set to 50 ms. When that timer runs out, the button signal has stabilized and you can just read it from a GPIO input.