5.1.TIMER 基础知识
TIMER分高级定时器,通用定时器L0,L1,L2和基本定时器。

5.2.硬件连接说明
TIMER 属于片内外设,对于外部硬件设计,只需要单独IO口外接信号线即可。
5.3.GD32 TIMER 外设原理简介(以 GD32F30X 的高级定时器为例)
GD32 TIMER 主要特性
◼ 总通道数: 4;
◼ 计数器宽度: 16位;
◼ 定时器时钟源可选:内部时钟,内部触发,外部输入,外部触发;
◼ 多种计数模式:向上计数,向下计数和中央计数;
◼ 可编程的预分频器: 16位。运行时可以被改变;
◼ 每个通道可配置:输入捕获模式,输出比较模式,可编程的PWM模式,单脉冲模式;
◼ 可编程的死区时间;
◼ 自动重装载功能;
◼ 可编程的计数器重复功能;
◼ 中止输入功能;
◼ 中断输出和DMA请求:更新事件,触发事件,比较/捕获事件和中止事件;
◼ 多个定时器的菊链使得一个定时器可以同时启动多个定时器;
◼ 定时器的同步允许被选择的定时器在同一个时钟周期开始计数;
◼ 定时器主/从模式控制器。
TIMER 结构框图介绍

5.4.软件配置说明
定时中断 TIMER4
通用定时器L0(TIMER1/2/3/4) 是4通道定时器,支持输入捕获,输出比较,产生PWM信号控制电机和电源管理。通用定时器L0计数器是16位无符号计数器。通用定时器L0是可编程的,可以被用来计数,其外部事件可以驱动其他定时器。
这一章,将使用定时器产生中断,然后在中断服务函数里面翻转 LED上的电平,来指示定时器中断的产生。接下来我们以通用定时器 TIMER4 为实例,来说明要经过哪些步骤,才能达到这个要 求,并产生中断。定时器配置步骤如下:
1)TIMER4 时钟使能
rcu_periph_clock_enable(RCU_TIMER4);
2) 初始化定时器参数,设置自动重装值,分频系数,计数方式等
在库函数中,定时器的初始化参数是通过初始化函数timer_parameter_struct 实现的:
void timer_init(uint32_t timer_periph, timer_parameter_struct* initpara);
第一个参数是确定是哪个定时器,这个比较容易理解。第二个参数是定时器初始化参数结构体指针,结构体类型为timer_parameter_struct ,下面我们看看这个结构体的定义:
/* TIMER init parameter struct definitions */ typedef struct { uint16_t prescaler; /*!
针对 TIMR4 初始化范例代码格式
timer_initpara.prescaler = 5999; //30M/6000 =500Hz timer_initpara.alignedmode = TIMER_COUNTER_EDGE; timer_initpara.counterdirection = TIMER_COUNTER_UP; timer_initpara.period = 4000-1; //800ms timer_initpara.clockdivision = TIMER_CKDIV_DIV1; timer_init(TIMER4, &timer_initpara);
对于定时器定时周期的计算,设 TIMER4 的经过总线分频后得到的时钟为 30MHz,通过预分频 5999,得到 TIMER4 每个计 数的时钟为 1/(30MHz / (5999+1)) =0.2ms,4000 得到的周期为 0.2ms *4000 =800ms
3)设置 TIMER 允许更新中断
因为我们要使用 TIMER4 的更新中断,寄存器的相应位便可使能更新中断。在库函数里面定时器中断使能是通过timer_interrupt_enable函数来实现的:
void timer_interrupt_enable(uint32_t timer_periph, uint32_t interrupt);
第一个参数是选择定时器号,这个容易理解。
第二个参数非常关键,是用来指明我们使能的定时器中断的类型。
4) TIMER4 中断优先级设置
在定时器中断使能之后,因为要产生中断,必不可少的要设置 NVIC 相关寄存器,设置中断优先级。通过nvic_irq_enable 函数实现中断优先级的设置。
针对 TIMR4 初始化范例代码格式
nvic_irq_enable(TIMER4_IRQn, 1, 1);
5)允许 TIMER工作,也就是使能 TIMER
光配置好定时器还不行,没有开启定时器,照样不能用。我们在配置完后要开启定时器,在固件库里面使能定时器的函数是通过timer_enable函数来实现的
void timer_enable(uint32_t timer_periph)
这个函数非常简单,比如我们要使能TIMER4,方法为:
timer_enable(TIMER4);
6)编写中断服务函数
在最后,还是要编写定时器中断服务函数,通过该函数来处理定时器产生的相关中断。中断产生后,通过状态寄存器的值来判断此次产生的中断属于什么类型。然后执行相关的操作,我们这里使用的是更新(溢出)中断,在处理完中断之后应来清除该中断标志。
在固件库函数里面,用来读取中断状态寄存器的值判断中断类型的函数是:
FlagStatus timer_interrupt_flag_get(uint32_t timer_periph, uint32_t interrupt)
该函数的作用是,判断定时器 TIMER 的中断类型,并判断是否发生中断。
针对 TIMR4 中断服务函数范例代码:
void TIMER4_IRQHandler(void) { if(SET == timer_interrupt_flag_get(TIMER4, TIMER_INT_UP)){ /* clear channel 0 interrupt bit */ timer_interrupt_flag_clear(TIMER4, TIMER_INT_UP); gd_eval_led_toggle(LED2); } }
PWM 输出 TIMER0
高级定时器(TIMER0和TIMER7)是四通道定时器,支持输入捕获和输出比较。可以产生PWM信号控制电机和电源管理。高级定时器含有一个16位无符号计数器。高级定时器是可编程的,可以用来计数,其外部事件可以驱动其他定时器。高级定时器包含了一个死区时间插入模块,非常适合电机控制。
本章,我们使用的是 TIMER0的通道0 输出 PWM(脉冲宽度调制)。
下面我们介绍通过库函数来配置该功能的步骤:
(1)开启 TIMER0 和 GPIO 时钟,配置 PA8复用功能输出。
rcu_periph_clock_enable(RCU_TIMER0); rcu_periph_clock_enable(RCU_GPIOA); gpio_init(GPIOA, GPIO_MODE_AF_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_8);
这里还需要说明一下, 对于定时器通道的引脚关系,引脚的IO口

