Notas de estudio STM32CubeMX (4) - uso retrasado del sistema

1. Introducción a SysTick

SysTick: el temporizador del sistema es un periférico en el núcleo CM3 y está integrado en el NVIC . El temporizador del sistema es un contador regresivo de 24 bits . El tiempo de cada contador es 1 / SYSCLK . Generalmente, configuramos el reloj del sistema SYSCLK en 72M . Cuando el valor del registro de valor recargado se reduce a 0, el temporizador del sistema generará una interrupción, que alternará entre sí.

Debido a que SysTick es un periférico que pertenece al núcleo CM3 , todos los microcontroladores basados ​​en el núcleo CM3 tienen este temporizador de sistema, lo que hace que el software sea fácil de trasplantar en el microcontrolador CM3 . El temporizador del sistema se usa generalmente en el sistema operativo para generar una base de tiempo y mantener el latido del sistema operativo.

2. Nueva construcción

1. Abra el software STM32CubeMX y haga clic en "Nuevo proyecto"

2. Elija MCU y paquete

3. Configure los
ajustes de reloj RCC, seleccione HSE (reloj externo de alta velocidad),

seleccione Configuración de reloj para resonador de cristal / cerámica (oscilador de cristal / resonador de cerámica) , configure el reloj del sistema SYSCLK a 72MHz,
modifique el valor de HCLK a 72, y presiona Enter. Modifica automáticamente todas las configuraciones

4. Es
un paso muy importante configurar el modo de depuración ; de lo contrario, la
configuración SYS del depurador no se reconocerá después del primer programa de programación , seleccione Depurar como cable serial

5. Configure los
ajustes de GPIO GPIO, busque el pin correspondiente de la luz LED en la figura de la derecha, seleccione GPIO_Output, el nivel bajo de salida se ilumina, puede agregar una etiqueta personalizada

6. Los
nombres de los elementos de la ruta de entrada del código generado y la

selección de elementos de un entorno de desarrollo de aplicaciones IDE MDK-ARM V5

cada periférico genera un ’.c/.h’archivo separado ,
no un gancho: Todo el código de inicialización se genera en main.c
comprobado: el código de inicialización se genera en el archivo periférico asociado . Por ejemplo, el código de inicialización GPIO se genera en gpio.c.
Haga clic en GENERAR CÓDIGO para generar código

Tres, retraso ordinario

3.1 Modificar la función principal para realizar la lámpara de agua

La salida del pin de función de adición se invierte mientras () bucle HAL_GPIO_TogglePin()y función de retardo HAL_Delay().

/**
  * @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();
  /* USER CODE BEGIN 2 */

  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
    
    
    /* USER CODE END WHILE */
    HAL_GPIO_TogglePin(LED_G_GPIO_Port,LED_G_Pin);
    HAL_Delay(500);
    HAL_GPIO_TogglePin(LED_G_GPIO_Port,LED_G_Pin);

    HAL_GPIO_TogglePin(LED_B_GPIO_Port,LED_B_Pin);
    HAL_Delay(500);
    HAL_GPIO_TogglePin(LED_B_GPIO_Port,LED_B_Pin);
    /* USER CODE BEGIN 3 */
  }
  /* USER CODE END 3 */
}

3.2 Comparación de la biblioteca HAL y el código de biblioteca estándar

STM32CubeMX usa el código generado por la biblioteca HAL:

/**
  * @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();
  /* USER CODE BEGIN 2 */

  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
    
    
    /* USER CODE END WHILE */
    HAL_GPIO_TogglePin(LED_G_GPIO_Port,LED_G_Pin);
    HAL_Delay(500);
    HAL_GPIO_TogglePin(LED_G_GPIO_Port,LED_G_Pin);

    HAL_GPIO_TogglePin(LED_B_GPIO_Port,LED_B_Pin);
    HAL_Delay(500);
    HAL_GPIO_TogglePin(LED_B_GPIO_Port,LED_B_Pin);
    /* USER CODE BEGIN 3 */
  }
  /* USER CODE END 3 */
}

HAL_StatusTypeDef HAL_Init(void)
{
    
    
  /* Configure Flash prefetch */
#if (PREFETCH_ENABLE != 0)
#if defined(STM32F101x6) || defined(STM32F101xB) || defined(STM32F101xE) || defined(STM32F101xG) || \
    defined(STM32F102x6) || defined(STM32F102xB) || \
    defined(STM32F103x6) || defined(STM32F103xB) || defined(STM32F103xE) || defined(STM32F103xG) || \
    defined(STM32F105xC) || defined(STM32F107xC)

  /* Prefetch buffer is not available on value line devices */
  __HAL_FLASH_PREFETCH_BUFFER_ENABLE();
#endif
#endif /* PREFETCH_ENABLE */

  /* Set Interrupt Group Priority */
  HAL_NVIC_SetPriorityGrouping(NVIC_PRIORITYGROUP_4);

  /* Use systick as time base source and configure 1ms tick (default clock after Reset is HSI) */
  HAL_InitTick(TICK_INT_PRIORITY);

  /* Init the low level hardware */
  HAL_MspInit();

  /* Return function status */
  return HAL_OK;
}

__weak HAL_StatusTypeDef HAL_InitTick(uint32_t TickPriority)
{
    
    
  /* Configure the SysTick to have interrupt in 1ms time basis*/
  if (HAL_SYSTICK_Config(SystemCoreClock / (1000U / uwTickFreq)) > 0U)
  {
    
    
    return HAL_ERROR;
  }

  /* Configure the SysTick IRQ priority */
  if (TickPriority < (1UL << __NVIC_PRIO_BITS))
  {
    
    
    HAL_NVIC_SetPriority(SysTick_IRQn, TickPriority, 0U);
    uwTickPrio = TickPriority;
  }
  else
  {
    
    
    return HAL_ERROR;
  }

  /* Return function status */
  return HAL_OK;
}

