STM32 TIM输入捕获 测量频率
输入捕获简介:
IC(Input Capture)输入捕获
输入捕获模式下,当通道输入引脚出现指定电平跳变时,当前CNT的值将被锁存到CCR中,可用于测量PWM波形的频率、占空比、脉冲间隔、电平持续时间等参数
每个高级定时器和通用定时器都拥有4个输入捕获通道
可配置为PWMI模式,同时测量频率和占空比
可配合主从触发模式,实现硬件全自动测量
频率测量:
输入捕获基本结构
主从触发模式:
接线图:
代码配置:
实现功能在屏幕上显示频率,频率通过ARR与PSC共同控制,而ARR也涉及到占空比的改变,所以我们选择更改PSC,在初始化后单独写一个函数更改PSC
需要调用到这个函数,单独用来写入PSC的函数
void TIM_PrescalerConfig(TIM_TypeDef* TIMx, uint16_t Prescaler, uint16_t TIM_PSCReloadMode);
void pWM_SetPrescaler(uint16_t Prescaler)
{
TIM_PrescalerConfig(TIM2, Prescaler, TIM_PSCReloadMode_Immediate);
}
函数介绍:
用结构体配置输入捕获单元的函数
注意:输入捕获与输出比较都有4个通道,OCInit,4个通道每个通道各占一个函数,而ICInit,4个通道是共用一个函数的,在结构体里会有一个参数,来配置具体哪个通道,因为可能有交叉通道的配置,所以函数合在一起比较方便
void TIM_ICInit(TIM_TypeDef* TIMx, TIM_ICInitTypeDef* TIM_ICInitStruct);
这个函数与上一个函数类似,都是用于初始化输入捕获单元的,但是上一个函数只是单一的配置一个通道,这个函数可以快速配置两个通道
void TIM_PWMIConfig(TIM_TypeDef* TIMx, TIM_ICInitTypeDef* TIM_ICInitStruct);
这个函数可以给输入捕获结构体赋一个初始值
void TIM_ICStructInit(TIM_ICInitTypeDef* TIM_ICInitStruct);
下面三个对应主从触发模式:
选择输入触发源TRGI
void TIM_SelectInputTrigger(TIM_TypeDef* TIMx, uint16_t TIM_InputTriggerSource);
选择输出触发源TRGO
void TIM_SelectOutputTrigger(TIM_TypeDef* TIMx, uint16_t TIM_TRGOSource);
选择从模式
void TIM_SelectSlaveMode(TIM_TypeDef* TIMx, uint16_t TIM_SlaveMode);
下面四个函数,分别单独配置通道1、2、3、4的分频器
void TIM_SetIC1Prescaler(TIM_TypeDef* TIMx, uint16_t TIM_ICPSC);
void TIM_SetIC2Prescaler(TIM_TypeDef* TIMx, uint16_t TIM_ICPSC);
void TIM_SetIC3Prescaler(TIM_TypeDef* TIMx, uint16_t TIM_ICPSC);
void TIM_SetIC4Prescaler(TIM_TypeDef* TIMx, uint16_t TIM_ICPSC);
分别读取4个通道的CCR,这4个函数和SetCompare1、2、3、4是对应的,输出比较模式下,CCR是只写的,要用SetCompare写入,输入捕获模式下,CCR是只读的,要用GetCapture读出
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);
输入捕获代码配置
根据结构图配置
1.定义结构体变量
定义GPIO、TimeBase时基单元、IC输入捕获单元结构体变量
//定义结构体变量
GPIO_InitTypeDef GPIO_InitStructure;//定义GPIO结构体变量
TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;//定义时基单元结构体变量
TIM_ICInitTypeDef TIM_ICInitStructure; //定义IC结构体变量
2.RCC开启时钟
把GPIO和TIM的时钟打开
//RCC开启时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);//开启GPIO A族时钟
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3,ENABLE);//开启TIM3时钟
3.GPIO初始化
把GPIO配置成输入模式,一般选择上拉输入或者浮空输入模式,这里选择TIM3_CH1通道,根据引脚图为PA6,所以这次配置这个引脚,模式选择上拉输入
//配置GPIO
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;//上拉输入
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;//配置引脚
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
4.配置时基单元
让CNT计数器在内部时钟的驱动下自增运行,这里的周期给到最大,PSC的值给72 - 1,这样标准频率就是72M / 72 = 1MHz 方便计算。
//配置时基单元
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);
5.配置输入捕获单元
包括滤波器、极性、直连通道还是交叉通道、分频器这些参数
//配置输入捕获单元
TIM_ICInitStructure.TIM_Channel = TIM_Channel_1;//选择通道 我们这里选择的是TIM3的CH1
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);
6.选择从模式的触发源
触发源选择为TI1FP1,这里调用一个库函数,给一个参数就行
//配置主从模式触发源
TIM_SelectInputTrigger(TIM3,TIM_TS_TI1FP1);//配置TRIG的触发源
7.选择触发之后执行的操作
执行Reset操作,这里也是调用一个库函数就行了
TIM_SelectSlaveMode(TIM3,TIM_SlaveMode_Reset);//配置从模式为Reset
最后调用TIM_CMD函数开启定时器,当我们需要读取最新一个周期的频率时,直接读取CCR寄存器,然后按照fc/N,计算一下就行了。
//启动定时器
TIM_Cmd(TIM3,ENABLE);
整体代码:
void IC_Init(void)
{
//定义结构体变量
GPIO_InitTypeDef GPIO_InitStructure;//定义GPIO结构体变量
TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;//定义时基单元结构体变量
TIM_ICInitTypeDef TIM_ICInitStructure; //定义IC结构体变量
//RCC开启时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);//开启GPIO A族时钟
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3,ENABLE);//开启TIM3时钟
//配置GPIO
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;//上拉输入
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;//配置引脚
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
//配置时基单元
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_ICInitStructure.TIM_Channel = TIM_Channel_1;//选择通道 我们这里选择的是TIM3的CH1
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_SelectInputTrigger(TIM3,TIM_TS_TI1FP1);//配置TRIG的触发源
TIM_SelectSlaveMode(TIM3,TIM_SlaveMode_Reset);//配置从模式为Reset
//启动定时器
TIM_Cmd(TIM3,ENABLE);
}
功能代码:
测量频率,在频幕上显示
uint32_t IC_GetFreg(void)
{
return 1000000 / (TIM_GetCapture1(TIM3) + 1);
}
主函数:
#include "IC.h"
int main(void)
{
LED_Init();
OLED_Init();
PWM_Init();
IC_Init();
pWM_SetPrescaler(720 - 1); //Freg = 72M / (PSC + 1) / 100
PWM_SetComPer(50); //Duty = CCR / 100
OLED_ShowString(1, 1, "Freg:00000Hz");
while(1)
{
OLED_ShowNum(1, 6, IC_GetFreg(), 5);
}
}