05:TIM定时器功能------输入捕获功能

目录

1:简历

2:频率测量

3:主从触发模式

4:结构

A:输入捕获功能测频率

1:连接图

2:函数介绍

3:测周法

4 输入捕获模式基本结构

5:步骤

6:代码

B :PWMI模式测频率占空比

1: 连接图

 2:PWMI模式的结构

 3:函数介绍

4:步骤

5:代码


1:简历

        IC(Input Capture)输入捕获

        输入捕获模式下,当通道输入引脚出现指定电平跳变时,当前CNT的值将被锁存到CCR中,可用于测量PWM波形的频率、占空比、脉冲间隔、电平持续时间等参数

        每个高级定时器和通用定时器都拥有4个输入捕获通道

        可配置为PWMI模式,同时测量频率和占空比

        可配合主从触发模式,实现硬件全自动测量

2:频率测量

对于STM32测频率而言,它也是只能测量数字信号的

 频率 : 是单位时间(1s)内周期性过程重复、循环或振动的次数

测频法 : 一般情况下T为1s,符合频率的定义,-----适合测量高频信号

测周法原理 : 先对信号的周期T进行测量,然后根据f=1/T而得到信号的频率。测量2个上升沿的时间, 没有一个精度无穷大的秒表来测量时间,所以使用这个方法来测力量(见 : 3:测周法)-----适合测量高频信号

当N越大时, 正负1的误差对我们的影响就越小

当: 待测频率<中界频率----使用测周法

        待测频率>中界频率----使用测频法

3:主从触发模式

主模式 : 可以将定时器内部的信号,映射到TRGO引脚 , 用于触发别的外设,所以这部分叫做主模式

从模式 : 就是接收其他外设或者自身外设的一些信号, 用于控制自身定时器的运行,也就是被别的信号控制

触发源选择 : 就是选择从模式的触发信号源的, 从模式的一部分, 触发源选择,选择指定的一个信号,得到TRGI,TRGI去触发从模式,从模式可以在从模式列表里,选择一项操作来自动执行

4:结构

输入捕获模式基本结构

PWMI模式的结构

A:输入捕获功能测频率

1:连接图

 

A0:为输出引脚,负责输出PWM波形

A6:为输入引脚复制计算输入的频率

2:函数介绍

在stm32f10x tim.h文件中的函数-----输入捕获的配置

void TIM_ICInit(TIM_TypeDef* TIMx, TIM_ICInitTypeDef* TIM_ICInitStruct);

TIM_ICInit :

TIM_ICInitTypeDef  TIM_initstruct;
    TIM_initstruct.TIM_Channel=TIM_Channel_1;  //选择的通道 PA6对应的为通道1
    TIM_initstruct.TIM_ICFilter=;   //滤波器
    TIM_initstruct.TIM_ICPolarity=TIM_ICPolarity_Rising; //极性 我们选择上升沿触发  
    TIM_initstruct.TIM_ICPrescaler=TIM_ICPSC_DIV1;    //分频器 不分频(1)就是每次触发都有效;2分频就是每隔一次有效一次,以此类推
    TIM_initstruct.TIM_ICSelection=TIM_ICSelection_DirectTI;   //选择触发信号从哪个引脚输入(直连输入)

    TIM_ICInit(TIM3,&TIM_initstruct);

在stm32f10x tim.h文件中的函数----触发源选择:配置TRGI的触发源为TI1FP1

void TIM_SelectInputTrigger(TIM_TypeDef* TIMx, uint16_t TIM_InputTriggerSource)

TIM_SelectInputTrigger : 第二个参数选择触发源

在stm32f10x tim.h文件中的函数-----配置从模式--配置从模式为Reseta

void TIM_SelectSlaveMode(TIM_TypeDef* TIMx, uint16_t TIM_SlaveMode)

在stm32f10x tim.h文件中的函数-----单独改变PSC的值

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

 TIM_PrescalerConfig : 可以改变PSC的值的函数

第三个参数(指定定时器预分频器的重装模式): TIM_PSCReloadMode_Update 预分频器在更新事件重装,在更新时间后面生效

TIM_PSCReloadMode_Immediate : 立刻生效

 

在stm32f10x tim.h文件中的函数---------通道X读取CCR的值