这里补充说明下关于TIMER的相关GPIO口的命名
TIMERx_CHx : 定时器通道x
TIMERx_CHx_ON :定时器反向通道
TIMERx_BRKIN :刹车引脚
TIMERx_ETI:外部时钟输入
(2)初始化 TIMER0 ,设置 TIMER0 的预分频和周期等参数, ,在上一节定时器中断章节我们已经有讲解,这里就不详细讲解,调用的格式为
timer_initpara.prescaler = 5999; timer_initpara.alignedmode = TIMER_COUNTER_EDGE; timer_initpara.counterdirection = TIMER_COUNTER_UP; timer_initpara.period = 4000; timer_initpara.clockdivision = TIMER_CKDIV_DIV1; timer_initpara.repetitioncounter = 0; timer_init(TIMER0, &timer_initpara);
3)设置 TIMER0_CH0 的 PWM 模式, 使能 TIMER0 的 CH0 输出。 在库函数中, PWM 通道设置是通过函数timer_channel_output_config来设置的
void timer_channel_output_config(uint32_t timer_periph, uint16_t channel, timer_oc_parameter_struct* ocpara)
我们直接来看看结构体timer_oc_parameter_struct的定义:
typedef struct { uint16_t outputstate; /*!< channel output state */ uint16_t outputnstate; /*!< channel complementary output state */ uint16_t ocpolarity; /*!< channel output polarity */ uint16_t ocnpolarity; /*!< channel complementary output polarity */ uint16_t ocidlestate; /*!< idle state of channel output */ uint16_t ocnidlestate; /*!< idle state of channel complementary output */ }timer_oc_parameter_struct;
针对 TIMR0 CH0 初始化范例代码格式
/* CH0, CH1 and CH2 configuration in PWM mode */ timer_ocinitpara.outputstate = TIMER_CCX_ENABLE; timer_ocinitpara.outputnstate = TIMER_CCXN_DISABLE; timer_ocinitpara.ocpolarity = TIMER_OC_POLARITY_HIGH; timer_ocinitpara.ocnpolarity = TIMER_OCN_POLARITY_HIGH; timer_ocinitpara.ocidlestate = TIMER_OC_IDLE_STATE_LOW; timer_ocinitpara.ocnidlestate = TIMER_OCN_IDLE_STATE_LOW; timer_channel_output_config(TIMER0, TIMER_CH_0, &timer_ocinitpara);
4)设置PWM输出以及脉冲宽度占空比
timer_channel_output_pulse_value_config(TIMER0, TIMER_CH_0, 2000); timer_channel_output_mode_config(TIMER0, TIMER_CH_0, TIMER_OC_MODE_PWM0); timer_channel_output_shadow_config(TIMER0, TIMER_CH_0, TIMER_OC_SHADOW_DISABLE); timer_primary_output_config(TIMER0,ENABLE);
5)使能 TIMER0
在完成以上设置了之后,我们需要使能 TIMER0。使能 TIMER0 的方法前面已经讲解过:
timer_enable(TIMER0);
通过以上 5 个步骤,我们就可以控制 TIMER0的 CH0 输出 PWM 波了。这里特别提醒一下大家,高级定时器虽然和通用定时器类似,但是高级定时器要想输出 PWM,必须多额外加一条函数
void timer_primary_output_config(uint32_t timer_periph, ControlStatus newvalue);
输入捕获 TIMER2
通用定时器L0(TIMER1/2/3/4) 是4通道定时器,支持输入捕获,输出比较,产生PWM信号控制电机和电源管理。通用定时器L0计数器是16位无符号计数器。通用定时器L0是可编程的,可以被用来计数,其外部事件可以驱动其他定时器。
本章要实现通过输入捕获,来获取TIMER2_CH0(PA6)上面的下降沿,下面我们介绍库函数配置上述功能输入捕获的步骤:
1)开启 TIMER2 时钟,配置 PA6为复用功能,并开启上拉电阻。
rcu_periph_clock_enable(RCU_TIMER2); rcu_periph_clock_enable(RCU_GPIOA); gpio_init(GPIOA, GPIO_MODE_IPU, GPIO_OSPEED_50MHZ, GPIO_PIN_6); //INCUPTURE -TIMER2
跟上一讲 PWM 输出类似,这里我们使用的是定时器2的通道 0,所以我们从对应的数据手册可以查看到对应的 IO 口为 PA6:

2) 初始化定时器参数,设置自动重装值, 分频系数,计数方式等
/* TIMER2 configuration */ timer_initpara.prescaler = 5999; timer_initpara.alignedmode = TIMER_COUNTER_EDGE; timer_initpara.counterdirection = TIMER_COUNTER_UP; timer_initpara.period = 4000; timer_initpara.clockdivision = TIMER_CKDIV_DIV1; timer_init(TIMER2, &timer_initpara);
3)设置 TIMER2 的输入捕获参数,开启输入捕获
库函数是通过 timer_input_capture_config 函数来初始化输入比较参数的: timer_input_capture_config(TIMER2,TIMER_CH_0,&timer_icinitpara);
同样,我们来看看参数设置结构体 TIM_ICInitTypeDef 的定义:
typedef struct { uint16_t icpolarity; /*!< channel input polarity */ uint16_t icselection; /*!< channel input mode selection */ uint16_t icprescaler; /*!< channel input capture prescaler */ uint16_t icfilter; /*!< channel input capture filter control */ }timer_ic_parameter_struct;
我们的配置代码是:
/* initialize TIMER channel input parameter struct */ timer_channel_input_struct_para_init(&timer_icinitpara); /* TIMER2 CH0 input capture configuration */ timer_icinitpara.icpolarity = TIMER_IC_POLARITY_RISING; timer_icinitpara.icselection = TIMER_IC_SELECTION_DIRECTTI; timer_icinitpara.icprescaler = TIMER_IC_PSC_DIV1; timer_icinitpara.icfilter = 0x0; timer_input_capture_config(TIMER2,TIMER_CH_0,&timer_icinitpara);
4) 使能捕获中断和NVIC
timer_interrupt_enable(TIMER2,TIMER_INT_CH0); nvic_irq_enable(TIMER2_IRQn, 1, 1);
5) 编写中断服务函数
void TIMER2_IRQHandler(void){……}
6) 使能定时器
timer_enable(TIMER2);
通过以上 6 步设置,定时器 2 的通道 0 就可以开始输入捕获了
外部时钟输入 TIMER1
通用定时器L0(TIMER1/2/3/4) 是4通道定时器,支持输入捕获,输出比较,产生PWM信号控制电机和电源管理。通用定时器L0计数器是16位无符号计数器。通用定时器L0是可编程的,可以被用来计数,其外部事件可以驱动其他定时器。
本章要实现使用TIMER1 PA0 作为时钟输入引脚,配置流程:
(1)使能GPIO,TIMER 时钟和GPIO口复用配置
rcu_periph_clock_enable(RCU_GPIOA); rcu_periph_clock_enable(RCU_AF); rcu_periph_clock_enable(RCU_TIMER1); gpio_init(GPIOA,GPIO_MODE_IN_FLOATING,GPIO_OSPEED_50MHZ,GPIO_PIN_0);

