我是靠谱客的博主 深情可乐,最近开发中收集的这篇文章主要介绍TIM高级定时器(1)输入捕获、测脉宽,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

一、定时器基础

通用定时器(定时、输出比较、输入捕获)
高级定时器(定时、输出比较、输入捕获、互补输出)

STM32S103RBT6的开发板有一个高级定时器TIM1;3个通用定时器TIM2/3/4
输出比较(输出PWM)
输入捕获(测量脉冲宽度,PWM输入(只能由通道1/2捕获))
互补输出:(即脉冲反向输出,1和0互补)
在这里插入图片描述

二、高级定时器

1. 高级定时器简介

TIM1是高级定时器,和其他的不同的是:

  1. 可以向上/向下/两边 (三种方式)计数,有一个重复计数器
  2. 有==4个GPIO(PA8PA11)==,其中,通道1 3有互补输出(PB13~PB15)(基本定时器无JPIO)
  3. 挂载在APB2上,时钟来自PCLK2,72MHz
2. 高级定时器时钟4种获取方式:
  1. 通道CH1/2/3/4(GPIO引脚接入时钟源)的外部时钟源模式1
    在这里插入图片描述

  2. ETR的外部时钟源模式2(只要高级/通用定时器有这个引脚)
    TIM1——PA12,TIM2——PA0,TIM3——PB1,TIM4——PB9,
    ETR引脚专门用于外部时钟源模式2的时钟源输入
    在这里插入图片描述

  3. 内部触发输入(一个TIM高级定时器的预分频器为另一个通用定时器提供时钟,很少使用)

  4. 内部时钟(APB2的PCLK2)

三、输入捕获

1. 输入捕获的过程

输入通道——>输入滤波和边沿检测——>捕获通道——>预分频器——>捕获寄存器

在这里插入图片描述

2. 输入捕获可以干什么?

测量脉冲宽度、测量PWM信号频率和占空比
测量脉冲宽度,四个输入通道都可以使用,只使用一个捕获通道即可
PWM输入捕获只能使用CH1和CH2俩个通道。其中,每个通道会被俩个捕获通道捕获,如TI1FP1捕获周期,TI2FP2捕获占空比

3. 输入捕获原理:

输入捕获可以对输入的信号的上升沿,下降沿或者双边沿进行捕获,常用的有测量输入信号的脉宽和测量PWM输入信号的频率和占空比这两种。
输入捕获的大概的原理就是,当捕获到信号的跳变沿的时候,把计数器CNT的值锁存到捕获寄存器CCR中,把前后两次捕获到的CCR寄存器中的值相减,就可以算出脉宽或者频率。如果捕获的脉宽的时间长度超过你的捕获定时器的周期,就会发生溢出,这个我们需要做额外的处理。

4. 输入通道

TIM1是高级定时器。有4个通道CH1-4,对应引脚PA8-11;3个互补通道CH1-3N,对应引脚PB13-15;以及外部数据ETR和外部控制信号BKIN,对应引脚PA12和PB12。

5. 捕获通道

捕获通道就是图中的IC1/2/3/4,每个捕获通道都有相对应的捕获寄存器CCR1/2/3/4,当发生捕获的时候,计数器CNT的值就会被锁存到捕获寄存器中。
输入通道是用来输入信号的,捕获通道是用来捕获输入信号的通道一个输入通道的信号可以同时输入给两个捕获通道。比如输入通道TI1的信号经过滤波边沿检测器之后的TIFP1和TIFP2可以进入到捕获通道IC1l和IC2,其实这就是我们后面要讲的PWM输入捕获,只有一路输入信号(TI1)却占用了两个捕获通道(IC1和IC2)。当只需要测量输入信号的脉宽时候,用一个捕获通道即可。

6.预分频器

预分频器决定每多少个周期的PWM(脉冲)进行一次捕获,如果每个边沿都进行捕获,则不需要进行分频

四、输入捕获使用的结构体测量脉冲宽度

