单片机之PWM输入捕获

首先要明白什么是PWM输入捕获?

第一,PWM输入捕获是基于TIM实现的一个功能;输入捕获就是当连接到定时器的引脚上产生电平变化时对应的捕获装置会立即将当前计数值复制到另一个寄存器中。你可以开启捕获中断然后在中断处理函数中读出保存的计数值。与输入捕获不同的是PWM输入模式会将同一个输入信号(TI1或TI2)连接到两个捕获装置(IC1和IC2)如果硬件不具备,也可以一个捕获装置,但是需要稍微复杂的配置。这两个捕获装置一个捕获上升沿一个捕获下降沿。TI1FP1、TI2FP2它们中的一个被选择为触发输入且从模式控制器被配置为复位模式。

简而言之,捕获就是捕获一个边沿信号的变化,pwm输入捕获最后还是捕获功能,只是多了一个跳变沿的设置(高电平和低电平),进而控制占空比,显现不一样的波形;

接下来就是如何实现捕获功能?

1)开启 TIM 时钟,配置 IO口;
2) 初始化 TIM, 设置 TIM 的 ARR 和 PSC;
3) 设置 TIM的输入比较参数,开启输入捕获;
4)使能捕获和更新中断(设置 TIM 的 DIER 寄存器);
5)设置中断分组,编写中断服务函数;
6)使能定时器(设置 TIM 的 CR1 寄存器);

以我的工程为例,进行演示;

1)开启 TIM17 时钟,配置 PA15口;这样是由于PA15复用了TIM17_CH1;

    RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOA,ENABLE);
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM17, ENABLE);
 
  GPIO_InitTypeDef GPIO_InitStructure;

  GPIO_PinAFConfig(GPIOA, GPIO_PinSource15, GPIO_AF_2); // tim17_ch1   pA15
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_15;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_Level_2;
  GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
  GPIO_Init(GPIOA, &GPIO_InitStructure);

2) 初始化 TIM, 设置 TIM 的 ARR 和 PSC;arr设置为最大值0xffff;psc设置为95,即(96-1),我的芯片系统时钟频率为96M;

  TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;

/* Time Base configuration */
  TIM_TimeBaseStructure.TIM_Prescaler = 95;
  TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
  TIM_TimeBaseStructure.TIM_Period = 0xffff;
  TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;
  TIM_TimeBaseInit(TIM17, &TIM_TimeBaseStructure);

3) 设置 TIM17的输入比较参数,开启输入捕获;

TIM_ICInitTypeDef TIM_ICInitStructure;

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_ICInit(TIM17, &TIM_ICInitStructure);

4)使能捕获和更新中断(设置 TIM 的 DIER 寄存器);

  TIM_DTS_Cfg(TIM17);
  TIM_TI1E_Set(TIM17);
  TIM_SelectInputTrigger(TIM17, TIM_TS_TI1FP1); 				//选择TIM17输入触发源:TIM经滤波定时器输入1
  TIM_SelectSlaveMode(TIM17, TIM_SlaveMode_Reset);              //选择从机模式:复位模式
  TIM_SelectMasterSlaveMode(TIM17, TIM_MasterSlaveMode_Enable); //开启复位模式
  TIM_ITConfig(TIM17, TIM_IT_CC1, ENABLE);      				//开启CC1中断

  /* TIM enable counter */
  TIM_Cmd(TIM17, ENABLE);

5)设置中断分组,编写中断服务函数;

NVIC_InitTypeDef NVIC_InitStructure;


  NVIC_InitStructure.NVIC_IRQChannel = TIM17_IRQn;
  NVIC_InitStructure.NVIC_IRQChannelPriority = 3;
  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
  NVIC_Init(&NVIC_InitStructure);

6)使能定时器(设置 TIM 的 CR1 寄存器);

写在第4步里面了;

第5步的中断服务函数编写:

变量定义为全局变量,不要写在函数里面;CCER寄存器是控制上升沿捕获还是下降沿捕获的;CCR1寄存器里存放的就是计数值;注意溢出的情况怎么处理的;

这里为什么要改变触发方式呢?

是由于这个芯片的TIM17只有一个通道,ch1通道;

u32 IC1Value = 0, IC1ValueOld = 0, cat_H = 0,cat_L=0,IC2ValueOld;

u8 catstep;
u32 duty_ok;

void TIM17_Handler(void)
{
    if((catstep==0)&&(TIM17->CCER==1))
    {
        IC1ValueOld = TIM17->CCR1;
    
        TIM17->CCER = 3;//下降沿
        duty_ok = 0;

    }
    
    else if((catstep==0)&&(TIM17->CCER==3))
    {
        IC1Value = TIM17->CCR1;
        if(IC1Value>IC1ValueOld)
        cat_H=IC1Value-IC1ValueOld;
        else cat_H=(IC1Value+65535-IC1ValueOld);//溢出


        TIM17->CCER = 1;//变上升沿触发

        catstep=1;
    }
//    
    else if ((catstep==1)&&(TIM17->CCER==1))
    {
        IC2ValueOld = TIM17->CCR1;
        IC1ValueOld =TIM17->CCR1;
        if(IC2ValueOld>IC1Value)
        cat_L=IC2ValueOld-IC1Value;
        else cat_L=(IC2ValueOld+65535-IC1Value);
        TIM17->CCER = 3;//下降沿
        catstep=0;
        duty_ok = 1;//建议duty=1时在while里面计算占空比
    }
   

  TIM_ClearITPendingBit(TIM17, TIM_IT_CC1);
}

最后在main函数里调用;注意一些变量的声明;

extern u32 cat_H;
extern u32 cat_L;
extern u32 duty_ok;
float duty;


//写在while循环里
if(duty_ok)duty=((float)cat_L/(float)(cat_L+cat_H));	//电平与信号相反

最后,如果不出意外,IO口触发电平的转换,就会有信号的变化; 可以弄个按键触发;

你可能感兴趣的:(单片机,嵌入式硬件)