【嵌入式学习-STM32F103-TIM-输入捕获】

文章详细介绍了STM32中输入捕获和输出比较的工作原理,包括它们在频率测量中的应用。输入捕获用于测量信号频率和占空比,而输出比较则根据比较结果改变输出电平。两者不能在同一定时器上同时使用。文中还阐述了测频法和测周法,以及输入捕获的电路结构、编程步骤和注意事项。此外,还提供了PWM模式下频率和占空比的测量方法。

回顾输出比较

对于输出比较的执行逻辑,根据CNT的大小关系,从通道引脚输出高低电平。
在这里插入图片描述

输入捕获理论

4个输入捕获和输出比较通道,共用4个CCR寄存器

另外它们的CH1到CH4,4个通道的引脚,也是共用的。

所以对于同一个定时器,输入捕获和输出比较只能使用其中一个,不能同时使用。

在这里插入图片描述
在这里插入图片描述
电平跳变:上升沿或下降沿
脉冲间隔:频率
电平持续:占空比
输入引脚电平跳变的瞬间,把CNT的值锁存在CCR中(把当前CNT的值读出来,写入到CCR中去)

在这里插入图片描述

上图,这4个是边沿信号输入引脚,一旦有边沿,比如上升沿,那这一块输入滤波和边沿检测就会检测到这个上升沿,让输入捕获电路产生动作。与外部中断类似,检测电平跳变,然后执行动作,只不过外部中断执行的动作是向CPU申请中断,而这里电路执行的动作就是控制后续电路,让当前CNT的值,锁存到CCR寄存器中

输入捕获和输出比较的区别

1、输出比较,是根据CNT和CCR大小关系来执行输出动作;
2、输入捕获,接收到输入信号,执行CNT锁存到CCR的动作。

频率测量相关知识

越往左,频率越高,越往右,频率越低

在这里插入图片描述
1、测频法(适用于高频)
在1s时间内,对信号上升沿计次,从0开始计算,每来一个上升沿(即来了一个周期的信号),计次+1。1s时间内,来了多少个周期,就是多少Hz。

频率的定义:1s内出现了多少个重复的周期,频率就是多少Hz。

2、测周法(适用于低频)

首先捕获信号的两个上升沿,然后测量它们之间的持续时间,但实际上我们并没有精度无穷大的秒表来测量时间,测量时间的方法实际上也是定时器计次,我们使用一个已知的标准频率fc的计次时钟,来驱动计数器,从一个上升沿开始计,计数器从0开始,一直计到下一个上升沿,停止,计一个数的时间是1/fc,计N个数,时间就是N/fc(周期),再取个倒数,就是fx = fc / N(频率)。

在这里插入图片描述
总结:测频法,适合测量高频信号,测周法,适合测量低频信号。

测频法:测量的是在闸门时间内的多个周期,所以它自带一个均值滤波,如果在闸门时间内波形频率有变化,那得到的其实是这段时间的平均频率。如果闸门时间选为1s,那么每隔1s才能得到一次结果。所以测频法更新结果慢,测量结果是一段时间的平均值,值比较平滑。

测周法:只测量一个周期,就能出一次结果,所以出结果的速度取决于待测信号的频率。缺点是由于它只测量一个周期,所以结果值会受噪声的影响,波动比较大。

输入捕获的各部分电路

第一个捕获通道,使用上升沿触发,用来捕获周期;第二个通道,使用下降沿触发,用来捕获占空比,两个通道同时对一个引脚进行捕获,就可以同时测量频率和占空比。

一个通道灵活测量两个引脚和两个通道同时捕获一个引脚,这就是交叉的作用。

TRC信号可以选择作为捕获部分的输入,主要为了无刷电机的驱动。

在这里插入图片描述
预分频器,每个通道各有一个,可以选择对前面的信号进行分频,分频之后的触发信号,可以触发捕获电路进行工作,每来一个触发信号,CNT的值就会向CCR转运一次,转运的同时会发生一个捕获事件,这个事件会在状态寄存器置标志位,同时也可以产生中断。如果需要在捕获的瞬间,处理一些事情,就可以开启捕获中断。

在这里插入图片描述
比如我们可以配置上升沿触发捕获,每来一个上升沿,CNT转运到CCR一次,又因为CNT计数器是由内部的标准时钟驱动的,所以CNT的数值,可以用来记录两个上升沿之间的时间间隔,这个时间间隔就是周期,再取个周期的倒数就是测周法测量的频率。

在这里插入图片描述
升沿用于触发输入捕获,CNT用于计数计时,每来一个上升沿,取一下CNT的值,自动存在CCR里,CCR捕获到的值,就是计数值N,CNT的驱动时钟就是fc,fc/N就是待测信号的频率。细节每次捕获之后都需要把CNT清零,这样下一次上升沿的时候,取出的CNT才是两个上升沿的时间间隔,在一次捕获后自动清零的步骤可以用主从触发模式自动来完成

