零基础国产GD32单片机编程入门(四)定时器详解及实战含源码

一.概要

定时器的简介
定时器就是计数器,应用在我们生活的方方面面,比如有闹钟、计时器等。在GD32F103C8T6定时器分为2类,即高级控制定时器(TIM0)、通用定时器(TIM1,TIM2,TIM3),要学会定时器要懂得分频设置、计数器设置。

1、高级定时器(TIM0)
高级定时器(TIM0)由一个16位的自动装载计数器组成,它由一个可编程的预分频器驱动。它适合多种用途,包含测量输入信号的脉冲宽度(输入捕获),或者产生输出波形(输出比较、PWM、嵌入死区时间的互补PWM等)。使用定时器预分频器和RCC时钟控制预分频器,可以实现脉冲宽度和波形周期从几个微秒到几个毫秒的调节。高级控制定时器(TIM0)和通用定时器(TIM1,TIM2,TIM3)是完全独立的,它们不共享任何资源。

2、通用定时器(TIM1,TIM2,TIM3)
通用定时器是一个通过可编程预分频器驱动的16位自动装载计数器构成。它适用于多种场合,包括测量输入信号的脉冲长度(输入捕获)或者产生输出波形(输出比较和PWM)。使用定时器预分频器和RCC时钟控制器预分频器,脉冲长度和波形周期可以在几个微秒到几个毫秒间调整。每个定时器都是完全独立的,没有互相共享任何资源。

高级定时器除了具备通用定时器的所有功能外,还支持更高级的功能,如定时器级联,还有面向更复杂的应用,如BLDC电机控制、高精度测量等。

我们以通用定时器为例,通用定时器能应付我们大部分使用场景,后面对定时器的内部构造,配置使用,实际使用进行一一讲解

二.通用定时器内部结构

定时器计时原理:
首先,设置预分频器的值,以确定输入到计数器的时钟频率。然后,设置自动装载寄存器的值,这个值决定了延时的长度。最后,启动定时器,开始计数。当计数器的值达到自动装载寄存器的值时,将触发一个中断,完成延时任务。通过调整预分频器和自动装载寄存器的值,可以实现不同长度的延时,从而满足不同的应用需求‌。
计数器、自动装载寄存器和预分频器寄存器这三个组成了时基单元。

通用定时器由4部分组成:①时基单元 ②时钟源 ③输入捕获 ④输出比较。

在这里插入图片描述

1.时基单元

可编程通用定时器的主要部分是一个16位计数器和与其相关的自动装载寄存器。这个计数器可以向上计数、向下计数或者向上向下双向计数。此计数器时钟由预分频器分频得到。 计数器、自动装载寄存器和预分频器寄存器可以由软件读写,在计数器运行时仍可以读写。

在这里插入图片描述

时基单元包含:
● 计数器寄存器(TIMERx_CNT) :向上计数、向下计数或者中心对齐向计数,最常用是向上对齐。
● 预分频器寄存器 (TIMERx_PSC) :可将时钟频率按1到65536之间的任意值进行分频,可在运行时改变其设置值。
● 自动装载寄存器 (TIMERx_CAR) :
在向上计数模式中,计数器从0计数到自动装载寄存器值(TIMERx_CAR计数器的内容),然后重新从0开始计数并且产生一个计数器溢出事件。

ARSE=0,当TIMERx_CAR值被修改时,同时马上更新影子寄存器的值;ARSE=1,当TIMERx_CAR值被修改时,必须在下一次更新事件UPE发生后才能更新影子寄存器的值,当计数器产生溢出条件时,产生更新事件。

自动装载寄存器是预先装载的,写或读自动重装载寄存器将访问预装载寄存器。根据在
TIMERx_CTL0寄存器中的自动装载预装载使能位(ARSE)的设置,预装载寄存器的内容被立即或在每次的更新事件UPE时传送到影子寄存器。当计数器达到溢出条件(向下计数时的下溢条件),产生更新事件。

在这里插入图片描述

上图中圈出来带了阴影的寄存器表示该寄存器存在影子寄存器,这些有影子寄存的寄存器在物理上对应了两个寄存器,一个是开放出来给程序员可以写入和读出的预装载寄存器(preloadregister),比如CAR,PSC,捕获/比较等寄存器;另一个并没有开放出来,即程序员看不见的、但在操作中真正起作用的影子寄存器(shadowregister)。

设计影子寄存器的好处:
每次发生更新事件(UPE)时,所有真正起作用的影子寄存器可以同时被更新为预装载寄存器 (preloadregister)里面的值,这样可以保证多个通道的操作能够准确同步;如果没有影子寄存器,预装载寄存器和影子寄存器 是直通的,当软件更新了预装载寄存器,也就立即更新了影子寄存器,由于软件不能同时更新多个影子寄存器,这就会导致多个通道的时序不能同步。

ARSE=0,当TIMERx_CAR值被修改时,同时马上更新影子寄存器的值;
ARSE=1,当TIMERx_CAR值被修改时,必须在下一次事件UPE发生后才能更新影子寄存器的值

2.时钟源

根据模式不同,选择的时钟源也不同:
如果定时器是选择主模式:
① 时钟源可以选择内部时钟 (TIMER_CK),计数器预分频器时钟源由内部时钟TIMER_CK驱动。

