STM32输入捕获

本次试验使用STM32的输入捕获功能,测量PWM的频率。需要初始化的模块有PWM输出和输入捕获。

PWM模块初始化设置定时器3通道1,对应引脚为PC6,设置计数频率为(72M/72),自动重装载值为500。

即产生2Khz的PWM波

PWM波初始化

TIM3_CH1_PWM_Init(500-1,72-1);	//2k,PC6;
TIM_SetCompare1(TIM3,250);	    //在main中初始化比较器值;
void TIM3_CH1_PWM_Init(u16 per,u16 psc)
{
	TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;
	TIM_OCInitTypeDef TIM_OCInitStructure;
	GPIO_InitTypeDef GPIO_InitStructure;
	
	/* 开启时钟 */
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC,ENABLE);
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3,ENABLE);
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);
	
	/*  配置GPIO的模式和IO口 */
	GPIO_InitStructure.GPIO_Pin=GPIO_Pin_6;
	GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
	GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AF_PP;//复用推挽输出
	GPIO_Init(GPIOC,&GPIO_InitStructure);
	
	GPIO_PinRemapConfig(GPIO_FullRemap_TIM3,ENABLE);//改变指定管脚的映射	
	
	TIM_TimeBaseInitStructure.TIM_Period=per;   //自动装载值
	TIM_TimeBaseInitStructure.TIM_Prescaler=psc; //分频系数
	TIM_TimeBaseInitStructure.TIM_ClockDivision=TIM_CKD_DIV1;
	TIM_TimeBaseInitStructure.TIM_CounterMode=TIM_CounterMode_Up; //设置向上计数模式
	TIM_TimeBaseInit(TIM3,&TIM_TimeBaseInitStructure);	
	
	TIM_OCInitStructure.TIM_OCMode=TIM_OCMode_PWM1;
	TIM_OCInitStructure.TIM_OCPolarity=TIM_OCPolarity_Low;
	TIM_OCInitStructure.TIM_OutputState=TIM_OutputState_Enable;
	TIM_OC1Init(TIM3,&TIM_OCInitStructure); //输出比较通道1初始化
	
	TIM_OC1PreloadConfig(TIM3,TIM_OCPreload_Enable); //使能TIMx在 CCR2 上的预装载寄存器
	TIM_ARRPreloadConfig(TIM3,ENABLE);//使能预装载寄存器
	
	TIM_Cmd(TIM3,ENABLE); //使能定时器
		
}

初始化输入捕获功能

输入捕获使用定时器5通道1(PA0),设置计数频率为1M,溢出值为最大(0XFFFF)。

输入捕获的原理是,当定时器捕获到一个上跳沿时,产生捕获中断,标志位TIM_IT_CC1置位,此时记录下计数器中的值(cap_value1),当再次进入中断时,再次记录计数器中的值(cap_value2)。即得到相邻的两个上跳沿之间的计数值,为cap_value2-cap_value1;

根据计数频率1M可以计算当前捕获的PWM波时间。