时基初始化结构体
typedef struct
{
  uint16_t TIM_Prescaler;    //分频因子                                72-1     即频率为1MHz,即1us    
  uint16_t TIM_CounterMode;      //计数模式(基本定时器只能向上)      向上/向下(基本定时器可以不配置)
  uint16_t TIM_Period;      //自动重装载值                             1000-1   计数1000次,即1ms,然后才会触发更新中断 
  uint16_t TIM_ClockDivision;  //外部输入时钟分频因子(基本定时器没有),只有使用死区时间时才使用
  uint8_t TIM_RepetitionCounter;  //重复计数器(高级定时器专属)       100,则每次重装载不触发中断,重装载100次以后才触发中断,即100ms
} TIM_TimeBaseInitTypeDef; //时基初始化结构体
输入捕获结构体
typedef struct
{
  uint16_t TIM_Channel;      //输入捕获的通道
  uint16_t TIM_ICPolarity;   //捕获的边沿(上升沿/下降沿)
  //上升沿  TIM_ICPolarity_Rising   下降沿  TIM_ICPolarity_Falling  双边沿  TIM_ICPolarity_BothEdge
  uint16_t TIM_ICSelection;  //输入通道和捕获通道的映射(直连/非直连 )  
  //直连   TIM_ICSelection_DirectTI   非直连   TIM_ICSelection_IndirectTI
  //如  TI1FP1属于直连,TI1FP2属于非直连
  uint16_t TIM_ICPrescaler;  //分频
  uint16_t TIM_ICFilter;     //是否需要滤波 0表示不滤波,其余数字表示每几个边沿脉冲捕获一次,其余被滤波
} TIM_ICInitTypeDef;//输入捕获结构体
其他函数
uint16_t TIM_GetCapture1(TIM_TypeDef* TIMx);//获取通道1捕获寄存器的值
void TIM_SetIC1Prescaler(TIM_TypeDef* TIMx, uint16_t TIM_ICPSC);//设置输入通道1的分频系数
void TIM_SetCompare1(TIM_TypeDef* TIMx, uint16_t Compare1);//设置通道1 捕获寄存器的比较值,即占空比
void TIM_SetCounter(TIM_TypeDef* TIMx, uint16_t Counter);//设置计数器的值
TIM_CounterModeConfig(TIM_TypeDef* TIMx, uint16_t TIM_CounterMode);//计数模式(上升/下降)配置
void TIM_ICInit(TIM_TypeDef* TIMx, TIM_ICInitTypeDef* TIM_ICInitStruct);//初始化TIM捕获通道
void TIM_OC1PreloadConfig(TIM_TypeDef* TIMx, uint16_t TIM_OCPreload);//捕获通道1 的 捕获边沿配置

五、测量高电平脉冲宽度

以通用定时器TIM3为例

要点
  1. 在中断服务函数中需要修改捕获的边沿(上升/下降)
  2. 需要判断中断是捕获中断还是更新中断(CNT计数器计数达到65535,产生更新中断)
