STM32 HAL 库中 TIM 定时器使用方法及案例
**在 STM32 的开发领域,定时器作为极为关键的外设,在众多场景中发挥着不可替代的作用。无论是精确的定时任务调度,如周期性的数据采集与处理;还是复杂的 PWM 输出应用,像电机转速的精准控制;亦或是时间测量相关的工作,比如测量外部信号的脉冲宽度,都离不开定时器的支持。本文将深入探讨 STM32 HAL 库中 TIM 定时器的使用方式,并结合具体案例详细阐述,帮助开发者更好地掌握这一强大工具。 **
TIM 定时器基础
在 STM32 体系中,TIM 定时器家族根据功能特性分为高级定时器、通用定时器和基本定时器。高级定时器功能最为丰富,除具备通用定时器的基本功能外,还拥有一些特殊功能,如带互补输出的 PWM 通道,常用于电机的全桥驱动控制。通用定时器则适用于大多数常规的定时、计数以及 PWM 输出场景。基本定时器相对简单,主要用于基本的定时功能。虽然它们的功能各有侧重,但底层工作原理却有相似之处。
工作原理
TIM 定时器本质上是一个计数器,其工作基于设定的时钟源进行计数操作。时钟源可以是内部的系统时钟,也可以是外部输入的时钟信号。当计数器数值达到预先设定的自动重载值(ARR)时,会触发溢出事件。这一事件可用于激活中断,使得 CPU 能够及时响应并执行特定的任务,比如更新传感器数据、控制通信接口的状态等。或是触发其他特定事件,如触发 DMA 传输,实现数据的自动搬运,提高系统效率。另外,通过对比较寄存器(CCR)的配置,能够实现定时比较功能,这在 PWM 输出等应用中发挥着重要作用。在 PWM 输出时,通过不断比较计数器值与 CCR 值,来确定输出引脚的电平状态,从而产生不同占空比的 PWM 波形。
HAL 库中 TIM 定时器的使用方法
初始化 TIM 定时器
利用 HAL 库初始化 TIM 定时器时,需要对定时器的时钟源、分频系数、计数模式以及自动重载值等关键参数进行配置。以下是一个通用定时器初始化的示例代码:
TIM_HandleTypeDef htim2;
// 定时器初始化函数
void TIM2_Init(void)
{
// 选择TIM2定时器
htim2.Instance = TIM2;
// 分频系数设置,72MHz系统时钟分频后为1MHz,即每1微秒计数一次
htim2.Init.Prescaler = 72 - 1;
// 设置为向上计数模式,计数器从0开始,每次计数增加1,直到达到自动重载值
htim2.Init.CounterMode = TIM_COUNTERMODE_UP;
// 自动重载值设置,计数到999后溢出,配合1MHz计数频率,实现1ms定时
htim2.Init.Period = 1000 - 1;
// 时钟分频设置,这里不分频
htim2.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
// 调用HAL库函数进行定时器初始化
if (HAL_TIM_Base_Init(&htim2)!= HAL_OK)
{
// 初始化失败,调用错误处理函数
Error_Handler();
}
}
在这段代码中,我们将 TIM2 的计数频率设置为 1MHz,每 1ms 便会产生一次溢出事件。这样的定时精度可以满足许多常见的应用需求,如 LED 的闪烁控制、简单的定时任务调度等。
启动和停止定时器
启动和停止定时器的操作非常简便,借助 HAL 库提供的函数即可完成:
// 启动定时器,使能定时器开始计数
HAL_TIM_Base_Start(&htim2);
// 停止定时器,计数器停止计数
HAL_TIM_Base_Stop(&htim2);
通过这两个函数,开发者可以灵活地控制定时器的运行状态。在需要进行精确时间测量时,先启动定时器,测量完成后及时停止,获取计数值进行后续处理。
定时器中断配置
若要在定时器溢出时执行特定操作,就需要进行中断配置。首先,在完成定时器初始化后,需使能定时器中断:
// 启动定时器中断,当定时器溢出时触发中断
HAL_TIM_Base_Start_IT(&htim2);
接着,在中断处理函数中编写具体执行代码。在 STM32 中,定时器中断处理函数通常位于stm32f4xx_it.c文件内:
void TIM2_IRQHandler(void)
{
// 检查是否发生更新中断标志
if (__HAL_TIM_GET_FLAG(&htim2, TIM_FLAG_UPDATE)!= RESET)
{
// 检查是否是更新中断源触发
if (__HAL_TIM_GET_IT_SOURCE(&htim2, TIM_IT_UPDATE)!= RESET)
{
// 清除中断标志位,准备下一次中断
__HAL_TIM_CLEAR_IT(&htim2, TIM_IT_UPDATE);
// 在此编写定时中断执行代码
// 例如:实现LED闪烁,假设PC13引脚连接LED
HAL_GPIO_TogglePin(GPIOC, GPIO_PIN_13);
}
}
}
上述代码展示了,当定时器 TIM2 产生溢出中断时,会切换 PC13 引脚的电平状态,从而实现 LED 的闪烁效果。通过这种方式,可以利用定时器中断实现各种周期性的任务,如周期性的状态监测、数据发送等。
案例:使用 TIM 定时器产生 PWM 波控制舵机
使用 CubeMX 配置 TIM 定时器
打开 CubeMX 并创建新项目:选择对应的 STM32 芯片型号后进入配置界面。
配置时钟:确保系统时钟设置正确,这里我们设置为 72MHz。
选择 TIM 定时器:以 TIM3 为例,在Pinout & Configuration选项卡中找到 TIM3,将其Channel1设置为PWM Generation CH1。
配置 TIM3 参数:在Configuration选项卡中设置定时器参数。Prescaler设置为 72 – 1,使得定时器时钟频率为 1MHz;Counter Mode选择Up向上计数模式;Period设置为 19999,配合 1MHz 时钟频率,产生周期为 20ms 的 PWM 信号(舵机控制信号周期通常为 20ms)。
配置 PWM 通道参数:在TIM3 Channel1中,Mode选择PWM mode 1,Pulse初始值可设置为 1500(对应 1.5ms 的脉冲宽度,一般为舵机的中间位置),Polarity设置为High高电平有效。
生成代码:完成上述配置后,点击Project Manager,设置好项目名称、路径等,然后点击Generate Code生成代码。
代码实现
生成代码后,在main.c文件中添加如下代码:
#include "main.h"
#include "stm32f4xx_hal.h"
TIM_HandleTypeDef htim3;
void SystemClock_Config(void);
static void MX_GPIO_Init(void);
static void MX_TIM3_Init(void);
int main(void)
{
HAL_Init();
SystemClock_Config();
MX_GPIO_Init();
MX_TIM3_Init();
// 启动PWM通道
HAL_TIM_PWM_Start(&htim3, TIM_CHANNEL_1);
while (1)
{
// 例如将舵机旋转到90度位置(假设对应2ms脉冲宽度,即2000的脉冲值)
__HAL_TIM_SET_COMPARE(&htim3, TIM_CHANNEL_1, 2000);
HAL_Delay(2000);
// 将舵机旋转到0度位置(假设对应1ms脉冲宽度,即1000的脉冲值)
__HAL_TIM_SET_COMPARE(&htim3, TIM_CHANNEL_1, 1000);
HAL_Delay(2000);
}
}
void SystemClock_Config(void)
{
// 时钟配置代码,由CubeMX生成
}
static void MX_GPIO_Init(void)
{
// GPIO初始化代码,由CubeMX生成
}
static void MX_TIM3_Init(void)
{
// TIM3初始化代码,由CubeMX生成
}
通过上述 CubeMX 配置和代码,我们实现了使用 TIM 定时器产生 PWM 波来控制舵机的转动。在实际应用中,可以根据具体需求调整 PWM 的脉冲宽度(即通过修改__HAL_TIM_SET_COMPARE函数中的参数),从而精确控制舵机的角度。
调整 PWM 占空比
在控制舵机时,通过修改比较寄存器(CCR)的值,也就是调整__HAL_TIM_SET_COMPARE函数中的参数,能够灵活调整 PWM 的占空比,进而控制舵机的角度。例如,将舵机旋转到某个特定角度对应的脉冲宽度值设置到__HAL_TIM_SET_COMPARE函数中,即可实现舵机的角度控制。
总结
通过上述内容的介绍以及实际案例的展示,我们深入了解了 STM32 HAL 库中 TIM 定时器的基本使用方法,涵盖定时器初始化、中断配置以及 PWM 输出等应用场景。定时器在 STM32 开发中占据着重要地位,熟练掌握其使用方法,对于构建复杂的嵌入式系统至关重要。希望本文能够助力大家在 STM32 开发过程中,更加高效地运用 TIM 定时器,实现更多创新的应用。
作者:B. D