蓝桥杯嵌入式STM32 G431 HAL库开发速成教程:定时器TIM的使用

一、TIM常用的函数

1.以中断模式开启定时器

HAL_TIM_Base_Start_IT(&htim1);

2.开启定时器

HAL_TIM_Base_Start(&htim1);

3.关闭定时器

HAL_TIM_Base_Stop(&htim1);

4.设置计数器的值

 __HAL_TIM_SET_COUNTER(&htim3, 0);  // 重置计数器

5.定时器中断回调函数

void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)

1)介绍:

void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) 是一个由 STM32 HAL 库提供的回调函数,用于处理定时器周期结束(即溢出)事件。这个函数是定时器中断服务例程的一部分,通常在定时器达到预设周期时自动被调用。让我们更详细地解释这个函数:

2)函数结构:

void:这表明函数不返回任何值。
HAL_TIM_PeriodElapsedCallback:这是函数的名称。
TIM_HandleTypeDef *htim:这是一个指向 TIM_HandleTypeDef 结构体的指针,该结构体包含了定时器的配置和状态信息。这个参数允许函数知道是哪个定时器触发了中断。

3)功能和用途:

当定时器的计数器达到其预设的周期值时(通常是自动重载寄存器的值),就会触发一个更新事件(或称为周期结束事件),并且如果使能了中断,就会调用这个回调函数。
这个函数通常用于执行周期性的任务,例如更新变量、检测输入、生成输出信号、触发其他事件等。

4)实现方式:

在默认情况下,HAL_TIM_PeriodElapsedCallback 函数在 HAL 库中是空实现的,用户需要根据自己的需求重写(override)这个函数。
当定时器中断发生时,HAL 库的中断处理函数会检查触发的中断类型,并调用相应的回调函数,比如本例中的 HAL_TIM_PeriodElapsedCallback。

5)示例用法:

void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
    if (htim->Instance == TIMx) // 替换TIMx为具体的定时器实例,如TIM1, TIM2等
    {
        // 在这里编写代码,这部分代码会在每个定时周期结束时执行
    }
}

这个回调函数通常用于执行需要在每个定时周期结束时执行的代码,例如翻转一个 LED、读取传感器数据或发送数据。

使用这个函数的主要优点是它允许在主循环之外异步执行代码,这对于实时任务和减少处理器负载非常有用。

二、配置STM32cubeMX

1.在TIM1中选择内部时钟作为时钟源,在NVIC Settings中勾选TIM1 update interrupt and TIM16 global interrupt。


TIM1 Update Interrupt:

这通常被用于周期性任务,如定期更新或检查某些变量、执行定时操作等。当 TIM1 的计数器溢出或达到特定值时,会触发更新中断。这是定时器最常见的使用场景之一。

TIM16 Global Interrupt:

TIM16 通常是一个基本的定时器,用于简单的延时或时间基准。其全局中断可以用于处理到达指定计时后的事件,如定时器溢出或达到预设值的情况。

2.将PSC配置为8000-1,将ARR配置为10000-1

计数器溢出频率:

CK_CNT_OV = CK_CNT / (ARR + 1) = CK_PSC / (PSC + 1) / (ARR + 1)

CK_PSC内部时钟设置的是80M

所以CK_CNT_OV=80000000/8000/10000=1HZ

所以计数器的计数时间为1s(时间是频率的倒数)

三、基本定时器的使用

效果:实现每隔1s,led1 亮一次

1.在/* USER CODE BEGIN 0 /与/ USER CODE END 0 */之间增加如下代码

int flag2=0;
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)  //定时器中断回调函数
{
    if(htim->Instance==TIM1)//判断是来自定时器1的
    {
		//编写功能
		flag2=!flag2;
		led(1,flag2);
    }
   HAL_TIM_Base_Start_IT(&htim1);//定时器中断默认是常开的
}


2.在main.c中的int main(void)函数添加如下代码

HAL_TIM_Base_Start_IT(&htim1);

四、定时器的延时us功能

1.配置cubeMX
配置TIM4的时钟源为内部时钟,PSC为80,ARR为65535

这里的预分频是对80M进行80分频,得到的就是1000k的计数频率,1000k的频率下进行计数,那计一个数就是1/1000k的时间,即10的负六次方,所以计一个数就是1us。

2.代码实现:

1)在/* USER CODE BEGIN 0 /与/ USER CODE END 0 */之间增加如下代码