如果定时器是选择从模式:
①时钟源可以选择外部输入脚 (TIMERx_ETI):计数器预分频器可以在外部引脚ETI的每个上升沿或下降沿计数。
②时钟源可以选择TIMERx_CIx通过数字滤波器采样后的信号:计数器预分频器可以在TIMERx_CI0/ TIMERx_CI1引脚的每个上升沿或下降沿计数。
③时钟源可以选择ITI0/1/2/3:计数器预分频器也可以在内部触发信号ITI0/1/2/3的上升沿计数。
在这里插入图片描述

我们通常使用内部时钟 (TIMER_CK)作为时钟源

3.输入捕获

捕获模式允许通道测量一个波形时序,频率,周期,占空比等。输入级包括一个数字滤波器,一个通道极性选择,边沿检测和一个通道预分频器。如果在输入引脚上出现被选择的边沿,TIMERx_CHxCV寄存器会捕获计数器当前的值。

在这里插入图片描述

4.输出比较

在输出比较模式,TIMERx可以产生时控脉冲,其位置,极性,持续时间和频率都是可编程的。当一个输出通道的CxCV寄存器与计数器的值匹配时,根据CHxCOMCTL的配置,这个通道的输出可以被置高电平,被置低电平或者反转。

如下图所示,比如配置自动装载CAR=63, 输出通道CxCV=3,输出比较的时序图

在这里插入图片描述

三.通用定时器内部特色

在这里插入图片描述

四.TIME定时器1ms中断例程

1.硬件准备
STLINK接GD32F103C8T6开发板,STLINK接电脑USB口。

在这里插入图片描述
2.实验原理
通过配置定时器1每1mS进入中断一次,每进入中断服务程序一次,增加一次计数,计数
到达500,控制PB4引脚输出高或低电平,从而实现1S钟周期闪烁。

3.主要代码

//定时器配置
void timer_config(void)
{
    /* -----------------------------------------------------------------------
	  系统主频108MHZ,timer_initpara.prescaler为107,timer_initpara.period为999,频率就为1KHZ
    ----------------------------------------------------------------------- */
    timer_parameter_struct timer_initpara;
    rcu_periph_clock_enable(RCU_TIMER1);
    timer_deinit(TIMER1);
    /* TIMER1 configuration */
    timer_initpara.prescaler         = 107;//108M主频,分频后就是1M频率
    timer_initpara.alignedmode       = TIMER_COUNTER_EDGE;
    timer_initpara.counterdirection  = TIMER_COUNTER_UP;
    timer_initpara.period            = 999;//1M频率,计数1000次,就是1ms
    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);
}


int main(void)
{

	rcu_ahb_clock_config(RCU_AHB_CKSYS_DIV1);//AHB主频是1分频
	systick_config();//系统主频108MHZ,采用外部晶振,由两个宏决定(__SYSTEM_CLOCK_108M_PLL_HXTAL与HXTAL_VALUE)
	rcu_periph_clock_enable(RCU_AF);//管脚复用时钟alternate function clock使能
	delay_1ms(1000);//等待1秒
	gpio_pin_remap_config(GPIO_SWJ_NONJTRST_REMAP, ENABLE);//PB4管脚默认是NJTRST,要当GPIO,需要重映射
	rcu_periph_clock_enable(RCU_GPIOB);//GPIOB时钟使能
	gpio_init(GPIOB, GPIO_MODE_OUT_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_4);//PB4配置成输出
	timer_config();//定时器初始化配置,1ms进入一次中断,TIMER1_IRQHandler()函数中实现LED闪烁
    while(1)
    {

    }
}

uint32_t Timcounter;
uint8_t  LedFlag;
//定时器溢出中断服务程序,配置的定时器溢出时间是1ms,所以1ms调用一次
void TIMER1_IRQHandler(void)
{
	timer_flag_clear(TIMER1,TIMER_FLAG_UP);
	Timcounter++;
	if(Timcounter>=500)
	{
		Timcounter=0;
		LedFlag^=0x01;

	}
	if(LedFlag)//计数到500ms,翻转输出
	{
		gpio_bit_set(GPIOB,GPIO_PIN_4);//PB4输出高电平
		
	}else
	{
		gpio_bit_reset(GPIOB,GPIO_PIN_4);//PB4输出低电平
	}
}

五.工程源代码下载

通过百度网盘分享的文件:6.定时器1ms.zip
链接:https://pan.baidu.com/s/1NlLrGcL9Afk2hNkPXCmoQw
提取码:mmib

如果链接失效,可以联系博主给最新链接
程序下载下来之后解压就行
CSDN代码

六.小结

通过定时器周期性地产生中断信号,可以实现系统定时和时间戳等功能。例如,在智能家居系统中,可以使用定时器控制各种设备的开关,在工业控制系统中,定时器可以用于检测传感器数据并执行相应的动作,定时器还可以配合PWM模块实现对电机等设备的精确控制。通过定时器产生固定频率的方波信号,然后使用PWM模块将其转化为可调节占空比的脉冲信号,从而实现对电机速度和输出功率的控制。

  • 9
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值