STM32输入捕获--“PWM输入模式”(可拓展多路同时捕获)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/wuyuzun/article/details/85043588

前言

  1. 博文基于STM32F103ZET6和标准固件库V3.5.0在MDK5环境下开发;
  2. 本博文只讨论输入捕获的PWM输入模式,这个模式是STM32输入捕获检测脉宽和频率的一种硬件处理机制,说白了就是STM32芯片专门用来进行对PWM进行捕获的一个功能;此方法相比较于传统的PWM的捕获方法,大大减小了代码量,提高了检测效率,而实际上对于PWM信号的检测还有其他方法(下面我会介绍,就是原子教程提供的方法),并且关于繁琐的寄存器的介绍这里就不多说了,有兴趣的话可以直接去我的另外一个博客里去看: https://blog.csdn.net/wuyuzun/article/details/73135662 ;(备注:此链接里的博客里有一个配套的例程,例程的思想来自于源子教程,然而本博客是向突出介绍“PWM输入模式”这种我认为更好的方法)
  3. 本片博文只介绍单路(一个定时器)的PWM输入模式的,如果想实现多路PWM同时检测,只需要对其他具有输入捕获功能的定时器相同配置即可(我会在另外一个博客里进行介绍);
  4. 如有不足之处,多指教;

什么是PWM输入模式以及相应配置流程

在这里插入图片描述
(截图来自《STM32中文参考手册_V10》第216页)
介绍:(我们通过比较原子提供的思路来分析一下“PWM输入模式的比较模式”)
原子的思路:
在这里插入图片描述
如图为某个引脚输入的PWM波,把它分为4~5的阶段进行编程:
① 此时设置好上升沿为触发中断,以及其他定时器配置;
② 此时产生了上升沿,进行捕获操作,CNT内的值捕获到CCR内,此时使CNT=0,CNT继续开始计数;当完成捕获,并且修改捕捉极性为下降沿捕获,当下降沿来到时,将会再次触发此中断函数;
③ 此时产生了下降沿,触发了中断函数;
④ 清0 TIMx_SR寄存器中CCxOF和CCxIF位。

PWM输入模式:
在这里插入图片描述
(图片中为定时器输入捕获模式涉及到的功能模块,来自《STM32中文使用手册》P200页)
如图,举一个输入引脚为例(但是只能举TIMx_CH1和TIMx_CH2,因为TIMx_CH3和TIMx_CH4没有今天所要讨论的PWM输入模式这个功能,),假设这里对TIMx_CH1输入的信号同原子思路中的一样;那么我们同样可以用上面那种图来分析①~⑤五个步骤:
①:配置相对应的输入捕获引脚TIMx_CH1和GPIO管脚的映射关系;
②:选择TIMx_CCR1为有效输入:置TIMx_CCMR1寄存器的CC1S=01(这步的配置决定了此时的CCR1寄存器是输入用的还是输出用的,因为每个可以执行捕获和比较功能的定时器同一时间,只能执行捕获或者输出,两者不能同时进行);在这里插入图片描述
③:选择TI1FP1的有效极性(用来捕获数据到TIMx_CCR1和清除计数器CNT),置CC1P=0(上升沿有效)
在这里插入图片描述
④:选择TIMx_CCR2的有效输入:置TIMx_CCMR1寄存器的CC2S=10(选中TI1)。(这里是需要特别注意的一个地方,从下图的配置选择或者从上面电路方框图的绿色剪头可以看出来,其实IC1和IC2配置时选择的输入信号都是来自于CH1通道进来的信号)在这里插入图片描述
⑤:选择TI1FP2的有效极性(捕获CNT的数据到TIMx_CCR2);置CC2P=1(下降沿有效)。(图片参考了CC1P的配置,这里可以注意到一个现象就是IC2选择下降沿触发捕获,而IC1选择的是信号上升沿触发捕获)
在这里插入图片描述
⑥:选择有效的触发输入信号:置TIMx_SMCR寄存器中的TS = 101(选择TI1FP1);
在这里插入图片描述
⑦:配置从模式寄存器为复位模式:置TIMx_SMCR中的SMS=100;(这一步决定每次上升沿出现,CNT就被清零)在这里插入图片描述
⑧:使能捕获:配置TIMx_CCER寄存器中CC1E=1且CC2E=1;

