TIM输入捕获-STM32
IC(Input Capture) 输入捕获
输入捕获模式下,当通道输入引脚出现指定电平跳变时,当前CNT的值将被锁存到CCR中,可用于测量PWM波形的频率、占空比、脉冲间隔、电平持续时间等参数
每个高级定时器和通用定时器都拥有4个输入捕获通道可配置为PWMI模式,同时测量频率和占空比可配合主从触发模式,实现硬件全自动测量
输出比较和输入捕获的区别:
输出比较,引脚是输出端口;输入捕获,引脚是输入端口。
输出比较,是根据CNT和CCR的大小关系来执行输出动作;输入捕获,是接收到输入信号,执行CNT锁存到CCR的动作。
一般我们可以根据分辨率的要求,先确定好ARR;比如分辨率,1%就足够了,那ARR给100-1,这样PSC决定频率,CCR决定占空比。
第一步,RCC开启时钟,把GPIO和TIM的时钟打开
第二步,GPIO初始化,把GPIO配置成输入模式,一般选择上拉输入或者浮空输入模式
第三步,配置时基单元,让CNT计数器在内部时钟的驱动下自增运行
第四步,配置输入捕获单元。包括滤波器、极性、直连通道还是交又通道、分频器这些参数;用一个结构体就可以统一进行配置了
第五步,选择从模式的触发源。触发源选择为TI1FP1,这里调用一个库函数,给一个参数就行了
第六步,选择触发之后执行的操作。执行Reset操作,这里也是调用一个库函数就行了
调用TIM_Cmd函数,开启定时器。
当我们需要读取最新一个周期的频率时,直接读取CCR寄存器,然后按照fc/N,计算一下就行了。
测试频率
#include "stm32f10x.h" // Device header
void IC_Init(void)
{
//第一步开启时钟,初始化RCC,选择TIM2
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3,ENABLE);
//设置输出PWM的GPIO端口
//使能GPIOA的时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
//GPIOA模式初始化
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);
//第二步选择时基单元的时钟,选择内部时钟,选择TIM2
TIM_InternalClockConfig(TIM3);
//第三步配置时基单元
TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStruct;
TIM_TimeBaseInitStruct.TIM_ClockDivision = TIM_CKD_DIV1;//时钟分频系数 1分频
TIM_TimeBaseInitStruct.TIM_CounterMode = TIM_CounterMode_Up;//计数的模式 向上计数
//频率为1KHz,占空比为50%的PWM波形
//计数器溢出频率:CK CNT_OV = CKCNT /(ARR + 1)= CK PSC /(PSC + 1)/(ARR +1)
//配置定时为1s,则CK CNT_OV=1;CKCNT=72MHz=72000000;
TIM_TimeBaseInitStruct.TIM_Period = 65536 - 1;//周期,ARR自动重装器的值 范围0~65536 设置为最大值,防止溢出
TIM_TimeBaseInitStruct.TIM_Prescaler = 72 - 1;//PSC预分频器的值 范围0~65536 最后1Mhz
TIM_TimeBaseInitStruct.TIM_RepetitionCounter = 0; //重复计数器的值 高级计数器才有
TIM_TimeBaseInit(TIM3,&TIM_TimeBaseInitStruct);
//第四步,配置输入捕获单元。包括滤波器、极性、直连通道还是交又通道、分频器这些参数
TIM_ICInitTypeDef TIM_ICInitStruct;
TIM_ICInitStruct.TIM_Channel = TIM_Channel_1;//选择通道 选择TIM3的通道1
TIM_ICInitStruct.TIM_ICFilter = 0xF;//用来配置输入捕获的滤波器。数越大滤波效果越好
TIM_ICInitStruct.TIM_ICPolarity = TIM_ICPolarity_Rising;//上升沿触发
TIM_ICInitStruct.TIM_ICPrescaler = TIM_ICPSC_DIV1;//配置分频器,不分频
TIM_ICInitStruct.TIM_ICSelection = TIM_ICSelection_DirectTI;//配置数据选择器,直连通道
TIM_ICInit(TIM3,&TIM_ICInitStruct);
//第五步,选择从模式的触发源。触发源选择为TI1FP1,这里调用一个库函数,给一个参数就行了
TIM_SelectInputTrigger(TIM3,TIM_TS_TI1FP1);
//第六步,选择触发之后执行的操作。执行Reset操作,这里也是调用一个库函数就行了
TIM_SelectSlaveMode(TIM3,TIM_SlaveMode_Reset);
//调用TIM_Cmd函数,开启定时器
TIM_Cmd(TIM3,ENABLE);
}
//函数返回的是最新"个周期的频率值,单位是Hz
//Freq = CK_PSC / (PSC + 1) / (ARR + 1)
//CK_PSC= 72MHz PSC + 1 =100
uint32_t IC_GetFreq(void)
{
return 10000000/(TIM_GetCapture1(TIM3)+1);
}
#include "stm32f10x.h" // Device header
void IC_Init(void)
{
//第一步开启时钟,初始化RCC,选择TIM2
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3,ENABLE);
//设置输出PWM的GPIO端口
//使能GPIOA的时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
//GPIOA模式初始化
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);
//第二步选择时基单元的时钟,选择内部时钟,选择TIM2
TIM_InternalClockConfig(TIM3);
//第三步配置时基单元
TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStruct;
TIM_TimeBaseInitStruct.TIM_ClockDivision = TIM_CKD_DIV1;//时钟分频系数 1分频
TIM_TimeBaseInitStruct.TIM_CounterMode = TIM_CounterMode_Up;//计数的模式 向上计数
//频率为1KHz,占空比为50%的PWM波形
//计数器溢出频率:CK CNT_OV = CKCNT /(ARR + 1)= CK PSC /(PSC + 1)/(ARR +1)
//配置定时为1s,则CK CNT_OV=1;CKCNT=72MHz=72000000;
TIM_TimeBaseInitStruct.TIM_Period = 65536 - 1;//周期,ARR自动重装器的值 范围0~65536 设置为最大值,防止溢出
TIM_TimeBaseInitStruct.TIM_Prescaler = 72 - 1;//PSC预分频器的值 范围0~65536 最后1Mhz
TIM_TimeBaseInitStruct.TIM_RepetitionCounter = 0; //重复计数器的值 高级计数器才有
TIM_TimeBaseInit(TIM3,&TIM_TimeBaseInitStruct);
//第四步,配置输入捕获单元。包括滤波器、极性、直连通道还是交又通道、分频器这些参数
TIM_ICInitTypeDef TIM_ICInitStruct;
TIM_ICInitStruct.TIM_Channel = TIM_Channel_1;//选择通道 选择TIM3的通道1
TIM_ICInitStruct.TIM_ICFilter = 0xF;//用来配置输入捕获的滤波器。数越大滤波效果越好
TIM_ICInitStruct.TIM_ICPolarity = TIM_ICPolarity_Rising;//上升沿触发
TIM_ICInitStruct.TIM_ICPrescaler = TIM_ICPSC_DIV1;//配置分频器,不分频
TIM_ICInitStruct.TIM_ICSelection = TIM_ICSelection_DirectTI;//配置数据选择器,直连通道
TIM_ICInit(TIM3,&TIM_ICInitStruct);
TIM_PWMIConfig(TIM3,&TIM_ICInitStruct);//在函数里,会自动把剩下的一个通道初始化成相反的配置
// TIM_ICInitStruct.TIM_Channel = TIM_Channel_2;//选择通道 选择TIM3的通道1
// TIM_ICInitStruct.TIM_ICFilter = 0xF;//用来配置输入捕获的滤波器。数越大滤波效果越好
// TIM_ICInitStruct.TIM_ICPolarity = TIM_ICPolarity_Falling;//上升沿触发
// TIM_ICInitStruct.TIM_ICPrescaler = TIM_ICPSC_DIV1;//配置分频器,不分频
// TIM_ICInitStruct.TIM_ICSelection = TIM_ICSelection_IndirectTI;//配置数据选择器,交叉输入
// TIM_ICInit(TIM3,&TIM_ICInitStruct);
//第五步,选择从模式的触发源。触发源选择为TI1FP1,这里调用一个库函数,给一个参数就行了
TIM_SelectInputTrigger(TIM3,TIM_TS_TI1FP1);
//第六步,选择触发之后执行的操作。执行Reset操作,这里也是调用一个库函数就行了
TIM_SelectSlaveMode(TIM3,TIM_SlaveMode_Reset);
//调用TIM_Cmd函数,开启定时器
TIM_Cmd(TIM3,ENABLE);
}
//函数返回的是最新"个周期的频率值,单位是Hz
//Freq = CK_PSC / (PSC + 1) / (ARR + 1)
//CK_PSC= 72MHz PSC + 1 =100
uint32_t IC_GetFreq(void)
{
return 10000000/(TIM_GetCapture1(TIM3)+1);
}
//获取占空比
//Duty = CCR / (ARR + 1)
uint32_t IC_GetDuty(void)
{
//高电平的计数值存在CCR2里;整个周期的计数值存在CCR1里;用CCR2/CCR1,就能得到占空比了
return (TIM_GetCapture2(TIM3)+1)*100/(TIM_GetCapture1(TIM3)+1);//范围是0%~100%
}