STM32 TIM_IC输入捕获篇

IC(Input Capture)输入捕获

输入捕获模式下,当通道输入引脚出现指定电平跳变时,当前CNT的值将被锁存到CCR中,可用于测量PWM波形的频率、占空比、脉冲间隔、电平持续时间等参数

每个高级定时器和通用定时器都拥有4个输入捕获通道,可配置为PWMI模式,同时测量频率和占空比,可配合主从触发模式,实现硬件全自动测量

频率测量:

        测频法适合频率较高的情况,由于测量方法为选取一段时间测量特定边沿取平均值,故波动较低,受噪声影响较小;测周法适合频率较低的情况,测量方法为选取一个周期,测量标准频率(即时钟),故波动较大,受噪声影响较大;当有一个频率,测频法和测周法的N相同,则误差相同,即为中界频率

正负1误差:在测量的时间(测频)或者周期(测周)中,可能出现测量的边沿(测频)或者频率(测周)不完整,只能舍弃或者当作一整个周期看待,若想减小正负1误差,需要尽量多计一些数

        这节主要采用的是测周法

输入捕获相关电路

        从左侧的四个通道引脚进入电路,首先1~3通道接入一个三输入的异或门,可用于三相无刷电机接入霍尔传感器检测转自位置使用,以驱动换相电路工作;接着进入输入滤波其和边沿检测器,对信号进行滤波和选择高/低电平触发。在下一步的输出上可分为两组:CH1和CH2、CH3和CH4,以前者举例:1、每条通道独立使用,CH1的信号得到TI1FP1输入到通道1的后续电路,或者CH1的信号得到TI1FP2输入到通道2的后续电路;CH2的信号同理     2、PWMI模式,可将一个引脚的输入同时映射到两个捕获单元,第一个捕获通道使用上升沿触发,用于捕获周期,第二个通道使用下降沿触发,用于捕获占空比,同时对一个引脚进行捕获即可同时测量频率和占空比

        输入信号进行滤波和极性选择后进入预分频器,分频后的触发信号即可进行触发捕获电路工作,每出现一个触发信号,CNT的值就会向CR寄存器转运一次,同时发生一个捕获事件,在状态寄存器置标志位的同时,也可产生中断

        测周法:若配置上升沿触发捕获,那么每出现一个上升沿,CNT转运置CCR一次,由于CNT由内部标准时钟驱动,故CNT的值可用于记录两个上升沿之间的时间间隔,即为周期,取倒数即为频率



主从触发模式

        主模式可将定时器内部信号映射至TRGO引脚,以触发其他外设;从模式可接受其他外设或自身外设的信号,用于控制自身定时器的运行;触发源选择,即选择从模式的触发信号源,选择指定信号,得到TRGI,从模式在列表中选择一项操作自动执行,以实现硬件自动化;

在输入捕获中,若想使用从模式进行操作,由于触发源选择中只有TI1FP1、TI2FP2,故只能使用通道1和通道2,通道3和通道4则不能使用,只能开启中断并手动清零

PWMI

        PWMI模式使用两个通道同时捕获一个引脚,可同时测量周期和占空比,TI1FP1配置上升沿触发,触发捕获和清零CNT,进行周期的捕获,而TI1FP2配置为下降沿触发,通过交叉通道触发通道2的捕获单元,CCR2捕获不触发CNT清零,是高电平期间的计数值,用CCR2/CCR1,即为占空比

初始化步骤

        1、RCC开启始终,打开GPIO和TIM时钟

        2、GPIO初始化,将GPIO配置为输入模式

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

        4、配置输入捕获单元,包括滤波器、极性、直连通道/交叉通道、分频器等

        5、选择从模式触发源,选择为TI1FP1

        6、选择触发后执行的操作,执行ReSet操作

        7、开启定时器

相关库函数

void TIM_ICInit(TIM_TypeDef* TIMx, TIM_ICInitTypeDef* TIM_ICInitStruct);
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);

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);

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);

        TIM_ICInit:用于结构体配置输入捕获单元,四个通道共用一个函数

        TIM_PWMIConfig:用于快速配置PWMI所需的两个输入通道

        TIM_ICStructInit:用于给输入捕获结构体赋初始值

        TIM_SelectInputTrigger:用于选择输入触发源TRGI

        TIM_SelectOutputTrigger:用于选择输出触发源TRGO

        TIM_SelectSlaveMode:用于选择从模式

        TIM_SetIC1Prescaler:用于单独配置各通道的分频器

        TIM_GetCapture1:用于读取各通道的CCR

代码实现

基本输入捕获模式:

//PWM.c文件 用于输出PWM波至IC输入口
#include "stm32f10x.h"                  // Device header

