定时器基础

定时器功能    定时、输出比较、输入捕获、互补输出

定时器分类    基本定时器、通用定时器、高级定时器

定时器资源    4292个高级定时器、10个通用定时器、2个基本定时器

APB1 定时器有 TIM2, TIM3 ,TIM4, TIM5, TIM6, TIM7, TIM12, TIM13,TIM14-90M

APB2 定时器有 TIM1, TIM8 ,TIM9, TIM10, TIM11—180M

 

定时器最主要的就是时基部分:包括 预分频器、计数器、自动重装载寄存器。

 

预分频器

1-16位的预分频器TIMx_PSC对内部时钟CK_INT进行分频之后,得到计数器时钟CK_CNT=CK_PSC/PSC+1

2-计数器CNT在计数器时钟的驱动下开始计数,计数一次的时间为1/CK_CNT

 

计数器、自动重装载寄存器:

定时器使能(CEN 1)后,计数器 CNTCK_CNT 驱动下向上计数,当 TIMx_CNT 值与 TIMx_ARR 的设定值相等时就自动生成事件并 TIMx_CNT 自动清零,然后自动重新开始计数,如此重复以上过程。

 

基本定时器(TIM6TIM7)功能简介

1-计数器16bit,只能向上计数

2-没有外部的GPIO,是内部资源,只能用来定时

3-时钟来自PCLK1,可实现1~65536分频

 

定时时间的计算:

1PSC = 9000-1,定时器频率=90M/(PSC+1)=10000HZ

2ARR = 4999,从0计数到4999,则计了5000

3T = 5000 /  10000 = 0.5S

TIM7初始化以及中断服务函数

void bsp_Init_TIM7(void)
{
	NVIC_InitTypeDef NVIC_InitStructure;//中断初始化结构体
	
	TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;//定时器初始化结构体
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM7, ENABLE);//开启TIM7时钟
	
	TIM_TimeBaseStructure.TIM_Prescaler = 9000 - 1; // 频率90M / 9000 = 10K

	TIM_TimeBaseStructure.TIM_Period = 5000 - 1;  //5000 / 10K = 0.5S一个周期
	TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; //计数模式,加计数
	TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1; //时钟分频因子,但是不用于分频,而是用于滤波
	//TIM_TimeBaseStructure.TIM_RepetitionCounter;
	
	TIM_TimeBaseInit(TIM7, &TIM_TimeBaseStructure);//初始化TIM7
	
	TIM_Cmd(TIM7, ENABLE);//使能TIM
	
	TIM_ITConfig(TIM7, TIM_IT_Update, ENABLE);//开中断 更新时触发
	
	//NVIC_InitTypeDef NVIC_InitStructure;//NVIC结构体赋值
	NVIC_InitStructure.NVIC_IRQChannel = TIM7_IRQn; //中断源
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;//抢占优先级
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;//响应优先级
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;//使能
	NVIC_Init(&NVIC_InitStructure);
}


void TIM7_IRQHandler(void)
{
	if (TIM_GetITStatus(TIM7, TIM_IT_Update) == SET) //设置的定时时间到
	{
		bsp_LedToggle(1);  //LED1翻转
		TIM_ClearITPendingBit(TIM7, TIM_IT_Update);//清除标志
	}
}


 

(输出比较)输出PWM

