一、 相关概念
通用定时器在输入捕获(Input Capture, IC)模式下,当通道输入引脚出现指定电平跳变时,当前CNT的值将被锁存到CCR中,常被用于测量PWM波形的频率、占空比、脉冲间隔、电平持续时间等参数。每个高级定时器和通用定时器都拥有4个输入捕获通道,并且可配置为PWMI模式,用来同时测量频率和占空比。可配合主从触发模式,实现硬件全自动测量。下图为输入捕获内部结构图,共有4个通道,由输入、滤波及CCR共同组成。
二、 结构及原理
如下图所示为STM32通用定时器的输入捕获部分的结构图,该图以通道1为例。
其中输入信号是TI1,来自外部待测信号,fDTS为采样时钟源,ICF[3:0]用来控制滤波器参数,其采样原理类似于按键去抖,以一定频率在某段时间对输入信号进行采样,若被采样点均为同一类型信号时,对该时间段信号进行平滑处理后输出为TI1F,如下图所示,滤波后的信号进入边沿检测器,使用CC1P进行极性选择,选择触发后续动作的边沿(上升沿或下降沿),该信号输出至分频器和从模式控制器,使用从模式控制器可以实现CNT的自动重置,是使用测周法测量频率的基础,分频器可控制每N个事件触发一次捕捉,捕捉后可以触发中断,从而完成一些附加功能,最后IC1PS输出,使得当前计数值CNT转运到CCR,完成一次输入捕捉。
三、 测频方法
常见的测频方法有两种,分别是测频法和测周法。
-
测频法
设定一个较长的闸门时间,对闸门时间T内的有效边沿(如上升沿)进行采样,计算上升沿个数N,则被测频率为单位时间内上升沿个数,即f=N/T。该方法常被用于高频信号测量,测量原理如图。
-
测周法
当被测频率较低时,通常使用测周法,即设定一个标准频率fc,从一个上升沿开始计数,到下一个上升沿停止计数,得到计数值N,被测频率就等于标准频率的N分频,即f=fc/N,测量原理如图。
四、 主从触发模式
主从触发模式是一个合成概念,其中包含了是主模式,从模式和触发源选择这三个功能,其中主模式就是定时器通道作为信号源,可以将定时器的内部信号,映射到TRGO引脚,用于触发别的外设;从模式就是接收其他外设或者自身外设的一些信号,用于控制自身定时器的运行,也就是被别的信号控制;触发源选择,就是对选择从模式的触发信号源,可以认为是从模式的一部分,选择指定的一个信号作为触发源TRGI,TRGI去触发从模式,从模式可以在列表里面选择一项来自动执行。
在测周法中,我们需要在下一个有效沿到来时将计数器重置,而触发模式中刚好包含了在触发后初始化计数器的功能(Reset),在将CNT转运至CCR后将CNT清零。主从触发模式所含内容如图所示。
五、 代码分析
本文使用文章stm32学习总结:定时器(2)通用定时器之输出比较(OC)及PWM-CSDN博客中的PWM部分作为待测信号源,使用TIM3进行频率检测。
- IC.c
#include "stm32f10x.h" // Device header
void IC_Init(void)
{
//第一个老朋友,外设时钟使能
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
//第二个老朋友,设置外设接口,Pin6复用上拉输入,输入待测信号;Pin5推挽输出,当检测到输入信号频率在指定范围内时给出动作
GPIO_InitTypeDef GPIO_InitStructure;
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);
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
TIM_InternalClockConfig(TIM3);//TIM3参数表
//配置时基单元
TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;
TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;//定义在定时器时钟(CK_INT)频率与数字滤波器(ETR,TIx)使用的采样频率之间的分频比例
TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInitStructure.TIM_Period = 65536 - 1; //ARR,防止溢出将寄存器值拉满
TIM_TimeBaseInitStructure.TIM_Prescaler = 72 - 1; //PSC,输出频率= 72MHz / (72 * 10)= 100KHz,即标准频率
TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0;
TIM_TimeBaseInit(TIM3, &TIM_TimeBaseInitStructure);//初始化TIM3
TIM_ICInitTypeDef TIM_ICInitStructure;
TIM_ICInitStructure.TIM_Channel = TIM_Channel_1;//选用TIM3的通道1
TIM_ICInitStructure.TIM_ICFilter = 0xF;//用于选择输入捕获的滤波器,一般地值越大滤波效果越好
TIM_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising;//边沿检测极性选择
TIM_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1;//此处不分频,不分频就是每次触发都有效,2分频就是每两次上升沿有效一次,以此类推
TIM_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI;//此处选择直连通道,配置数据选择器,可以选择直连通道或者交叉通道
TIM_ICInit(TIM3, &TIM_ICInitStructure);
TIM_SelectInputTrigger(TIM3, TIM_TS_TI1FP1);//配置触发模式TRGI的触发源为TI1FP1
TIM_SelectSlaveMode(TIM3, TIM_SlaveMode_Reset);//配置从模式为Reset,给计数器清零,以便重新计数
TIM_Cmd(TIM3, ENABLE);
}
uint32_t IC_GetFreq(void)
{
//fc=72/(PSC + 1)= 1MHZ
//执行公式fx = fc / N
//输出比较模式下,CCR是只写的,要用setCompare写入
//输入捕获模式下,CCR是只读的,要用GetCapture读出
return 1000000 / (TIM_GetCapture1(TIM3) + 1);
}
- Main.c
#include "stm32f10x.h" // Device header
#include "Delay.h"
#include "PWM.h"
#include "IC.h"
#define TEST_FREQ 100000//被测频率期望值
char flag = 0;//频率检测标志位
int main(void)
{
GPIO_init();
PWM_Init();
IC_Init();
while (1)
{
if(GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_1) == 1)
{
TIM_Cmd(TIM2, ENABLE);
PWM_SetCompare1(5);
}
else TIM_Cmd(TIM2, DISABLE);
if(IC_GetFreq() <= (TEST_FREQ * 1.05) && IC_GetFreq() >= (TEST_FREQ * 0.95)) //当被测信号频率在该范围内时,标志位置1
{
flag = 1;
}
if(flag == 1)//标志位为1时,输出高电平
{
GPIO_SetBits(GPIOA, GPIO_Pin_5);
}
else GPIO_ResetBits(GPIOA, GPIO_Pin_5);
}
}
六、 总结
本文主要围绕通用定时器的输入捕获功能进行了介绍,探讨了其结构及测频原理,使用PWM进行输入,并对其进行检测,围绕代码对该功能的使用做出了说明。