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