TIM输入捕获
概念
IC(Input Capture)输入捕获 输入捕获模式下,当通道输入引脚出现指定电平跳变时,当前CNT的值将被锁存到CCR中,可用于测量PWM波形的频率、占空比、脉冲间隔、电平持续时间等参数
每个高级定时器和通用定时器都拥有4个输入捕获通道
可配置为PWMI模式,同时测量频率和占空比
可配合主从触发模式,实现硬件全自动测量
频率测量
测频法:在闸门时间T内,对上升沿计次,得到N,则频率 f_x=N / T,适合于高频信号
测周法:两个上升沿内,以标准频率fc计次,得到N ,则频率 f_x=f_c / N,适合于低频信号
中界频率:测频法与测周法误差相等的频率点 f_m=√f_c / T
都以上升沿为一个周期的开始进行描述
输入捕获通道
主从触发模式
输入捕获基本结构
右上角图解释:当第一次遇到上升沿时,CCR1=CNT,CNT自动复位清零。之后CNT++,在第二次遇到上升沿时候,再次执行CCR1=CNT,CNT=0的操作,这时候CCR1=CNT的值就是CNT++的值,也就是一个周期的时间
CNT有上限65535,根据ARR=65535得出
PWMI基本结构
右上角图解释:当第一次遇到上升沿时,CCR1=CNT,CNT自动复位清零。之后CNT++,在遇到下降沿的时候,CCR2=CNT也就是CCR2为高电平期间的计数值,但是不触发CNT清零,CNT仍继续++,在第二次遇到上升沿时候,再次执行CCR1=CNT,CNT=0的操作,这时候CCR1=CNT的值就是CNT++的值,也就是一个周期的时间。
代码
IC代码
#include "stm32f10x.h" // Device header
void IC_Init(void)
{
/*开启时钟*/
RCC_APB1PeriphClockCmd (RCC_APB1Periph_TIM3 ,ENABLE );//开启TIM3的时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA ,ENABLE);//开启GPIOA的时钟
/*GPIO初始化*/
GPIO_InitTypeDef GPIO_InitSturcture;
GPIO_InitSturcture.GPIO_Mode=GPIO_Mode_IPU;
GPIO_InitSturcture.GPIO_Pin=GPIO_Pin_6;
GPIO_InitSturcture.GPIO_Speed=GPIO_Speed_50MHz;
GPIO_Init(GPIOA,&GPIO_InitSturcture);//将PA6引脚初始化为上拉输入
/*配置时钟源*/
TIM_InternalClockConfig(TIM3); //选择TIM2为内部时钟,若不调用此函数,TIM默认也为内部时钟
/*时基单元初始化*/
TIM_TimeBaseInitTypeDef TIM_TimebaseinitStructure;//定义结构体变量
TIM_TimebaseinitStructure.TIM_ClockDivision=TIM_CKD_DIV1 ;//时钟分频,选择不分频,此参数用于配置滤波器时钟,不影响时基单元功能
TIM_TimebaseinitStructure.TIM_CounterMode=TIM_CounterMode_Up ;//计数器模式,选择向上计数
TIM_TimebaseinitStructure.TIM_Period=65536-1;//计数周期,即ARR的值
TIM_TimebaseinitStructure.TIM_Prescaler=72-1;//预分频器,即PSC的值
TIM_TimebaseinitStructure.TIM_RepetitionCounter=0;//重复计数器,高级定时器才会用到
TIM_TimeBaseInit(TIM3,&TIM_TimebaseinitStructure); //将结构体变量交给TIM_TimeBaseInit,配置TIM2的时基单元
TIM_ICInitTypeDef TIM_ICInitstructure;//定义结构体变量
TIM_ICInitstructure.TIM_Channel=TIM_Channel_1;//选择配置定时器通道1
TIM_ICInitstructure.TIM_ICFilter=0XF; //输入滤波器参数,可以过滤信号抖动
TIM_ICInitstructure.TIM_ICPolarity=TIM_ICPolarity_Rising;//极性,选择为上升沿触发捕获
TIM_ICInitstructure.TIM_ICPrescaler=TIM_ICPSC_DIV1;//捕获预分频,选择不分频,每次信号都触发捕获
TIM_ICInitstructure.TIM_ICSelection=TIM_ICSelection_DirectTI;//输入信号交叉,选择直通,不交叉
TIM_ICInit(TIM3,&TIM_ICInitstructure);//将结构体变量交给TIM_ICInit,配置TIM3的输入捕获通道
TIM_SelectInputTrigger(TIM3,TIM_TS_TI1FP1);//触发源选择TI1FP1
TIM_SelectSlaveMode(TIM3,TIM_SlaveMode_Reset);//从模式选择复位
//即TI1产生上升沿时,会触发CNT归零
TIM_Cmd (TIM3,ENABLE );
}
uint32_t IC_Getfreq(void)
{
return 10000000/TIM_GetCapture1(TIM3);//测周法得到频率fx = fc / N,这里不执行+1的操作也可
}
main代码
#include "stm32f10x.h" // Device header
#include "Delay.h"
#include "LED.h"
#include "OLED.h"
#include "PWM.h"
#include "IC.h"
uint8_t i;
int main(void)
{
OLED_Init();
PWM_Init ();
IC_Init();
OLED_ShowString(1,1,"Freq00000Hz");//1行1列显示字符串Freq:00000Hz
Pwm_SetPrescaler(720-1); //freq=72M/(psc+1)/100
pwm_setcompare(50); //duty=CRR/100
while(1)
{
OLED_ShowNum(1,6,IC_Getfreq(),5);//不断刷新显示输入捕获测得的频率
}
}
PWMI模式测频率占空比
IC代码
#include "stm32f10x.h" // Device header
void IC_Init(void)
{
/*开启时钟*/
RCC_APB1PeriphClockCmd (RCC_APB1Periph_TIM3 ,ENABLE );//开启TIM3的时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA ,ENABLE);//开启GPIOA的时钟
/*GPIO初始化*/
GPIO_InitTypeDef GPIO_InitSturcture;
GPIO_InitSturcture.GPIO_Mode=GPIO_Mode_IPU;
GPIO_InitSturcture.GPIO_Pin=GPIO_Pin_6;
GPIO_InitSturcture.GPIO_Speed=GPIO_Speed_50MHz;
GPIO_Init(GPIOA,&GPIO_InitSturcture);//将PA6引脚初始化为上拉输入
/*配置时钟源*/
TIM_InternalClockConfig(TIM3); //选择TIM2为内部时钟,若不调用此函数,TIM默认也为内部时钟
/*时基单元初始化*/
TIM_TimeBaseInitTypeDef TIM_TimebaseinitStructure; //定义结构体变量
TIM_TimebaseinitStructure.TIM_ClockDivision=TIM_CKD_DIV1 ; //时钟分频,选择不分频,此参数用于配置滤波器时钟,不影响时基单元功能
TIM_TimebaseinitStructure.TIM_CounterMode=TIM_CounterMode_Up ; //计数器模式,选择向上计数
TIM_TimebaseinitStructure.TIM_Period=65536-1; //计数周期,即ARR的值
TIM_TimebaseinitStructure.TIM_Prescaler=72-1; //预分频器,即PSC的值
TIM_TimebaseinitStructure.TIM_RepetitionCounter=0; //重复计数器,高级定时器才会用到
TIM_TimeBaseInit(TIM3,&TIM_TimebaseinitStructure); //将结构体变量交给TIM_TimeBaseInit,配置TIM2的时基单元
TIM_ICInitTypeDef TIM_ICInitstructure; //定义结构体变量
TIM_ICInitstructure.TIM_Channel=TIM_Channel_1; //选择配置定时器通道1
TIM_ICInitstructure.TIM_ICFilter=0XF; //输入滤波器参数,可以过滤信号抖动
TIM_ICInitstructure.TIM_ICPolarity=TIM_ICPolarity_Rising; //极性,选择为上升沿触发捕获
TIM_ICInitstructure.TIM_ICPrescaler=TIM_ICPSC_DIV1; //捕获预分频,选择不分频,每次信号都触发捕获
TIM_ICInitstructure.TIM_ICSelection=TIM_ICSelection_DirectTI; //输入信号交叉,选择直通,不交叉
TIM_ICInit(TIM3,&TIM_ICInitstructure); //将结构体变量交给TIM_ICInit,配置TIM3的输入捕获通道
TIM_PWMIConfig(TIM3,&TIM_ICInitstructure); //将结构体变量交给TIM_PWMIConfig,配置TIM3的输入捕获通道
//此函数同时会把另一个通道配置为相反的配置,实现PWMI模式
TIM_SelectInputTrigger(TIM3,TIM_TS_TI1FP1); //触发源选择TI1FP1
TIM_SelectSlaveMode(TIM3,TIM_SlaveMode_Reset); //从模式选择复位
//即TI1产生上升沿时,会触发CNT归零
TIM_Cmd (TIM3,ENABLE );
}
uint32_t IC_Getfreq(void)
{
return 1000000/TIM_GetCapture1(TIM3);//测周法得到频率fx = fc / N,这里不执行+1的操作也可
}
uint32_t IC_getDuty(void)
{
return (TIM_GetCapture2(TIM3)+1)*100/(TIM_GetCapture1(TIM3)+1);//占空比Duty = CCR2 / CCR1 * 100,这里不执行+1的操作也可
}
main代码
#include "stm32f10x.h" // Device header
#include "Delay.h"
#include "LED.h"
#include "OLED.h"
#include "PWM.h"
#include "IC.h"
uint8_t i;
int main(void)
{
OLED_Init();
PWM_Init ();
IC_Init();
OLED_ShowString(1,1,"Freq:00000Hz");//1行1列显示字符串Freq:00000Hz
OLED_ShowString(2,1,"Duty:00%");//1行1列显示字符串Freq:00000Hz
Pwm_SetPrescaler(7200-1); //freq=72M/(psc+1)/100
pwm_setcompare(80); //duty=CRR/100
while(1)
{
OLED_ShowNum(1,6,IC_Getfreq(),5);//不断刷新显示输入捕获测得的频率
OLED_ShowNum(2,6,IC_getDuty(),2);//不断刷新显示输入捕获测得的频率
}
}
后续补充
1.测频率的范围
最低频率为1M/65535=15Hz,如果要降低最低频率的限制可以将预分频(PSC)加大,使得标准频率降低,所支持测量的最低频率也就更低。
最大频率无明显界限,随着待测频率的增加误差会增大。