How to use the timer to capture a PWM wave signal frequency and duty cycle

Disclaimer: This article is a blogger original article, if reproduced, please indicate the source https://blog.csdn.net/qq_36554582/article/details/88357473

The experiment will use the Timer 2 channels 2 generate both the frequency and duty cycle of the PWM signal can be adjusted, then the channel 1 of timer 3 to capture the way in which the frequency and duty cycle of the PWM wave.
1, first of all look at the generator PWM wave, that is, and the blog post is the same, but only for a timer:

void PWMOut_Init_Adjust_Duty_Fre(void)//输出两路频率可调、占空比可调的PWM波
{
	TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
	TIM_OCInitTypeDef  TIM_OCInitStructure;
	NVIC_InitTypeDef NVIC_InitStructure;
	GPIO_InitTypeDef GPIO_InitStructure;

	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);

	/* GPIOA and GPIOB clock enable */
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);

	GPIO_InitStructure.GPIO_Pin =  GPIO_Pin_1 | GPIO_Pin_2;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;

	GPIO_Init(GPIOA, &GPIO_InitStructure);

	
	NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn;
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2;
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
	NVIC_Init(&NVIC_InitStructure);
	
	  /* Time base configuration */
	TIM_TimeBaseStructure.TIM_Period = 65535;//必须是这个数值65535
	TIM_TimeBaseStructure.TIM_Prescaler = 71;
	TIM_TimeBaseStructure.TIM_ClockDivision = 0;
	TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;

	TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);

	/* Output Compare Toggle Mode configuration: Channel1 */
	TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_Toggle;//输出比较翻转模式
	TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
	TIM_OCInitStructure.TIM_Pulse = CCR1_Val;//跳变值,也可初始化为CCR1_Val*Duty1
	TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;
	TIM_OC2Init(TIM2, &TIM_OCInitStructure);

	TIM_OC2PreloadConfig(TIM2, TIM_OCPreload_Disable); //使能或者失能TIMx在CCR1上的预装载寄存器

	/* Output Compare Toggle Mode configuration: Channel2 */
	TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
	TIM_OCInitStructure.TIM_Pulse = CCR2_Val;//跳变值,也可初始化为CCR2_Val*Duty2
	TIM_OC3Init(TIM2, &TIM_OCInitStructure);

	TIM_OC3PreloadConfig(TIM2, TIM_OCPreload_Disable);
	
	TIM_Cmd(TIM2,ENABLE);
	TIM_ITConfig(TIM2,TIM_IT_CC2 | TIM_IT_CC3,ENABLE);
}

2, Timer 2 interrupt service function :( generate PWM wave)

void TIM2_IRQHandler(void)
{
	if(TIM_GetITStatus(TIM2,TIM_IT_CC2) != RESET)//TIM_IT_CC1为捕获中断
	{
		TIM_ClearITPendingBit(TIM2,TIM_IT_CC2);
		capture = TIM_GetCapture2(TIM2);//获取当前计数器中的值
		if(PA6_state == 0)
		{
			TIM_SetCompare2(TIM2,capture + (u16)(CCR1_Val*Duty1));//注意此时的CCR1_Val是指的整个一个PWM周期内的总计数值,而在频率可调、占空比固定位50%的程序中,CCR1_Val指的是半个周期的计数值
			PA6_state = 1;
		}
		else if(PA6_state == 1)
		{
			TIM_SetCompare2(TIM2,capture + (u16)(CCR1_Val*(1-Duty1)));
			PA6_state = 0;
		}
	}
	if(TIM_GetITStatus(TIM2,TIM_IT_CC3) != RESET)
	{
		TIM_ClearITPendingBit(TIM2,TIM_IT_CC3);
		capture = TIM_GetCapture3(TIM2);
		if(PA7_state == 0)
		{
			TIM_SetCompare3(TIM2,capture + (u16)(CCR2_Val*Duty2));
			PA7_state = 1;
		}
		else if(PA7_state == 1)
		{
			TIM_SetCompare3(TIM2,capture + (u16)(CCR2_Val*(1-Duty2)));
			PA7_state = 0;
		}
	}
}

