GD32F407单片机开发入门(六)定时器TIMER详解及实战含源码
文章目录
- 一.概要
- 二.通用定时器内部结构
- 1.时基单元
- 2.时钟源
- 3.输入捕获
- 4.输出比较
- 三.通用定时器内部特色
- 四.TIME定时器1ms中断例程
- 五.工程源代码下载
- 六.小结
一.概要
定时器就是计数器,应用在我们生活的方方面面,比如有闹钟、计时器等。在GD32F407VET6定时器分为3类,即高级控制定时器(TIM0,TIM7)、通用定时器(TIM1,TIM2,TIM3,TIM4,TIM8,TIM9,TIM10,TIM11,TIM12,TIM13),基本定时器(TIM5,TIM6),要学会定时器要懂得分频设置、计数器设置等。
1、高级控制定时器
高级控制定时器由一个16位的自动装载计数器组成,它由一个可编程的预分频器驱动。它适合多种用途,包含测量输入信号的脉冲宽度(输入捕获),或者产生输出波形(输出比较、PWM、嵌入死区时间的互补PWM等)。使用定时器预分频器和RCC时钟控制预分频器,可以实现脉冲宽度和波形周期从几个微秒到几个毫秒的调节。高级控制定时器(TIM0)和通用定时器(TIM1,TIM2,TIM3等)是完全独立的,他们不共享任何资源,但他们可以被同步在一起形成一个更大的定时器。
2、通用定时器
通用定时器是一个通过可编程预分频器驱动的16位自动装载计数器构成。它适用于多种场合,包括测量输入信号的脉冲长度(输入捕获)或者产生输出波形(输出比较和PWM)。使用定时器预分频器和RCC时钟控制器预分频器,脉冲长度和波形周期可以在几个微秒到几个毫秒间调整。每个定时器都是完全独立的,没有互相共享任何资源,他们可以一起同步操作。
3、基本定时器
基本定时器 包含一个 16 位自动重载计数器,该计数器由可编程预分频器驱动。此类定时器不仅可用作通用定时器以生成时基,还可以专门用于驱动数模转换器 (DAC) ,基本定时器可以配置产生DMA请求,TRGO触发连接到DAC 。
我们以通用定时器为例,通用定时器能应付我们一般使用场景,后面对定时器的内部构造,配置使用,实际使用进行一一讲解
二.通用定时器内部结构
通用定时器由4部分组成:①时基单元 ②时钟源 ③输入捕获 ④输出比较。
1.时基单元
时基单元包含:
● 计数器寄存器(TIMERx_CNT) :存储定时器当前的计数值,有向上计数、向下计数或者中心对齐向计数方式,最常用是向上对齐,CNT 达到自动重载值(溢出或下溢)时,触发更新事件(Update Event),可用于生成定时中断或DMA请求。
● 预分频器寄存器 (TIMERx_PSC) :可将时钟频率按1到65536之间的任意值进行分频,可在运行时改变其设置值。
● 自动装载寄存器 (TIMERx_CAR) :
在向上计数模式中,TIMERx_CNT计数器从0计数到自动装载寄存器值(TIMERx_CAR的内容),然后重新从0开始计数并且产生一个计数器溢出事件。
自动装载寄存器是预先装载的,写或读自动重装载寄存器将访问预装载寄存器。如下图所示,根据在TIMERx_CTL0寄存器中的自动装载预装载使能位(ARSE)的设置,预装载寄存器的内容被立即或在每次的更新事件UPE时传送到影子寄存器。当计数器达到溢出条件(向下计数时的下溢条件),产生更新事件。
ARSE=0,当TIMERx_CAR值被修改时,同时马上更新影子寄存器的值。
ARSE=1,当TIMERx_CAR值被修改时,必须在下一次更新事件UPE发生后才能更新影子寄存器的值,当计数器产生溢出条件时,产生更新事件。
上图中圈出来带了阴影的寄存器表示该寄存器存在影子寄存器,这些有影子寄存的寄存器在物理上对应了两个寄存器,一个是开放出来给程序员可以写入和读出的预装载寄存器(preloadregister),比如TIMERx_CAR,TIMERx_PSC,捕获/比较等寄存器;另一个并没有开放出来,即程序员看不见的、但在操作中真正起作用的影子寄存器(shadowregister)。
设计影子寄存器的好处:
每次发生更新事件(UPE)时,所有真正起作用的影子寄存器可以同时被更新为预装载寄存器 (preloadregister)里面的值,这样可以保证多个通道的操作能够准确同步;如果没有影子寄存器,预装载寄存器和影子寄存器是直通的,当软件更新了预装载寄存器,也就立即更新了影子寄存器,由于软件不能同时更新多个影子寄存器,这就会导致多个通道的时序不能同步。
2.时钟源
根据模式不同,选择的时钟源也不同。
主模式:
1.时钟源可以选择内部时钟 (TIMER_CK),计数器预分频器时钟源由内部时钟TIMER_CK驱动。
从模式:
1.时钟源可以选择外部输入脚 (TIMERx_ETI):计数器预分频器可以在外部引脚ETI的每个上升沿或下降沿计数。
2.时钟源可以选择TIMERx_CIx通过数字滤波器采样后的信号:计数器预分频器可以在TIMERx_CI0/ TIMERx_CI1引脚的每个上升沿或下降沿计数。
3.时钟源可以选择ITI0/1/2/3:计数器预分频器也可以在内部触发信号ITI0/1/2/3的上升沿计数。
我们通常使用内部时钟 (TIMER_CK)作为时钟源。
3.输入捕获
捕获模式允许通道测量一个波形时序,频率,周期,占空比等。输入级包括一个数字滤波器,一个通道极性选择,边沿检测和一个通道预分频器。如果在输入引脚上出现被选择的边沿,TIMERx_CHxCV寄存器会捕获计数器当前的值。
4.输出比较
在输出比较模式,TIMERx可以产生时控脉冲,其位置,极性,持续时间和频率都是可编程的。当一个输出通道的CxCV寄存器与计数器的值匹配时,根据CHxCOMCTL的配置,这个通道的输出可以被置高电平,被置低电平或者反转。
输出比较的时序图如下图所示,比如配置自动装载CAR=63, 输出通道CxCV=3。
三.通用定时器内部特色
总通道数:4;
计数器宽度:16位(TIMER2和3),32位(TIMER1和4);
时钟源可选:内部时钟,内部触发,外部输入,外部触发;
多种计数模式:向上计数,向下计数和中央计数;
正交编码器接口:被用来追踪运动和分辨旋转方向和位置;
霍尔传感器接口:用来做三相电机控制;
可编程的预分频器:16位,运行时可以被改变;
每个通道可配置:输入捕获模式,输出比较模式,可编程的PWM模式,单脉冲模式;
自动重装载功能;
中断输出和DMA请求:更新事件,触发事件,比较/捕获事件;
多个定时器的菊链使得一个定时器可以同时启动多个定时器;
定时器的同步允许被选择的定时器在同一个时钟周期开始计数;
定时器主/从模式控制器。
四.TIME定时器1ms中断例程
1.硬件准备
STLINK接GD32F407VET6开发板,STLINK接电脑USB口。
2.实验原理
通过配置定时器1每1mS进入中断一次,每进入中断服务程序一次,增加一次计数,计数到达500,控制PB4引脚输出高或低电平,从而实现1S钟周期闪烁。
3.主要代码
#include "gd32f4xx.h"
#include "gd32f4xx_libopt.h"
#include "systick.h"//定时器配置
void timer_config(void)
{/* -----------------------------------------------------------------------系统主频168MHZ,timer_initpara.prescaler为167,timer_initpara.period为999,频率就为1KHZ----------------------------------------------------------------------- */timer_parameter_struct timer_initpara;rcu_periph_clock_enable(RCU_TIMER1);rcu_timer_clock_prescaler_config(RCU_TIMER_PSC_MUL4);//AP1总线最高42MHZ,所以TIME1到168M需要4倍频timer_deinit(TIMER1);/* TIMER1 configuration */timer_initpara.prescaler = 167;timer_initpara.alignedmode = TIMER_COUNTER_EDGE;timer_initpara.counterdirection = TIMER_COUNTER_UP;timer_initpara.period = 999;timer_initpara.clockdivision = TIMER_CKDIV_DIV1;timer_initpara.repetitioncounter = 0;timer_init(TIMER1,&timer_initpara);nvic_priority_group_set(NVIC_PRIGROUP_PRE1_SUB3);nvic_irq_enable(TIMER1_IRQn, 0, 1);timer_interrupt_enable(TIMER1, TIMER_INT_UP);/* auto-reload preload enable */timer_auto_reload_shadow_enable(TIMER1);/* auto-reload preload enable */timer_enable(TIMER1);
}
uint32_t TIME1_CNT; //读取定时器计数寄存器
int main(void)
{systick_config();//配置系统主频168M,外部8M晶振,配置在#define __SYSTEM_CLOCK_168M_PLL_8M_HXTAL (uint32_t)(168000000)rcu_periph_clock_enable(RCU_GPIOB);//GPIOB时钟使能gpio_mode_set(GPIOB, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, GPIO_PIN_4);//PB4配置成输出gpio_output_options_set(GPIOB, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_4);//PB4配置成推挽输出,50M速度timer_config();//定时器1配置,1ms中断一次while(1){TIME1_CNT=timer_counter_read(TIMER1);//读取TIMER1_CNT寄存器值}
}uint32_t Timcounter;//时间计数,1ms增加一次
uint8_t LedFlag;//亮或者灭控制标志
//定时器1中断服务程序,1ms中断一次
void TIMER1_IRQHandler(void)
{if(SET == timer_interrupt_flag_get(TIMER1, TIMER_INT_FLAG_UP))//读取到溢出中断{timer_interrupt_flag_clear(TIMER1,TIMER_INT_FLAG_UP);//清溢出中断标志Timcounter++;if(Timcounter>=500)//计数到500ms,LED灯输出状态变换一次{Timcounter=0;LedFlag^=0x01;}if(LedFlag)//计数到500ms,翻转输出{gpio_bit_set(GPIOB,GPIO_PIN_4);//PB4输出高电平}else{gpio_bit_reset(GPIOB,GPIO_PIN_4);//PB4输出低电平}}
}
4.调试代码
如下图在定时器1的溢出中断服务程序中设置断点,可以看到1ms就会运行到断点处。中断发生时,读取计数器寄存器(TIMERx_CNT)与自动装载寄存器 (TIMERx_CAR),可以发现两个值是相等,退出中断后,计数器寄存器(TIMERx_CNT)又会从0开始计数。
去掉程序中的断点,全速运行,可以看到LED灯以1S周期闪烁。
五.工程源代码下载
源代码链接如下:
CSDN
六.小结
通过定时器周期性地产生中断信号,可以实现系统定时和时间戳等功能。例如,在智能家居系统中,可以使用定时器控制各种设备的开关,在工业控制系统中,定时器可以用于检测传感器数据并执行相应的动作,定时器还可以配合PWM模块实现对电机等设备的精确控制。通过定时器产生固定频率的方波信号,然后使用PWM模块将其转化为可调节占空比的脉冲信号,从而实现对电机速度和输出功率的控制。