STM32 HAL库 基本定时器介绍及循环点亮LED例程 CubeMX

STM32定时器介绍

定时器类别

STM32拥有三类定时器,以F429为例:

  • 基本定时器:TIM6、TIM7
  • 通用定时器:TIM2至TIM5、TIM9至TIM14
  • 高级定时器:TIM1、TIM8
    所有定时器之间相互独立。

定时器时钟

F429封装图
参考手册Block Diagram,很容易可以得到每个定时器的时钟来源。很容易可以发现F429的两个基本定时器TIM6、TIM7均挂载于APB1。APB1的时钟频率可以在CubeMX中设置。

如图,该工程中APB1定时器的频率为75MHz。

计数模式(Counter Mode)

定时器有三种计数模式:

  • 向上计数
  • 向下计数
  • 向上/向下计数(中间对齐)

基本定时器TIM6、TIM7可以且仅能采用向上计数模式。

工作方式

TIM6、TIM7中与定时器计数密切相关的是四个寄存器,分别为:

  • 状态寄存器(TIMx_SR)
    在这里插入图片描述

  • 计数器寄存器(TIMx_CNT)
    在这里插入图片描述

  • 预分频寄存器(TIMx_PSC)
    在这里插入图片描述

  • 自动重载寄存器(TIMx_ARR)
    在这里插入图片描述

四个寄存器的作用可以简单概括为:

  • 状态寄存器负责控制定时器中断
  • 计数器寄存器负责计数
  • 预分频寄存器包含每次发生计数器更新事件(计数次数+1)时,要装载到实际的预分频寄存器的值
  • 自动重载寄存器与ARR寄存器的影子寄存器进行比较。二者相等时,该寄存器溢出,发生定时器更新事件,表明计数次数更新。如果更新中断打开,则此时还会发生更新中断。

定时器每触发一次更新事件(计数+1)的时间间隔为:
T o u t = ( A R R + 1 ) ∗ ( P S C + 1 ) f c l k T_{out} = \frac{(ARR+1)*(PSC+1)}{f_{clk}} Tout=fclk(ARR+1)(PSC+1)
其中,

  • A R R ARR ARR为自动重载寄存器的值
  • P S C PSC PSC为预分频寄存器的值
  • f c l k f_{clk} fclk为定时器频率

假设我们想要TIM6以1s的间隔计数, f c l k f_{clk} fclk已经得知为75MHz,那么可以令 A R R ARR ARR为10000,令 P S C PSC PSC为7500,从而令 T o u t T_{out} Tout等于1s.

注意ARR和PSC都为16位寄存器,也就是其写入范围是0到65535.

实例

预期目标

使用基本定时器TIM6在定时器中断中以1s的间隔点亮LED0,在main.c的While(1)中以200ms间隔点亮LED1,比较二者的点亮间隔。

CubeMX配置

此处只介绍TIM6的配置。如下图:
CubeMX配置
注意红框中的几个选项:

  • Prescaler (PSC - 16 bits value):PSC寄存器的写入值
  • Counter Mode:计数方式。由于TIM6是基本寄存器,此处应只有Up(向上计数)可选
  • Counter Period (AutoReload Register - 16 bits value ):ARR寄存器的写入值
  • auto-reload preload:影子寄存器使能,此处开启

不要忘记在NVIC中开启TIM6的中断。
NVIC
设置完成后,生成工程。

tim.c部分

CubeMX生成的有关定时器的函数均包含于此。

MX_TIM6_Init()

TIM6初始化函数。CubeMX已经自动配置。

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 = 7500;
  htim6.Init.CounterMode = TIM_COUNTERMODE_UP;
  htim6.Init.Period = 10000;
  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 */

}

HAL_TIM_Base_MspInit() 和 HAL_TIM_Base_MspDeInit()

MSP初始化函数。CubeMX已经自动配置。

HAL_TIM_IRQHandler()

定时器中断服务函数。由于我们之前在CubeMX中启用了TIM6的中断,因此CubeMX已经自动配置。该函数声明位置在stm32f4xx_hal_tim.c的3815行。在我们的工程中,stm32f4xx_it.c中调用了它,并重新定义了专为TIM6服务的中断服务函数:

/**
  * @brief This function handles TIM6 global interrupt, DAC1 and DAC2 underrun error interrupts.
  */
void TIM6_DAC_IRQHandler(void)
{
  HAL_TIM_IRQHandler(&htim6);
}

HAL_TIM_PeriodElapsedCallback()

这个函数是定时器中断的计数后回调函数,十分重要。这是一个弱定义函数,其原始声明为:

__weak void HAL_TIM_PeriodElapsedCallback (TIM_HandleTypeDef * htim)

该函数的形参为指向TIM_HandleTypeDef的句柄htim的指针,用于确认是哪个定时器申请的中断。TIM_HandleTypeDef应当已经在tim.c的头部由CubeMX声明。

我们需要在tim.c中重写这个函数,让定时器每次更新事件(计数+1)后调用该函数然后退出中断。

void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
  UNUSED(htim);
  if (htim->Instance == TIM6)	//确认中断由TIM6申请
  {
    LED0_TOGGLE();		//反转LED0电平
  }
}

回调函数不止这一种,还有这些:

void HAL_TIM_PeriodElapsedHalfCpltCallback(TIM_HandleTypeDef *htim);
void HAL_TIM_OC_DelayElapsedCallback(TIM_HandleTypeDef *htim);
void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim);
void HAL_TIM_IC_CaptureHalfCpltCallback(TIM_HandleTypeDef *htim);
void HAL_TIM_PWM_PulseFinishedCallback(TIM_HandleTypeDef *htim);
void HAL_TIM_PWM_PulseFinishedHalfCpltCallback(TIM_HandleTypeDef *htim);
void HAL_TIM_TriggerCallback(TIM_HandleTypeDef *htim);
void HAL_TIM_TriggerHalfCpltCallback(TIM_HandleTypeDef *htim);
void HAL_TIM_ErrorCallback(TIM_HandleTypeDef *htim);

main.c部分

在int main中首先要检查CubeMX是否初始化了对应的定时器。

 MX_TIM6_Init();

然后打开TIM6的时基:

 HAL_TIM_Base_Start_IT(&htim6);

形参为对应定时器的指针,即htim6的地址。

然后。。就设置好了,LED0已经会以1s为间隔翻转了。

最后我们在While(1)里再写一个功能,让LED1以0.2s的间隔翻转,以此对比LED0和LED1的反转速度来看看效果。

 while (1)
  {
    LED1_TOGGLE();
    delay_ms(200);
  }

实物演示就不放了。以上就是一个基本定时器最简单的用法。

  • 24
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值