void TIM3_Init(u16 arr,u16 psc)
{
	GPIO_InitTypeDef GPIO_InitStructure;
	TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
	TIM_ICInitTypeDef TIM3_ICInitStructure;
	NVIC_InitTypeDef NVIC_InitStructure;

	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE); //使能 TIM3 时钟
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); //使能 GPIOA 时钟

    //初始化 GPIOA.6 
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6; //PA6设置
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; //PA6 输入
	GPIO_Init(GPIOA, &GPIO_InitStructure); //初始化 GPIOA.6
	GPIO_ResetBits(GPIOA,GPIO_Pin_0); //PA6 下拉

	//初始化 TIM3 参数
	TIM_TimeBaseStructure.TIM_Period = arr; 
	//设定计数器自动重装值,即计数器CNT最大计数值,一般配置为0xFFFF,即65535;或者配置为1000,表示1ms触发一次更新中断
	TIM_TimeBaseStructure.TIM_Prescaler =psc; //预分频器,一般配置为71,表示每计数一次,时间过了1us
	TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1; // TDTS = Tck_tim,72MHz
	TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; //TIM 向上计数模式
	TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure); //初始化TIM

	//初始化TIM3 输入捕获通道1
	TIM3_ICInitStructure.TIM_Channel = TIM_Channel_1; //选择输入端IC1
	TIM3_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising; //上升沿捕获
	TIM3_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI; //直连,映射到 TI1 上
	TIM3_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1; //不分频
	TIM3_ICInitStructure.TIM_ICFilter = 0x00; //配置输入滤波器 不滤波
	TIM_ICInit(TIM3, &TIM3_ICInitStructure); //初始化TIM3

	//初始化NVIC 中断优先级分组
	NVIC_InitStructure.NVIC_IRQChannel = TIM3_IRQn; //TIM3 中断
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2; //主优先级 2 级
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; //从优先级 0 级
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ 通道被使能
	NVIC_Init(&NVIC_InitStructure); //初始化 NVIC
	
	TIM_ClearITPendingBit(TIM3,TIM_IT_Update|TIM_IT_CC1,ENABLE);
	TIM_ITConfig( TIM3,TIM_IT_Update|TIM_IT_CC1,ENABLE);//允许 更新中断、 捕获中断
	TIM_Cmd(TIM3,ENABLE ); //使能定时器3

}
//定时器输入捕获中断标志结构体
typedef struct
{
	u8  Capture_FinishFlag;  //捕获结束标志位
	u8  Capture_StartFlag;   //捕获开始标志位
	u16 Capture_Value;       //捕获寄存器的值
	u16 Period_Flag          //重装载寄存器更新标志位,表示产生了多少次更新中断
}TIM_MyFlagTypeDef;
TIM_MyFlagTypeDef TIM_MyFlagStructure={0,0,0,0};
//定时器3 中断服务程序
void TIM3_IRQHandler(void)
{
	//更新中断检测,被捕获信号的周期大于定时器最长定时时
	if(TIM_GetITStatus(TIM3, TIM_IT_Update)!=ReSET)
	{
		TIM_MyFlagStructure.Period_Flag++;   
		TIM_ClearITPendingBit(TIM3, TIM_IT_Update);       
	}
	//捕获中断检测
	if(TIM_GetITStatus(TIM3, TIM_IT_CC1)!=RESET)
	{	
		//捕获上升沿中断
		if(TIM_MyFlagStructure.Capture_StartFlag==0)//第一次捕获
		{
			TIM_SetCounter(TIM3,0);//计数器请0
			TIM_MyFlagStructure.Period_Flag=0;//重装载寄存器清0
			TIM_MyFlagStructure.Capture_Value=0;//捕获值清0
			TIM_OC1PolarityConfig(TIM3,TIM_ICPolarity_Falling);//改变通道1捕获的边沿
			TIM_MyFlagStructure.Capture_StartFlag=1;//开始捕获,标志位置1
		}
		//下降沿捕获(因为第一次捕获时改变了捕获的边沿,因此第二次捕获的是下降沿)
		else  //第二次捕获,即一个高电平脉宽
		{
			TIM_MyFlagStructure.Capture_Value=TIM_GetCapture1(TIM3);//获取通道1 捕获寄存器的值
			TIM_OC1PolarityConfig(TIM3,TIM_ICPolarity_Rising);//重新捕获上升沿
			TIM_MyFlagStructure.Capture_StartFlag=0;//可以再次进行下一次捕获
			TIM_MyFlagStructure.Period_Flag=0; //更新标志清0
			TIM_MyFlagStructure.Capture_FinishFlag=1;//第一次捕获结束
		}
		TIM_ClearITPendingBit(TIM3, TIM_IT_CC1); 
	}
}
//mian函数主要内容
u32 time;
u32 TIM_PscCLK=SYSCLK_FREQ_72MHz/72;
TIM3_Init(65535,71);
while(1)
{
	if(TIM_MyFlagStructure.Capture_FinishFlag==1)//捕获了一个周期了
	{
		time=TIM_MyFlagStructure.Period_Flag*65535+(TIM_MyFlagStructure.Capture_Value+1);//计算高电平时间的计数器值
		printf(高电平脉宽时间未:%d.%d sn,time/TIM_PscCLK,time%TIM_PscCLK);
		TIM_MyFlagStructure.Capture_FinishFlag=0;
	}
}

最后

以上就是深情可乐为你收集整理的TIM高级定时器(1)输入捕获、测脉宽的全部内容,希望文章能够帮你解决TIM高级定时器(1)输入捕获、测脉宽所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(36)

评论列表共有 0 条评论

立即
投稿
返回
顶部