STM32CUBEMX 使用教程6 — TIM 定时器配置、定时中断

发布于:2025-07-01 ⋅ 阅读:(17) ⋅ 点赞:(0)

往期文章推荐:

STM32CUBEMX 使用教程5 — DMA配置 & 串口结合DMA实现数据搬运

STM32CUBEMX 使用教程4 — 串口 (USART) 配置、重定向 printf 输出

STM32CUBEMX 使用教程3 — 外部中断(EXTI)的使用

STM32CUBEMX 使用教程2 — GPIO的使用、输入/输出

STM32CUBEMX 使用教程 1 — 配置环境、新建工程

STM32CUBEMX 详细安装教程

一、了解什么是定时器

什么是定时器?定时器实现的基本原理是什么?定时器可以做什么?

为了能搞懂上面的问题,文章直接用STM32F103ZET6作讲解说明定时器的原理和基本用途。

STM32F103的定时器属于MCU内部的硬件资源,数量有很多,分类上大致分为:

1)基本定时器

2)通用定时器

3)高级定时器

这里用基本定时器说明工作原理,如下的基本定时器的框图:

首先需要明确的事情:定时器的本质就是一个计数器,通过在一定的计数频率下计量一定的装载值实现计数定时的功能。

如上图中:基本定时器中有一个 CNT计数器(1)用来计数,这个计数器的计数值来自于重装载寄存器。基本定时的时钟(2)来源于RCC的时钟(实际为APB2),通过控制器(4)复位、使能定时器功能,并通过PSC预分频器(3)设置时钟的分频提供给CNT计数器。从而实现计数器在某个频率下计数,达到装载值寄存器中的设定数时完成计数,实现时间定时。

二、STM32F103 的定时器其他特性

(1)计数模式

STM32F103中的定时器除了基本定时器(仅有向上计数),其他的定时器都有向上计数、向下计数、中央对齐模式(向上/向下计数)。

向上计数模式:计数器从0计数到自动加载值(TIMx_ARR计数器的内容),然后重新从0开始计数并且产生一个计数器溢出事件。

向下模式:计数器从自动装入的值(TIMx_ARR计数器的值)开始向下计数到0,然后从自动装入的值重新开始并且产生一个计数器向下溢出事件。

中央对齐模式:计数器从0开始计数到自动加载的值(TIMx_ARR寄存器)−1,产生一个计数器溢出事件,然后向下计数到1并且产生一个计数器下溢事件;然后再从0开始重新计数。

(2)更新中断

所有的定时器都可以产生更新中断事件,在定时器计数到装载值时溢出,会产生更新事件 UEV ,如果设置了中断允许标志位,还会生成更新中断 UIF并跳转至中断入口地址处(中断函数)。

如下是向上模式下溢出后生成更新事件和更新中断的时序图:

(3)输入捕获模式

在输入捕获模式下,当检测到ICx信号上相应的边沿后,计数器的当前值被锁存到捕获/比较寄存器(TIMx_CCRx)中。当发生捕获事件时,相应的CCxIF标志(TIMx_SR寄存器)被置1,如果开放了中断或者DMA操作,则将产生中断或者DMA请求。

(4)PWM 模式

脉冲宽度调制模式可以产生一个由TIMx_ARR寄存器确定频率、由TIMx_CCRx寄存器确定占空比的信号。在TIMx_CCMRx寄存器中的OCxM位写入‘110’(PWM模式1) 或‘111’(PWM模式2),能够独立地设置每个OCx输出通道产生一路PWM。

基本定时器、通用定时器、高级定时器的比较:

三、STM32CUBEMX 配置定时器

配置定时器 TIM2 定时100ms,超时溢出后产生更新中断。

需要先介绍一下定时器怎么实现固定时间的定时:

1)在STM32F103 中 TIM2 的时钟来源于 APB1 的 2 倍,即 72 MHz;

2)TIM2的预分频系数 1~65535 可选;

3)定时器计数器 CNT 为 16bit,最大值 65535;

所以定时器的超时时间计算公式如下:

Tout = ((Psc + 1) x (arr + 1))/ 72000000 s
其中:
Tout:定时器超时溢出时间
Psc:预分频系数
arr:装载值。也就是计数器的计数值
上面的方式计算出来的是单位是秒!!!

要定时100ms的时间,按照上面的公式,Psc = 7199,arr = 999,得到 Tout = 0.1s = 1000ms。

相关配置如下:

(1)因为只需要作为定时使用,所以比较简单,开始定时器,并配置相关的定时参数即可。如下:

(2)开启定时器中断功能,只有开启了才能触发溢出中断,如下:

(3)配置中断的优先级,包括抢占优先级,子优先级。如下:

生成代码后,在文件 tim.c 中 TIM2 的配置代码如下:

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 = 7199;
  htim2.Init.CounterMode = TIM_COUNTERMODE_UP;
  htim2.Init.Period = 999;
  htim2.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
  htim2.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_ENABLE;
  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();
  }

定时器使能和中断配置如下:

void HAL_TIM_Base_MspInit(TIM_HandleTypeDef* tim_baseHandle)
{
  if(tim_baseHandle->Instance==TIM2)
  {
  /* USER CODE BEGIN TIM2_MspInit 0 */


  /* USER CODE END TIM2_MspInit 0 */
    /* TIM2 clock enable */
    __HAL_RCC_TIM2_CLK_ENABLE();


    /* TIM2 interrupt Init */
    HAL_NVIC_SetPriority(TIM2_IRQn, 3, 0);
    HAL_NVIC_EnableIRQ(TIM2_IRQn);
  /* USER CODE BEGIN TIM2_MspInit 1 */


  /* USER CODE END TIM2_MspInit 1 */
  }
}

相应的中断入口函数在 stm32f1xx_it.c 中,如下:

void TIM2_IRQHandler(void)
{
  /* USER CODE BEGIN TIM2_IRQn 0 */


  /* USER CODE END TIM2_IRQn 0 */
  HAL_TIM_IRQHandler(&htim2);
  /* USER CODE BEGIN TIM2_IRQn 1 */


  /* USER CODE END TIM2_IRQn 1 */
}


网站公告

今日签到

点亮在社区的每一天
去签到