一、输入捕获的介绍
通用定时器具有多种功能,输入捕获就是其中一种。STM32F1 除了基本定时器 ,其他定时器都具有输入捕获功能。输入捕获可以对输入的信号的上升沿,下降沿或者双边沿进行捕获,通常用于测量输入信号的脉宽、测量 PWM 输入信号的频率及占空比。
输入捕获的工作原理是:在输入捕获模式下,当相应的 IC 信号检测到信号的变换后,将使用捕获/比较寄存器(TIMx_CCRx)来锁存计数器的值。简单的说就是通过检测 TIMx_CHx 上的边沿信号,在边沿信号发生跳变(比如上升沿/下降沿)的时候,将当前定时器的值(TIMx_CNT)存放到对应的通道的捕获/比较寄存(TIMx_CCRx)里面,完成一次捕获。同时还可以配置捕获时是否触发中断/DMA 等。下面我们以输入捕获测量脉宽为例,通过一个简图来介绍输入捕获的工作原理,
从上图可以看出,t1-t2 时间就是需要测量的高电平时间,假如定时器工作在向上计数模式,测量方法是:首先设置定时器通道 1为上升沿捕获,这样在 t1 时刻,就会捕获到当前的 CNT 值,记录为CCRx1,然后立即清零 CNT,并设置通道 2为下降沿捕获,这样到 t2 时刻,又会发生捕获事件,得到此时的 CNT 值,记为 CCRx2。根据定时器的计数频率,我们就可以算出 t1-t2 的时间,得到高电平脉宽。在 t1-t2 时间内可能会出现 N 次定时器溢出,因此我们还需要对定时器溢出进行处理,防止因高电平时间过长发生溢出导致测量数据不准。CNT计数的次数等于:N*ARR+CCRx2,有了这个计数次数,再乘以 CNT 的计数周期,即可得到 t2-t1 的时间长度,即高电平持续时间。
图1:
而相比输出比较(OC):输入捕获是截取外部信号变化(电平跳变),把计数值(CNT)的保存到捕获/比较寄存器(CCR)中,而输出比较是依据计数值(CNT)和捕获/比较寄存器(CCR)来输出电平值(高电平/低电平),所以输出比较可以进行PWM波的生成和信号的生成,输入捕获可以测量信号的频率。
二、输入捕获配置步骤
图2:
由图1和图2可得:信号从TIMx_CH1通道进入经过滤波器,边沿检测器后进行分频处理,由从模式控制计数值(CNT)的存储。
1.使能定时器和端口时钟,并设置引脚模式
RCC_APB1PeriphClockCmd()//进行定时器使能
RCC_APB2PeriphClockCmd();//进行端口时钟使能
//GPIO的基本配置
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Mode = ;
GPIO_InitStructure.GPIO_Pin = ;
GPIO_InitStructure.GPIO_Speed =;
GPIO_Init();
2.时基单元的配置和输入捕获基本配置
TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStruct;
TIM_TimeBaseInitStruct.TIM_ClockDivision=; //分频系数
TIM_TimeBaseInitStruct.TIM_CounterMode=; //计数模式
//定时器频率 = 72M/(重装载值+1)/(预分频值+1)
TIM_TimeBaseInitStruct.TIM_Period= ; //重装载值
TIM_TimeBaseInitStruct.TIM_Prescaler= //预分频
TIM_TimeBaseInitStruct.TIM_RepetitionCounter=;
TIM_TimeBaseInit();
三、代码案例
所要实现的功能是:按键不按下的时候是低电平(GPIO中配置了上拉输入模式)使用TIM2的CH1检测按键按下的高电平时间, 将检测的高电平脉宽时间通过OLED显示屏显示出来
由此图可以看出,按键不按下的时候,PA0所检测的为低电平,也就是图1点。按键按下时,PA0口检测跳变为高电平(上升沿),输入捕获开始收集高电平时间。当按键松手的时候,PA0口检测电平跳变为低电平(下降沿),输入捕获停止收集高点平时间。
理论想法是这样的,因此需要定时器进行输入捕获,用中断来控制输入捕获的开始和结束,然后oled屏能够时刻记录高电平显示时间。
1,定时器2的输入捕获通道1配置
void timer_gpio_config(void)
{
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE);
TIM_InternalClockConfig(TIM2);//内部时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStruct;
TIM_TimeBaseInitStruct.TIM_ClockDivision=TIM_CKD_DIV1;
TIM_TimeBaseInitStruct.TIM_CounterMode=TIM_CounterMode_Up;
//定时器频率 = 72M/(重装载值+1)/(预分频值+1)
TIM_TimeBaseInitStruct.TIM_Period= 10000 - 1;
TIM_TimeBaseInitStruct.TIM_Prescaler= 7200 - 1; //10000HZ 0.0001秒
TIM_TimeBaseInitStruct.TIM_RepetitionCounter=0;
TIM_TimeBaseInit(TIM2,&TIM_TimeBaseInitStruct);
TIM_ICInitTypeDef TIM_ICInitStructure;
TIM_ICInitStructure.TIM_Channel = TIM_Channel_1;
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(TIM2, &TIM_ICInitStructure);
TIM_ITConfig(TIM2,TIM_IT_Update|TIM_IT_CC1,ENABLE);
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
NVIC_InitTypeDef NVIC_InitStruct;
NVIC_InitStruct.NVIC_IRQChannel=TIM2_IRQn;
NVIC_InitStruct.NVIC_IRQChannelCmd=ENABLE;
NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority=2;
NVIC_InitStruct.NVIC_IRQChannelSubPriority=2;
NVIC_Init(&NVIC_InitStruct);
TIM_Cmd(TIM2,ENABLE);
}
2.OLED用的是江科大的模板。
3.中断函数,能够实时显示高电平时间
void TIM2_IRQHandler(void)
{
if(TIM_GetITStatus(TIM2,TIM_IT_CC1)==SET&&Falling_Flag==0){
Capture1_Count=0;
TIM_ClearITPendingBit(TIM2,TIM_IT_CC1);
TIM_SetCounter(TIM2,0);
Falling_Flag=1;
TIM_OC1PolarityConfig(TIM2,TIM_OCPolarity_High);
}
if(TIM_GetITStatus(TIM2,TIM_IT_CC1)==RESET&&Falling_Flag==1){
if(TIM_GetITStatus(TIM2,TIM_IT_Update)==SET){
Spill_Count++;
}
Capture1_Count=(TIM_GetCapture1(TIM2)+Spill_Count*10000)/10;
}
if(TIM_GetITStatus(TIM2,TIM_IT_CC1)==SET&&Falling_Flag==1){
Capture1_Count=(TIM_GetCapture1(TIM2)+Spill_Count*10000)/10;//得到最终的计数值(原本记一个数是0.1ms,现在把单位转换为1ms)
Spill_Count=0;
TIM_SetCounter(TIM2,0);
Falling_Flag=0;
TIM_OC1PolarityConfig(TIM2,TIM_OCPolarity_Low);
}
OLED_ShowNum(3,1,Capture1_Count/1000,4);
OLED_ShowNum(3,6,Capture1_Count%100,2);
OLED_ShowNum(4,12,Spill_Count,2);
TIM_ClearITPendingBit(TIM2,TIM_IT_Update|TIM_IT_CC1);
}
总结
对于定时器输入捕获,除了单个定时器进行输入捕获,也可以设置主从模式进行定时器中断控制。输入捕获大致用于信号的获取和利用。