在这里插入图片描述
滤波器工作原理:以采样频率对输入信号进行采样,当连续N个值都为高电平,输出才为高电平,连续N个值为低电平,输出才为低电平,如果信号出现高频抖动,导致连续采样N个值不全都一样,那输出就不会变化,这样就可以达到滤波的效果。采样频率越低,采样个数N越大,滤波效果就越好。

在这里插入图片描述
TI1就是CH1的引脚,TI1F就是滤波后的信号,fDTS是滤波器的采样时钟来源,CCMR1寄存器的ICF位可以控制滤波器的参数。

主从触发模式的作用,如何来完成硬件自动化的操作?

在这里插入图片描述
主模式:可以将定时器内部的信号,映射到TRGO引脚,用于触发别的外设

从模式:接收其他外设或者自身外设的一些信号,用于控制自身定时器的运行,也就是被别的信号控制

触发源选择:选择从模式的触发信号源,选择指定的一个信号得到TRGI,TRGI去触发从模式,从模式可以在以上列表选择一项操作来自动执行。如果想让TI1FP1信号自动触发CNT清零,那触发源选择就可以选择TI1FP1,从模式执行的操作就可以选择执行Reset的操作。这样TI1FP1的信号就可以自动触发从模式,从模式自动清零CNT,实现硬件全自动测量。

以上三个东西对应库函数的三个函数,调用参数即可。

在这里插入图片描述

输入捕获基本结构

在这里插入图片描述
这个结构只使用了一个通道,所以目前只能测量频率,在右上角是时基单元,将时基单元配置好,启动定时器,CNT就会在预分频之后的这个时钟驱动下,不断自增,这个CNT就是测周法用来计数计时的东西,经过预分频之后这个位置的时钟频率就是驱动CNT的标准频率fc=72M/(PSC+1)。

然后下面输入捕获通道1的GPIO口,输入一个这样的方波信号,经过滤波器和边沿检测,选择TI1FP1为上升沿触发,之后输入选择智联的通道,分频器选择不分频,当TI1FP1出现上升沿之后,==CNT的当前计数值转运到CCR1里,==同时触发源选择,选中TI1FP1为触发信号,从模式选择复位操作,这样TI1FP1的上升沿也会通过上面一路。

==先后顺序:==先转运CNT的值到CCR里,再触发从模式给CNT清零,或者是非阻塞的同时转移,CNT的值转移到CCR,同时0转移到CNT里,先捕获再清零

信号出现一个上升沿,CCR1=CNT,就是把CNT的值转运到CCR1里面去,这是输入捕获自动执行的,然后CNT=0,清零计数器,这是从模式自动执行的。然后在一个周期内,CNT在标准时钟的驱动下,不断自增,并且由于之前清零过,所以CNT就是从上升沿开始,从0开始计时,一直++,直到下一次上升沿来临,然后执行相同的操作。CCR1始终保持为最新一个周期的计数值。这个计数值就是计次N,fc/N就是信号的频率

在这里插入图片描述

注意事项

1、CNT的值有上限,ARR一般设置为最大65535,CNT最大也为65535

2、从模式触发源选择,只有TI1FP1和TI2FP2,所以想使用从模式自动清零CNT,就只能用通道1和通道2

PWMI基本结构

PWMI模式使用了两个通道同时捕获一个引脚,可以同时测量周期和占空比

在这里插入图片描述
首先,TI1FP1配置上升沿触发,触发捕获和清零CNT,正常地捕获周期。这时TI1FP2配置为下降沿触发,通过交叉通道,去触发通道2的捕获单元。

在这里插入图片描述
最开始上升沿,CCR1捕获,CCR1捕获,同时清零CNT,之后CNT一直++,然后再下降沿时刻,触发CCR2捕获,所以CCR2的值,就是CNT从a到b的计数值,就是高电平期间的计数值。CCR2捕获并不触发CNT清零,所以CNT继续++,直到下一次上升沿,CCR1捕获周期,CNT清零,此时,CCR1就是一整个周期的计数值。占空比:CCR2/CCR1。
在这里插入图片描述

输入捕获模式测频率

硬件接线图

在这里插入图片描述

输入捕获的编程步骤

在这里插入图片描述

第一步,RCC开启时钟,把GPIO和TIM的时钟打开

第二步,GPIO初始化,把GPIO配置成输入模式,一般选择上拉输入或者浮空输入模式

第三步,配置时基单元,让CNT计数器在内部时钟的驱动下自增运行

第四步,配置输入捕获单元,包括滤波器、极性、直连通道还是交叉通道、分频器等参数

第五步,选择从模式的触发源,触发源选择为TI1FP1,调用库函数,给定一个参数即可

第六步,选择从模式触发后的执行操作,执行Reset操作,这里调用库函数即可

最后,调用TIM_Cmd函数,开启定时器

这样所有电路就能配合起来,按照我们的要求工作。当我们需要读取最新一个周期的频率时,直接读取CCR寄存器,然后按照fc/N,计算即可。

