概要
IC(Input Capture)输入捕获
- 输入捕获模式下,当通道输入引脚出现指定电平跳变时,当前CNT的值将被锁存到CCR中,用于测量PWM频率、占空比、脉冲间隔、电平持续时间等参数。
- 每个高级定时器和通用定时器拥有4个输入捕获通道,基本定时器无IC通道
- 可配置为PWMI模式,同时测量频率和占空比(开通两个Channel 1和 2)
- 可配置主从出发模式,实现硬件全自动测量(从模式 Reset功能实现自动清除CNT)
主从触发模式
主模式
- Reset、Enable、Update、OC1、OC1REF等等这些都是外设的信号,通过其他外设的信号通过TRGO触发其他外设。
- 有待补充
从模式
- ITR0、ITR1、ITR2、ITR3、TIF_ED、Tl1FP1等等都是其他外设或自身外设一些信号,捕获PWM需要使用到Tl1FP1信号源。通过TIM_SelectInputTrigger函数选择对应的定时器以及信号源即可完成从模式的触发源选择工作。
- 再通过TRGI通道选择从模式的功能,我们需要CNT自动清0,选择Reset功能,这里使用TIM_SelectSlaveMode函数可以指定选择所需要的功能。当然这个函数只能选择Reset、Gated、Trigger、External1这下面四个功能,剩余需要使用到其他函数。
TIM_SelectInputTrigger(TIM3, TIM_TS_TI1FP1);
TIM_SelectSlaveMode(TIM3, TIM_SlaveMode_Reset);
输入捕获基本结构
基本结构
- PWM波从GPIO输入,就经过滤波器、边沿检测极性选择上端沿之后,每一次上端沿触发都代表一个周期,我们只需要知道一个周期内CNT计数值,即可以通过 Freq = Fc / CNT 得出PWM的波形,其中 Fc 为时基单元分配的时钟信号,函数 TIM_InternalClockConfig(TIM3) 为其分配一个72MHz的内部时钟;。
- 配置时基单元,通过TIM_TimeBaseInit函数对时基单元的初始化操作,其中我们需要设置ARR的值为上限,代表尽可能多计数不清零,让从模式自动清0,对于何时清0,这得依靠TI1FP1的信号,及输入信号。每一次上端沿都触发一下Reset。再此之前我们需要将CNT的值保存到CCR1之中。
- 配置IC单元(输入捕获单元),通过TIM_ICInit 函数初始化IC单元,我们不需要自己保存CNT的值,TIM_ICPolarity设置成上端沿,即表示为上端沿保存CNT的值进入CCR1中。
- 通过TIM_GetCapture1 函数获得CCR的值
TIM_TimeBaseInitTypeDef TIM_TimeBaseInitTypeDefStructure;
TIM_TimeBaseStructInit(&TIM_TimeBaseInitTypeDefStructure);
TIM_TimeBaseInitTypeDefStructure.TIM_ClockDivision = TIM_CKD_DIV1;
TIM_TimeBaseInitTypeDefStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInitTypeDefStructure.TIM_Period = 0xFFFF;
TIM_TimeBaseInitTypeDefStructure.TIM_Prescaler = 72 - 1;
TIM_TimeBaseInitTypeDefStructure.TIM_RepetitionCounter = 0;
TIM_TimeBaseInit(TIM3, &TIM_TimeBaseInitTypeDefStructure);
TIM_ICInitTypeDef TIM_ICInitTypeDefStructure;
TIM_ICStructInit(&TIM_ICInitTypeDefStructure);
TIM_ICInitTypeDefStructure.TIM_Channel = TIM_Channel_1;
TIM_ICInitTypeDefStructure.TIM_ICFilter = 0xf;
TIM_ICInitTypeDefStructure.TIM_ICPolarity = TIM_ICPolarity_Rising;
TIM_ICInitTypeDefStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1;
TIM_ICInitTypeDefStructure.TIM_ICSelection = TIM_ICSelection_DirectTI;
TIM_ICInit(TIM3, &TIM_ICInitTypeDefStructure);
PWMI结构
- 相比基本结构多出了下面TI1FP2通道,这里设置Channel 2配置可以轻松配置下断沿触发一次CNT存入CCR2中,可以手动设置。
TIM_ICInitTypeDefStructure.TIM_Channel = TIM_Channel_2;
TIM_ICInitTypeDefStructure.TIM_ICPolarity = TIM_ICPolarity_Falling;
TIM_ICInitTypeDefStructure.TIM_ICSelection = TIM_ICSelection_IndirectTI;
TIM_ICInit(TIM3, &TIM_ICInitTypeDefStructure);
- 使用TIM_PWMIConfig 函数配置的话,只能配置Ch 1和Ch 2通道的,不能配置Ch 3和Ch 4通道的,其中输入TIM_ICInitTypeDef 结构体中,Ch 1配置同结构体相同,相反Ch 2与结构体设置相反。
TIM_PWMIConfig(TIM3, &TIM_ICInitTypeDefStructure);
代码实现流程
- RCC开启时钟,把GPIO和TIM的时钟打开
- GPIO初始化,把GPIO配置成输入模式(一般上拉输入模式和浮空输入模式)
- 配置时基单元,让CNT计数器在内部时钟的驱动下自增运行
- 配置输入捕获单元,包括滤波器、极性、直连通道还是交叉通道、分频器这些参数(结构体统一配置)
- 选择从模式的触发源,触发源选择TL1FP1,这里调用一个库函数,给一个参数即可
- 选择触发之后执行的操作,执行Reset操作,这里调用一个库函数即可
- 调用TIM_Cmd开启定时器
Profile
#include "stm32f10x.h"
void IC_Init(void)
{
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);
GPIO_InitTypeDef GPIO_InitTypeDefStrcuture;
GPIO_InitTypeDefStrcuture.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_InitTypeDefStrcuture.GPIO_Pin = GPIO_Pin_6;
GPIO_InitTypeDefStrcuture.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitTypeDefStrcuture);
TIM_InternalClockConfig(TIM3);
TIM_TimeBaseInitTypeDef TIM_TimeBaseInitTypeDefStructure;
TIM_TimeBaseStructInit(&TIM_TimeBaseInitTypeDefStructure);
TIM_TimeBaseInitTypeDefStructure.TIM_ClockDivision = TIM_CKD_DIV1;
TIM_TimeBaseInitTypeDefStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInitTypeDefStructure.TIM_Period = 0xFFFF;
TIM_TimeBaseInitTypeDefStructure.TIM_Prescaler = 72 - 1;
TIM_TimeBaseInitTypeDefStructure.TIM_RepetitionCounter = 0;
TIM_TimeBaseInit(TIM3, &TIM_TimeBaseInitTypeDefStructure);
TIM_ICInitTypeDef TIM_ICInitTypeDefStructure;
TIM_ICStructInit(&TIM_ICInitTypeDefStructure);
TIM_ICInitTypeDefStructure.TIM_Channel = TIM_Channel_1;
TIM_ICInitTypeDefStructure.TIM_ICFilter = 0xf;
TIM_ICInitTypeDefStructure.TIM_ICPolarity = TIM_ICPolarity_Rising;
TIM_ICInitTypeDefStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1;
TIM_ICInitTypeDefStructure.TIM_ICSelection = TIM_ICSelection_DirectTI;
TIM_ICInit(TIM3, &TIM_ICInitTypeDefStructure);
TIM_ICInitTypeDefStructure.TIM_Channel = TIM_Channel_2;
TIM_ICInitTypeDefStructure.TIM_ICPolarity = TIM_ICPolarity_Falling;
TIM_ICInitTypeDefStructure.TIM_ICSelection = TIM_ICSelection_IndirectTI;
TIM_ICInit(TIM3, &TIM_ICInitTypeDefStructure);
TIM_SelectInputTrigger(TIM3, TIM_TS_TI1FP1);
TIM_SelectSlaveMode(TIM3, TIM_SlaveMode_Reset);
TIM_Cmd(TIM3, ENABLE);
}
uint32_t IC_GetFreq(void)
{
return 1000000 / (TIM_GetCapture1(TIM3) + 1);
}
uint32_t IC_GetDuty(void)
{
return (TIM_GetCapture2(TIM3) + 1) * 100 / (TIM_GetCapture1(TIM3) + 1);
}