掌握定时器基于GD32F407VE的天空星的配置
Timer定时器详解:从基础到高级应用
一、概述
定时器是现代微控制器中不可或缺的重要外设,它可以产生精确的时间间隔、延时、定时等功能,广泛应用于**定时、计数、脉冲宽度调制(PWM)**等领域。
- 基本定时器:提供精确的时间基准和周期性中断
- 通用定时器:支持PWM输出、输入捕获等高级功能
- 高级定时器:满足复杂的控制需求,如电机驱动
定时器的主要功能和应用场景
定时器功能 | 应用场景 | 描述 | 实例 |
---|---|---|---|
定时器定时 | LED闪烁 | 定时器每隔一段时间触发中断,切换LED状态,实现定时闪烁效果。 | 指示灯每秒闪烁一次,显示设备运行状态。 |
实时时钟(RTC) | 定时器每秒触发一次中断,用于更新时间信息。 | 时钟更新显示时间,每分钟增加1。 | |
定时器计数 | 测量转速 | 定时器计数旋转编码器的脉冲,计算出电机的转速。 | 电机控制系统中实时测量转速,反馈调速信息。 |
事件计数 | 计数生产线上通过的物品数量或其他事件次数。 | 生产线计数器,记录产品通过的数量。 | |
脉冲宽度调制(PWM) | LED亮度调节 | 通过改变PWM信号的占空比,实现从暗到亮的平滑过渡。 | 调节台灯亮度,根据需求设置亮暗。 |
电机速度控制 | 改变PWM信号的占空比控制电机的转速。 | 控制小车电机转速,实现速度精准控制。 | |
音频信号生成 | 利用PWM生成特定频率音频信号。 | 蜂鸣器报警,根据信号产生不同频率的警报音。 |
定时器工作原理
定时器本质上是一个电子计数器,通过计数系统时钟周期来实现定时功能。核心计算公式为:
计数值 = 系统主频 / 目标频率
例如:
- 系统主频:168 MHz
- 目标频率:10,000 Hz
- 计数值 = 168,000,000 / 10,000 = 16,800
这意味着定时器需要计数16,800个系统时钟周期才能产生10kHz的定时事件。
GD32F4定时器分类
- 基本定时器:用于简单的定时和计数
- 通用定时器:功能丰富,适合信号测量、PWM生成
- 高级定时器:专为高要求控制场景设计,如电机控制
二、基本定时器
2.1 初始化配置
基本定时器的初始化步骤:
/*** @brief Timer定时器初始化配置* @param rcu TIMER的RCU* @param timer_periph TIMERx(x=0,1,2,3,4,5,6,7,8,9,10,11,12,13)* @param t_perscaler 分频系数* @param t_period 周期*/
static void timer_init_config(rcu_periph_enum rcu, uint32_t timer_periph,uint16_t t_perscaler, uint32_t t_period) {// 时钟使能rcu_periph_clock_enable(rcu);// 重置timer_deinit(timer_periph);// 定义结构体变量timer_parameter_struct initpara;// 给结构体成员配置默认值timer_struct_para_init(&initpara);// 修改关键成员// SystemCoreClock/用户指定的频率 用户指定的频率 >= 2564initpara.period = t_period - 1; // 周期initpara.prescaler = t_perscaler - 1; // 分频 // 初始化定时器timer_init(timer_periph, &initpara);// 启动定时器timer_enable(timer_periph);
}
/*** @brief 输出通道配置* * @param timer_periph TIMERx(x=0,1,2,3,4,5,6,7,8,9,10,11,12,13)* @param channel TIMER_CH_0, TIMER_CH_1, TIMER_CH_2, TIMER_CH_3* @param flag 1 正极, 2 负极, 3 正负极*/
static void timer_channel_config(uint32_t timer_periph, uint16_t channel, uint8_t flag) {// ====================== PWM相关timer_oc_parameter_struct ocpara;// 初始化结构体默认参数timer_channel_output_struct_para_init(&ocpara);// 修改关键成员if (flag == 1) {ocpara.outputstate = TIMER_CCX_ENABLE; // 正极} else if (flag == 2) { // 负极ocpara.outputnstate = TIMER_CCXN_ENABLE; // 负极} else { // 正负极ocpara.outputstate = TIMER_CCX_ENABLE; // 正极ocpara.outputnstate = TIMER_CCXN_ENABLE; // 负极}// 输出通道配置timer_channel_output_config(timer_periph, channel, &ocpara);// 配置模式 TIMER_OC_MODE_PWM0 和 TIMER_OC_MODE_PWM1 相反timer_channel_output_mode_config(timer_periph, channel, TIMER_OC_MODE_PWM0);
}
/*** @brief 更新指定Timer的channel的占空比** @param timer_periph TIMERx(x=0,1,2,3,4,5,6,7,8,9,10,11,12,13)* @param channel TIMER_CH_0, TIMER_CH_1, TIMER_CH_2, TIMER_CH_3* @param t_period 周期 [1, 65536]* @param duty 占空比 [0.0, 100.0]*/
void TIMER_channel_duty_update(uint32_t timer_periph, uint16_t channel, uint32_t t_period, float duty) {// 占空比timer_channel_output_pulse_value_config(timer_periph, channel, (duty / 100.0) * (t_period - 1));
}
2.2 中断处理
定时器中断服务函数:
写在TIMER.c文件下面
// 定时器5中断函数
void TIMER5_DAC_IRQHandler() { if (SET == timer_interrupt_flag_get(TIMER5, TIMER_INT_FLAG_UP)) {timer_interrupt_flag_clear(TIMER5, TIMER_INT_FLAG_UP);TIMER5_irq_callback(); // 中断函数回调函数}
}
2.3 倍频和分频技术
在GD32中,定时器时钟可能经过倍频处理:
// 4倍频配置
//rcu_timer_clock_prescaler_config(RCU_TIMER_PSC_MUL4);
// 分频配置
//timer_initpara.prescaler = 10 - 1; // 10分频/*** @brief 更新指定Timer的周期和分频** @param timer_periph TIMERx(x=0,1,2,3,4,5,6,7,8,9,10,11,12,13)* @param period 周期 [1, 65536] * @param prescaler 分频系数 [1, 65536]*/
static void TIMER_period_prescaler_update(uint32_t timer_periph, uint32_t period, uint16_t prescaler) {timer_autoreload_value_config(timer_periph, period-1); // 周期,自动重载值timer_prescaler_config(timer_periph, prescaler-1, TIMER_PSC_RELOAD_NOW); // 分频
}
分频系数的计算公式:
- 真实频率 = 系统频率 / 分频系数
- 实际周期值 = (系统频率 / 分频系数) / 目标频率 - 1
三、PWM与通用定时器
3.1 PWM原理
PWM(脉宽调制)通过调节信号的占空比来控制输出的平均电压:
3.2 PWM输出配置
// 初始化
void Buzzer_init() {// PB9 复用推挽输出 AF1 IOGPIO_output_af(RCU_GPIOB, GPIOB, GPIO_PIN_9, GPIO_OTYPE_PP, GPIO_AF_1);timer_init_config(TIMER_RCU, TIMER_PERIPH, PRESCALER, SystemCoreClock/10000);// 定时器初始化 初始化1次timer_channel_config(TIMER_PERIPH, TIMER_CH); // 通道配置,配置1次
}
static void PWM_config(u16 hz) {// 定时器1配置u16 period_t = (SystemCoreClock / PRESCALER / hz); // 时钟使能rcu_periph_clock_enable(TIMER_RCU);// 4倍频,最大值为168Mrcu_timer_clock_prescaler_config(RCU_TIMER_PSC_MUL4);// 重置timer_deinit(TIMER_PERIPH);// 定义结构体变量timer_parameter_struct initpara;// 给结构体成员配置默认值timer_struct_para_init(&initpara);// 修改关键成员// SystemCoreClock/用户指定的频率 用户指定的频率 >= 2564initpara.period = period_t - 1; // 周期initpara.prescaler = PRESCALER - 1; // 分频 // 初始化定时器timer_init(TIMER_PERIPH, &initpara);// 启动定时器timer_enable(TIMER_PERIPH);// ====================== PWM相关timer_oc_parameter_struct ocpara;// 初始化结构体默认参数timer_channel_output_struct_para_init(&ocpara);// 修改关键成员ocpara.outputstate = TIMER_CCX_ENABLE; // PWM和引脚关联了,后续可以输出方波// 输出通道配置timer_channel_output_config(TIMER_PERIPH, TIMER_CH, &ocpara);// 配置模式 TIMER_OC_MODE_PWM0 和 TIMER_OC_MODE_PWM1 相反timer_channel_output_mode_config(TIMER_PERIPH, TIMER_CH, TIMER_OC_MODE_PWM0);// 占空比timer_channel_output_pulse_value_config(TIMER_PERIPH, TIMER_CH, 0.5 * (period_t - 1));
}
3.3 动态调整占空比
/*** @brief 更新指定Timer的channel的占空比** @param timer_periph TIMERx(x=0,1,2,3,4,5,6,7,8,9,10,11,12,13)* @param channel TIMER_CH_0, TIMER_CH_1, TIMER_CH_2, TIMER_CH_3* @param t_period 周期 [1, 65536]* @param duty 占空比 [0.0, 100.0]*/
static void TIMER_channel_duty_update(uint32_t timer_periph, uint16_t channel, uint32_t t_period, float duty) {// 占空比timer_channel_output_pulse_value_config(timer_periph, channel, (duty / 100.0) * (t_period - 1));
}
3.4 蜂鸣器应用
利用PWM生成音频信号:
四、高级定时器
高级定时器(TIMER0和TIMER7)支持更复杂的功能,如互补PWM输出和死区控制。
4.1 互补PWM输出
// 保护电路也是公共的// break 只针对高级定时器TIMER0 & TIMER7,需要打开互补保护电路/* TIMER通道互补保护电路 */timer_break_parameter_struct breakpara;/* 初始化TIMER break参数结构体 */timer_break_struct_para_init(&breakpara);/* break输入的极性 HIGH */breakpara.breakpolarity = TIMER_BREAK_POLARITY_HIGH;/* 输出自动的启用 */breakpara.outputautostate = TIMER_OUTAUTO_ENABLE;/* bread输入的启用*/breakpara.breakstate = TIMER_BREAK_ENABLE;/* 死区时间 [0, 255] */// breakpara.deadtime = 128;/* 配置TIMER break */timer_break_config(TIMER0, &breakpara);/* 启用TIMER break */timer_break_enable(TIMER0);
4.2 死区时.间配置
防止互补输出同时导通:
breakpara.deadtime = 100; // 设置死区时间
五、定时器库封装
为了提高代码复用性和可维护性,可以封装定时器驱动库:
5.1 配置文件
TIMER_config.h
#ifndef __TIMER_CONFIG_H__
#define __TIMER_CONFIG_H__#include "gd32f4xx.h"#define USE_TIMER_0 0 // 高级
#define USE_TIMER_1 0
#define USE_TIMER_2 0
#define USE_TIMER_3 1 // LED5 ~ 8
#define USE_TIMER_4 0
#define USE_TIMER_5 0 //基本
#define USE_TIMER_6 0 //基本
#define USE_TIMER_7 0 // 高级
#define USE_TIMER_8 0
#define USE_TIMER_9 0
#define USE_TIMER_10 0
#define USE_TIMER_11 0
#define USE_TIMER_12 0
#define USE_TIMER_13 0#if USE_TIMER_0
// 启用TIMER0的情况下,才需要配置如下参数
#define TM0_PRESCALER 10
#define TM0_FREQ 1000
#define TM0_PERIOD (SystemCoreClock / TM0_PRESCALER / TM0_FREQ)// TIMER0CHx对应的引脚所有参数
// TIMER0_CH0 ON PE8
#define TM0_CH0_ON RCU_GPIOE, GPIOE, GPIO_PIN_8, GPIO_OTYPE_PP, GPIO_AF_1
// TIMER0_CH0 OP PE9
#define TM0_CH0_OP RCU_GPIOE, GPIOE, GPIO_PIN_9, GPIO_OTYPE_PP, GPIO_AF_1//// TIMER0_CH1 ON PE10
//#define TM0_CH1_ON RCU_GPIOE, GPIOE, GPIO_PIN_10, GPIO_OTYPE_PP, GPIO_AF_1
//// TIMER0_CH1 OP PE11
//#define TM0_CH1_OP RCU_GPIOE, GPIOE, GPIO_PIN_11, GPIO_OTYPE_PP, GPIO_AF_1#endif#if USE_TIMER_1
// 启用TIMER1的情况下,才需要配置如下参数
#define TM1_PRESCALER 10
#define TM1_FREQ 1000
#define TM1_PERIOD (SystemCoreClock / TM1_PRESCALER / TM1_FREQ)// TIMER1CHx对应的引脚所有参数
// #define TM1_CH0 RCU_GPIOA, GPIOA, GPIO_PIN_8, GPIO_AF_2
#define TM1_CH1 RCU_GPIOB, GPIOB, GPIO_PIN_9, GPIO_AF_1#endif#if USE_TIMER_3
// 启用TIMER3的情况下,才需要配置如下参数
#define TM3_PRESCALER 10
#define TM3_FREQ 1000
#define TM3_PERIOD (SystemCoreClock / TM3_PRESCALER / TM3_FREQ)// TIMER3CHx对应的引脚所有参数
#define TM3_CH0 RCU_GPIOD, GPIOD, GPIO_PIN_12, GPIO_OTYPE_PP, GPIO_AF_2
#define TM3_CH1 RCU_GPIOD, GPIOD, GPIO_PIN_13, GPIO_OTYPE_PP, GPIO_AF_2
#define TM3_CH2 RCU_GPIOD, GPIOD, GPIO_PIN_14, GPIO_OTYPE_PP, GPIO_AF_2
#define TM3_CH3 RCU_GPIOD, GPIOD, GPIO_PIN_15, GPIO_OTYPE_PP, GPIO_AF_2
#endif#endif
5.2 统一接口函数
TIMER.h文件
#ifndef __TIMER_H__
#define __TIMER_H__#include "gd32f4xx.h"
#include "TIMER_config.h"// 初始化
void TIMER_init();/*** @brief 更新指定Timer的channel的占空比** @param timer_periph TIMERx(x=0,1,2,3,4,5,6,7,8,9,10,11,12,13)* @param channel TIMER_CH_0, TIMER_CH_1, TIMER_CH_2, TIMER_CH_3* @param t_period 周期 [1, 65536]* @param duty 占空比 [0.0, 100.0]*/
void TIMER_channel_duty_update(uint32_t timer_periph, uint16_t channel, uint32_t t_period, float duty);#endif
TIMER.c文件
#include "TIMER.h"
#include "gpio_cfg.h"/*** @brief Timer定时器初始化配置** @param rcu TIMER的RCU* @param timer_periph TIMERx(x=0,1,2,3,4,5,6,7,8,9,10,11,12,13)* @param t_perscaler 分频系数* @param t_period 周期*/
static void timer_init_config(rcu_periph_enum rcu, uint32_t timer_periph,uint16_t t_perscaler, uint32_t t_period) {// 时钟使能rcu_periph_clock_enable(rcu);// 重置timer_deinit(timer_periph);// 定义结构体变量timer_parameter_struct initpara;// 给结构体成员配置默认值timer_struct_para_init(&initpara);// 修改关键成员// SystemCoreClock/用户指定的频率 用户指定的频率 >= 2564initpara.period = t_period - 1; // 周期initpara.prescaler = t_perscaler - 1; // 分频 // 初始化定时器timer_init(timer_periph, &initpara);// 启动定时器timer_enable(timer_periph);
}/*** @brief 输出通道配置* * @param timer_periph TIMERx(x=0,1,2,3,4,5,6,7,8,9,10,11,12,13)* @param channel TIMER_CH_0, TIMER_CH_1, TIMER_CH_2, TIMER_CH_3* @param flag 1 正极, 2 负极, 3 正负极*/
static void timer_channel_config(uint32_t timer_periph, uint16_t channel, uint8_t flag) {// ====================== PWM相关timer_oc_parameter_struct ocpara;// 初始化结构体默认参数timer_channel_output_struct_para_init(&ocpara);// 修改关键成员if (flag == 1) {ocpara.outputstate = TIMER_CCX_ENABLE; // 正极} else if (flag == 2) { // 负极ocpara.outputnstate = TIMER_CCXN_ENABLE; // 负极} else { // 正负极ocpara.outputstate = TIMER_CCX_ENABLE; // 正极ocpara.outputnstate = TIMER_CCXN_ENABLE; // 负极}// 输出通道配置timer_channel_output_config(timer_periph, channel, &ocpara);// 配置模式 TIMER_OC_MODE_PWM0 和 TIMER_OC_MODE_PWM1 相反timer_channel_output_mode_config(timer_periph, channel, TIMER_OC_MODE_PWM0);
}/*** @brief 更新指定Timer的channel的占空比** @param timer_periph TIMERx(x=0,1,2,3,4,5,6,7,8,9,10,11,12,13)* @param channel TIMER_CH_0, TIMER_CH_1, TIMER_CH_2, TIMER_CH_3* @param t_period 周期 [1, 65536]* @param duty 占空比 [0.0, 100.0]*/
void TIMER_channel_duty_update(uint32_t timer_periph, uint16_t channel, uint32_t t_period, float duty) {// 占空比timer_channel_output_pulse_value_config(timer_periph, channel, (duty / 100.0) * (t_period - 1));
}// 初始化
void TIMER_init() {// 4倍频,最大值为168Mrcu_timer_clock_prescaler_config(RCU_TIMER_PSC_MUL4);#if USE_TIMER_0 // ====== 定时器0// 公共的// 定时器初始化配置timer_init_config(RCU_TIMER0, TIMER0, TM0_PRESCALER, TM0_PERIOD); // ====== 通道0 ==========// 如果有定义TM0_CH0_ON 和 TM0_CH0_OP 两个宏,不关心定义#if defined (TM0_CH0_ON) && defined (TM0_CH0_OP)// 引脚IOGPIO_output_af(TM0_CH0_ON);GPIO_output_af(TM0_CH0_OP);// 通道配置timer_channel_config(TIMER0, TIMER_CH_0, 3); // 3为正负极#endif// ====== 通道1 ==========#if defined (TM0_CH1_ON) && defined (TM0_CH1_OP)// 引脚IOGPIO_output_af(TM0_CH1_ON);GPIO_output_af(TM0_CH1_OP);// 通道配置timer_channel_config(TIMER0, TIMER_CH_1, 3); // 3为正负极#endif// 保护电路也是公共的// break 只针对高级定时器TIMER0 & TIMER7,需要打开互补保护电路/* TIMER通道互补保护电路 */timer_break_parameter_struct breakpara;/* 初始化TIMER break参数结构体 */timer_break_struct_para_init(&breakpara);/* break输入的极性 HIGH */breakpara.breakpolarity = TIMER_BREAK_POLARITY_HIGH;/* 输出自动的启用 */breakpara.outputautostate = TIMER_OUTAUTO_ENABLE;/* bread输入的启用*/breakpara.breakstate = TIMER_BREAK_ENABLE;/* 死区时间 [0, 255] */// breakpara.deadtime = 128;/* 配置TIMER break */timer_break_config(TIMER0, &breakpara);/* 启用TIMER break */timer_break_enable(TIMER0);#endif#if USE_TIMER_3 // ====== 定时器3// 公共的 定时器初始化配置timer_init_config(RCU_TIMER3, TIMER3, TM3_PRESCALER, TM3_PERIOD); // ============ 通道#if defined (TM3_CH0)GPIO_output_af(TM3_CH0);timer_channel_config(TIMER3, TIMER_CH_0, 1); // 1为正极#endif#if defined (TM3_CH1)GPIO_output_af(TM3_CH1);timer_channel_config(TIMER3, TIMER_CH_1, 1); // 1为正极#endif#if defined (TM3_CH2)GPIO_output_af(TM3_CH2);timer_channel_config(TIMER3, TIMER_CH_2, 1); // 1为正极#endif#if defined (TM3_CH3)GPIO_output_af(TM3_CH3);timer_channel_config(TIMER3, TIMER_CH_3, 1); // 1为正极#endif#endif}