/**
  * @brief This function handles System tick timer.
  */
void SysTick_Handler(void)
{
    
    
  /* USER CODE BEGIN SysTick_IRQn 0 */

  /* USER CODE END SysTick_IRQn 0 */
  HAL_IncTick();
  /* USER CODE BEGIN SysTick_IRQn 1 */

  /* USER CODE END SysTick_IRQn 1 */
}

Utilice el código de biblioteca estándar STM32:

/**
  * @brief  主函数
  * @param  无  
  * @retval 无
  */
int main(void)
{
    
    	
	/* LED 端口初始化 */
	LED_GPIO_Config();

	/* 配置SysTick 为10us中断一次 */
	SysTick_Init();

	for(;;)
	{
    
    

		LED1( ON ); 
		SysTick_Delay_Ms( 1000 );
		LED1( OFF );
	  
		LED2( ON );
		SysTick_Delay_Ms( 1000 );
		LED2( OFF );
	} 	
}

/**
  * @brief  启动系统滴答定时器 SysTick
  * @param  无
  * @retval 无
  */
void SysTick_Init(void)
{
    
    
	/* SystemFrequency / 1000    1ms中断一次
	 * SystemFrequency / 100000	 10us中断一次
	 * SystemFrequency / 1000000 1us中断一次
	 */
//	if (SysTick_Config(SystemFrequency / 100000))	// ST3.0.0库版本
	if (SysTick_Config(SystemCoreClock / 100000))	// ST3.5.0库版本
	{
    
     
		/* Capture error */ 
		while (1);
	}
}

// couter 减1的时间 等于 1/systick_clk
// 当counter 从 reload 的值减小到0的时候,为一个循环,如果开启了中断则执行中断服务程序,
// 同时 CTRL 的 countflag 位会置1
// 这一个循环的时间为 reload * (1/systick_clk)

void SysTick_Delay_Us( __IO uint32_t us)
{
    
    
	uint32_t i;
	SysTick_Config(SystemCoreClock/1000000);
	
	for(i=0;i<us;i++)
	{
    
    
		// 当计数器的值减小到0的时候,CRTL寄存器的位16会置1	
		while( !((SysTick->CTRL)&(1<<16)) );
	}
	// 关闭SysTick定时器
	SysTick->CTRL &=~SysTick_CTRL_ENABLE_Msk;
}

void SysTick_Delay_Ms( __IO uint32_t ms)
{
    
    
	uint32_t i;	
	SysTick_Config(SystemCoreClock/1000);
	
	for(i=0;i<ms;i++)
	{
    
    
		// 当计数器的值减小到0的时候,CRTL寄存器的位16会置1
		// 当置1时,读取该位会清0
		while( !((SysTick->CTRL)&(1<<16)) );
	}
	// 关闭SysTick定时器
	SysTick->CTRL &=~ SysTick_CTRL_ENABLE_Msk;
}

HAL_InitTick(TICK_INT_PRIORITY);Correspondencia SysTick_Init();
HAL_SYSTICK_Config(SystemCoreClock / (1000U / uwTickFreq))correspondencia SysTick_Config(SystemCoreClock/1000000)
HAL_Delay(500);correspondenciaSysTick_Delay_Ms(500);

Cuarto, el retraso en la interrupción

En la interfaz GPIO - (3) el estudio ESP8266 observa el HAL_GPIO_EXTI_Callbackantirrebote clave agregado

/* USER CODE BEGIN 1 */
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
    
    
	if(GPIO_Pin==KEY1_Pin)
	{
    
    
        HAL_Delay(100);
        if(HAL_GPIO_ReadPin(KEY1_Pin_Port,KEY1_Pin)==1)
        {
    
    
            HAL_GPIO_TogglePin(LED_G_GPIO_Port,LED_G_Pin);
        }
	}
}
/* USER CODE END 1 */

Ahora, descargar en la MCU solo hará que no tenga respuesta después de presionar el botón. Por eso, de hecho, el problema radica en HAL_Delay()eso.

Después de ingresar a la función de devolución de llamada, hemos quedado HAL_Delayatrapados en un bucle sin fin, porque la prioridad de Systick era demasiado baja.

La prioridad de preferencia de la interrupción Systick es la misma que la prioridad de preferencia de la interrupción externa. Entonces, la interrupción Systick no debe dispararse cuando se dispara la interrupción externa. Se ha encontrado el problema. Simplemente reduzca la prioridad de preferencia de la interrupción externa. .

  • Anticipe la prioridad, cuanto menor sea el número, mayor será la prioridad
  • Si la prioridad de preferencia es la misma, determine la subprioridad. Del mismo modo, cuanto menor sea el número, mayor será la prioridad

Cinco, asuntos que necesitan atención

El código de usuario se agregará USER CODE BEGIN Ny USER CODE END Nentre, de lo contrario, el próximo uso después de que STM32CubeMX vuelva a generar el código, se eliminará.


Escrito por Leung el 13 de enero de 2021

• Referencia: "Guía de desarrollo Embedded-STM32" Parte dos Conceptos básicos - Capítulo 2 Temporizador del sistema Systick (Biblioteca HAL)
    Tutorial práctico STM32CubeMX (3) -Interrupción externa (función de interrupción y HAL_Delay para evitar pits)

Supongo que te gusta

Origin blog.csdn.net/qq_36347513/article/details/112553860
Recomendado
Clasificación