void bsp_Init_TIMxPwm(void)
{
	GPIO_InitTypeDef             GPIO_InitStructure;
    TIM_TimeBaseInitTypeDef      TIM_TimeBaseStructure;
    TIM_OCInitTypeDef            TIM_OCInitStructure;
	
	//开时钟
	RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
	
	//GPIO结构体赋值初始化
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
	GPIO_InitStructure.GPIO_Speed = GPIO_Fast_Speed;
	GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;//推挽
	GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL; //无上拉或下拉
	GPIO_Init(GPIOA, &GPIO_InitStructure);
	
	//引脚复用初始化,只要不做为普通IO就需要调用这个函数
	GPIO_PinAFConfig(GPIOA, GPIO_PinSource5, GPIO_AF_TIM2);
	
	TIM_TimeBaseStructure.TIM_Prescaler = 90 - 1;//  90M / 90 = 1M
	TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; //计数器模式为加计数
	TIM_TimeBaseStructure.TIM_Period = 10000 - 1; //频率为 1M / 10K = 100Hz 
	TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;
	TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);
	
	TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1; //0-CCR为有效 CCR-ARR为无效
	TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;//使能
	TIM_OCInitStructure.TIM_Pulse = 1000; // ARR是10000 CRR是1000, 占空比10%
	TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; //有效部分为高
	TIM_OC1Init(TIM2, &TIM_OCInitStructure);
	
	//时钟使能
	TIM_OC1PreloadConfig(TIM2, TIM_OCPreload_Enable);  //CRR1寄存器预加载配置
	TIM_ARRPreloadConfig(TIM2, ENABLE); //ARR寄存器预加载配置
	TIM_Cmd(TIM2, ENABLE); //开启TIM
}

初始化结构体详解:

1-TIM_OCMode:比较输出模式选择,总共有八种,常用的为 PWM1/PWM2。它设定CCMRx 寄存器 OCxM[2:0]位的值。

2-TIM_OutputState:比较输出使能,决定最终的输出比较信号 OCx 是否通过外部引脚输出。它设定 TIMx_CCER 寄存器 CCxE/CCxNE 位的值。

