El LED parpadea incluso cuando no presiono el botón

He escrito un programa en Keil que hace parpadear un LED a través de una interrupción GPIO externa. Así es como lo he configurado en STM32CubeMX:

Al principio, habilité y configuré RCC como puede ver y configuré PA0 para interrupción externa y PB1 como salida.

Figura 1

Para la fuente del reloj, lo configuré como puede ver a continuación.

Figura 2

y para pines

figura 3

Figura 4

Marqué la casilla de verificación "Interrupción de Línea 0 y Línea 1 EXTI". No estoy seguro de que sea necesario marcar esta casilla.

Figura 5

Después de la configuración, generé el siguiente código fuente (main.c):

/* Includes ------------------------------------------------------------------*/
#include "stm32f0xx_hal.h"

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

/* USER CODE BEGIN 0 */

/* USER CODE END 0 */

/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
static void MX_GPIO_Init(void);

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();

  /* Configure the system clock */
  SystemClock_Config();

  /* System interrupt init*/
  HAL_NVIC_SetPriority(SysTick_IRQn, 0, 0);

  /* Initialize all configured peripherals */
  MX_GPIO_Init();

  /* USER CODE BEGIN 2 */

  /* USER CODE END 2 */

  /* USER CODE BEGIN 3 */
  /* Infinite loop */
  while (1)
  {

  }
  /* USER CODE END 3 */

}

/** System Clock Configuration
*/
void SystemClock_Config(void)
{

  RCC_ClkInitTypeDef RCC_ClkInitStruct;
  RCC_OscInitTypeDef RCC_OscInitStruct;

  RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI;
  RCC_OscInitStruct.HSIState = RCC_HSI_ON;
  RCC_OscInitStruct.HSICalibrationValue = 16;
  RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
  RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSI;
  RCC_OscInitStruct.PLL.PLLMUL = RCC_PLL_MUL12;
  RCC_OscInitStruct.PLL.PREDIV = RCC_PREDIV_DIV1;
  HAL_RCC_OscConfig(&RCC_OscInitStruct);

  RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_SYSCLK;
  RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
  RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
  RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1;
  HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_1);

  __SYSCFG_CLK_ENABLE();

}

/** Configure pins as 
        * Analog 
        * Input 
        * Output
        * EVENT_OUT
        * EXTI
*/
void MX_GPIO_Init(void)
{

  GPIO_InitTypeDef GPIO_InitStruct;

  /* GPIO Ports Clock Enable */
  __GPIOF_CLK_ENABLE();
  __GPIOA_CLK_ENABLE();
  __GPIOB_CLK_ENABLE();

  /*Configure GPIO pin : PA0 */
  GPIO_InitStruct.Pin = GPIO_PIN_0;
  GPIO_InitStruct.Mode = GPIO_MODE_IT_RISING;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

  /*Configure GPIO pin : PB1 */
  GPIO_InitStruct.Pin = GPIO_PIN_1;
  GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  GPIO_InitStruct.Speed = GPIO_SPEED_HIGH;
  HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);

  /* EXTI interrupt init*/
  HAL_NVIC_SetPriority(EXTI0_1_IRQn, 0, 0);
  HAL_NVIC_EnableIRQ(EXTI0_1_IRQn);

}

/* USER CODE BEGIN 4 */

/* USER CODE END 4 */

#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

/**
  * @}
  */ 

/**
  * @}
*/ 

Para manejar la interrupción externa de GPIO, abrí el archivo 'stm32f0xx_it.c' y lo coloqué HAL_GPIO_TogglePin(GPIOB , GPIO_PIN_1)entre HAL_NVIC_ClearPendingIRQ(EXTI0_1_IRQn)y HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_0)luego el código fuente de la interrupción es este:

/* Includes ------------------------------------------------------------------*/
#include "stm32f0xx_hal.h"
#include "stm32f0xx.h"
#include "stm32f0xx_it.h"

/* External variables --------------------------------------------------------*/

/******************************************************************************/
/*            Cortex-M4 Processor Interruption and Exception Handlers         */ 
/******************************************************************************/

/**
* @brief This function handles System tick timer.
*/
void SysTick_Handler(void)
{
  HAL_IncTick();
  HAL_SYSTICK_IRQHandler();
}

/**
* @brief This function handles EXTI Line 0 and Line 1 interrupts.
*/
void EXTI0_1_IRQHandler(void)
{
  HAL_NVIC_ClearPendingIRQ(EXTI0_1_IRQn);
  HAL_GPIO_TogglePin(GPIOB , GPIO_PIN_1);
  HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_0);
}

Construí el archivo HEX correctamente y lo descargué a la MCU (sin ningún problema ni error). Ahora, cuando lo ejecuto, hay un problema. El LED parpadea rápidamente incluso cuando no presiono el botón. Mirar:

figura6

figura7

¿Por qué? Además, cuando presiono el botón, cambia el LED pero parpadea entre cada pulsación. Parece que algo cambia el estado del pin PB1. ¿Cuál es el problema? ¿Cómo puedo corregirlo?

Nunca he usado esa serie de procesadores, pero noté que GPIO_InitStruct.Pull = GPIO_NOPULLes posible que deba cambiar eso para ponerlo a tierra (si está disponible) o usar una resistencia externa para ponerlo a tierra. No estoy seguro de si puede haber otros problemas, pero vale la pena intentarlo.
@PeterJ Gracias Peter por responder. Ya lo probé. Quiero decir que ya levanté la resistencia interna (para el ruido) pero eso no funciona. en los tutoriales de ST, nunca usan una resistencia pull-up.

Respuestas (1)

Debe usar la resistencia pullup / pulldown interna del chip o suministrar su propia resistencia.

También puede, al mismo tiempo, contrarrestar la entrada agregando otra resistencia más pequeña y un condensador pequeño:

esquemático

simular este circuito : esquema creado con CircuitLab

La teoría de funcionamiento es que cuando el interruptor está abierto, el pullup / pulldown "tira" del pin de entrada a un valor conocido. Si su interruptor conecta el pin a tierra, entonces una resistencia pullup conectará el pin a + V C C cuando el interruptor no está siendo presionado. Cuando se presiona el interruptor, tanto el pin como la resistencia se conectan a tierra, por lo que el pin se vuelve 0 V y una pequeña corriente (unos pocos mA según el voltaje y la resistencia) fluye a través de la resistencia.

Gracias. Cuando lo bajé (mediante una resistencia externa como ilustraste en la figura), ¡funciona correctamente! ¡bien hecho!
También tengo un problema simple ahora, ¡es un rebote! ¿Cómo puedo rebotarlo?
En algunos casos, para 5V usan 10nf para antirrebote, pero mi MCU funciona con 3.3v. en su opinión, ¿el condensador de 10nf es adecuado para ello?
Usualmente uso pullup de 10K, capacitor de 100nF y resistencia de descarga de 100Ω.
"resistencia de descarga"? ¿Cuál es el uso de esta resistencia?
Descarga el condensador lentamente creando una transición suave cuando presiona el botón.
Si agrega el condensador y la resistencia de descarga en el esquema anterior, será una excelente respuesta.