从波形的角度分析工作原理
在这里插入图片描述
①:在一处完成上述配置(当然,上述的配置只是简单地寄存器配置,并没写中断函数等等,这个工作,可以放在后续):
②:一条路上的CH1,TI1,TI1FP1,TI1FP2的上升沿同时产生,CNT内的值被捕获到了CCR1内并且CNT被清零,从新开始计数;
③:一条路上的CH1,TI1,TI1FP1,TI1FP2的下降沿同时产生,CNT内的值被捕获到了CCR2内,不清零CNT;
④~⑤:在编写的中断函数内即可进行逻辑操作,获取此时CCR1(周期)和CCR2(高电平时间),即可计算占空比 = CCR2/CCR1;
下面即使相对应的代码:

/*---------------PWM输入对应管脚配置-----------------*/
static void PWM_Intput_GPIO_Config(void) 
{
  GPIO_InitTypeDef GPIO_InitStructure;

	// TIM1 对应 PA8
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
  GPIO_InitStructure.GPIO_Pin =  GPIO_Pin_8;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;  //浮空输入模式;
  GPIO_Init(GPIOA, &GPIO_InitStructure);	

}

/*-------------中断嵌套配置------------*/
static void PWM_Intput_NVIC_Config(void)
{
    NVIC_InitTypeDef NVIC_InitStructure; 

    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0);		
	
    NVIC_InitStructure.NVIC_IRQChannel = TIM1_CC_IRQn; 	
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;	 
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;	
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init(&NVIC_InitStructure);
}

/*-------------TIM1模式配置------------*/
static void PWM_Intput_Mode_Config(void)
{

	RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1,ENABLE);

/*--------------------时基结构初始化-------------------------*/
	TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
	TIM_TimeBaseStructure.TIM_Period=0xffff;				//ARR=65535us
	TIM_TimeBaseStructure.TIM_Prescaler= 72-1;				//PSC = 1M = 1us;
	TIM_TimeBaseStructure.TIM_ClockDivision=TIM_CKD_DIV1;	//分频因子为0,即不分频;	
	TIM_TimeBaseStructure.TIM_CounterMode=TIM_CounterMode_Up; //CNT为向上计数模式;		
	TIM_TimeBaseStructure.TIM_RepetitionCounter=0;	
	TIM_TimeBaseInit(TIM1, &TIM_TimeBaseStructure);

	/*-------------------输入捕获结构体初始化------------------*/	

  TIM_ICInitTypeDef  TIM_ICInitStructure;
  //配置CH1
  TIM_ICInitStructure.TIM_Channel = TIM_Channel_1;
  TIM_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising;     //上升沿触发
  TIM_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI; //IC1直接连接TI1FP1
  TIM_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1;           //对输入的PWM信号不分频
  TIM_ICInitStructure.TIM_ICFilter = 0x0;
  TIM_PWMIConfig(TIM1, &TIM_ICInitStructure);
  
  //配置CH2
  TIM_ICInitStructure.TIM_Channel = TIM_Channel_2;
  TIM_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Falling;      //下降沿触发;
  TIM_ICInitStructure.TIM_ICSelection = TIM_ICSelection_IndirectTI; //IC2间接连接TI1FP2
  TIM_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1;				//对输入的PWM信号不分频
  TIM_ICInitStructure.TIM_ICFilter = 0x0;
  TIM_PWMIConfig(TIM1, &TIM_ICInitStructure);
	
  //选择输入捕获的触发信号;
  TIM_SelectInputTrigger(TIM1, TIM_TS_TI1FP1);		

  // 选择从模式
  // PWM输入模式时,从模式必须工作在复位模式,当捕获开始时,计数器CNT被复位清零;
  TIM_SelectSlaveMode(TIM1, TIM_SlaveMode_Reset);
  TIM_SelectMasterSlaveMode(TIM1,TIM_MasterSlaveMode_Enable); 

  // 使能捕获中断,这个中断主要针对的是主捕获通道(TI1FP1)
  TIM_ITConfig(TIM1, TIM_IT_CC1, ENABLE);	
  // 清除中断标志位
  TIM_ClearITPendingBit(TIM1, TIM_IT_CC1);
	
  // 计数器开始计数
  TIM_Cmd(TIM1, ENABLE);
}