uint16_t TIM_GetCapture1(TIM_TypeDef* TIMx);
uint16_t TIM_GetCapture2(TIM_TypeDef* TIMx);
uint16_t TIM_GetCapture3(TIM_TypeDef* TIMx);
uint16_t TIM_GetCapture4(TIM_TypeDef* TIMx);

PA6对应的为通道1,所以选择  TIM_GetCapture1---选择那个通道取决于引脚的定义

3:测周法

实例使用的是测周法 ; 对于STM32测频率而言,它也是只能测量数字信号的

测周法:两个上升沿内,以标准频率fc计次,得到N ,则频率 fx=fc / N

 

计数器自增的频率 = 计数标准频率 fc = CK_PSC (72mHZ) / 预分频(PSC)   

N : 简单理解就是CCR的值 (详情请看简历第二条)

4 输入捕获模式基本结构

 

5:步骤

1 : RCC开启时钟,(TIM外设---RCC_APB1PeriphClockCmd和GPIO外设----RCC_APB2PeriphClockCmd的时钟打开)

2 : 配置GPIO----GPIO_Init    (最后写第二步)

3 : 时钟选择----TIM_InternalClockConfig(内部)

4 :  配置时基单元-----TIM_TimeBaseInit()

5 :  配置输入捕获(ic)----TIM_ICInit()

6 : 触发源选择: 配置TRGI的触发源为TI1FP1----------TIM_SelectInputTrigger()

7 : 配置从模式"配置从模式为Reset--------TIM_SelectSlaveMode()

8 : 启动定时器-----TIM_Cmd()

6:代码

PA0口使用TIM2输出一个PWM波形,PA6口测频率

#include "stm32f10x.h"                  // Device header
#include "Delay.h"
#include "OLED.h"
#include "PWM.h"
#include "IC.h"
void PWM_init(){
	//第一步,RCC开启时钟,把我们要用的TIM外设和GPIO外设的时钟打开
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE);
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
	

	//第二步,配置GPIO
	GPIO_InitTypeDef GPIO_INITStruct;
	GPIO_INITStruct.GPIO_Mode=GPIO_Mode_AF_PP;  //复用推挽输出
	GPIO_INITStruct.GPIO_Pin=GPIO_Pin_0 ;
	GPIO_INITStruct.GPIO_Speed= GPIO_Speed_50MHz;
	GPIO_Init(GPIOA,&GPIO_INITStruct);
	//第三步,时钟源选择(内部时钟)
	TIM_InternalClockConfig(TIM2);
	//第四步,配置时基单元
	TIM_TimeBaseInitTypeDef TIM_INITStruct;
	TIM_INITStruct.TIM_ClockDivision=TIM_CKD_DIV1;
	TIM_INITStruct.TIM_CounterMode=TIM_CounterMode_Up;  向上计数
	TIM_INITStruct.TIM_Period=100-1;     //ARR
	TIM_INITStruct.TIM_Prescaler=720-1;			//PSC
	TIM_INITStruct.TIM_RepetitionCounter=0;
	TIM_TimeBaseInit(TIM2,&TIM_INITStruct);
	//第五步,配置输出比较单元
	TIM_OCInitTypeDef TIM_OCInitStructure;
	TIM_OCStructInit(&TIM_OCInitStructure);//给输出比较结构体赋一个默认的值
	TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1; //选择PWM1的模式
	TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; //有效电频为低电频
	TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;  //使能
	TIM_OCInitStructure.TIM_Pulse = 0;		//CCR
	TIM_OC1Init(TIM2, &TIM_OCInitStructure);
	//第六步,启动定时器
	TIM_Cmd(TIM2,ENABLE);
}

void PWM_SetCompare1(uint16_t Compare)
{
	TIM_SetCompare1(TIM2, Compare);
}

void PWM_SetPrescaler(uint16_t Prescaler)
{	
	//可以单独改变PSC的值
	TIM_PrescalerConfig(TIM2, Prescaler, TIM_PSCReloadMode_Immediate);
}