(2)通过查看数据手册,可以看到TIMER1_CH0_ETI,根据前面所讲,是可以支持外部时钟输入的。
TIMER的结构体,初始化定时器参数,设置自动重装值, 分频系数,计数方式等
//ETI timer_initpara.prescaler = 1; // 2 分频 timer_initpara.alignedmode = TIMER_COUNTER_EDGE; timer_initpara.counterdirection = TIMER_COUNTER_UP; timer_initpara.period = 65535; timer_initpara.clockdivision = TIMER_CKDIV_DIV1; timer_initpara.repetitioncounter = 0; timer_init(TIMER1,&timer_initpara); timer_enable(TIMER1);
(3)配置TIMER的时钟来源和时钟源处理的配置
timer_input_trigger_source_select(TIMER1,TIMER_SMCFG_TRGSEL_ETIFP); timer_external_clock_mode1_config(TIMER1, TIMER_EXT_TRI_PSC_OFF, TIMER_ETP_RISING, 0);
(4)使能TIMER
timer_enable(TIMER1);
5.5.TIMER 使用注意事项
TIMER 高级定时器 做定时用的时候(使用到UPDAT中断),在产生中断之后,高级定时器的其他所有的状态标志位会被置位,但是不会置位中断标志位.
本教程由GD32 MCU方案商聚沃科技原创发布,了解更多GD32 MCU教程,关注聚沃科技官网
-
单片机
+关注
关注
6074文章
45340浏览量
663536 -
开发板
+关注
关注
25文章
6122浏览量
113322 -
Timer
+关注
关注
1文章
64浏览量
13472 -
GD32
+关注
关注
7文章
429浏览量
26938
发布评论请先 登录
GD32 MCU 入门教程】GD32 MCU 常见外设介绍(12)FMC 模块介绍
《GD32 MCU原理及固件库开发指南》 + 初读感悟
兆易创新GD32 MCU选型手册,适用于GD32全系列MCU
【GD32 MCU 入门教程】一、GD32 MCU 开发环境搭建(1)使用Keil开发GD32
【GD32 MCU 入门教程】一、GD32 MCU 开发环境搭建(2)使用 IAR 开发 GD32
【GD32 MCU 入门教程】一、GD32 MCU 开发环境搭建(3)使用 Embedded Builder 开发 GD32
【GD32 MCU 入门教程】二、GD32 MCU 烧录说明(1)ISP 烧录
【GD32 MCU 入门教程】GD32 MCU 常见外设介绍(14)RTC 模块介绍
【GD32 MCU入门教程】GD32 MCU GPIO 结构与使用注意事项

【GD32 MCU 入门教程】GD32 MCU 常见外设介绍 (5) TIMER 模块介绍
评论