Notas de estudio de STM32CubeMX (5) -uso básico de la interfaz del temporizador

1. Introducción al temporizador

La serie STM32F1, además de los productos basados ​​en Internet, un total de 8temporizadores, divididos en temporizadores básicos, temporizadores de uso general y temporizadores avanzados.
Temporizador básico TIM6 y TIM7un temporizador que cuenta solo 16 bits, solo el tiempo, sin E / S externa.
El temporizador de propósito general TIM2/3/4/5 es un temporizador de 16 bits que puede contar hacia arriba / hacia abajo. Puede ser temporizado, comparación de salida y captura de entrada. Cada temporizador tiene cuatro E / S externas.
El temporizador avanzado TIM1/8 es un temporizador de 16 bits que puede contar hacia arriba / hacia abajo. Puede ser temporizado, comparación de salida, captura de entrada y señales de salida complementarias del motor trifásico. Cada temporizador tiene 8 E / S externas.

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

Tres, temporizador básico TIM6

3.1 Configuración de parámetros

En la Timersselección de TIM6configuraciones, y verifique la Activatedactivación

En Parameter Settingsparámetros específicos.

Tclk es el reloj interno CK_INT, que se divide por el preescalador APB1. Si el coeficiente del preescalador APB1 es igual a 1, la frecuencia permanece sin cambios; de lo contrario, la frecuencia se multiplica por 2 y el coeficiente del preescalador APB1 en la función de biblioteca es 2, es decir PCLK1 = 36M, como se muestra en la figura, el reloj temporizador Tclk = 36 * 2 = 72M.

Tiempo de desbordamiento del temporizador:

Todos = 1 / (Tclk / (psc + 1)) ∗ (arr + 1)

  • Reloj temporizador Tclk: 72MHz
  • Prescaler psc: 71
  • Registro de recarga automática arr: 999

