STM32 学习笔记_8 定时器中断:输入捕获

输入捕获

输入引脚发生跳变时,cnt的值会被记录到ccr中,可以用于测量pwm信号等。配置成pwmi模式还可以同时测量频率和占空比。主从触发模式可以实现硬件全自动测量。

高级定时器和通用定时器才有的功能。

这个功能只能测数字信号,对于a信号需要通过比较器等简历ad转换为数字信号。
image-20230514152436899

测周法速度快,一个周期就测出结果来,但是噪声影响误差可能大。

image-20230514153612001

输入信号经过滤波去除一些毛刺,让信号更稳定;分两路传输,比如CH1分IC1 IC2,这样方便切换,而且方便拓展,比如PWMI要同时计算占空比和频率。

TRC和异或电路用于三相电机。

我们配置psc,设定如上升沿保存一下ccr值,就可以记录两个上升沿之间时间周期了。然后cnt清零。

image-20230514155546416

滤波ICF配置:连续n个相同的事件才会被记录。比如一直是稳定的高电平。如果信号一直抖动就不会记录。如果噪声大可以把这个参数设大一些。

滤波后检测边沿,通过TIFP进行选择。

输出可以设置分频,CC1E使能。TIFP会自动从模式触发cnt清零。

主模式:自身定时器输出信号去触发别的外设。

从模式:接收其他(或自身)外设的信号用于控制自身定时器的运行。

image-20230514223643350

比如本次我们要用到的功能就是从模式的reset,reset cnt。

还有一些其他的用途比如两个定时器级联,第一个定时器预分频后的输出给第二个定时器,这样两者预分频可以计数的周期就更大了。

总结原理:

image-20230514223844690

fc:时钟源频率/psc.

N:最新的ccr值。

fc/N可算出信号频率。

  • 注意cnt有上限如65535,因此如果信号频率太低可能溢出,这时我们可以把psc调大一点。
  • 1 2定时器只能设置1 2 的从模式,如果想用3 4定时器去触发reset指令,需要用到中断函数,比较消耗资源。

image-20230514224320580

通过上图方式获取频率和占空比。CCR1是整个周期长度,CCR2是高电平周期长度,做比可以求得占空比。

代码:输入捕获模式测频率

我们没有信号发生器,所以利用上节课的PWM波形输出给另一个引脚,另一个引脚IC获得其频率。

image-20230514225032359

因为我们要尝试不同的输入波形,因此psc的值会改变。因此可以写一个改变psc的函数。

image-20230515121232376

初始化函数类似OC。下面的可以同时初始化多个通道。

image-20230515121553377

赋初值。

image-20230515121605528

选触发源。

image-20230515121728362

这个是选择主模式输出的触发源和选择从模式的模式。

image-20230515121928357

读取ccr值。oc状态下ccr只写,可以用setCompare写入。ic状态只读,用这四个函数读。

#include "stm32f10x.h"

void IC_Init(){
    
    
    //1. 打开输入接收的RCC,GPIO
    //2. 时基单元,启动计数器
    //3. 设置输入捕获单元
    //4. 选用触发源
    //5. 设置触发后的reset操作
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);
    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);
    
    TIM_InternalClockConfig(TIM3);
    
    TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;
    TIM_TimeBaseInitStructure.TIM_ClockDivision=TIM_CKD_DIV1;
    TIM_TimeBaseInitStructure.TIM_CounterMode=TIM_CounterMode_Up;
    TIM_TimeBaseInitStructure.TIM_Period=65536-1;//满计时,尽量避免溢出
    TIM_TimeBaseInitStructure.TIM_Prescaler=72-1;//输入信号频率:1MHz
    TIM_TimeBaseInitStructure.TIM_RepetitionCounter=0;
    TIM_TimeBaseInit(TIM3,&TIM_TimeBaseInitStructure);
    
    TIM_ICInitTypeDef TIM_ICInitStructure;
    TIM_ICInitStructure.TIM_Channel=TIM_Channel_1;//PA6对应定时器3 ch1
    TIM_ICInitStructure.TIM_ICPolarity=TIM_ICPolarity_Rising;
    TIM_ICInitStructure.TIM_ICFilter=0xF;//滤波消除毛刺,越大效果越好,看需求
    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);//定时器1的从模式
    
    TIM_SelectSlaveMode(TIM3,TIM_SlaveMode_Reset);
    
    TIM_Cmd(TIM3,ENABLE);
}

uint32_t IC_GetFreq(void){
    
    
    //fc: 1MHz
    return 1000000/(TIM_GetCapture1(TIM3)+1);//CH1的捕获
}

main里设置psc=720,则输入频率为1MHz,1000000,设置ccr值为50。

	PWM_SetPrescaler(720-1);//freq: 72M/100/720
    TIM_SetCompare1(TIM2,50);//duty: 50/100	

OC:PWM设置ccr=50,psc 7200, period 100(因为duty=ccr/(arr+1),所以如果修改输出引脚的分频采用修改arr的方案,那么占空比也会随之改变,不好计算。不如我们固定arr,修改psc。),也就是占空比50/100为一半。因此输出1kHz的波形。

IC:100 0000/1000=1000. 两次相邻的上升沿之间计数1k,用总频率1M/1k得出输入波形。

至于get函数为什么+1,题主也想不太明白,据老师所说可能是到了那里刚好跳变没有记录上上升沿之类的。

代码:检测频率和上升沿

基本不太变,把其中一个IC初始化函数改成同时初始化两个通道的函数。初始化只需要改这一条就行,库函数自动把另一个通道调整为相反的。比如通道1直连上升沿触发,通道2交叉下降沿触发。

TIM_PWMIConfig(TIM3, &TIM_ICInitStructure);

再写一个获取占空比的函数:

uint32_t IC_GetDuty(void){
    
    
    return (TIM_GetCapture2(TIM3)+1)*100/(TIM_GetCapture1(TIM3)+1);
}

改setprescaler改频率,改setcompare改duty。

  • 输入信号频率1MHz,计数器最大65535,因此最低不溢出的频率是1M/65535≈15Hz。
  • 要求误差如千分之一,那么频率为1M/1k=1k.

猜你喜欢

转载自blog.csdn.net/jtwqwq/article/details/130699656