STM32—定时器(TIM)_基本定时

本文详细介绍了STM32F103C8T6芯片中的定时器结构和工作原理,包括基本定时器和通用定时器的差异,如预分频器、计数器、自动重装寄存器等,并提供了配置定时器的步骤和时序描述。此外,文章还展示了如何设置中断,以及中断处理函数的实现,最后给出了一个具体的定时器初始化代码示例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

本文主要通过介绍定时器基本结构去学习如何使用定时器进行定时。

一、定时器基本介绍

定时器可以对输入的时钟进行计数,并在计数值达到设定值时触发中断,从而达到计时功能。

本文从通用定时器介绍。本文所使用芯片为 STM32F103C8T6,拥有TIM1-TIM4 四个定时器资源。

1.1、基本定时器结构 

图.2为基本定时器结构

 红色框选部分为时基单元。

【1】内部时钟(CK_INT)输入到PSC预分频器,预分频器会对输入时钟进行分频。如PSC=0时为1分频,即CK_CNT=CK_INT/1,  PSC=1时,CK_CNT=CK_INT/2。

【2】CNT计数器:对预分频后的时钟进行计数,计时时钟每来一个上升沿,计数器+1,直到达到最大计数值,即65535。最大值后再增加则会回到0,从头开始。

【3】自动重装寄存器:存储了CNT计数器需要计数的值,当计数器计数值等于自动重装值,则会产生中断信号,并重置计数器。

【4】更新中断:即为【3】所产生的中断信号(图3蓝色框选部分)。更新中断之后就会通往NMIC,再配置好NMIC的定时器通道,更新中断就可得到CPU相应

【5】更新事件:同为【3】所产生的信号,但器不会触发中断,而是触发内部其他电路工作。

1.2、通用定时器结构介绍

【1】图四中,红色框选部分与基本定时器结构相同。但是基本定时器仅有向上计数模式,而通用定时器与高级定时器可支持向下计数与中央对齐计数。

  • 向下计数:从自动重装寄存器设定值向下递减1,直到为0,,并产生中断信号从而触发更新中断或更新时间。
  • 中央对齐计数:CNT从0开始计数,计数值与自动重装值相等时,申请中断,随后又向下自减至0,再次申请中断,以此循环。

【2】 输入时钟:绿色框选部分为输入时钟,对于基本定时器而言,只有内部时钟可选择。对于通用定时器,可以选择外部时钟。

1.3、定时器定时配置流程

1.4、时序描述

1.4.1、预分频器时序

【1】预分频控制寄存器:仅供读写作用,并不直接决定分频系数。

【2】缓冲寄存器:真正决定分频系数的寄存器。

当预分频控制寄存器的分频系数由0>1时,预分频缓冲器并未立即更新分频系数,而是等待本次计数周期结束时,产生更新事件后,预分频控制寄存器的分频系数的值才会被传递到预分频缓存寄存器,此时分频系数才真正变为1。

计数器计数频率:CK_CNT = CK_PSC / (PSC + 1)。

1.4.2、计数器时序

 分频系数为2,CK_CNT=72MHz。CNT_EN为时钟使能,高电平启动。

【1】CK_CNT:由于分频系数为2,因此CK_CNT=CK_INT/2=36MHz。

【2】计数器寄存器:上升沿自增,增加到0036时,发生溢出,尝产生更新事件,更短中断标志位置1,申请中断。中断响应后需手动清零标志位UIF

计数器溢出频率CK_CNT_OV = CK_CNT / (ARR + 1)= CK_PSC / (PSC + 1) / (ARR + 1)。

例如,需要定时1s。

定时  f=1s=1Hz=72MHz  /  7200  /  10000.

此时预分频值 (PSC + 1)为720,自动重装值 (ARR + 1)为1000.

二、现象代码(定时器定时中断)

以上为该例程硬件接线图

2.1、Timer.c文件

以下代码为该文件全部代码(不包含头文件)

extern int16_t NUM;