3-TIM_OutputNState:比较互补输出使能,决定 OCx 的互补信号 OCxN 是否通过外部引脚输出。它设定 CCER 寄存器 CCxNE 位的值。(适用于TIM1TIM8

4-TIM_Pulse比较输出脉冲宽度,实际设定比较寄存器 CCR 的值,决定脉冲宽度。可设置范围为 0 65535

5-TIM_OCPolarity比较输出极性,可选 OCx 为高电平有效或低电平有效。它决定着定时器通道有效电平。它设定 CCER 寄存器的 CCxP 位的值。

6-TIM_OCNPolarity:比较互补输出极性,可选OCxN 为高电平有效或低电平有效。它设定 TIMx_CCER 寄存器的 CCxNP 位的值。(适用于TIM1TIM8

7-TIM_OCIdleState:空闲状态时通道输出电平设置,可选输出 1 或输出 0,即在空闲状态(BDTR_MOE 位为 0)时,经过死区时间后定时器通道输出高电平或低电平。它设定CR2 寄存器的 OISx 位的值。(适用于TIM1TIM8

8-TIM_OCNIdleState:空闲状态时互补通道输出电平设置,可选输出 1 或输出 0,即在空闲状态(BDTR_MOE 位为 0)时,经过死区时间后定时器互补通道输出高电平或低电平,设定值必须与 TIM_OCIdleState 相反。它设定是 CR2 寄存器的 OISxN 位的值。(适用于TIM1和TIM8

 

其他常用函数:

1、设置比较值函数:(CCRX)也就是OC初始化结构体中的Pulse, 即修改占空比

void TIM_SetCompareX(TIM_TypeDef* TIMx, uint16_t Comparex);

函数名中的X表示通道号,TIMX是定时器号,Comparex是修改值

TIM_SetCompare1(TIM2, pwm_value);

 2、使能输出比较预装载:

void TIM_OCxPreloadConfig(TIM_TypeDef* TIMx, uint16_t TIM_OCPreload);

使能CCRx寄存器,函数名的x是通道名,

TIM_OCPreload可选TIM_OCPreload_EnableTIM_OCPreload_Disable

TIM_OC1PreloadConfig(TIM2, TIM_OCPreload_Enable);  //CRR1寄存器预加载配置

3、使能自动重装载的预装载寄存器允许位:TIMxARR使能

void TIM_ARRPreloadConfig(TIM_TypeDef* TIMx, FunctionalState NewState);

TIM_ARRPreloadConfig(TIM2, ENABLE); //ARR寄存器预加载配置

输入捕获:

原理:通过检测TIMx_CHx上的边沿信号,在边沿信号发生跳变(比如上升沿/下降沿)的时候,将当前定时器的值(TIMx_CNT)存放到对应的捕获/比较寄存器(TIMx_CCRx)里面,完成一次捕获。

 

 初始化结构体详解:

1-TIM_Channel:捕获通道 ICx 选择,可选 TIM_Channel_1 TIM_Channel_2
TIM_Channel_3 TIM_Channel_4 四个通道。它设定 CCMRx 寄存器 CCxS 位 的值。

2-TIM_ICPolarity:输入捕获边沿触发选择,可选上升沿触发、下降沿触发或边沿跳变触发。它设定 CCER 寄存器 CCxP 位和 CCxNP 位的值。

3-TIM_ICSelection:输入通道选择,捕获通道 ICx 的信号可来自三个输入通道,分别为
TIM_ICSelection_DirectTITIM_ICSelection_IndirectTI TIM_ICSelection_TRC

它设定 CCRMx 寄存器的 CCxS[1:0]位的值。

4-TIM_ICPrescaler:输入捕获通道预分频器,可设置 1 2 4 8 分频,它设定 CCMRx寄存器的 ICxPSC[1:0]位的值。如果需要捕获输入信号的每个有效边沿,则设置 1 分频即可。

5-TIM_ICFilter:输入捕获滤波器设置,可选设置 0x0 0x0F。它设定 CCMRx 寄存器ICxF[3:0]位的值。一般我们不使用滤波器,即设置为 0

 

其他常用函数:

1、 通道极性设置独立函数:

void TIM_OCxPolarityConfig(TIM_TypeDef* TIMx, uint16_t TIM_OCPolarity);

TIM_OC1PolarityConfig(TIM5,TIM_ICPolarity_Rising);//OC1设置为上升沿捕获

 2、获取通道捕获值

uint32_t TIM_GetCapturex(TIM_TypeDef* TIMx);

val=TIM_GetCapture2(TIM5);//把当前的捕获值赋给val

 

2、 计数清零:

void TIM_SetCounter(TIM_TypeDef* TIMx, uint32_t Counter);

TIM_SetCounter(TIM5,0);  //TIM5计数清0

 输入捕获例程:

TIM_ICInitTypeDef  TIM5_ICInitStructure;

//定时器5通道1输入捕获配置
//arr:自动重装值(TIM2,TIM5是32位的!!)
//psc:时钟预分频数
void TIM5_CH2_Cap_Init(void)
{
	GPIO_InitTypeDef GPIO_InitStructure;
	TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
	NVIC_InitTypeDef NVIC_InitStructure;

	
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM5,ENABLE);  	//TIM5时钟使能    
	RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE); 	//使能PORTA时钟	
	
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1; //GPIOA0
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;//复用功能
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;	//速度100MHz
	GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; //推挽复用输出
	GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_DOWN; //下拉
	GPIO_Init(GPIOA,&GPIO_InitStructure); //初始化PA0

	GPIO_PinAFConfig(GPIOA,GPIO_PinSource1,GPIO_AF_TIM5); //PA0复用位定时器5
  
	  
	TIM_TimeBaseStructure.TIM_Prescaler=90 - 1;  //定时器分频   1us计数器+1
	TIM_TimeBaseStructure.TIM_CounterMode=TIM_CounterMode_Up; //向上计数模式
	TIM_TimeBaseStructure.TIM_Period=0xffffffff - 1;   //自动重装载值
	TIM_TimeBaseStructure.TIM_ClockDivision=TIM_CKD_DIV1; 
	
	TIM_TimeBaseInit(TIM5,&TIM_TimeBaseStructure);
	

	//初始化TIM5输入捕获参数
	TIM5_ICInitStructure.TIM_Channel = TIM_Channel_2; //CC1S=01 	选择输入端 IC1映射到TI1上
  TIM5_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising;	//下降沿捕获
  TIM5_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI; //映射到TI1上
  TIM5_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1;	 //配置输入分频,不分频 
  TIM5_ICInitStructure.TIM_ICFilter = 0x00;//IC1F=0000 配置输入滤波器 不滤波
  TIM_ICInit(TIM5, &TIM5_ICInitStructure);
		
	TIM_ITConfig(TIM5,TIM_IT_Update|TIM_IT_CC2,ENABLE);//允许更新中断 ,允许CC1IE捕获中断	
	//同时打开溢出中断和捕获中断
	
  TIM_Cmd(TIM5,ENABLE ); 	//使能定时器5

 
  NVIC_InitStructure.NVIC_IRQChannel = TIM5_IRQn;
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=2;//抢占优先级3
	NVIC_InitStructure.NVIC_IRQChannelSubPriority =0;		//子优先级3
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;			//IRQ通道使能
	NVIC_Init(&NVIC_InitStructure);	//根据指定的参数初始化VIC寄存器、
	
	
}
//捕获状态
//[7]:0,没有成功的捕获;1,成功捕获到一次.
//[6]:0,还没捕获到低电平;1,已经捕获到低电平了.
//[5:0]:捕获低电平后溢出的次数(对于32位定时器来说,1us计数器加1,溢出时间:4294秒)

uint8_t  TIM5CH1_CAPTURE_STA=0;	//输入捕获状态		    				
uint32_t	TIM5CH1_CAPTURE_VAL;	//输入捕获值(TIM2/TIM5是32位)

//定时器5中断服务程序	 
void TIM5_IRQHandler(void)
{ 		    

 	if((TIM5CH1_CAPTURE_STA&0X80)==0)//最高位为0 还未成功捕获	
	{
		if(TIM_GetITStatus(TIM5, TIM_IT_Update) != RESET)//溢出
		{	     
			if(TIM5CH1_CAPTURE_STA&0X40)//已经捕获到低电平了(捕获下降沿,但没有捕获上升沿)
			{
				if((TIM5CH1_CAPTURE_STA&0X3F)==0X3F)//低电平太长了 0011 1111  后六位用来计数 
				{
					TIM5CH1_CAPTURE_STA|=0X80;		//标记成功捕获了一次
					TIM5CH1_CAPTURE_VAL=0XFFFFFFFF;
				}

                                else TIM5CH1_CAPTURE_STA++;
			}	 
		}

		if(TIM_GetITStatus(TIM5, TIM_IT_CC2) != RESET)//捕获1发生捕获事件  !=RESET 就是 == SET
		{	
			if(TIM5CH1_CAPTURE_STA&0X40)		//捕获到一个上升沿 		
			{	  			
				TIM5CH1_CAPTURE_STA|=0X80;		//标记成功捕获到一次高电平脉宽 1100 0000 表示2次捕获完成
				TIM5CH1_CAPTURE_VAL=TIM_GetCapture2(TIM5);//获取当前的捕获值.
	 			TIM_OC2PolarityConfig(TIM5,TIM_ICPolarity_Rising); //CC1P=0 设置为下降沿捕获, 开始下一轮捕获 //这个函数是用来修改捕获方式的,不用重新配置结构体
			}

                        else  								//还未开始,第一次捕获下降沿
			{
				TIM5CH1_CAPTURE_STA=0;			//清空
				TIM5CH1_CAPTURE_VAL=0;
				TIM5CH1_CAPTURE_STA|=0X40;		//标记捕获到了上升沿 0100 0000
				TIM_Cmd(TIM5,DISABLE ); 	//关闭定时器5
	 			TIM_SetCounter(TIM5,0); //计数清0
	 			TIM_OC2PolarityConfig(TIM5,TIM_ICPolarity_Falling);		//CC1P=1 设置为上升沿捕获
				TIM_Cmd(TIM5,ENABLE ); 	//使能定时器5
			}		    
		}			     	    					   
 	}
	TIM_ClearITPendingBit(TIM5, TIM_IT_CC2|TIM_IT_Update); //清除中断标志位
}

 

 

 

猜你喜欢

转载自blog.csdn.net/canvas_kin/article/details/81201578