STM32定时中断之TIM(一)- 时钟源选择详解

一,stm32f103的定时器资源

 

stm32f103有一个高级定时器(TIM1),两个通用定时器(TIM2,TIM3)。以及一个基本定时器(TIM4)。

对于通用定时器,是使用最广泛的定时器资源,有:输入捕获(可以测出输入信号的频率,占空比),输出比较(可以输出PWM波,驱动电机),编码器模式(编码器测转速),基本计数模式,主从触发模式。

对于高级定时器,其功能在基本定时器的基础上又加上了:死区生成,互补输出,刹车输入等功能

对于基本定时器,其功能只有计数定时功能

本节先介绍定时器最简单的功能:定时产生中断。

二,定时器硬件框图介绍:

(一)基本定时器:

核心:由自动重装寄存器(ARR)预分频器(PSC)和计数器(CNT)组成的时基单元

预分频器:预分频可以以系数介于1至65536之间的任意数值对计数器时钟分频。它是通过一个16位寄存器 (TIMx_PSC)的计数实现分频。因为TIMx_PSC控制寄存器具有缓冲,可以在运行过程中改变它 的数值,新的预分频数值将在下一个更新事件时起作用

简单来说就是对输入的时钟信号(包括外部时钟信号)进行分频,

比如:时钟频率为72MHz,PSC=1,则不分频,一秒计数72000000个脉冲

若PSC=2,则一秒计数36000000个脉冲,PSC最大65536,以此类推。。。

计数器(CNT):就是对分频后的时钟信号的脉冲的上升沿计数,最多可以累积65535。

自动重装寄存器(ARR):ARR的值就是用户设置的值,当计数器计数的个数达到ARR的设定值是时计数器清零(向上计数),并且产生一次中断,一次事件触发

 

(二)通用定时器:

基本功能:

16位可编程(可以实时修改)预分频器,计数器时钟频率的分频系数为1~65536之间的任意 数值

● 4个独立通道: ─ 输入捕获 ─ 输出比较 ─ PWM生成(边缘或中间对齐模式) ─ 单脉冲模式输出

● 使用外部信号控制定时器和定时器互连的同步电路

● 如下事件发生时产生中断/DMA: 

更新:计数器向上溢出/向下溢出,计数器初始化(通过软件或者内部/外部触发)

 触发事件(计数器启动、停止、初始化或者由内部/外部触发计数) 

输入捕获 

输出比较

● 支持针对定位的增量(正交)编码器和霍尔传感器电路

● 触发输入作为外部时钟或者按周期的电流管理

 

 先看上半部分:

 外部触发输入(ETR):TIMx_ETR:定时器的输入时钟信号(在APB1总线上);

内部触发输入(ITRx):使用一个定时器作为另一个定时器的预分频器,如可以配置一个定时 器Timer1而作为另一个定时器Timer2的预分频器,ITR0~ITR3:其他定时器的输入信号

内部时钟(CK_INT):RCC的TIMxCLK

其他本节的不做介绍,后面会说。本节对32的定时器的结构有个大概了解即可

 下半部分:

输入捕获的通道(CH1~CH4)输入捕获的通道(CH1~CH4),这四个通道可以通对应的外部引脚和外部连接 ,用于输入外部的频率。

输出比较的通道(CH1~CH4)也是和外部连接的,和上述的CH1~CH4是共用的,因为单片机没发同时在同一个引脚输入捕获和输出比较。

三,定时中断代码:

如何开启定时钟中断呢?,如何使用外部时钟输入呢?

下面通过编程实现:

(一)初始化定时器:

1.开启RCC时钟

2.选择外部时钟(72MHz)

3.配置时基单元(PSC,ARR)

4开启中中断

5使能定时器

相关库函数:

void TIM_DeInit(TIM_TypeDef* TIMx);

初步初始化定时器
void TIM_TimeBaseInit(TIM_TypeDef* TIMxTIM_TimeBaseInitTypeDef*TIM_TimeBaseInitStruct);

配置时基单元
void TIM_TimeBaseStructInit(TIM_TimeBaseInitTypeDef* TIM_TimeBaseInitStruct);

给时基单元赋初值初始化时基单元
void TIM_ITConfig(TIM_TypeDef* TIMx, uint16_t TIM_IT, FunctionalState NewState);

定时中断开启或关闭
void TIM_Cmd(TIM_TypeDef* TIMx, FunctionalState NewState);

定时器使能
void TIM_InternalClockConfig(TIM_TypeDef* TIMx);

选择内部时钟源
void TIM_ITRxExternalClockConfig(TIM_TypeDef* TIMx, uint16_t TIM_InputTriggerSource);

选择其他定时器的输入作为时钟源
void TIM_TIxExternalClockConfig(TIM_TypeDef* TIMx, uint16_t TIM_TIxExternalCLKSource,
    uint16_t TIM_ICPolarity, uint16_t ICFilter);

选择外部引脚输入的信号作为时钟源
void TIM_ETRClockMode1Config(TIM_TypeDef* TIMx, uint16_t TIM_ExtTRGPrescaler, uint16_t TIM_ExtTRGPolarity,uint16_t ExtTRGFilter);

选择内部时钟1信号作为时钟源
void TIM_ETRClockMode2Config(TIM_TypeDef* TIMx, uint16_t TIM_ExtTRGPrescaler,  uint16_t TIM_ExtTRGPolarity, uint16_t ExtTRGFilter);

选择内部时钟2信号作为时钟源
void TIM_SetCounter(TIM_TypeDef* TIMx, uint16_t Counter);

手动改写计数器的值
void TIM_SetAutoreload(TIM_TypeDef* TIMx, uint16_t Autoreload);

手动改写ARR的值
uint16_t TIM_GetCounter(TIM_TypeDef* TIMx);