void IC_init(){
	//第一步,RCC开启时钟,把我们要用的TIM外设和GPIO外设的时钟打开
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3,ENABLE);
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
	//第二步,配置GPIO
	GPIO_InitTypeDef GPIO_INITStruct;
	GPIO_INITStruct.GPIO_Mode=GPIO_Mode_IPU;  //上拉输入
	GPIO_INITStruct.GPIO_Pin=GPIO_Pin_6 ;
	GPIO_INITStruct.GPIO_Speed= GPIO_Speed_50MHz;
	GPIO_Init(GPIOA,&GPIO_INITStruct);
	//第三步,时钟源选择(内部时钟)
	TIM_InternalClockConfig(TIM3);
	//第四步,配置时基单元
	TIM_TimeBaseInitTypeDef TIM_INITStruct;
	TIM_INITStruct.TIM_ClockDivision=TIM_CKD_DIV1;
	TIM_INITStruct.TIM_CounterMode=TIM_CounterMode_Up;  向上计数
	TIM_INITStruct.TIM_Period=65536 - 1;		//ARR
	TIM_INITStruct.TIM_Prescaler=72-1;			//PSC
	TIM_INITStruct.TIM_RepetitionCounter=0;
	TIM_TimeBaseInit(TIM3,&TIM_INITStruct);
	//第五步,配置输入捕获(ic)
	TIM_ICInitTypeDef TIM_initstruct;
	TIM_initstruct.TIM_Channel=TIM_Channel_1;  //选择的通道 PA6对应的为通道1
	TIM_initstruct.TIM_ICFilter=0xF;   //滤波器
	TIM_initstruct.TIM_ICPolarity=TIM_ICPolarity_Rising; //极性 我们选择上升沿触发  
	TIM_initstruct.TIM_ICPrescaler=TIM_ICPSC_DIV1;    //分频器 不分频(1)就是每次触发都有效;2分频就是每隔一次有效一次,以此类推
	TIM_initstruct.TIM_ICSelection=TIM_ICSelection_DirectTI;   //选择触发信号从哪个引脚输入(直连输入)
	TIM_ICInit(TIM3,&TIM_initstruct);
	//第六步,触发源选择: 配置TRGI的触发源为TI1FP1
	TIM_SelectInputTrigger(TIM3, TIM_TS_TI1FP1);
	//第七步,配置从模式-:配置从模式为Reseta
	TIM_SelectSlaveMode(TIM3, TIM_SlaveMode_Reset);
	//第八步,启动定时器
	TIM_Cmd(TIM3,ENABLE);

}

uint32_t IC_GetFreq(void)   //Fc=72mHZ/(PSC+1)  psc=72-1  FC=1000 000
{    //高电平的计数值存在CCR2里,整个周期的计数值存在CCR1里
	return 1000000 / (TIM_GetCapture1(TIM3) + 1);  //FX=FC/N  N就是读取CCR的值
}


int main(void)
{
	OLED_Init();
	PWM_init();
	IC_init();
	
	OLED_ShowString(1, 1, "Freq:00000Hz");
																		//pwm文件中ARR定时了为100
	PWM_SetPrescaler(720 - 1);			//Freq = 72M / (PSC + 1) / 100    改变PA0引脚PSC预分频器的值
	PWM_SetCompare1(50);				//Duty = CCR / 100   		改变PA0引脚CCR的值
	
	while (1)
	{
		OLED_ShowNum(1, 6, IC_GetFreq(), 5);
	}
}

 不使用一个定时器? 输出比较使用TMI2(输出pwm),  输入捕获使用TIM3(测频率)

 4个输入捕获和输出比较通道(CH),共用4个CCR寄存器, 它们的CH1到CH4,4个通道的引脚,也是共用的. 对于同一个定时器,输入捕获和输出比较只能使用其中一个,不能同时使用

计算输入捕获

输入捕获使用了TIM3通用定时器

高电平的计数值存在CCR2里,整个周期的计数值存在CCR1里

 

引脚通道

输入捕获

 本次使用的是同用定时器TIM3的PA6引脚, 根据引脚的定义我们应该使用通道1

输入捕获的通道选择是在配置IC时选择的(输入捕获的配置): TIM_initstruct.TIM_Channel=TIM_Channel_1; ---通道1

主从触发模式------清零CNT

       上升沿用于触发输入捕获,CNT用于计数计时 .每来一个上升沿,取一下CNT的值,自动存在CCR里. CCR捕获到到的值。就是计数值N.  CNT的驱动时钟,就是fc 

        每次捕获之后我们都要把CNT清0一下,下次上升沿再捕获的时候, 取出的CNT的值就是两次上升沿的时间间隔.

        在一次捕获后自动将CNT清零的步骤,可以用主从触发模式,自动来完成

        硬件电路就可以在捕获之后自动完成CNT的清零工作; 

        TI1FP1信号和TI1的边沿信号都可以通向从模式控制器, TI1FP1还可以同时触发从模式, 从模式里面,就有电路,可以自动完成CNT的清零

 想TI1FP1信号户社知分CNT清零:

1 : 触发源选择-------选中这里的TI1FP1    TIM_SelectInputTrigger

2 : 从模式-------------选执行Reset的操作    TIM_SelectSlaveMode

注意:

这里CNT的值是有上限的,ARR一般设置为最大65535,CNT最大也只能计65535个数 

        在触发源选择中只有TF1FP1,TF2FP2的信号,没有TF3FP3,TF4FP4的信号; 如果想使用从模式自动清零CNT,就只能用通道1和通道2; 对于通道3和通道4,就只能开启捕获束断。手动清零这样子比较消耗系统资源

B :PWMI模式测频率占空比

1: 连接图

和 A:输入捕获功能测频率是一个连接图

 2:PWMI模式的结构

 3:函数介绍

在stm32f10x tim.h文件中的函数-----打开PWMI模式

void TIM_PWMIConfig(TIM_TypeDef* TIMx, TIM_ICInitTypeDef* TIM_ICInitStruct);

只支持通道1和通道2 

4:步骤

1 : RCC开启时钟,(TIM外设---RCC_APB1PeriphClockCmd和GPIO外设----RCC_APB2PeriphClockCmd的时钟打开)

2 : 配置GPIO----GPIO_Init    (最后写第二步)

3 : 时钟选择----TIM_InternalClockConfig(内部)

4 :  配置时基单元-----TIM_TimeBaseInit()

5 :  配置输入捕获(ic)----TIM_ICInit()

6: 打开PWMI模式-----TIM_PWMIConfig();

7 : 触发源选择: 配置TRGI的触发源为TI1FP1----------TIM_SelectInputTrigger()

8 : 配置从模式"配置从模式为Reset--------TIM_SelectSlaveMode()

9 : 启动定时器-----TIM_Cmd()

5:代码

#include "stm32f10x.h"                  // Device header
#include "Delay.h"
#include "OLED.h"
#include "PWM.h"
#include "IC.h"
void PWM_init(){
	//第一步,RCC开启时钟,把我们要用的TIM外设和GPIO外设的时钟打开
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE);
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
	

	//第二步,配置GPIO
	GPIO_InitTypeDef GPIO_INITStruct;
	GPIO_INITStruct.GPIO_Mode=GPIO_Mode_AF_PP;  //复用推挽输出
	GPIO_INITStruct.GPIO_Pin=GPIO_Pin_0 ;
	GPIO_INITStruct.GPIO_Speed= GPIO_Speed_50MHz;
	GPIO_Init(GPIOA,&GPIO_INITStruct);
	//第三步,时钟源选择(内部时钟)
	TIM_InternalClockConfig(TIM2);
	//第四步,配置时基单元
	TIM_TimeBaseInitTypeDef TIM_INITStruct;
	TIM_INITStruct.TIM_ClockDivision=TIM_CKD_DIV1;
	TIM_INITStruct.TIM_CounterMode=TIM_CounterMode_Up;  向上计数
	TIM_INITStruct.TIM_Period=100-1;     //ARR
	TIM_INITStruct.TIM_Prescaler=720-1;			//PSC
	TIM_INITStruct.TIM_RepetitionCounter=0;
	TIM_TimeBaseInit(TIM2,&TIM_INITStruct);
	//第五步,配置输出比较单元
	TIM_OCInitTypeDef TIM_OCInitStructure;
	TIM_OCStructInit(&TIM_OCInitStructure);//给输出比较结构体赋一个默认的值
	TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1; //选择PWM1的模式
	TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; //有效电频为低电频
	TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;  //使能
	TIM_OCInitStructure.TIM_Pulse = 0;		//CCR
	TIM_OC1Init(TIM2, &TIM_OCInitStructure);
	//第六步,启动定时器
	TIM_Cmd(TIM2,ENABLE);
}

void PWM_SetCompare1(uint16_t Compare)
{
	TIM_SetCompare1(TIM2, Compare);
}

void PWM_SetPrescaler(uint16_t Prescaler)
{	
	//可以单独改变PSC的值
	TIM_PrescalerConfig(TIM2, Prescaler, TIM_PSCReloadMode_Immediate);
}