主要函数

//输入捕获,通过结构体配置输入捕获单元,4个通道公用一个函数,在结构体里会额外有一个参数,可以用来选择具体是配置哪个通道
//因为有交叉通道,函数合在一起比较方便
TIM_ICInit

//输入捕获的初始化函数,与上一个函数类似,都是用于初始化输入捕获单元,
//但是上一个函数只是单一地配置一个通道,
//而这个函数可以快速配置两个通道
TIM_PWMIConfig

//可以给输入捕获结构体赋初始值
TIM_ICStructInit

//选择输入触发源TRGI
TIM_SelectInputTrigger

//选择输出触发源
TIM_SelectOutputTrigger

//选择从模式
TIM_SelectSlaveMode

//分别单独配置通道1、2、3、4的分频器
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);

//分别读取4个通道的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);

/*
输出比较模式下,CCR是只写的,要用SetCompare写入,
输入捕获模式下,CCR是只读的,要用GetCapture读出
*/

在这里插入图片描述
在这里插入图片描述

程序现象

在这里插入图片描述

代码

main.c

#include "stm32f10x.h"                  // Device header
#include "Delay.h"
#include "OLED.h"
#include "PWM.h"
#include "IC.h"


int main(void)
{
   
   
	OLED_Init();
	PWM_Init();
	IC_Init();
	
	OLED_ShowString(1,1,
#include "led.h" #include "delay.h" #include "key.h" #include "sys.h" #include "exti.h" #include "timer.h" #include "usart.h" #include "IWDG.h" //int main(void) //中断 //{ ////delay_init(); //LED_Init(); ////KEY_Init(); ////NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); ////EXTIX_Init(); //LED=0; //while(1); //} //int main(void) //定时器中断 //{ // NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); // delay_init(); // LED_Init(); // // TIM3_Int_Init(1999,7199);//((1+7199)/72M)*(1+9999)=1秒*/反 // while(1); //} //int main(void) //pwm //{ // u16 ledpwmval=0; // u8 dir=1; // delay_init(); // NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); // uart_init(115200); // LED_Init (); // // TIM3_PWM_Init(199,7199);//50Hz // while(1) // { // delay_ms(10); // if(dir)ledpwmval++; // else ledpwmval --; // if(ledpwmval >1000) // dir=0; // if(ledpwmval ==0) // dir=1; // TIM_SetCompare2(TIM3,5); // delay_ms(500); // TIM_SetCompare2(TIM3,10); // delay_ms(500); // TIM_SetCompare2(TIM3,15); // delay_ms(500); // TIM_SetCompare2(TIM3,20); // delay_ms(500); // TIM_SetCompare2(TIM3,25); // delay_ms(500); // } //} //int main() //串口 //{ // u16 t; // u16 len; // u16 times=0; // delay_init(); // NVIC_PriorityGroupConfig (NVIC_PriorityGroup_2 ); // uart_init(115200); // LED_Init(); // KEY_Init(); // while(1) // { // if(USART_RX_STA&0x8000) // { // len=USART_RX_STA&0x3fff;//得到此次接收的数据长度 // printf("\r\n您发送的消息为:\r\n\r\n"); // for(t=0;t<len;t++) // { // USART_SendData(USART1,USART_RX_BUF[t]); // while(USART_GetFlagStatus(USART1,USART_FLAG_TC)!=SET); // } // printf("\r\n\r\n");//插入换行 // USART_RX_STA=0; // } // else // { // times++; // if(times%500000==0) // { // LED=!LED; // } // } // } //} extern void TIM4_Cap_Init(u16 arr,u16 psc); extern u8 TIM4CH1_CAPTURE_STA; //输入捕获状态 输入捕获实验 extern u16 TIM4CH1_CAPTURE_VAL; //输入捕获值 int main(void) { u32 temp=0; delay_init(); //延时函数初始化 NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //设置NVIC中断分组2:2位抢占优先级,2位响应优先级 uart_init(115200); //串口初始化为115200 LED_Init(); //LED端口初始化 // TIM3_PWM_Init(899,0); //不分频。PWM频率72000/(899+1)=80Khz TIM4_Cap_Init(0XFFFF,72-1); //以1Mhz的频率计数 while(1) { delay_ms(10); TIM_SetCompare2(TIM3,TIM_GetCapture2(TIM3)+1); if(TIM_GetCapture2(TIM3)==300) TIM_SetCompare2(TIM3,0); if(TIM4CH1_CAPTURE_STA&0X80)//成功捕获到了一次上升沿 { temp=TIM4CH1_CAPTURE_STA&0X3F; temp*=65536; //溢出时间总和 temp+=TIM4CH1_CAPTURE_VAL;//得到总的高电平时间 printf("HIGH:%d us\r\n",temp);//打印总的高点平时间 TIM4CH1_CAPTURE_STA=0;//开启下一次捕获 } } }
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值