即 Tout = 1/(72MHz/(71+1))∗(999+1) = 1ms

  • Prescaler (número de prescaler de reloj): 72-1 则驱动计数器的时钟 CK_CNT = CK_INT(即72MHz)/(71+1) = 1MHz
  • Modo contador: Up (modo de conteo progresivo) 基本定时器只能是向上计数
  • Periodo de contador (valor de recarga automática): 1000-1 则定时时间 1/CK_CLK*(999+1) = 1ms
  • auto-reload-preload (recarga automática): Habilitar (habilitar) `
  • Parámetros TRGO (salida de disparo): no habilitado 在定时器的定时时间到达的时候输出一个信号(如:定时器更新产生TRGO信号来触发ADC的同步转换)

3.2 Configuración de NVIC

Habilitar la interrupción del temporizador

3.3 Generar código

Nombres de elementos de ruta y

selección de entrada 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
verificado: archivo de código de inicialización generado en el 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

3.4 Modificar la función de devolución de llamada de interrupción

Abra el stm32f1xx_it.carchivo de rutina del servicio de interrupción, busque la función de servicio de TIM6_IRQHandler()
interrupción de rutina del servicio de interrupción TIM6, que se denomina controlador de interrupción del temporizadorHAL_TIM_IRQHandler()

Abra el stm32f1xx_hal_tim.carchivo, busque el prototipo del controlador de interrupciones del temporizador HAL_TIM_IRQHandler(), su función principal es determinar qué tipo de evento se genera la interrupción del temporizador, borrar el indicador de interrupción y luego llamar a la función de devolución de llamada de interrupción HAL_TIM_PeriodElapsedCallback().

/ * NOTA: Esta función no debe modificarse, cuando se necesita la devolución de llamada,
la HAL_GPIO_EXTI_Callback podría implementarse en el archivo de usuario
* /
Esta función no debe cambiarse, si necesita usar la función de devolución de llamada, vuelva a implementar la función en el archivo de usuario.

HAL_TIM_PeriodElapsedCallback()De acuerdo con el indicador oficial, deberíamos definir la función nuevamente, que __weakes una bandera debilitada. La función con esta es una función debilitada, es decir, puede escribir una función con exactamente el mismo nombre y parámetros en otro lugar, y el compilador ignorará esta función. En su lugar UNUSED(htim), ejecute la función que escribió; y , esta es una definición a prueba de errores. Cuando el número de temporizador pasado no realiza ningún procesamiento, el compilador no informará una advertencia. De hecho, ya no necesitamos preocuparnos por la función de servicio de interrupción cuando estamos desarrollando. Solo necesitamos encontrar la función de devolución de llamada de interrupción y reescribirla. Hay otro aspecto muy conveniente de esta función de devolución de llamada que no se refleja aquí. Cuando se habilitan múltiples interrupciones, STM32CubeMX organizará automáticamente las funciones de servicio de varias interrupciones juntas y llamará a una función de devolución de llamada, es decir, no importa cuántas interrupciones, solo necesitamos reescribir una función de devolución de llamada y juzgar el número del temporizador entrante.

Luego solo stm32f1xx_it.cagregamos la parte inferior de este documentoHAL_TIM_PeriodElapsedCallback()

/* USER CODE BEGIN 1 */
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
    
    
    static uint32_t time = 0;
	if(htim->Instance == TIM6)  // 定时器6基地址
	{
    
    
        // 自定义应用程序
        time++;           // 每1ms进来1次
        if(time == 1000)  // 每1秒LED灯翻转一次
        {
    
    
            HAL_GPIO_TogglePin(LED_G_GPIO_Port,LED_G_Pin);
            time = 0;
        }
	}
}
/* USER CODE END 1 */

3.5 Agregar función de inicio del temporizador

Ahora ingrese la función principal y agregue la función de temporizador antes del ciclo while HAL_TIM_Base_Start_IT(). El htim6 que se pasa aquí es la estructura justo después de que se haya inicializado el temporizador.

/**
  * @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_TIM6_Init();
  /* USER CODE BEGIN 2 */
  HAL_TIM_Base_Start_IT(&htim6);  
  /* USER CODE END 2 */

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

    /* USER CODE BEGIN 3 */
  }
  /* USER CODE END 3 */
}

Ahora, el fenómeno experimental es que la luz LED se mueve una vez cada segundo.

3.6 Comparación de códigos de biblioteca estándar y biblioteca HAL

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

/**
  * @brief TIM6 Initialization Function
  * @param None
  * @retval None
  */
static void MX_TIM6_Init(void)
{
    
    

  /* USER CODE BEGIN TIM6_Init 0 */

  /* USER CODE END TIM6_Init 0 */

  TIM_MasterConfigTypeDef sMasterConfig = {
    
    0};

  /* USER CODE BEGIN TIM6_Init 1 */

  /* USER CODE END TIM6_Init 1 */
  htim6.Instance = TIM6;
  htim6.Init.Prescaler = 72-1;
  htim6.Init.CounterMode = TIM_COUNTERMODE_UP;
  htim6.Init.Period = 1000-1;
  htim6.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_ENABLE;
  if (HAL_TIM_Base_Init(&htim6) != HAL_OK)
  {
    
    
    Error_Handler();
  }
  sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
  sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
  if (HAL_TIMEx_MasterConfigSynchronization(&htim6, &sMasterConfig) != HAL_OK)
  {
    
    
    Error_Handler();
  }
  /* USER CODE BEGIN TIM6_Init 2 */

  /* USER CODE END TIM6_Init 2 */
}

/**
  * @brief This function handles TIM6 global interrupt.
  */
void TIM6_IRQHandler(void)
{
    
    
  /* USER CODE BEGIN TIM6_IRQn 0 */

  /* USER CODE END TIM6_IRQn 0 */
  HAL_TIM_IRQHandler(&htim6);
  /* USER CODE BEGIN TIM6_IRQn 1 */

  /* USER CODE END TIM6_IRQn 1 */
}

void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
    
    
    static uint32_t time = 0;
    if(htim->Instance == TIM6)
    {
    
    
        // 自定义应用程序
        time++;
        if(time == 1000)
        {
    
    
            HAL_GPIO_TogglePin(LED_G_GPIO_Port,LED_G_Pin);
            time = 0;
        }
    }
}

HAL_TIM_Base_Start_IT(&htim6); 

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

/**
 @brief 定时器中断配置(使用TIM6基本定时器)
 @param 无
 @return 无
*/
void BASIC_TIM_Config(void)
{
    
    
	TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
	/*
	可以从上图看出基本定时器和通用定时器使用APB1总线,
	高级定时器使用APB2总线。
	*/
	// 开启定时器时钟,即内部时钟 CK_INT=72M
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM6, ENABLE);

	/*
	预分频将输入时钟频率按1~65536之间的值任意分频,分频值决定了计数频率。
	计数值为计数的个数,当计数寄存器的值达到计数值时,产生溢出,发生中断。
	如系统时钟为72MHz,预分频 TIM_Prescaler = 71,
	计数值 TIM_Period = 1000,
	则 TIM_Period * (TIM_Prescaler + 1) / 72000000 = 0.001,
	即每1ms产生一次中断。
	*/
	// 自动重装载寄存器周的值(计数值)
	TIM_TimeBaseStructure.TIM_Period = 1000;
 
	// 累计 TIM_Period 个频率后产生一个更新或者中断
	// 时钟预分频数为 71,
	// 则驱动计数器的时钟 CK_CNT = CK_INT / (71+1)=1M
	TIM_TimeBaseStructure.TIM_Prescaler = 71;

	// 时钟分频因子 ,基本定时器没有,不用管
	//TIM_TimeBaseStructure.TIM_ClockDivision=TIM_CKD_DIV1;

	// 计数器计数模式,基本定时器只能向上计数,没有计数模式的设置
	//TIM_TimeBaseStructure.TIM_CounterMode=TIM_CounterMode_Up;

	// 重复计数器的值,基本定时器没有,不用管
	//TIM_TimeBaseStructure.TIM_RepetitionCounter=0;

	/*
	完成时基设置
	*/
	// 初始化定时器
	TIM_TimeBaseInit(TIM6, &TIM_TimeBaseStructure);

	/*
	为了避免在设置时进入中断,这里需要清除中断标志位。
	如果是向上计数模式(基本定时器采用向上计数),
	则采用函数 TIM_ClearFlag(TIM6, TIM_FLAG_Update),
	清除向上溢出中断标志。
	*/
	// 清除计数器中断标志位
	TIM_ClearFlag(TIM6, TIM_FLAG_Update);

	// 使能计数器
	TIM_ITConfig(TIM6,TIM_IT_Update,ENABLE);

	// 开启计数器
	TIM_Cmd(TIM6, ENABLE);

	// 暂时关闭定时器的时钟,等待使用
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM6, DISABLE);
}

/**
 @brief NVIC初始化(使用TIM6基本定时器)
 @param 无
 @return 无
*/
void BASIC_TIM_NVIC_Config(void)
{
    
    
	NVIC_InitTypeDef NVIC_InitStructure;
	// 设置中断组为 0
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0);
	// 设置中断来源
	NVIC_InitStructure.NVIC_IRQChannel = TIM6_IRQn ;
	// 设置主优先级为 0
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
	// 设置抢占优先级为 3
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
	NVIC_Init(&NVIC_InitStructure);
}

#define BASIC_TIM_IRQHandler TIM6_IRQHandler
// 1ms发生一次中断,time 记录中断次数
uint16_t time;

void BASIC_TIM_IRQHandler(void)
{
    
    
	if(TIM_GetITStatus(TIM6, TIM_IT_Update) != RESET)
	{
    
    
		time++;
		TIM_ClearITPendingBit(TIM6, TIM_FLAG_Update);
	}
}

RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM6, ENABLE);

MX_TIM6_Init();Correspondencia BASIC_TIM_Config();BASIC_TIM_NVIC_Config();
HAL_TIM_Base_Init(&htim6)correspondencia TIM_TimeBaseInit(TIM6, &TIM_TimeBaseStructure)
HAL_TIM_Base_Start_IT(&htim6);correspondenciaRCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM6, ENABLE);

Cuatro, 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 14 de enero de 2021

• Referencia: Tutorial 3 de la serie STM32CubeMX: Temporizador básico
    Tutorial de combate real de STM32CubeMX (4) -Temporizador básico (iluminación fija)
    "Guía de desarrollo de Embedded-STM32" Parte 2 Conceptos básicos-Capítulo 4 Temporizador (Biblioteca HAL)

Supongo que te gusta

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