提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
一,输入捕获简介
- IC(Input Capture)输入捕获
- 输入捕获模式下,当通道输入引脚出现指定电平跳变时,当前CNT的值将被锁存到CCR中,可用于测量PWM波形的频率、占空比、脉冲间隔、电平持续时间等参数。
- 每个高级定时器和通用定时器都拥有4个输入捕获通道 。
- 可配置为PWMI模式,同时测量频率和占空比。
- 可配合主从触发模式,实现硬件全自动测量。
- 左侧为定时器输入捕获部分,右边为定时器输出比较部分。
- 四个输入捕获和四个输出比较共用四个捕获/比较寄存器,它们的引脚也是共用的。
- 同一定时器,捕获,比较功能不可同时使用。
工作流程
(STM32选用测周法测量)
信号从通道一进入,遇到输入滤波器和边沿检测器(每个通道有两组,分别输出TIxFP1,TIxFP2)输出TI1FP1和TI1FP2信号(TI1FP2输入至通道2中),输出信号经过数据选择器(可选择TI1FP1,也可选择通道二输入的TI2FP1),经过选择器的信号,再由预分频器进行分频(系数自由选择),然后从预分频器每输出一个信号,触发一次捕获事件(在状态寄存器置标志位,也可产生中断,我们可选择在中断中处理一些事情),同时CNT的值向CCR转运一次(CNT由内部标准时钟驱动,可用来计算信号周期)。
注:每次触发捕获信号时,我们都要清零CNT的值。(可通过主从触发模式完成)
关于滤波器
每经过N个信号为高电平,输出为高电平;N个信号为低电平,输出为低电平
采样系数越大,采样周期越大,N越大,数据越准确。
频率测量
-
测频法:在闸门时间T内,对上升沿计次,得到N,则频率f_x=N / T (时间T内,每来一个上升沿,N+1)
测频法适用于信号频率较高的情况,减少误差;若在信号频率较低时,当闸门时间T到达时,计数仍为0,这是测得频率为0,但真实频率不为0,产生误差。
测频法测得为频率的均值,当在时间T内,频率发生改变时,测频法是这段时间的均值;且更新慢(每隔T更新一次),值比较平滑。 -
测周法:两个上升沿内,以标准频率fc计次,得到N ,则频率f_x=f_c / N (两个信号上升沿之间,使用标准频率为fc计数器计次,计次为N;一个计数时间1/fc,N个计次时间为N/fc,即为信号周期)
测周法适用于频率较低的情况,减少误差;若在信号频率较大时,在两个上升沿内,计数器并未完成一次计数,频率为0,产生误差。
测周法测得为信号的实时频率,即两个上升沿之间的周期倒数。更新速度取决于信号频率,更新更快,但只测一个周期,结果值易受干扰。 -
中界频率:测频法与测周法误差相等的频率点f_m=√f_c / T
PWM的频率通常很大,那为什么还是用测周法?
对于测周法而言
被测信号频率远低于标准信号频率时,被测信号脉冲很多(N很大),测周法得到的结果就很准确。
对于测频法而言
被测信号频率远高于标准信号频率(单位时间内计次的快慢)时,时间T内测得 的N就越大(N很大),测频法得到的结果就很准确。
主从触发模式
主模式:可以将定时器内部的信号映射到TRGO引脚,触发其他外设。
从模式:接收其他外设或自身外设的信号,执行自身定时器的运行,被别的信号所控制。、
触发源选择:选择从模式信号触发源的,选择指定的信号,得到TRGI,触发从模式,选择指定操作。
详细介绍查看手册
输入捕获基本结构
工作流程:
配置时基单元,PSC输出的频率(72MHZ/预分频系数)为标准频率,计数器开始自增。GPIO输入PWM信号,经过滤波器,边沿检测器(选择上升沿触发),每一个上升沿,输出一个信号TI1FP1,数据选择器选择TI1FP1为输入信号,经过预分频器,输出信号。CCR1读取CNT的值,并由从模式清零CNT,进入下一检测。
PWMI基本结构
工作流程基本一致,PWM信号经过边沿检测器,其中一个配置为下降沿触发,输出TI1FP2信号到通道二的数据选择器,选择其为输入信号,经过预分频器,输出信号。CCR2读取CNT的值,此为一个PWM周期中,保持高电平,CNT的计数。CCR2/CCR1=占空比。
二, 配置输入捕获功能
- 第一步:开启时钟,打开GPIO,TIM时钟。
- 第二步:GPIO初始化,配置为输入模式。
- 第三步:配置时基单元,CNT在内部时钟(用作标准频率fc)的驱动下自增运行。
- 第四步:配置输入捕获单元,包括滤波器,极性,直连通道还是交叉通道,分频器等(结构体配置)。
- 第五步:选择从模式触发源触发源为TI1FP1。
- 第六步:开启定时器。
最后读取CCR寄存器,得到N,f=fc/N;
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);//结构体赋初始值
void TIM_SelectInputTrigger(TIM_TypeDef* TIMx, uint16_t TIM_InputTriggerSource);//选择输入触发源TRGI
void TIM_SelectOutputTrigger(TIM_TypeDef* TIMx, uint16_t TIM_TRGOSource);//选择主模式输出的触发源,TRGO
void TIM_SelectSlaveMode(TIM_TypeDef* TIMx, uint16_t TIM_SlaveMode);//选择从模式
/*单独配置四个预分频器的参数*/
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);
/*分别读取四个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);
第一步:开启时钟
/* 时钟配置*/
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3,ENABLE);//配置定时器3时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);//配置GPIOA的时钟
我们捕获使用TIM3,输出PWM使用TIM2
上文介绍过,同一定时器捕获输出只能选择一个。
第二步:配置GPIO
/*初始化GPIO*/
GPIO_InitTypeDef GPIO_InitStruct;//定义结构体变量
GPIO_InitStruct.GPIO_Mode=GPIO_Mode_IPU;
GPIO_InitStruct.GPIO_Pin=GPIO_Pin_6;//选择PA6通道打开
GPIO_InitStruct.GPIO_Speed=GPIO_Speed_50MHz;//扫描速率
GPIO_Init(GPIOA,&GPIO_InitStruct);//初始化
第三步:配置时基单元
TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStruct;
TIM_TimeBaseInitStruct.TIM_ClockDivision=TIM_CKD_DIV1;//选择时钟滤波频率为0
TIM_TimeBaseInitStruct.TIM_CounterMode=TIM_CounterMode_Up;//CNT向上计数
TIM_TimeBaseInitStruct.TIM_Period=65536-1;//ARR,最大值防止计数溢出。
TIM_TimeBaseInitStruct.TIM_Prescaler=72-1;//PSC,确定fc=1MHZ
TIM_TimeBaseInitStruct.TIM_RepetitionCounter=0;//高级定时器的重复计数器
TIM_TimeBaseInit(TIM3, &TIM_TimeBaseInitStruct);//初始化时基单元
注:如果被测频率太低,一个PWM周期内,CNT的值会溢出;这时我们可以加大PSC的值,降低fc频率。
第四步:初始化输入捕获单元
/*初始化输入捕获*/
TIM_ICInitTypeDef TIM_ICInitStruct;
TIM_ICInitStruct.TIM_Channel=TIM_Channel_1; //通道选择,选择TIM1,为通道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_SelectInputTrigger(TIM3, TIM_TS_TI1FP1); //触发源选择TI1FP1
TIM_SelectSlaveMode(TIM3, TIM_SlaveMode_Reset); //从模式选择复位
//即TI1产生上升沿时,会触发CNT归零
第六步:定时器使能
/*TIM使能*/
TIM_Cmd(TIM3, ENABLE); //使能TIM3,定时器开始运行
获取结果
uint32_t IC_GetFreq(void)
{
return 1000000 / (TIM_GetCapture1(TIM3)+1); //测周法得到频率fx = fc / N,这里不执行+1的操作也可
}