void PWM_Init(void)
{
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB | RCC_APB2Periph_AFIO, ENABLE);
	
	GPIO_PinRemapConfig(GPIO_PartialRemap_TIM3, ENABLE);//使用正点原子精英板,需要对TIM3进行重映射
	
	GPIO_InitTypeDef GPIO_InitStructure;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOB, &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 = 99;
	TIM_TimeBaseInitStructure.TIM_Prescaler = 719;
	TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0;//重复计数器,高级定时器才可使用,置0
	TIM_TimeBaseInit(TIM3, &TIM_TimeBaseInitStructure);
	
	TIM_OCInitTypeDef TIM_OCInitStructure;
	TIM_OCStructInit(&TIM_OCInitStructure); //用于给结构体中的所有变量赋初始值
											//避免使用高级定时器时因为部分变量未赋值而报错
	TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM2;
	TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;
	TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
	//TIM_OCInitStructure.TIM_Pulse = 50;
	TIM_OC2Init(TIM3, &TIM_OCInitStructure);
	TIM_OC2PreloadConfig(TIM3, TIM_OCPreload_Enable);  //使能TIM3在CCR2上的预装载寄存器
	TIM_Cmd(TIM3, ENABLE);

}

void PWM_SetCompare2(uint16_t Compare)
{
	TIM_SetCompare2(TIM3, Compare);
}

void PWM_SetPrescaler(uint16_t Prescaler)
{
	TIM_PrescalerConfig(TIM3, Prescaler, TIM_PSCReloadMode_Update);
}



//IC.c文件

#include "stm32f10x.h"      
void IC_Init(void)
{
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
	
	GPIO_InitTypeDef GPIO_InitStructure;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOA, &GPIO_InitStructure);
	
	//TIM_InternalClockConfig(TIM2); 		//这句不写也没有影响,默认使用内部时钟
	
	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 = 71;
	TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0;//重复计数器,高级定时器才可使用,置0
	TIM_TimeBaseInit(TIM2, &TIM_TimeBaseInitStructure);
	
	TIM_ICInitTypeDef TIM_ICInitStructure;
	TIM_ICInitStructure.TIM_Channel = TIM_Channel_2;	//使用TIM2_CH2
	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_SelectInputTrigger(TIM2, TIM_TS_TI2FP2);
	TIM_SelectSlaveMode(TIM2, TIM_SlaveMode_Reset);

	TIM_Cmd(TIM2, ENABLE);
}

uint32_t IC_GetFreq(void)
{
	return 1000000 / TIM_GetCapture2(TIM2);
}



//main.c 文件

int main(void)
{
	delay_init();
	OLED_Init();
	PWM_Init();
	IC_Init();
	
	PWM_SetPrescaler(719);	//Freq = 72M/ (PSC+1) / (ARR+1)
	PWM_SetCompare2(50);
	
	OLED_ShowString(1,1,"Freq:00000Hz");
	
	int i;
	while(1)
	{
		OLED_ShowNum(1,6, IC_GetFreq(), 5);
		for(i=0; i<100; i++)
		{
			PWM_SetCompare2(i);
			delay_ms(10);
		}
		for(i=0; i<100; i++)
		{
			PWM_SetCompare2(100-i);
			delay_ms(10);
		}
	}
}

PWMI模式:

//PWM输出部分同上

//PWMI部分代码:
#include "stm32f10x.h"                  // Device header

void IC_Init(void)
{
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
	
	GPIO_InitTypeDef GPIO_InitStructure;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOA, &GPIO_InitStructure);
	
	//TIM_InternalClockConfig(TIM2); 		//这句不写也没有影响,默认使用内部时钟
	
	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 = 71;
	TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0;//重复计数器,高级定时器才可使用,置0
	TIM_TimeBaseInit(TIM2, &TIM_TimeBaseInitStructure);
	
	TIM_ICInitTypeDef TIM_ICInitStructure;
	TIM_ICInitStructure.TIM_Channel = TIM_Channel_2;	//使用TIM2_CH2
	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_PWMIConfig(TIM2, &TIM_ICInitStructure);
	//TIM_ICInit(TIM2, &TIM_ICInitStructure);
	
	TIM_SelectInputTrigger(TIM2, TIM_TS_TI2FP2);
	TIM_SelectSlaveMode(TIM2, TIM_SlaveMode_Reset);

	TIM_Cmd(TIM2, ENABLE);
}

uint32_t IC_GetFreq(void)
{
	return 1000000 / TIM_GetCapture2(TIM2);
}

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


//main函数:
int main(void)
{
	delay_init();
	OLED_Init();
	PWM_Init();
	IC_Init();
	
	PWM_SetPrescaler(719);	//Freq = 72M/ (PSC+1) / (ARR+1)
	PWM_SetCompare2(50);
	
	OLED_ShowString(1,1,"Freq:00000Hz");
	OLED_ShowString(2,1,"Duty:00%");
	
	int i;
	while(1)
	{
		OLED_ShowNum(1,6, IC_GetFreq(), 5);
		for(i=0; i<100; i++)
		{
			PWM_SetCompare2(i);
			delay_ms(10);
			OLED_ShowNum(2,6, IC_GetDuty(), 2);
		}
		for(i=0; i<100; i++)
		{
			PWM_SetCompare2(100-i);
			delay_ms(10);
			OLED_ShowNum(2,6, IC_GetDuty(), 2);
		}
	}
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值