TIM5_CH1_Input_Init(0xffff-1,71);    //输入捕获初始化
void TIM5_CH1_Input_Init(u16 arr,u16 psc)
{
	TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;
	TIM_ICInitTypeDef TIM_ICInitStructure;
	NVIC_InitTypeDef NVIC_InitStructure;
	GPIO_InitTypeDef GPIO_InitStructure;
	
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM5,ENABLE);//使能TIM5时钟
	
	GPIO_InitStructure.GPIO_Pin=GPIO_Pin_0;//管脚设置
	GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IPD;	 //设置下拉输入模式
	GPIO_Init(GPIOA,&GPIO_InitStructure); 	   /* 初始化GPIO */
	
	TIM_TimeBaseInitStructure.TIM_Period=arr;   //自动装载值
	TIM_TimeBaseInitStructure.TIM_Prescaler=psc; //分频系数
	TIM_TimeBaseInitStructure.TIM_ClockDivision=TIM_CKD_DIV1;
	TIM_TimeBaseInitStructure.TIM_CounterMode=TIM_CounterMode_Up; //设置向上计数模式
	TIM_TimeBaseInit(TIM5,&TIM_TimeBaseInitStructure);	
	
	TIM_ICInitStructure.TIM_Channel=TIM_Channel_1; //通道1
	TIM_ICInitStructure.TIM_ICFilter=0x00;  //滤波
	TIM_ICInitStructure.TIM_ICPolarity=TIM_ICPolarity_Rising;//捕获极性
	TIM_ICInitStructure.TIM_ICPrescaler=TIM_ICPSC_DIV1; //分频系数
	TIM_ICInitStructure.TIM_ICSelection=TIM_ICSelection_DirectTI;//直接映射到TI1
	TIM_ICInit(TIM5,&TIM_ICInitStructure);
	TIM_ITConfig(TIM5,TIM_IT_Update|TIM_IT_CC1,ENABLE);
	
	NVIC_InitStructure.NVIC_IRQChannel = TIM5_IRQn;//中断通道
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=2;//抢占优先级
	NVIC_InitStructure.NVIC_IRQChannelSubPriority =0;		//子优先级
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;			//IRQ通道使能
	NVIC_Init(&NVIC_InitStructure);
		
	TIM_Cmd(TIM5,ENABLE); //使能定时器
}

 输入捕获中断处理程序分析:

此处设置一个结构体,保存捕获到的信息;Cap_Value1和Cap_Value2较容易理解,就是两次捕获的计数器值;

Get_high的意思是一个标志位,=1表示捕获到一次高电平,=0表示没有捕获到一次高电平

Get_once=1表示成功捕获一次(即捕获到两次上跳沿)

typedef struct
{
	u8 Get_high;	//捕获到高电平; (标志位)
	u8 Get_once;	//成功捕获一次;即捕获两次高电平;(标志位)
	u16 Cap_Value1;	//捕获到第一次高电平时的CNT计数值;
	u16 Cap_Value2;	//捕获到第二次高电平时的CNT计数值;
}Capture;

当接收到一次上跳,进入中断,此时还没有捕获成功。记录此时的CNT计数器的值为cap_value2,并刷新状态(cap.Get_high=1;)。第二次碰到上升沿时(此时已经捕获到一次上升沿,即cap.Get_high=1),进入中断,刷新cap.Get_once状态为1,即成功捕获一个周期,记录下此时的CNT计数值作为cap_value2。

void TIM5_IRQHandler(void)
{
	if(cap.Get_once==0)		//如果还未捕捉成功;
	{
		if(TIM_GetITStatus(TIM5,TIM_IT_CC1))	//捕获中断;
		{
			if(cap.Get_high==1)		//已经捕获了一次高电平,再次进入中断,说明捕获成功了;
			{
				cap.Get_once=1;		//捕获成功;
				cap.Cap_Value2=TIM_GetCapture1(TIM5);		//保存此时计数器的值;
			}
			else  //如果还没捕获一次高电平,说明是第一次捕获;
			{
				cap.Get_high=1;
				cap.Cap_Value1=TIM_GetCapture1(TIM5);//记录此时的CNT值;
			}
		}
	}
	TIM_ClearITPendingBit(TIM5,TIM_IT_CC1|TIM_IT_Update);
}

主程序处理

主程序中判断cap.Get_once状态,是否成功捕获到一个PWM周期,

比较Cap_value1和Cap_value2的值,如果Cap_value2比Cap_value1大,表示在一个溢出周期内,

如果Cap_value2比Cap_value1小,表示在捕获计数时,产生了一个溢出,

       if(cap.Get_once==1)	//成功捕获一次;
		{
			if(cap.Cap_Value2>cap.Cap_Value1)	//如果没有发生溢出;
			{
				indata=cap.Cap_Value2-cap.Cap_Value1;	//记录捕获的计数值;
			}
			else
			{
				indata=(0xffff-cap.Cap_Value1)+cap.Cap_Value2;	
			}
			//清除状态;
 			cap.Get_high=0;
			cap.Get_once=0;
			cap.Cap_Value1=0;
			cap.Cap_Value2=0;
			printf("高电平持续时间:%d us\r\n",indata); //总的高电平时间
		}

猜你喜欢

转载自blog.csdn.net/stm32_newlearner/article/details/82825206