一、GD32F4定时器资源

GD32F427ZGT6(主频200MHz)集成了丰富的定时器资源,分为高级定时器、通用定时器、基本定时器及SysTick系统定时器,可满足电机控制、PWM输出、事件计数等多样化需求。其定时器分类及关键特性如下:


📊 一、定时器类型及资源概览

类型 定时器编号 计数器位数 通道数 关键特性 适用场景
高级定时器 TIMER0、TIMER7 16位 4 死区互补输出、刹车功能、编码器接口、霍尔传感器接口、重复计数器(RCR) 电机控制、电源管理
通用定时器L0 TIMER1(32位)
TIMER2/3(16位)
TIMER4(32位)
16/32位 4 编码器接口、输入捕获/输出比较、PWM生成、支持向上/向下/中央计数模式 通用PWM、编码器计数
通用定时器L1 TIMER8、TIMER11 16位 2 基础输入捕获/输出比较、PWM生成 简易PWM、信号测量
通用定时器L2 TIMER9/10/12/13 16位 1 仅内部时钟、支持单通道PWM 简单定时任务
基本定时器 TIMER5、TIMER6 16位 0 无外部引脚,仅内部时钟、自动重装载、触发DAC/DMA 时基生成、定时触发
SysTick 内核集成 24位递减 - 固定1ms中断配置(默认系统心跳) 操作系统调度、毫秒级延时

💡 :TIMER1/TIMER4为32位计数器,适合长周期定时;TIMER13等单通道定时器节省资源,适合简单任务。


⚙️ 二、高级定时器特殊功能详解

高级定时器(TIMER0/TIMER7)在电机控制中具备不可替代的优势:

  1. 死区插入:防止H桥电路上下管直通,确保电机驱动安全。
  2. 重复计数器(RCR):支持8位重复计数(最高40位定时),减少中断频率,提升实时性。
  3. 刹车输入:紧急事件可立即关闭PWM输出,保护硬件。

⏱️ 三、时钟配置要点

定时器时钟源灵活,但需注意分频机制:

  1. 时钟源选择
    • 内部时钟(CK_INT,200MHz)
    • 外部引脚(ETR/TIx)
    • 其他定时器触发(ITRx)。
  2. 倍频机制
    APB1总线默认50MHz(200MHz AHB四分频),但定时器可通过rcu_timer_clock_prescaler_config()实现2倍频或4倍频,最终时钟可达100MHz或200MHz。
    示例代码(4倍频至200MHz):
    rcu_periph_clock_enable(RCU_TIMER1);
    rcu_timer_clock_prescaler_config(RCU_TIMER_PSC_MUL4);  // 4倍频
    

⚠️ 四、关键编程注意事项

  1. 中断配置
    • 更新中断需使能timer_interrupt_enable(TIMERx, TIMER_INT_UP)并设置NVIC优先级。
    • 基本定时器无外部引脚,仅支持内部触发。
  2. 预分频与重装载值计算
    定时周期公式:
    T = ( P S C + 1 ) × ( A R R + 1 ) C K _ T I M E R T = \frac{(PSC + 1) \times (ARR + 1)}{CK\_TIMER} T=CK_TIMER(PSC+1)×(ARR+1)
    示例(1ms定时,CK_TIMER=200MHz):
    timer_initpara.prescaler = 199;    // 分频200
    timer_initpara.period = 999;       // 计数1000次 → 1ms
    
  3. 影子寄存器
    通过timer_auto_reload_shadow_enable()使能后,ARR变更在更新事件生效,避免计数中途数值跳变。

🔍 五、对比:SysTick vs 外设定时器

特性 SysTick 外设定时器(如TIMER1)
优先级 内核中断,优先级可调 外设中断,需NVIC配置
灵活性 固定24位递减,仅中断 支持PWM/捕获/编码器等多模式
适用场景 操作系统时基、delay_ms() 精准硬件控制(如PWM占空比调节)
配置复杂度 简单(库函数SysTick_Config() 需初始化结构体

💎 总结

GD32F427ZGT6的定时器系统兼顾高性能(32位计数、200MHz时钟)与灵活性(死区控制、编码器接口等),特别适合电机控制、实时信号处理等场景。开发时需重点关注:

  1. 定时器类型与通道数的匹配需求;
  2. 时钟倍频机制避免误用APB总线频率;
  3. 高级功能如RCR减少中断负载。
    实际应用参考:1秒LED闪烁DHT11驱动中的μs延时

二、初始化定时器

这里笔者使用的是timer6,附上初始化代码

/**
 * @brief      基本定时器TIMER6定时中断初始化
 * @note
 *              基本定时器的时钟来自APB1,当PPRE1 ≥ 2分频时
 *              基本定时器的时钟为APB1时钟的倍频,而APB1为50M,因此定时器TIMER6时钟 = 100Mhz
 *              定时器溢出时间计算方法: Tout = ((arr + 1) * (psc + 1)) / Ft us.
 *              Ft=定时器工作频率,单位:Mhz
 *
 * @param       arr: 自动重装载值
 * @param       psc: 时钟预分频值
 * @retval      无
 */
void timer6_int_init(uint16_t arr, uint16_t psc)
{
    timer_parameter_struct timer_initpara;               /* timer_initpara用于配置定时器的参数 */

    /* 使能RCU时钟 */ 
    rcu_periph_clock_enable(RCU_TIMER6);                 /* 使能TIMER6的时钟 */

    /* 复位TIMER6 */
    timer_deinit(TIMER6);                                /* 复位TIMER6 */
    timer_struct_para_init(&timer_initpara);             /* 初始化timer_initpara为默认值 */

    /* 配置TIMER6 */
    timer_initpara.prescaler         = psc;              /* 设置预分频值 */
    timer_initpara.counterdirection  = TIMER_COUNTER_UP; /* 设置向上计数模式 */
    timer_initpara.period            = arr;              /* 设置自动重装载值 */
    timer_initpara.clockdivision     = TIMER_CKDIV_DIV1; /* 设置时钟分频因子 */
    timer_init(TIMER6, &timer_initpara);                 /* 根据参数初始化定时器 */

    /* 使能定时器及中断功能*/
    timer_interrupt_enable(TIMER6, TIMER_INT_UP);        /* 使能定时器的更新中断 */
    nvic_irq_enable(TIMER6_IRQn, 1, 3);                  /* 配置NVIC优先级,抢占优先级1,响应优先级3 */
    timer_enable(TIMER6);                                /* 使能定时器TIMER6 */
}

主要按照自己的要求配置定时器中断优先级,然后继续编写定时器中断部分代码

/**
 * @brief TIMER6中断服务函数
 */
void TIMER6_IRQHandler(void)
{
    if (timer_interrupt_flag_get(TIMER6, TIMER_INT_FLAG_UP) == SET) {
        timer_interrupt_flag_clear(TIMER6, TIMER_INT_FLAG_UP); // 清除中断标志
        
        // 用户代码 - 每1ms执行一次
        // 例如:LED翻转、系统节拍更新等
    }
}

当我们要实现1ms定时操作时,往初始化定时器函数传入预分频参数199,自动重装载值为999,即可实现定时器1ms中断。
现在这个定时器在往后的章节里主要充当LVGL的1ms中断来源。

Logo

智能硬件社区聚焦AI智能硬件技术生态,汇聚嵌入式AI、物联网硬件开发者,打造交流分享平台,同步全国赛事资讯、开展 OPC 核心人才招募,助力技术落地与开发者成长。

更多推荐