第7章 通用定时器介绍及应用
第七章 通用定时器介绍及应用
1. 定时器分类

通用定时器和高级定时器其实也就是在基本定时器的基础上,添加了一些其他功能,如: 输入捕获、 输出比较、输出 PWM 和单脉冲模式等。 而通用定时器数量较多,其特性也有一些的差异,但是基本原理都一样。
2. 通用定时器使用示例
2.1 定时器中断
定时器属于 STM32F407 的内部资源,只需要软件设置好即可正常工作。 我们通过 LED1 来指示 STM32F407 的定时器进入中断的频率, LED0 则指示程序的运行状态。
2.1.1 TIM相关参数宏定义
#ifndef __GTIM_H__
#define __GTIM_H__
#include <sys.h>
#include <led.h>
#define GTIMx TIM3
#define GTIMx_IRQn TIM3_IRQn
#define GTIMx_IRQHandler TIM3_IRQHandler
#define GTIMx_CLK_ENABLE() __HAL_RCC_TIM3_CLK_ENABLE()
void TIMx_Init(uint16_t arr, uint16_t psc);
#endif /* __TIM_H__ */
2.1.2 TIM模式和中断配置
#include <gtim.h>
#include <usart.h>
#include <stdio.h>
TIM_HandleTypeDef TIM3_Handler;
void TIMx_Init(uint16_t arr, uint16_t psc)
{
TIM3_Handler.Instance = TIM3;
TIM3_Handler.Init.Period = arr;
TIM3_Handler.Init.Prescaler = psc;
TIM3_Handler.Init.CounterMode = TIM_COUNTERMODE_UP;
TIM3_Handler.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
HAL_TIM_Base_Init(&TIM3_Handler);
HAL_TIM_Base_Start_IT(&TIM3_Handler);
}
void HAL_TIM_Base_MspInit(TIM_HandleTypeDef *htim)
{
if(htim->Instance == TIM3)
{
__HAL_RCC_TIM3_CLK_ENABLE();
HAL_NVIC_SetPriority(GTIMx_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(GTIMx_IRQn);
}
}
void TIM3_IRQHandler(void)
{
HAL_TIM_IRQHandler(&TIM3_Handler);
}
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
if(htim->Instance == TIM3)
{
printf("TIM3_IRQHandler!!!\r\n");
LED_TOGGLE(LED1_GPIO_Pin);
}
}
2.1.3 主函数测试
#include <bsp_init.h>
int main(void)
{
bsp_init();
printf("Hello World!\n");
while(1)
{
LED_TOGGLE(LED0_GPIO_Pin);
printf("LED0_GPIO_Pin 1s\r\n");
delay_ms(1000);
}
}
2.2 定时器输出PWM
使用 TIM14 通道 1(由 PF9 复用)输出 PWM, PF9 引脚连接了 LED0, 从而实现 PWM 输出控制 LED0 亮度。
2.2.1 TIM配置
#include <gtim.h>
TIM_HandleTypeDef TIM14_Handler;
TIM_OC_InitTypeDef TIM14_CH1_Handler;
void TIM14_PWM_Init(uint16_t arr, uint16_t psc)
{
/* Mode Init */
TIM14_Handler.Instance = TIM14;
TIM14_Handler.Init.Period = arr;
TIM14_Handler.Init.Prescaler = psc;
TIM14_Handler.Init.CounterMode = TIM_COUNTERMODE_UP;
TIM14_Handler.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
HAL_TIM_PWM_Init(&TIM14_Handler);
/* PWM Init */
TIM14_CH1_Handler.OCMode = TIM_OCMODE_PWM1; // PWM1模式
TIM14_CH1_Handler.Pulse = arr/2; // 占空比50%
TIM14_CH1_Handler.OCPolarity = TIM_OCPOLARITY_LOW;
HAL_TIM_PWM_ConfigChannel(&TIM14_Handler, &TIM14_CH1_Handler, TIM_CHANNEL_1);
HAL_TIM_PWM_Start(&TIM14_Handler, TIM_CHANNEL_1);
}
// tim底层驱动,会被HAL_TIM_PWM_Init()调用
void HAL_TIM_PWM_MspInit(TIM_HandleTypeDef *htim)
{
GPIO_InitTypeDef GPIO_InitStruct;
__HAL_RCC_TIM14_CLK_ENABLE();
__HAL_RCC_GPIOF_CLK_ENABLE();
GPIO_InitStruct.Pin = GPIO_PIN_9;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_PULLUP;
GPIO_InitStruct.Speed = GPIO_SPEED_HIGH;
GPIO_InitStruct.Alternate = GPIO_AF9_TIM14;
HAL_GPIO_Impare)
{
TIM14->CCR1 = compare;
}
2.2.2 设置占空比
// 设置占空比
void TIM_SetCompare(uint16_t compare)
{
TIM14->CCR1 = compare;
}
2.2.3 主函数测试
#include <bsp_init.h>
#include <gtim.h>
int main(void)
{
bsp_init();
uint8_t dir = 1; // 1:正序,0:倒序
uint16_t led_duty = 0; // LED PWM输出占空比
// time = (500*84)/84 = 500ms
// 84/84 = 1Mhz
// PWM频率1Mhz/500 = 2KHz
TIM14_PWM_Init(500-1, 84-1);
while(1)
{
if(dir)
led_duty++;
else
led_duty--;
if(led_duty >= 500)
{
dir = 0;
}
if(led_duty == 0)
{
dir = 1;
}
TIM_SetCompare(led_duty);
}
}
2.3 输入捕获
STM32F407 的定时器除了 TIM6 和 TIM7,其他定时器都有输入捕获功能。输入捕获,简单的说就是通过检测 TIMx_CHy 上的边沿信号,在边沿信号发生跳变(比如上升沿/下降沿)时,会发生捕获事件,将当前定时器的值( TIMx_CNT)锁存到对应通道的捕获/比较寄存器(TIMx_CCRy)里,完成一次捕获。同时还可以配置捕获事件发生时是否触发捕获中断/DMA。另外还要考虑测量的过程中是否可能发生定时器溢出,如果可能溢出,还要做溢出处理。
使用 TIM5_CH1 来做输入捕获,捕获 PA0 上的高电平脉宽,并将脉宽时间通过串口打印出来,然后通过按 WK_UP 按键,模拟输入高电平, 例程中能测试的最长高电平脉宽时间为: 4194303 us。
2.3.1 TIM相关参数宏定义
#ifndef __GTIME_H__
#define __GTIME_H__
#include "sys.h"
// 输入捕获状态机状态定义
#define CAP_IDLE 0x00 // 空闲状态
#define CAP_RISING 0x40 // 已捕获上升沿
#define CAP_COMPLETE 0x80 // 捕获完成
#define CAP_OVF_MASK 0x3F // 溢出计数器掩码(最大63次)
// 使用结构体优化状态管理
typedef struct {
uint8_t status; // 状态标志 (CAP_IDLE/CAP_RISING/CAP_COMPLETE + 溢出计数)
uint16_t cap_val; // 捕获值
uint32_t timestamp; // 上次处理时间(用于超时检测)
} CapState_t;
void TIM5_CH1_Init(uint32_t arr, uint16_t psc);
#endif /* __GTIME_H__ */
2.3.2 TIM模式配置
/**
* @brief TIM5 输入捕获初始化
* @param arr: 自动重装载值
* @param psc: 预分频系数
* @note 配置TIM5通道1为输入捕获模式
* 时钟频率 = APB1时钟(84MHz) / (psc + 1)
* 本例中: 84MHz / 84 = 1MHz (1us计数周期)
*/
void TIM5_CH1_Init(uint32_t arr, uint16_t psc)
{
TIM_IC_InitTypeDef TIM_ICInitStructure;
// 定时器基础配置
TIM5_Handle.Instance = TIM5;
TIM5_Handle.Init.Period = arr;
TIM5_Handle.Init.Prescaler = psc;
TIM5_Handle.Init.CounterMode = TIM_COUNTERMODE_UP;
TIM5_Handle.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
HAL_TIM_IC_Init(&TIM5_Handle);
// 输入捕获通道配置
TIM_ICInitStructure.ICPolarity = TIM_ICPOLARITY_RISING; // 初始上升沿触发
TIM_ICInitStructure.ICSelection = TIM_ICSELECTION_DIRECTTI; // 直接映射到TI1
TIM_ICInitStructure.ICPrescaler = TIM_ICPSC_DIV1;
TIM_ICInitStructure.ICFilter = 0; // 无滤波器
HAL_TIM_IC_ConfigChannel(&TIM5_Handle, &TIM_ICInitStructure, TIM_CHANNEL_1);
// 启用中断
__HAL_TIM_ENABLE_IT(&TIM5_Handle, TIM_IT_UPDATE); // 溢出中断
HAL_TIM_IC_Start_IT(&TIM5_Handle, TIM_CHANNEL_1); // 捕获中断
// 清除任何挂起的中断标志
__HAL_TIM_CLEAR_IT(&TIM5_Handle, TIM_IT_UPDATE);
__HAL_TIM_CLEAR_IT(&TIM5_Handle, TIM_IT_CC1);
}
/**
* @brief TIM5 MSP初始化
* @param htim: TIM句柄
* @note 配置GPIO和NVIC
*/
void HAL_TIM_IC_MspInit(TIM_HandleTypeDef *htim)
{
if(htim->Instance == TIM5)
{
GPIO_InitTypeDef GPIO_InitStructure;
// 启用时钟
__HAL_RCC_GPIOA_CLK_ENABLE();
__HAL_RCC_TIM5_CLK_ENABLE();
// 配置PA0为TIM5通道1的复用功能
GPIO_InitStructure.Pin = GPIO_PIN_0;
GPIO_InitStructure.Mode = GPIO_MODE_AF_PP; // 复用推挽输出
GPIO_InitStructure.Pull = GPIO_PULLDOWN;
GPIO_InitStructure.Speed = GPIO_SPEED_FREQ_HIGH;
GPIO_InitStructure.Alternate = GPIO_AF2_TIM5; // TIM5复用功能
HAL_GPIO_Init(GPIOA, &GPIO_InitStructure);
// 配置NVIC
HAL_NVIC_SetPriority(TIM5_IRQn, 1, 0); // 中等优先级
HAL_NVIC_EnableIRQ(TIM5_IRQn);
}
}
/**
* @brief TIM5中断服务程序
*/
void TIM5_IRQHandler(void)
{
HAL_TIM_IRQHandler(&TIM5_Handle);
}
2.2.3 输入捕获回调函数
/**
* @brief 输入捕获回调函数
* @param htim: TIM句柄
* @note 状态机:
* 空闲状态 -> 捕获到上升沿: 计数器清零,改为下降沿捕获
* 已捕获上升沿 -> 捕获到下降沿: 记录捕获值,完成捕获
*/
void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim)
{
if (htim->Channel == HAL_TIM_ACTIVE_CHANNEL_1)
{
if (TIM5CH1_CAP.status & CAP_COMPLETE) return; // 已完成,忽略新事件
if (TIM5CH1_CAP.status & CAP_RISING)
{
// 下降沿捕获: 完成测量
TIM5CH1_CAP.status |= CAP_COMPLETE; // 标记完成
TIM5CH1_CAP.cap_val = HAL_TIM_ReadCapturedValue(htim, TIM_CHANNEL_1);
// 重置为上升沿捕获模式
__HAL_TIM_SET_CAPTUREPOLARITY(htim, TIM_CHANNEL_1, TIM_ICPOLARITY_RISING);
}
else
{
// 上升沿捕获: 开始测量
TIM5CH1_CAP.status = CAP_RISING; // 设置状态
TIM5CH1_CAP.cap_val = 0; // 清零捕获值
// 重置计数器并切换为下降沿捕获
__HAL_TIM_SET_COUNTER(htim, 0);
__HAL_TIM_SET_CAPTUREPOLARITY(htim, TIM_CHANNEL_1, TIM_ICPOLARITY_FALLING);
}
}
}
2.3.4 更新中断回调函数
/**
* @brief 定时器溢出回调函数
* @param htim: TIM句柄
* @note 处理计数器溢出情况
*/
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
if (htim->Instance == TIM5)
{
if ((TIM5CH1_CAP.status & CAP_RISING) && !(TIM5CH1_CAP.status & CAP_COMPLETE))
{
uint8_t ovf_count = TIM5CH1_CAP.status & CAP_OVF_MASK;
if (ovf_count < CAP_OVF_MASK)
{
// 增加溢出计数
TIM5CH1_CAP.status = (TIM5CH1_CAP.status & ~CAP_OVF_MASK) | (ovf_count + 1);
}
else
{
// 溢出次数达到最大值,强制完成捕获
TIM5CH1_CAP.status |= CAP_COMPLETE;
TIM5CH1_CAP.cap_val = 0xFFFF;
}
}
}
}
2.3.5 主函数测试
#include "bsp_init.h"
#include "gtim.h"
#include <stdio.h>
extern volatile CapState_t TIM5CH1_CAP;
int main(void)
{
bsp_init();
TIM5_CH1_Init(0xFFFF, 84-1);
uint32_t last_process = 0;
while(1)
{
// 每10ms处理一次捕获数据
if (HAL_GetTick() - last_process >= 10)
{
last_process = HAL_GetTick();
if (TIM5CH1_CAP.status & CAP_COMPLETE)
{
// 计算高电平持续时间 (单位: us)
uint32_t overflow_count = TIM5CH1_CAP.status & CAP_OVF_MASK;
uint32_t high_time = (uint32_t)overflow_count * 65536 + TIM5CH1_CAP.cap_val;
printf("High time: %lu us\r\n", high_time);
// 重置捕获状态
TIM5CH1_CAP.status = CAP_IDLE;
}
static uint8_t led_counter = 0;
if (++led_counter >= 50) // 50 * 10ms = 500ms
{
led_counter = 0;
LED_TOGGLE(LED0_GPIO_Pin);
}
}
}
}
2.4 脉冲计数
前面的三个通用定时器实验的时钟源都是来自内部时钟 (CK_INT),本实验我们将使用外部时钟模式 1:外部输入引脚 (TIx)作为定时器的时钟源。关于这个外部输入引脚(TIx),我们使用 WK_UP 按键按下产生的高电平脉冲作为定时器的计数器时钟,每按下一次按键产生一次高电平脉冲,计数器加一。
使用 TIM2_CH1 做输入捕获,我们将捕获 PA0 上的高电平脉宽,并将脉宽进行计数,通过串口打印出来。
2.4.1 定时器TIM2输入捕获初始化
/**
* @brief 定时器2输入捕获初始化
* @param psc 预分频值 (0-65535)
* @note 配置PA0作为TIM2_CH1输入,工作在外部触发模式
*/
void TIM2_Mode_Init(uint16_t psc)
{
GPIO_InitTypeDef GPIO_InitStruct = {0};
TIM_SlaveConfigTypeDef sSlaveConfig = {0};
// 1. 使能时钟
__HAL_RCC_TIM2_CLK_ENABLE();
__HAL_RCC_GPIOA_CLK_ENABLE();
// 2. 配置GPIO (PA0: TIM2_CH1)
GPIO_InitStruct.Pin = GPIO_PIN_0;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; // 复用推挽
GPIO_InitStruct.Pull = GPIO_PULLDOWN; // 下拉电阻
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH; // 高速模式
GPIO_InitStruct.Alternate = GPIO_AF1_TIM2; // 复用为TIM2
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
// 3. 配置定时器基础参数
TIM2_Handler.Instance = TIM2;
TIM2_Handler.Init.Prescaler = psc; // 预分频器
TIM2_Handler.Init.CounterMode = TIM_COUNTERMODE_UP; // 向上计数
TIM2_Handler.Init.Period = 0xFFFF; // 自动重载值 (65535)
TIM2_Handler.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1; // 时钟分频
HAL_TIM_IC_Init(&TIM2_Handler);
// 4. 配置从模式:外部时钟模式1
sSlaveConfig.SlaveMode = TIM_SLAVEMODE_EXTERNAL1; // 外部时钟模式
sSlaveConfig.InputTrigger = TIM_TS_TI1FP1; // 触发源:TIM2_CH1
sSlaveConfig.TriggerPolarity = TIM_TRIGGERPOLARITY_RISING; // 上升沿触发
sSlaveConfig.TriggerPrescaler = TIM_TRIGGERPRESCALER_DIV1;
sSlaveConfig.TriggerFilter = 0; // 无滤波
if (HAL_TIM_SlaveConfigSynchronization(&TIM2_Handler, &sSlaveConfig) != HAL_OK)
{
while(1);
}
// 5. 配置中断
HAL_NVIC_SetPriority(TIM2_IRQn, 1, 3); // 中断优先级
HAL_NVIC_EnableIRQ(TIM2_IRQn); // 使能中断
__HAL_TIM_ENABLE_IT(&TIM2_Handler, TIM_IT_UPDATE); // 使能更新中断
// 6. 启动输入捕获通道
if (HAL_TIM_IC_Start(&TIM2_Handler, TIM_CHANNEL_1) != HAL_OK)
{
while(1);
}
}
2.4.2 获取当前脉冲计数值
/**
* @brief 获取当前脉冲计数值(原子操作)
* @retval 累计脉冲计数值
*/
uint32_t TIM2_CH1_GetCount(void)
{
uint32_t count, overflow;
// 原子操作:读取时禁止中断
__disable_irq();
overflow = g_overflow_count;
count = __HAL_TIM_GET_COUNTER(&TIM2_Handler);
__enable_irq();
return (overflow * 0x10000) + count; // 组合溢出值和当前计数值
}
2.4.3 重启脉冲计数器
/**
* @brief 重启脉冲计数器
*/
void TIM2_CH1_Restart(void)
{
// 原子操作:重置时禁止中断
__disable_irq();
__HAL_TIM_DISABLE(&TIM2_Handler); // 关闭定时器
g_overflow_count = 0; // 重置溢出计数
__HAL_TIM_SET_COUNTER(&TIM2_Handler, 0); // 计数器归零
__HAL_TIM_ENABLE(&TIM2_Handler); // 重新使能定时器
__enable_irq();
}
2.4.4 TIM2中断服务函数
/**
* @brief 定时器2中断服务函数
* @note 处理计数器溢出事件
*/
void TIM2_IRQHandler(void)
{
if (__HAL_TIM_GET_FLAG(&TIM2_Handler, TIM_FLAG_UPDATE) != RESET)
{
if (__HAL_TIM_GET_IT_SOURCE(&TIM2_Handler, TIM_IT_UPDATE) != RESET)
{
g_overflow_count++; // 溢出计数增加
__HAL_TIM_CLEAR_IT(&TIM2_Handler, TIM_IT_UPDATE); // 清除中断标志
}
}
}
2.4.5 主函数测试
#include "bsp_init.h"
#include "gtim.h"
#include <stdio.h>
int main(void)
{
// 1. 初始化硬件
bsp_init();
printf("Pulse Counter Started\r\n");
// 2. 初始化定时器(不分频)
TIM2_Mode_Init(0);
TIM2_CH1_Restart();
// 3. 主循环变量
uint32_t last_count = 0;
uint8_t led_blink = 0;
while(1)
{
// 按键处理:KEY0按下时重启计数器
if(key_scan(0) == KEY0_Press)
{
printf("Counter Reset\r\n");
TIM2_CH1_Restart();
last_count = 0; // 重置上次计数值
}
// 获取当前计数值(约每20ms一次)
uint32_t current_count = TIM2_CH1_GetCount();
// 检测计数值变化
if(current_count != last_count)
{
printf("CNT: %lu\r\n", current_count);
last_count = current_count;
}
// LED闪烁指示系统运行(约400ms周期)
if(++led_blink >= 20)
{
led_blink = 0;
LED_TOGGLE(LED0_GPIO_Pin);
}
delay_ms(20);
}
}
3. 通用定时器常见函数(HAL库)
3.1 时基配置函数
3.1.1 HAL_TIM_Base_Init
- 函数原型:
HAL_StatusTypeDef HAL_TIM_Base_Init(TIM_HandleTypeDef *htim)
-
参数:
htim:定时器句柄指针,包含配置结构体
-
配置结构体:
typedef struct {
uint32_t Prescaler; // 预分频值 (0-65535)
uint32_t CounterMode; // 计数模式:
// TIM_COUNTERMODE_UP (上计数)
// TIM_COUNTERMODE_DOWN (下计数)
// TIM_COUNTERMODE_CENTERALIGNED[1/2/3] (中央对齐)
uint32_t Period; // 自动重载值 (0-65535)
uint32_t ClockDivision; // 时钟分频:TIM_CLOCKDIVISION_DIV[1/2/4]
uint32_t RepetitionCounter; // 重复计数器 (高级定时器)
uint32_t AutoReloadPreload; // 自动重载预装载:
// TIM_AUTORELOAD_PRELOAD_ENABLE/DISABLE
} TIM_Base_InitTypeDef;
-
功能:配置定时器基本参数
-
示例配置:
TIM_HandleTypeDef htim3;
htim3.Instance = TIM3;
htim3.Init.Prescaler = 8399; // 84MHz/(8400) = 10kHz
htim3.Init.CounterMode = TIM_COUNTERMODE_UP;
htim3.Init.Period = 9999; // 10000计数 = 1秒 @10kHz
htim3.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
htim3.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_ENABLE;
HAL_TIM_Base_Init(&htim3);
3.2 PWM配置函数
3.2.1 HAL_TIM_PWM_ConfigChannel
- 函数原型:
HAL_StatusTypeDef HAL_TIM_PWM_ConfigChannel(
TIM_HandleTypeDef *htim,
TIM_OC_InitTypeDef *sConfig,
uint32_t Channel)
- 通道配置结构体:
typedef struct {
uint32_t OCMode; // 输出模式:TIM_OCMODE_PWM1/PWM2
uint32_t Pulse; // 脉冲值 (占空比 = Pulse/(Period+1))
uint32_t OCPolarity; // 输出极性:TIM_OCPOLARITY_HIGH/LOW
uint32_t OCNPolarity; // 互补输出极性 (高级定时器)
uint32_t OCFastMode; // 快速模式:TIM_OCFAST_ENABLE/DISABLE
uint32_t OCIdleState; // 空闲状态 (高级定时器)
uint32_t OCNIdleState; // 互补空闲状态 (高级定时器)
} TIM_OC_InitTypeDef;
-
功能:配置PWM通道参数
-
示例配置:
TIM_OC_InitTypeDef sConfigOC;
sConfigOC.OCMode = TIM_OCMODE_PWM1;
sConfigOC.Pulse = 5000; // 50%占空比 @Period=9999
sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH;
sConfigOC.OCFastMode = TIM_OCFAST_DISABLE;
HAL_TIM_PWM_ConfigChannel(&htim3, &sConfigOC, TIM_CHANNEL_1);
3.3 输入捕获配置函数
3.3.1 HAL_TIM_IC_ConfigChannel
- 函数原型:
HAL_StatusTypeDef HAL_TIM_IC_ConfigChannel(
TIM_HandleTypeDef *htim,
TIM_IC_InitTypeDef *sConfig,
uint32_t Channel)
- 输入捕获配置结构体:
typedef struct {
uint32_t ICPolarity; // 捕获极性:
// TIM_ICPOLARITY_RISING/FALLING/BOTHEDGE
uint32_t ICSelection; // 输入选择:
// TIM_ICSELECTION_DIRECTTI/INDIRECTTI/TRC
uint32_t ICPrescaler; // 输入预分频:TIM_ICPSC_DIV[1/2/4/8]
uint32_t ICFilter; // 输入滤波器 (0x0-0xF)
} TIM_IC_InitTypeDef;
-
功能:配置输入捕获通道
-
示例配置:
TIM_IC_InitTypeDef sConfigIC;
sConfigIC.ICPolarity = TIM_ICPOLARITY_RISING;
sConfigIC.ICSelection = TIM_ICSELECTION_DIRECTTI;
sConfigIC.ICPrescaler = TIM_ICPSC_DIV1;
sConfigIC.ICFilter = 6; // 过滤高频噪声
HAL_TIM_IC_ConfigChannel(&htim3, &sConfigIC, TIM_CHANNEL_2);
3.4 启动/停止函数
3.4.1 基本定时器控制
- 函数原型:
// 启动定时器 (无中断)
HAL_StatusTypeDef HAL_TIM_Base_Start(TIM_HandleTypeDef *htim)
// 启动定时器 (带更新中断)
HAL_StatusTypeDef HAL_TIM_Base_Start_IT(TIM_HandleTypeDef *htim)
// 停止定时器
HAL_StatusTypeDef HAL_TIM_Base_Stop(TIM_HandleTypeDef *htim)
HAL_StatusTypeDef HAL_TIM_Base_Stop_IT(TIM_HandleTypeDef *htim)
3.4.2 PWM控制
- 函数原型:
// 启动PWM输出
HAL_StatusTypeDef HAL_TIM_PWM_Start(TIM_HandleTypeDef *htim, uint32_t Channel)
// 启动PWM输出 (带中断)
HAL_StatusTypeDef HAL_TIM_PWM_Start_IT(TIM_HandleTypeDef *htim, uint32_t Channel)
// 停止PWM输出
HAL_StatusTypeDef HAL_TIM_PWM_Stop(TIM_HandleTypeDef *htim, uint32_t Channel)
3.4.3 输入捕获控制
- 函数原型:
// 启动输入捕获
HAL_StatusTypeDef HAL_TIM_IC_Start(TIM_HandleTypeDef *htim, uint32_t Channel)
// 启动输入捕获 (带中断)
HAL_StatusTypeDef HAL_TIM_IC_Start_IT(TIM_HandleTypeDef *htim, uint32_t Channel)
// 停止输入捕获
HAL_StatusTypeDef HAL_TIM_IC_Stop(TIM_HandleTypeDef *htim, uint32_t Channel)
3.5 中断处理函数
3.5.1 HAL_TIM_IRQHandler
- 函数原型:
void HAL_TIM_IRQHandler(TIM_HandleTypeDef *htim)
-
功能:定时器中断统一处理入口
-
使用位置:
void TIM3_IRQHandler(void) {
HAL_TIM_IRQHandler(&htim3);
}
3.5.2 回调函数 (用户实现)
- 更新中断回调:
__weak void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
- 输入捕获回调:
__weak void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim)
- 输出比较回调:
__weak void HAL_TIM_OC_DelayElapsedCallback(TIM_HandleTypeDef *htim)
- 示例实现:
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) {
if(htim->Instance == TIM3) {
// 处理TIM3更新中断
HAL_GPIO_TogglePin(GPIOB, GPIO_PIN_0);
}
}
void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim) {
if(htim->Channel == HAL_TIM_ACTIVE_CHANNEL_2) {
uint32_t capture = HAL_TIM_ReadCapturedValue(htim, TIM_CHANNEL_2);
// 处理捕获值
}
}
3.6 实用辅助函数
3.6.1 寄存器访问宏
// 获取计数器值
__HAL_TIM_GET_COUNTER(htim)
// 设置计数器值
__HAL_TIM_SET_COUNTER(htim, value)
// 获取比较值
__HAL_TIM_GET_COMPARE(htim, Channel)
// 设置比较值 (动态调整PWM占空比)
__HAL_TIM_SET_COMPARE(htim, Channel, value)
// 设置自动重载值
__HAL_TIM_SET_AUTORELOAD(htim, value)
3.6.2 状态标志操作
// 检查中断标志
__HAL_TIM_GET_FLAG(htim, TIM_FLAG_UPDATE)
// 清除中断标志
__HAL_TIM_CLEAR_FLAG(htim, TIM_FLAG_UPDATE)
// 使能/禁用中断
__HAL_TIM_ENABLE_IT(htim, TIM_IT_UPDATE)
__HAL_TIM_DISABLE_IT(htim, TIM_IT_UPDATE)

浙公网安备 33010602011771号