void Timer_Init(void)
{
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE);  //开启时钟,TIM2是APB1总线的外设
	
	TIM_InternalClockConfig(TIM2);
	
	TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;
	TIM_TimeBaseInitStructure.TIM_ClockDivision=TIM_CKD_DIV1;		//指定参数分频值(选择1分频),DIV22分频 DIV4 44分频 
	TIM_TimeBaseInitStructure.TIM_CounterMode=TIM_CounterMode_Up;//选择技术模式;
	TIM_TimeBaseInitStructure.TIM_Period=10000-1;
	TIM_TimeBaseInitStructure.TIM_Prescaler=720-1;
	TIM_TimeBaseInitStructure.TIM_RepetitionCounter=0;
	TIM_TimeBaseInit(TIM2,&TIM_TimeBaseInitStructure);			//配置时基单元
	
	TIM_ClearFlag(TIM2,TIM_FLAG_Update);
	
	TIM_ITConfig(TIM2,TIM_IT_Update,ENABLE);
	
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
	
	NVIC_InitTypeDef NVIC_InitStruct;
	NVIC_InitStruct.NVIC_IRQChannel=TIM2_IRQn;
	NVIC_InitStruct.NVIC_IRQChannelCmd=ENABLE;
	NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority=2;
	NVIC_InitStruct.NVIC_IRQChannelSubPriority=1;
	NVIC_Init(&NVIC_InitStruct);
	
	TIM_Cmd(TIM2,ENABLE);
}

void TIM2_IRQHandler(void)
{
	if(TIM_GetITStatus(TIM2,TIM_IT_Update)==SET)
	{
	
		NUM++;
		TIM_ClearITPendingBit(TIM2,TIM_IT_Update);
	}
}

2.1.1、TIM部分

RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE);  //开启时钟,TIM2是APB1总线的外设
	
	TIM_InternalClockConfig(TIM2);
	
	TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;
	TIM_TimeBaseInitStructure.TIM_ClockDivision=TIM_CKD_DIV1;	//指定参数分频值(选择1分频),DIV22分频 DIV4 44分频 
	TIM_TimeBaseInitStructure.TIM_CounterMode=TIM_CounterMode_Up;//选择计数模式;
	TIM_TimeBaseInitStructure.TIM_Period=10000-1;      //ARR
	TIM_TimeBaseInitStructure.TIM_Prescaler=720-1;      //PSC
	TIM_TimeBaseInitStructure.TIM_RepetitionCounter=0;
	TIM_TimeBaseInit(TIM2,&TIM_TimeBaseInitStructure);			//配置时基单元
	
	TIM_ClearFlag(TIM2,TIM_FLAG_Update);
	
	TIM_ITConfig(TIM2,TIM_IT_Update,ENABLE);

【1】TIM_InternalClockConfig():使用内部时钟函数。单片机上电默认使用内部时钟,因此可以不写改代码。

【2】TIM_ClockDivision:指定时钟分频,DIV2 2分频 DIV4 4分频 。本例中选择不分频。

滤波器主要依靠采用频率以及采用点数工作,其信号来源可以是内部时钟分频而来,而分频值即由该参数决定。此处可任意分配值。

【3】TIM_CounterMode:计数模式,继续向上、向下或对齐计数模式。本例选择向上计数模式。

【4】TIM_Period: ARR自动重装寄存器值

【5】TIM_Prescaler:        PSC预分频计数器置

【6】TIM_TimeBaseInitStructure:高级定时器才拥有,因此此处给0.

【7】TIM_ClearFlag():使能中断函数。

【8】TIM_ClearFlag();引用该函数是为了解决复位立刻进中断的现象。

2.1.2、NVIC部分

    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
	
	NVIC_InitTypeDef NVIC_InitStruct;
	NVIC_InitStruct.NVIC_IRQChannel=TIM2_IRQn;
	NVIC_InitStruct.NVIC_IRQChannelCmd=ENABLE;
	NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority=2;
	NVIC_InitStruct.NVIC_IRQChannelSubPriority=1;
	NVIC_Init(&NVIC_InitStruct);
	
	TIM_Cmd(TIM2,ENABLE);

【1】NVIC_PriorityGroupConfig():中断分组,配置优先级分组:抢占优先级和次优先级。

【2】NVIC_IRQChannel:指定要启用或禁用的IRQ通道。

【3】NVIC_IRQChannelCmd:使能

【4】NVIC_IRQChannelPreemptionPriority:抢占优先级

【5】NVIC_IRQChannelSubPriority:响应优先级

2.1.3、中断函数

void TIM2_IRQHandler(void)
{
	if(TIM_GetITStatus(TIM2,TIM_IT_Update)==SET)
	{
		NUM++;
		TIM_ClearITPendingBit(TIM2,TIM_IT_Update);
	}
}

【1】TIM_GetITStatus():查看TIMx的更新事件中断标志位

3.1main.c 主程序代码

三、函数简介

