【江科大】STM32:TIM输入捕获(理论部分)

发布时间:2024年01月22日

IC(Input Capture)输入捕获

输入捕获模式下,当通道输入引脚出现指定电平跳变(上升沿或者下降沿)时,(控制)当前CNT的值将被锁存到CCR中,可用于测量PWM波形的频率、占空比、脉冲间隔、电平持续时间等参数
每个高级定时器和通用定时器都拥有4个输入捕获通道
可配置为PWMI(input)模式,同时测量频率和占空比
可配合主从触发模式,实现硬件全自动测量

(输入捕获,接收到输入信号,执行CNT锁存到CCR的动作)
(输出比较,是根据CNT和CCR的比较关系执行输出动作)
在这里插入图片描述
测频法:在闸门时间T内,对上升沿计次,得到N,则频率 (适合测量高频信号
f x = N / T f_x=N / T fx?=N/T N越大,误差和越小 ,因为容易计数遗漏 (记录的次数多了,一次记错也影响不大)
测周法:两个上升沿内,以标准频率fc计次,得到N ,则频率 f = 1/t (通过计时器记录一个上升加一个下降沿的时间)(适合测量低频信号
f x = f c / N f_x=f_c / N fx?=fc?/N N越大,误差和越小 多计算一些数
在这里插入图片描述
那多高算高频率,多低算低频率。就涉及到中界频率:
中界频率:测频法与测周法误差相等的频率点
f m = √ f c / T f_m=√f_c / T fm?=fc?/T
测量的是数字信号。

  • 因此测频法适用于频率大于中界频率,测周法适合小于中界频率。
  • 红外射频,上升沿计次+1,结合定时器,在中断里每隔1S取一下计次值,同时清零,为下一次做准备。
  • CNT计数器是由内部的标准时钟驱动的,所以CNT的数值,可以用来计算两个上升沿之间的时间间隔,这就是一个周期,取个倒数 就是测周法测量的频率
  • 每来一个上升沿,取CNT的值自动存到CCR里面,CCR捕获到的值就是就是计数值N,CNT的驱动时钟就是fc ,fc/N就得到了待测信号的频率。
  • 计数器计时频率:提高标准频率fc,频率就会越大
    fc = CK_CNT =CK_PSC/(PSC+1) CK_PSC = 72MHZ
    捕获后清零的操作,用的是主从触发模式。

PWM频率

Freq = CK_PSC / (PSC + 1) / (ARR + 1)
在这里插入图片描述

知识点补充

1. 滤波器的工作原理:

以采样频率对输入信号进行采样,当连续N个值都为高电平,输出才为高电平,反之亦然,如果信号出现高频抖动,导致连续 采样N个值不全都一样。那输出不会变化。达到滤波的效果。
特点
采样频率越低,采样个数N越大,滤波器效果就越好。
如果噪声比较大,就将采样频率从的值调大一点,就可以过滤噪声

2. 边沿检测器:

用来捕获上升沿或者下降沿。

  1. CC1P:用来选择极性
    最终到达Tl1FP1触发信号,选择数据选择器。
    通过数据选择器进入捕获电路
    到达Tl1FP2触发信号,连接到通道2的后续电路,
    同样通道2还有Tl2FP1,连接通道1的后续电路
    还有TI2FP2,连接通道2的后续电路。共有4种连接方式
  2. CC1S:配置数据选择器
  3. ICPS:配置分频器系数
  4. CC1E控制输出使能或失能,如果使能输出,输出的产生指定边沿信号,经过层层电路,到达捕获电路,就可以让CNT的值转运到CCR里面。
    每捕获一次CNT,都要将CNT清零,方便下一次捕获,硬件电路自动完成清零CNT,也就是图中Tl1FP1连接的从模式来处理(自动化)。

自动化清零CNT

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

输入捕获的基本结构

在这里插入图片描述
只有一个通道只能用来测频率。

PWMI基本结构

fx=fc/N N=CNT
因为CNT在清零后一直++
CCR1是一整个周期的计数值
CCR2是高电平期间的计数值
占空比:CCR2/CCR1
在这里插入图片描述

这里可以看出来 N = CCR1

uint32_t IC_GetFreq(void)
{                     // fx =fc/n   fc  = CK_PSC / (PSC + 1)  -> 72000000Hz/72 = 1MHZ
	return 1000000/(TIM_GetCapture1(TIM3)+1); // 占空比= fc/N   N就是读取CCR的值
}
uint32_t IC_GetDuty(void)   //获得PWM的占空比
{
	return TIM_GetCapture2(TIM3)/TIM_GetCapture1(TIM3);  //CRR2/CRR1
}

滤波器和分频器的区别

滤波器不会改变信号的原有频率,只会滤除高频噪音。
分频器是对信号进行分频。改变了原有的频率

误差分析

除了由±1误差,还有晶振误差

通过直接在PWM.c文件中修改 PSC和ARR不方便,因此创建一个函数

  1. 据PWM频率:
    Freq = CK_PSC / (PSC + 1) / (ARR + 1) :
    72MHZ/(PSC+1)/(ARR+1) = 1000 PSC+1 =72000000/1000000=720HZ
  2. PWM占空比:
    Duty = CCR / (ARR + 1)
    因此修改ARR会同时影响 频率和占空比,所以修改PSC调节频率最合适
    固定ARR = 100-1;
    CCR的值 直接就是占空比
    在这里插入图片描述

#include “stm32f10x.h” // Device header
//1.配置GPIO
//2.选择内部时钟
//3.配置时基单元
//4.配置输入捕获单元
//5.选择从模式触发源
//6.选择触发之后执行的操作
//7.开启定时器

pwm.c

在这里插入图片描述

main.c

在这里插入图片描述

IC.c

void IC_Init(void)
{
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3,ENABLE);//给TIM2使能
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);//给GPIO使能
	
	
	GPIO_InitTypeDef GPIO_InitStruct;
	GPIO_InitStruct.GPIO_Mode =  GPIO_Mode_IPU;  //上拉输入,
	GPIO_InitStruct.GPIO_Pin = GPIO_Pin_6;   //根据引脚表的出CH_1所在引脚时PA0
	GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOA,&GPIO_InitStruct);
	
	
	TIM_InternalClockConfig(TIM3); //选择内部时钟                           
	
	//时基单元
	 TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStruct;
	TIM_TimeBaseInitStruct.TIM_ClockDivision = TIM_CKD_DIV1;  //每一个时钟后面都会加一个滤波器,作用就是为是信号更加稳定,使用的采样的方式,在输入的脉冲中采样,按照n/f,因此采样系数越大,延迟越大
	TIM_TimeBaseInitStruct.TIM_CounterMode = TIM_CounterMode_Up;
	TIM_TimeBaseInitStruct.TIM_Period = 65536-1;  //ARR =100
	TIM_TimeBaseInitStruct.TIM_Prescaler = 72-1;  // psc = 720//预分频器,72MHZ进行7200分频 ,72000/7200 = 10KHZ  1ms = 1KHZ  10KHZ下记10000个数 10000/10 =1000kHZ = 1S
	TIM_TimeBaseInitStruct.TIM_RepetitionCounter = 0;
    TIM_TimeBaseInit(TIM3,&TIM_TimeBaseInitStruct);
    
	//初始化输入捕获单元
	TIM_ICInitTypeDef TIM_ICInitStruct;
	TIM_ICInitStruct.TIM_Channel =  TIM_Channel_1 ;
	TIM_ICInitStruct.TIM_ICFilter = 0xF;  //数值越大,采样效果越好(以采样频率对输入信号进行采样,当连续N个值都为高电平,输出才为高电平,反之亦然,如果信号出现高频抖动,导致连续 采样N个值不全都一样。那输出不会变化。达到滤波的效果。)
	TIM_ICInitStruct.TIM_ICPolarity = TIM_ICPolarity_Rising; //极性选择    上升沿,下降沿 双沿
	TIM_ICInitStruct.TIM_ICPrescaler = TIM_ICPSC_DIV1;//设置分频值
	TIM_ICInitStruct.TIM_ICSelection = TIM_ICSelection_DirectTI; ///通道选择 。直连,交叉
	TIM_ICInit(TIM3,&TIM_ICInitStruct);
    
	//配置触发源
	TIM_SelectInputTrigger(TIM3, TIM_TS_TI1FP1);
	

	//选择从模式 自动清理CNT
	 TIM_SelectSlaveMode(TIM3,TIM_SlaveMode_Reset);
	 
	 //启动时基单元
	 TIM_Cmd(TIM3,ENABLE);
}
uint32_t IC_GetFreq(void)
{                     // fx =fc/n   fc  = CK_PSC / (PSC + 1)  -> 72000000Hz/72 = 1MHZ
	return 1000000/(TIM_GetCapture1(TIM3)+1); // freq= fc/N   N就是读取CCR的值
}