/*---------------PWM输入对应管脚配置-----------------*/
static void PWM_Intput_GPIO_Config(void) 
{
  GPIO_InitTypeDef GPIO_InitStructure;

	// TIM1 对应 PA8
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
  GPIO_InitStructure.GPIO_Pin =  GPIO_Pin_8;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;  //浮空输入模式;
  GPIO_Init(GPIOA, &GPIO_InitStructure);	

}

/*-------------中断嵌套配置------------*/
static void PWM_Intput_NVIC_Config(void)
{
    NVIC_InitTypeDef NVIC_InitStructure; 

    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0);		
	
    NVIC_InitStructure.NVIC_IRQChannel = TIM1_CC_IRQn; 	
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;	 
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;	
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init(&NVIC_InitStructure);
}

void TIM1_CC_IRQHandler(void)
{
  uint8_t IC1_CCR1,IC2_CCR2;
  TIM_ClearITPendingBit(TIM1, TIM_IT_CC1);
  IC1_CCR1 = TIM_GetCapture1(TIM1);   //获取周期值CCR1
  IC2_CCR2 = TIM_GetCapture2(TIM1);   //获取高电平时间CCR2
	
	/*逻辑代码*/

}

/*-------------TIM1模式配置------------*/
static void PWM_Intput_Mode_Config(void)
{

	RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1,ENABLE);

/*--------------------时基结构初始化-------------------------*/
	TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
	TIM_TimeBaseStructure.TIM_Period=0xffff;				//ARR=65535us
	TIM_TimeBaseStructure.TIM_Prescaler= 72-1;				//PSC = 1M = 1us;
	TIM_TimeBaseStructure.TIM_ClockDivision=TIM_CKD_DIV1;	//分频因子为0,即不分频;	
	TIM_TimeBaseStructure.TIM_CounterMode=TIM_CounterMode_Up; //CNT为向上计数模式;		
	TIM_TimeBaseStructure.TIM_RepetitionCounter=0;	
	TIM_TimeBaseInit(TIM1, &TIM_TimeBaseStructure);

	/*-------------------输入捕获结构体初始化------------------*/	

  TIM_ICInitTypeDef  TIM_ICInitStructure;
  //配置CH1
  TIM_ICInitStructure.TIM_Channel = TIM_Channel_1;
  TIM_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising;     //上升沿触发
  TIM_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI; //IC1直接连接TI1FP1
  TIM_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1;           //对输入的PWM信号不分频
  TIM_ICInitStructure.TIM_ICFilter = 0x0;
  TIM_PWMIConfig(TIM1, &TIM_ICInitStructure);
  
  //配置CH2
  TIM_ICInitStructure.TIM_Channel = TIM_Channel_2;
  TIM_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Falling;      //下降沿触发;
  TIM_ICInitStructure.TIM_ICSelection = TIM_ICSelection_IndirectTI; //IC2间接连接TI1FP2
  TIM_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1;				//对输入的PWM信号不分频
  TIM_ICInitStructure.TIM_ICFilter = 0x0;
  TIM_PWMIConfig(TIM1, &TIM_ICInitStructure);
	
  //选择输入捕获的触发信号;
  TIM_SelectInputTrigger(TIM1, TIM_TS_TI1FP1);		

  // 选择从模式
  // PWM输入模式时,从模式必须工作在复位模式,当捕获开始时,计数器CNT被复位清零;
  TIM_SelectSlaveMode(TIM1, TIM_SlaveMode_Reset);
  TIM_SelectMasterSlaveMode(TIM1,TIM_MasterSlaveMode_Enable); 

  // 使能捕获中断,这个中断主要针对的是主捕获通道(TI1FP1)
  TIM_ITConfig(TIM1, TIM_IT_CC1, ENABLE);	
  // 清除中断标志位
  TIM_ClearITPendingBit(TIM1, TIM_IT_CC1);
	
  // 计数器开始计数
  TIM_Cmd(TIM1, ENABLE);
}

猜你喜欢

转载自blog.csdn.net/wuyuzun/article/details/85043588