3.1、时钟源选择(部分函数)

 

3.1.1、选择内部时钟

//定时器默认使用内部定时器,可以不用写这个函数

TIM_InternalClockConfig(TIM_TypeDef* TIMx)

效果如下图

3.1.2、选择ITRx其他定时器时钟

//参数1:选择定时器

//参数2:选择要接入那个其他定时器

TIM_ITRxExternalClockConfig(TIM_TypeDef* TIMx, uint16_t TIM_InputTriggerSource)

效果如下图

3.1.3、选择Tlx捕获通道时钟

参数1:选择定时器

参数2:选择Tlx某个引脚

参数3:输入极性

参数4:滤波器

TIM_TIxExternalClockConfig(TIM_TypeDef* TIMx, uint16_t TIM_TIxExternalCLKSource,

uint16_t TIM_ICPolarity, uint16_t ICFilter);

3.1.4、选择ETR外部时钟模式1的输入时钟

//参数1:选择定时器

//参数2:外部触发预分频器---对ETR外部时钟提前做一次预分频

//参数3:极性

//参数4:滤波器

TIM_ETRClockMode1Config(TIM_TypeDef* TIMx, uint16_t TIM_ExtTRGPrescaler, uint16_t TIM_ExtTRGPolarity,uint16_t ExtTRGFilter)

3.1.5、选择ETR外部时钟模式2的输入时钟

//参数1:选择定时器

//参数2:外部触发预分频器---对ETR外部时钟提前做一次预分频

//参数3:极性

//参数4:滤波器

TIM_ETRClockMode2Config(TIM_TypeDef* TIMx, uint16_t TIM_ExtTRGPrescaler, 
 uint16_t TIM_ExtTRGPolarity, uint16_t ExtTRGFilter

3.1.6、单独配置ETR预分频器、极性。滤波器等参数

TIM_ETRConfig(TIM_TypeDef* TIMx, uint16_t TIM_ExtTRGPrescaler, uint16_t TIM_ExtTRGPolarity,uint16_t ExtTRGFilter)

3.2、 时基单元

3.2.1、时基单元初始化

参数1-TIMx:选择某个定时器

参数2-TIM_TimeBaseInitStruct:结构体,内部包含了配置时基单元的基本信息

TIM_TimeBaseInit(TIM_TypeDef* TIMx, TIM_TimeBaseInitTypeDef* TIM_TimeBaseInitStruct)

3.2.2、将结构体初始化为默认值

TIM_TimeBaseStructInit(TIM_TimeBaseInitTypeDef* TIM_TimeBaseInitStruct)

结构体内含信息:

TIM_Prescaler;

3.2.3、运行控制

//参数1:选择定时器

//参数2:使能or失能

TIM_Cmd(TIM_TypeDef* TIMx, FunctionalState NewState) 

3.3、中断输出控制

//参数1:选择定时器

//参数2:选择配置那个中断输出

//参数3;使能or失能

TIM_ITConfig(TIM_TypeDef* TIMx, uint16_t TIM_IT, FunctionalState NewState)

3.4、NVIC配置 

详见前文

3.5、补充函数

3.5.1、单独写预分频值

//参数1:选择定时器

//参数2、写入预分频的值

//参数3、写入模式(用到再详查资料)

TIM_PrescalerConfig(TIM_TypeDef* TIMx, uint16_t Prescaler, uint16_t TIM_PSCReloadMode)

3.5.2、改变计数器的计数模式

//参数2:选择新的计数器模式

TIM_CounterModeConfig(TIM_TypeDef* TIMx, uint16_t TIM_CounterMode)

3.5.3、自动重装器预装功能配置

TIM_ARRPreloadConfig(TIM_TypeDef* TIMx, FunctionalState NewState)

3.5.4、计数器写入一个值

TIM_SetCounter(TIM_TypeDef* TIMx, uint16_t Counter)

3.5.5、自动重装器写入一个值

TIM_SetAutoreload(TIM_TypeDef* TIMx, uint16_t Autoreload)

3.5.6、获取当前计数器的值

 TIM_GetCounter(TIM_TypeDef* TIMx)

3.5.7、获取当前预分频的值

TIM_GetPrescaler(TIM_TypeDef* TIMx)

问题解决

一上电就出现中断在  TIM_TimeBaseInit();后加上函数

TIM_ClearFlag(TIM2,TIM_FLAG_Update).

本文以重新优化内容排布,以后将会不定期优化更新。

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

橘洲青年

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值