void Delay_us(uint16_t delay)
{
	//注意这个不是IT
 	HAL_TIM_Base_Start(&htim4);        // 启动定时器
 	 __HAL_TIM_SET_COUNTER(&htim4, 0);  // 重置计数器
 	 // 延时循环
  	while (__HAL_TIM_GET_COUNTER(&htim4) < delay)
	  {
   	 // do nothing
  	}
	 HAL_TIM_Base_Stop(&htim4);         // 停止定时器
}

2)在while(1)中添加如下代码

	  	led(1,0);
		Delay_us(50000);		Delay_us(50000);		Delay_us(50000);		Delay_us(50000);		Delay_us(50000);		
		Delay_us(50000);		Delay_us(50000);		Delay_us(50000);		Delay_us(50000);		Delay_us(50000);
		Delay_us(50000);		Delay_us(50000);		Delay_us(50000);		Delay_us(50000);		Delay_us(50000);		
		Delay_us(50000);		Delay_us(50000);		Delay_us(50000);		Delay_us(50000);		Delay_us(50000);		
		led(1,1);
		Delay_us(50000);		Delay_us(50000);		Delay_us(50000);		Delay_us(50000);		Delay_us(50000);		
		Delay_us(50000);		Delay_us(50000);		Delay_us(50000);		Delay_us(50000);		Delay_us(50000);
		Delay_us(50000);		Delay_us(50000);		Delay_us(50000);		Delay_us(50000);		Delay_us(50000);		
		Delay_us(50000);		Delay_us(50000);		Delay_us(50000);		Delay_us(50000);		Delay_us(50000);	

每次延迟50000us,20*50000us=1000000us=1s
所以每隔1s,led1 亮一次

3)注意事项:
本例中是启动定时器,并不是启动定时器中断!

HAL_TIM_Base_Start(&htim4); // 启动定时器
HAL_TIM_Base_Start_IT(&htim4); //启动定时器中断

五、 定时器和定时器中断的区别

HAL_TIM_Base_Start(&htim4); HAL_TIM_Base_Start_IT(&htim4);
这两个是 STM32 HAL 库中用于启动基本定时器的两种不同函数,它们的主要区别在于是否涉及中断的使用。以下是这两个函数的详细比较:

1.HAL_TIM_Base_Start(&htim4);

功能:

此函数启动定时器,使其开始计数,但不涉及中断的使用。定时器计数值的变化需要通过轮询(即在程序的主循环中不断检查)来监控。

应用场景:

当你需要简单的时间基准或延时,且不需要中断来处理定时器事件时,可以使用这个函数。例如,实现一个阻塞型的延时函数。

示例:

// 阻塞式延时
HAL_TIM_Base_Start(&htim4);
while (__HAL_TIM_GET_COUNTER(&htim4) < desired_delay)
{
    // 延时循环,直到达到预设的计数值
}
HAL_TIM_Base_Stop(&htim4);

2.HAL_TIM_Base_Start_IT(&htim4);

功能:

此函数启动定时器并启用与该定时器相关的中断。当定时器事件(如溢出)发生时,将自动调用相应的中断服务例程(ISR),例如 HAL_TIM_PeriodElapsedCallback。

应用场景:

当你需要在定时器达到特定状态时立即执行某些操作,并且不想在主循环中不断检查定时器状态时,使用此函数。这适用于需要非阻塞性或异步处理的情况,如定期更新状态、读取数据等。

示例:

// 使用中断的定时器
HAL_TIM_Base_Start_IT(&htim4);
// ...

// 中断服务例程
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
    if (htim->Instance == TIM4)
    {
        // 定时器事件处理代码
    }
}

总结:

HAL_TIM_Base_Start 用于不需要中断处理的简单定时任务,如阻塞式延时或基本的时间测量。

HAL_TIM_Base_Start_IT 用于需要定时器中断处理的情况,允许程序异步响应定时器事件,适用于更复杂或实时的应用场景。
选择哪种方法取决于具体需求,比如是否需要程序在定时器事件发生时立即做出响应,以及是否希望程序能够继续执行其他任务而不被定时器的监控阻塞。

作者:Comedy_宁

物联沃分享整理
物联沃-IOTWORD物联网 » 蓝桥杯嵌入式STM32 G431 HAL库开发速成教程:定时器TIM的使用

发表评论