获取现在的计数值
uint16_t TIM_GetPrescaler(TIM_TypeDef* TIMx);

获取现在的预分频器的值
FlagStatus TIM_GetFlagStatus(TIM_TypeDef* TIMx, uint16_t TIM_FLAG);
void TIM_ClearFlag(TIM_TypeDef* TIMx, uint16_t TIM_FLAG);
ITStatus TIM_GetITStatus(TIM_TypeDef* TIMx, uint16_t TIM_IT);
void TIM_ClearITPendingBit(TIM_TypeDef* TIMx, uint16_t TIM_IT);

库函数太多了……………………………………………..

下面吧库函数按照上面的步骤用起来就可以初始化定时器中断了!

void TImer_Init(void)
{
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE);
	
	TIM_InternalClockConfig(TIM2);
	
	TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStruct;
	TIM_TimeBaseInitStruct.TIM_ClockDivision=TIM_CKD_DIV1;
	TIM_TimeBaseInitStruct.TIM_CounterMode=TIM_CounterMode_Up;
	TIM_TimeBaseInitStruct.TIM_Period=10000-1;
	TIM_TimeBaseInitStruct.TIM_Prescaler=7200-1;
	TIM_TimeBaseInitStruct.TIM_RepetitionCounter=0x00;
	TIM_TimeBaseInit(TIM2,&TIM_TimeBaseInitStruct);
	
	TIM_ClearFlag(TIM2,TIM_FLAG_Update);
	
	TIM_ITConfig(TIM2, TIM_IT_Update,ENABLE);
	
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
	NVIC_InitTypeDef NVIC_InitStructure;
	NVIC_InitStructure.NVIC_IRQChannel=  TIM2_IRQn  ;
	NVIC_InitStructure.NVIC_IRQChannelCmd= ENABLE;
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=1;
	NVIC_InitStructure.NVIC_IRQChannelSubPriority=1;
	NVIC_Init(&NVIC_InitStructure);
	
	TIM_Cmd(TIM2,ENABLE);
	
}

这里对72MHz的时钟信号7200分频,->每秒计数72000000/7200=10000个脉冲

然后设置ARR为10000,即计时器计数10000个脉冲清零,同时中时产生中断,顾中断周期为一秒。
 

 然后配制好了定时器中断,就写一个中断服务函数(中断函数名在setup_stm32f10x_md.s文件里有声明)

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

这是模板,检查中断标志位后清除。

在主函数用OLED显示Num这个就可以看到Num每秒自增1了;

#include "stm32f10x.h"
#include "OLED.h"
#include "Timer.h"
uint16_t Num;
int main(void)

{	
	OLED_Init();
	TImer_Init();
	OLED_ShowString(1,1,"Hollow,Word");
	while(1)
	{
		 OLED_ShowNum(2,1,Num,5);
		OLED_ShowNum(3,1,TIM_GetCounter(TIM2),5);
	}
}
void TIM2_IRQHandler ()
{
	if(TIM_GetITStatus(TIM2,TIM_IT_Update)==SET)
	{
		Num++;
		TIM_ClearITPendingBit(TIM2,TIM_IT_Update);
	}
	

OLED_ShowNum(3,1,TIM_GetCounter(TIM2),5);

这个可以显示计数值,你可以看到计数值在1秒内从0-9999,然后变为零,变得非常快!

四,外部信号作为时钟源

前面介绍了内部时钟作为时钟源触发定时器中断的情况,用到了TIM_InternalClockConfig(TIM2);函数,若我们想从外部引脚输入的脉冲作为时钟源达到定时计数功能,也可以做到。我们需要先初始化外部引脚,后改变时钟源的选择,便可达到要求。(在对射式红外口之间遮挡一次变可产生一个脉冲)

如图所示。PA0引脚作为了时钟脉冲输入

需初始化GPIO为输入模式:

	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
	GPIO_InitTypeDef GPIO_InitStructure;
	GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IPU;
	GPIO_InitStructure.GPIO_Pin=GPIO_Pin_0;
	GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
	GPIO_Init(GPIOA,&GPIO_InitStructure);

 改变时钟源的选择:

    TIM_ETRClockMode1Config(TIM2,TIM_ExtTRGPSC_OFF, TIM_ExtTRGPolarity_Inverted, 0x0F);外部时钟模式

  改变PSC,ARR寄存器值

TIM_TimeBaseInitStruct.TIM_Period=10-1;
  TIM_TimeBaseInitStruct.TIM_Prescaler=1-1;

我们不分频,ARR设置为10;那么一个脉冲就计数一次,10个脉冲产生一次中断

如果:

TIM_TimeBaseInitStruct.TIM_Period=5-1;
 TIM_TimeBaseInitStruct.TIM_Prescaler=3-1;

那么三个脉冲计数一次,计数5次产生一个中断;

除了上面说的要改,其他的都不改。

主函数:

int main(void)

{	
	OLED_Init();
	TImer_Init();
	OLED_ShowString(1,1,"Num:");
	OLED_ShowString(2,1,"CNT:");
	while(1)
	{
		OLED_ShowNum(1,5,Num,5);
		OLED_ShowNum(2,5,TIM_GetCounter(TIM2),5);
	}
}
void TIM2_IRQHandler ()
{
	if(TIM_GetITStatus(TIM2,TIM_IT_Update)==SET)
	{
		Num++;
		TIM_ClearITPendingBit(TIM2,TIM_IT_Update);
	}
	
	
	
	
}

遮挡一下,TIM_GetCounter(TIM2)就加一次,遮挡累积10下后,产生了中断,Num就加1;

这就是定时器中断的两种应用。

 

物联沃分享整理
物联沃-IOTWORD物联网 » STM32定时中断之TIM(一)- 时钟源选择详解

发表评论