3, reads the PWM wave configuration program timer 3:

void PWM_Input_Init(void)
{
	TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
	TIM_ICInitTypeDef  TIM_ICInitStructure;
	GPIO_InitTypeDef GPIO_InitStructure;
	NVIC_InitTypeDef NVIC_InitStructure;
	
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
	
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;

    GPIO_Init(GPIOA, &GPIO_InitStructure);
	
	//注意一定不要忘了配置TIM_TimeBaseInit(),每次只要使用定时器的任何模式,都需要使用TIM_TimeBaseInit()
	//不要在定时器2里面配置过了,在这个定时器3的配置程序中就忘了,他们是互不影响的
	TIM_TimeBaseStructure.TIM_Period = 65535;
	TIM_TimeBaseStructure.TIM_Prescaler = 71;
	TIM_TimeBaseStructure.TIM_ClockDivision = 0;
	TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;

	TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure);
	
	NVIC_InitStructure.NVIC_IRQChannel = TIM3_IRQn;
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init(&NVIC_InitStructure);
    	
    TIM_ICInitStructure.TIM_Channel = TIM_Channel_1;
    TIM_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising;
    TIM_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI;
    TIM_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1;
    TIM_ICInitStructure.TIM_ICFilter = 0x0;

    TIM_PWMIConfig(TIM3, &TIM_ICInitStructure);
	
    TIM_SelectInputTrigger(TIM3, TIM_TS_TI1FP1);

    TIM_SelectSlaveMode(TIM3, TIM_SlaveMode_Reset);

    TIM_SelectMasterSlaveMode(TIM3, TIM_MasterSlaveMode_Enable);

    TIM_Cmd(TIM3, ENABLE);

    TIM_ITConfig(TIM3, TIM_IT_CC1,ENABLE);
}

4, read wave PWM interrupt service functions:

void TIM3_IRQHandler(void)
{
  TIM_ClearITPendingBit(TIM3, TIM_IT_CC1);
  IC2Value = TIM_GetCapture1(TIM3);

  if (IC2Value != 0)
  {
    DutyCycle = (TIM_GetCapture2(TIM3) * 100) / IC2Value;
    Frequency = SystemCoreClock / IC2Value;
  }
  else
  {
    DutyCycle = 0;
    Frequency = 0;
  }
}

5, the display function:

sprintf((char*)str,"Frequency=%d",1000000/CCR1_Val);//72分频,所以计数频率是1MHz,所以PWM波频率就是1000000/CCR1_Val
LCD_DisplayStringLine(Line1,str);
sprintf((char*)str,"Duty1=%.1f",Duty1);
LCD_DisplayStringLine(Line2,str);
sprintf((char*)str,"Frequency=%d",Frequency/72);//读取的PWM波的频率,除以72是因为定时器计数的时候进行了72分频
LCD_DisplayStringLine(Line3,str);
sprintf((char*)str,"DutyCycle=%d%s",DutyCycle,"%");//读取PWM波的周期
LCD_DisplayStringLine(Line4,str);

After we finished reading the data to calculate the time during PWM wave frequency, if you divide the timer, then the last calculated result also requires divided by the corresponding division factor is the correct result, for example, in the allocation of timer, when the division was 72, then I conducted when displayed in the LCD, so that the variable Frequencyand divided by 72, the true frequency of such calculated result is PWM wave.

Then briefly about the basic principles of the capture PWM wave:

  • Each timer has four input capture channels IC1, IC2, IC3, IC4, and a set of IC1 and IC2, IC3 and IC4 as a group, you may set the correspondence relationship between the pins and the register
  • TIM same channel signals are mapped two ICx
  • Edge signal in one of the two is selected as the trigger signal (i.e. the rising or falling edge triggered)
  • When the trigger signal comes, is arranged to trigger a capture register signals have been captured "a PWM" period (i.e., two consecutive rising or falling), inside which the count value is equal to a PWM wave cycle within the TIM valuen
  • Also other ACQ channel capture trigger and counts the number of the next signal edge of the opposite polarity, i.e., a high level duration of the PWM period duration or lowm
  • Therefore:
PWM波的周期为:
T=(1/定时器计数频率)*n
PWM波的频率为:
f=1/T=定时器计数频率/n

If m is the duration of high level, the duty cycle of the PWM wave:

Duty=(m/n)*100(百分制)

If m is the duration of a low level, the duty cycle of the PWM wave:

Duty=((n-m)/n)*100(百分制)

Because the counter is 16 bits, so a cycle count up to 65535, the minimum frequency measured =

定时器时钟频率/65535

If you want to measure lower frequency, we can use another method of measurement:
1, the timer configuration program:

u8 TIM3CH2_Capture_Sta = 0;
u16 TIM3CH2_Capture_Val = 0;
void PWMInput_Init(void)
{
	GPIO_InitTypeDef GPIO_InitStructure;
	NVIC_InitTypeDef NVIC_InitStructure;
	TIM_ICInitTypeDef  TIM_ICInitStructure;
	
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
	
	
	TIM_ICInitStructure.TIM_Channel = TIM_Channel_2;
	TIM_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising;
    TIM_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI;
    TIM_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1;
    TIM_ICInitStructure.TIM_ICFilter = 0x0;
	TIM_ICInit(TIM3,&TIM_ICInitStructure);
	
	
	
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;

    GPIO_Init(GPIOA, &GPIO_InitStructure);
	
	NVIC_InitStructure.NVIC_IRQChannel = TIM3_IRQn;
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2;
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init(&NVIC_InitStructure);
	
	TIM_ITConfig(TIM3,TIM_IT_CC2 | TIM_IT_Update,ENABLE);
	TIM_Cmd(TIM3, ENABLE);
}

2, the interrupt handler:

void TIM3_IRQHandler(void)
{
	if((TIM3CH2_Capture_Sta & 0x80) == 0)
	{
		if(TIM_GetITStatus(TIM3,TIM_IT_Update) != RESET)
		{
			if(TIM3CH2_Capture_Sta & 0x40)
			{
				if((TIM3CH2_Capture_Sta & 0x3f) == 0x3f)
				{
					TIM3CH2_Capture_Sta |= 0x80;
					TIM3CH2_Capture_Val = 0xffff;
				}
			}
			else
			{
				TIM3CH2_Capture_Sta++;
			}
		}
		if(TIM_GetITStatus(TIM3,TIM_IT_CC2) != RESET)
		{
			if(TIM3CH2_Capture_Sta & 0x40)
			{
				TIM3CH2_Capture_Sta |= 0x80;
				TIM3CH2_Capture_Val = TIM_GetCapture2(TIM3);
				TIM_OC2NPolarityConfig(TIM3,TIM_ICPolarity_Rising);
			}
			else
			{
				TIM3CH2_Capture_Sta = 0;
				TIM3CH2_Capture_Val = 0;
				TIM3CH2_Capture_Sta |= 0x40;
				TIM_SetCounter(TIM3,0);
				TIM_OC2NPolarityConfig(TIM3,TIM_ICPolarity_Falling);
			}
		}
	}
	TIM_ClearITPendingBit(TIM3,TIM_IT_CC2 | TIM_IT_Update);
}

Using this method, although you can measure low frequency, but the interrupt service routine slightly more complicated point, if you know the first measurement method has been sufficient, try not to choose the second method. Rationale for the second method in my previous blog there to explain:
blog links: https://blog.csdn.net/qq_36554582/article/details/81611272
References:
HTTPS: //blog.csdn. net / dainifeixiang / article / details / 5499485

Guess you like

Origin blog.csdn.net/qq_36554582/article/details/88357473