void IC_init(){
	//第一步,RCC开启时钟,把我们要用的TIM外设和GPIO外设的时钟打开
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3,ENABLE);
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
	//第二步,配置GPIO
	GPIO_InitTypeDef GPIO_INITStruct;
	GPIO_INITStruct.GPIO_Mode=GPIO_Mode_IPU;  //上拉输入
	GPIO_INITStruct.GPIO_Pin=GPIO_Pin_6 ;
	GPIO_INITStruct.GPIO_Speed= GPIO_Speed_50MHz;
	GPIO_Init(GPIOA,&GPIO_INITStruct);
	//第三步,时钟源选择(内部时钟)
	TIM_InternalClockConfig(TIM3);
	//第四步,配置时基单元
	TIM_TimeBaseInitTypeDef TIM_INITStruct;
	TIM_INITStruct.TIM_ClockDivision=TIM_CKD_DIV1;
	TIM_INITStruct.TIM_CounterMode=TIM_CounterMode_Up;  向上计数
	TIM_INITStruct.TIM_Period=65536 - 1;		//ARR
	TIM_INITStruct.TIM_Prescaler=72-1;			//PSC
	TIM_INITStruct.TIM_RepetitionCounter=0;
	TIM_TimeBaseInit(TIM3,&TIM_INITStruct);
	//第五步,配置输入捕获(ic)
	TIM_ICInitTypeDef TIM_initstruct;
	TIM_initstruct.TIM_Channel=TIM_Channel_1;  //选择的通道 PA6对应的为通道1
	TIM_initstruct.TIM_ICFilter=0xF;   //滤波器
	TIM_initstruct.TIM_ICPolarity=TIM_ICPolarity_Rising; //极性 我们选择上升沿触发  
	TIM_initstruct.TIM_ICPrescaler=TIM_ICPSC_DIV1;    //分频器 不分频(1)就是每次触发都有效;2分频就是每隔一次有效一次,以此类推
	TIM_initstruct.TIM_ICSelection=TIM_ICSelection_DirectTI;   //选择触发信号从哪个引脚输入(直连输入)
	TIM_ICInit(TIM3,&TIM_initstruct);
	TIM_PWMIConfig(TIM3,&TIM_initstruct);
	
	//第六步,触发源选择: 配置TRGI的触发源为TI1FP1
	TIM_SelectInputTrigger(TIM3, TIM_TS_TI1FP1);
	//第七步,配置从模式-:配置从模式为Reseta
	TIM_SelectSlaveMode(TIM3, TIM_SlaveMode_Reset);
	//第八步,启动定时器
	TIM_Cmd(TIM3,ENABLE);

}

uint32_t IC_GetFreq(void)   //Fc=72mHZ/(PSC+1)  psc=72-1  FC=1000 000
{
	return 1000000 / (TIM_GetCapture1(TIM3) + 1);  //FX=FC/N  N就是读取CCR的值
}


uint32_t IC_duty_cycle(void){
	//高电平的计数值存在CCR2里,整个周期的计数值存在CCR1里
	return TIM_GetCapture2(TIM3)*100/TIM_GetCapture1(TIM3);

}



int main(void)
{
	OLED_Init();
	PWM_init();
	IC_init();
	
	OLED_ShowString(1, 1, "Freq:00000Hz");
	OLED_ShowString(2, 1, "Duty:00%");

																		//pwm文件中ARR定时了为100
	PWM_SetPrescaler(720 - 1);			//Freq = 72M / (PSC + 1) / 100    改变PA0引脚PSC预分频器的值
	PWM_SetCompare1(50);				//Duty = CCR / 100   									改变PA0引脚CCR的值
	
	while (1)
	{
		OLED_ShowNum(1, 6, IC_GetFreq(), 5);
		OLED_ShowNum(2, 6, IC_duty_cycle(), 2);
	}
}

 占空比

uint32_t IC_duty_cycle(void){
    //高电平的计数值存在CCR2里,整个周期的计数值存在CCR1里
    return TIM_GetCapture2(TIM3)*100/TIM_GetCapture1(TIM3);

}

和  A:输入捕获功能测频率的代码相比,  只在配置输入捕获(IC)的时候打开了PWMI通道

TIM_PWMIConfig();

  • 1
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值