GD32F4学习之路第三章----定时器使用
GD32F427ZGT6的定时器系统兼顾。
·
一、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)在电机控制中具备不可替代的优势:
- 死区插入:防止H桥电路上下管直通,确保电机驱动安全。
- 重复计数器(RCR):支持8位重复计数(最高40位定时),减少中断频率,提升实时性。
- 刹车输入:紧急事件可立即关闭PWM输出,保护硬件。
⏱️ 三、时钟配置要点
定时器时钟源灵活,但需注意分频机制:
- 时钟源选择:
- 内部时钟(CK_INT,200MHz)
- 外部引脚(ETR/TIx)
- 其他定时器触发(ITRx)。
- 倍频机制:
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倍频
⚠️ 四、关键编程注意事项
- 中断配置:
- 更新中断需使能
timer_interrupt_enable(TIMERx, TIMER_INT_UP)并设置NVIC优先级。 - 基本定时器无外部引脚,仅支持内部触发。
- 更新中断需使能
- 预分频与重装载值计算:
定时周期公式:
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 - 影子寄存器:
通过timer_auto_reload_shadow_enable()使能后,ARR变更在更新事件生效,避免计数中途数值跳变。
🔍 五、对比:SysTick vs 外设定时器
| 特性 | SysTick | 外设定时器(如TIMER1) |
|---|---|---|
| 优先级 | 内核中断,优先级可调 | 外设中断,需NVIC配置 |
| 灵活性 | 固定24位递减,仅中断 | 支持PWM/捕获/编码器等多模式 |
| 适用场景 | 操作系统时基、delay_ms() |
精准硬件控制(如PWM占空比调节) |
| 配置复杂度 | 简单(库函数SysTick_Config()) |
需初始化结构体 |
💎 总结
GD32F427ZGT6的定时器系统兼顾高性能(32位计数、200MHz时钟)与灵活性(死区控制、编码器接口等),特别适合电机控制、实时信号处理等场景。开发时需重点关注:
- 定时器类型与通道数的匹配需求;
- 时钟倍频机制避免误用APB总线频率;
- 高级功能如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中断来源。
更多推荐



所有评论(0)