第7章 通用定时器介绍及应用

第七章 通用定时器介绍及应用

1. 定时器分类

屏幕截图 20250629 170602png

通用定时器和高级定时器其实也就是在基本定时器的基础上,添加了一些其他功能,如: 输入捕获、 输出比较、输出 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)
posted @ 2025-07-04 00:02  hazy1k  阅读(44)  评论(0)    收藏  举报