在这里插入图片描述

PWM模式测频率和占空比

uint32_t IC_GetFreq(void)
{                     // fx =fc/n   fc  = CK_PSC / (PSC + 1)  -> 72000000Hz/72 = 1MHZ
	return 1000000/(TIM_GetCapture1(TIM3)+1); // 占空比= fc/N   N就是读取CCR的值
}
uint32_t IC_GetDuty(void)
{
	return (TIM_GetCapture2(TIM3)+1)*100/(TIM_GetCapture1(TIM3)+1);  //*100可以变为整数
}

在这里插入图片描述

//配置成两个通道同时捕获一个引脚
//初始化输入捕获单元
TIM_ICInitTypeDef TIM_ICInitStruct;
TIM_ICInitStruct.TIM_Channel =  TIM_Channel_1 ;
TIM_ICInitStruct.TIM_ICFilter = 0xF;  //数值越大,采样效果越好(以采样频率对输入信号进行采样,当连续N个值都为高电平,输出才为高电平,反之亦然,如果信号出现高频抖动,导致连续 采样N个值不全都一样。那输出不会变化。达到滤波的效果。)
TIM_ICInitStruct.TIM_ICPolarity = TIM_ICPolarity_Rising; //极性选择    上升沿,下降沿 双沿
TIM_ICInitStruct.TIM_ICPrescaler = TIM_ICPSC_DIV1;//设置分频值
TIM_ICInitStruct.TIM_ICSelection = TIM_ICSelection_DirectTI; ///通道选择 。直连,交叉
TIM_ICInit(TIM3,&TIM_ICInitStruct);

//如何配置成两个通道同时捕获一个引脚,采用下面的函数
//只支持通道1和通道2
TIM_PWMIConfig(TIM3,&TIM_ICInitStruct);  //这个函数会自动将配置呈相反的,上升沿变下降沿,直连变交叉

//配置触发源
TIM_SelectInputTrigger(TIM3, TIM_TS_TI1FP1);


//选择从模式 自动清理CNT
 TIM_SelectSlaveMode(TIM3,TIM_SlaveMode_Reset

);

在这里插入图片描述
定时器输入捕获库函数

//也有四个通道,初始化输入捕获单元
void TIM_ICInit(TIM_TypeDef* TIMx, TIM_ICInitTypeDef* TIM_ICInitStruct);
//给初始化PWMI
void TIM_PWMIConfig(TIM_TypeDef* TIMx, TIM_ICInitTypeDef* TIM_ICInitStruct);
//给结构体初始化值
void TIM_ICStructInit(TIM_ICInitTypeDef* TIM_ICInitStruct);


//选择输入触发源 (从模式) 
void TIM_SelectInputTrigger(TIM_TypeDef* TIMx, uint16_t TIM_InputTriggerSource);
//选择输出触发源
void TIM_SelectOutputTrigger(TIM_TypeDef* TIMx, uint16_t TIM_TRGOSource);
//选择从模式
void TIM_SelectSlaveMode(TIM_TypeDef* TIMx, uint16_t TIM_SlaveMode);  

//分别单独配置通道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);
void TIM_SetClockDivision(TIM_TypeDef* TIMx, uint16_t TIM_CKD);


//分别读取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);
文章来源:https://blog.csdn.net/weixin_52958292/article/details/135750923
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。