STM32F103 捕获配置

在《STM32F103 PWM配置》我们介绍了PWM配置,这一节将会介绍输入捕获配置。

一、输入捕获概述

1.1 通用定时器框图
img

在通用定时器框图中,主要涉及如下几个部分:

  • 时钟源的选择(最上面部分);
  • 时基单元(中间部分;);
  • 输入捕获(左下部分);
  • PWM输出(右下部分)。

其中时钟源的选择以及时基单元配置我们在《STM32F103定时器配置》介绍过,而PWM配置在《STM32F103 PWM配置》中介绍过,本节主要介绍输入捕获。

1.2 输入捕获原理

输入捕获模式可以用来测量脉冲宽度或者测量频率。STM32的定时器,除了TIM6TIM7,其它的定时器都有输入捕获的功能。

下面以一个简单的脉冲输入为例,简单地讲述一下输入捕获用于测量脉冲宽度的工作原理:

先设置输入捕获为上升沿检测,记录发生上升沿时TIMx_CNT的值。

然后配置捕获信号为下降沿捕获,当下降沿到来的时候发生捕获,并记录此时的TIMx_CNT的值。

这样,前后两次TIMx_CNT的值之差就是高电平的脉宽。

同时根据TIMx的计数频率,我们就能知道高电平脉宽的准确时间。

1.3 输入捕获的通道概览

每一个捕获/比较通道都是围绕着着一个捕获/比较寄存器(TIMx_CCRx、包含影子寄存器),包括捕获的输入部分(数字滤波、多路复用和预分频器),和输出部分(比较器和输出控制)。

捕获/比较模块由一个预装载寄存器和一个影子寄存器组成。读写过程仅操作预装载寄存器;

  • 在捕获模式下,捕获发生在影子寄存器上,然后再复制到预装载寄存器中;
  • 在比较模式下,预装载寄存器的内容被复制到影子寄存器中,然后影子寄存器的内容和计数器进行比较;
img

输入部分对相应的TIx输入信号采样,并产生一个滤波后的信号TIxF

然后,一个带极性选择的边缘检测器产生一个信号(TIxFPx),它可以作为从模式控制器的输入触发或者作为捕获控制。该信号通过预分频进入捕获寄存器(ICxPS)。

一句话总结工作过程:通过检测TIMx_CHx通道上的边沿信号,在边沿信号发生跳变(比如上升沿/下降沿)的时候,将当前定时器的值(TIMx_CNT)存放到对应的捕获/比较寄存器(TIMx_CCRx)里面,完成一次捕获。同时,还可以配置捕获时是否触发中断/DMA等。

1.3.1 设置输入捕获滤波器

输入捕获滤波器ICxF[3:0],这个用于设置采样频率和数字滤波器长度。

其中:fCK_INT是定时器的输入频率,fDTS是根据TIMx_CR1CKD[1:0]的设置来确定的。

这里滤波器的作用是什么意思呢?数字滤波器由一个事件计数器组成,它记录到N个事件后会产生一个输出的跳变。

也就是说连续N次采样,如果都是高电平,则说明这是一个有效的触发,就会进入输入捕捉中断(如果设置了的话)。这样就可以滤除那些高电平脉宽低于8个采样周期的脉冲信号,从而达到滤波的作用。

1.3.2 设置输入捕获极性

捕获输出极性CCxP,这个用于设置捕捉事件是发生在上升沿还是下降沿。

1.3.3 设置输入捕获映射关系

img

TIMx_CH1TIMx_CH2两条通道的情况下,我们可以看出除了TIMx_CH1捕捉到的信号可以连接到IC1TIMx_CH2捕捉到的信号可以连接到IC2之外,TIMx_CH1捕捉到的信号也可以连接到IC2TIMx_CH2捕捉到的信号也可以连接到IC1

一般情况下,我们设置成TIMx_CH1捕捉到的信号可以连接到IC1TIMx_CH2捕捉到的信号可以连接到IC2

输入捕获选择(CCxS)配置为:CC1通道被配置为输入、IC1映射在TI1上(01)。

1.3.4 设置输入捕获分频器

输入捕获预分频器ICxPSC:设置的是每N个事件触发一次捕捉。

也就是说,我们可以设置成每2次上升沿事件触发一次捕捉。

二、输入捕获源码

2.1 输入捕获初始化步骤

输入捕获配置流程如下:

(1) TIMx时钟使能:通过配置RCC_APB1ENR/RCC_APB2ENR寄存器使能TIMx时钟;

(2)GPIO口配置:以TIM2_CH1(PA0)为例;

  • 配置PA0为下拉输入;
  • GPIOA时钟使能;

(3) 配置TIMx时基单元;

  • 配置TIMx_ARR寄存器自动重装载的值(0xFFFF);
  • 配置TIMx_PSC频寄存器预分频系数(71);

(4) 配置输入捕获相关寄存器;

  • 配置TIMx_CCMRx寄存器:
    • 输入捕获预滤波器(ICxF)配置;
    • 输入捕获选择(CCxS)配置为CC1通道被配置为输入、IC1映射在TI1上(01);
    • 输入捕获预分频器(ICxPSC)配置为无预分频器(00);
  • 配置TIMx_CCER寄存器:
    • 捕获输出使能(CCxE)配置为使能(1);
    • 捕获输出极性(CCxP)配置(0:上升沿捕获,1:下降沿捕获);

(5) 配置TIMx_DIER寄存器:

  • 更新中断(UIE)配置为允许(1b);
  • 捕获/比较中断(CCxE)配置为允许(1b);

(6) 设置NVIC;

(7) 中断处理函数;

  • 设置中断服务函数(包括清除中断标志,清SR寄存器状态标志位(UIF=0CCxIF=0))。

(8) 允许TIMx工作:配置TIMx_CR101

2.2 源码实现
2.2.1 输入捕获初始化

输入捕获初始化函数TIM_CAP_Init定义如下:

/******************************************************************************************************
 *
 *	  Description:    电平脉宽捕获
             timn:	 定时器   TIMER1~5 8     定时器8程序有问题 勿用
		  Channel:	  输入通道 CAP_CH1~2
		     mode:	  0:捕获低电平   1:捕获高电平 
 *
 ******************************************************************************************************/
void TIM_CAP_Init(TIMn timn,CAP_CHANNEL Channel,u8 mode)
{
	u8 REMAP=0x00;                          //映射情况 0x00默认 0x01  0x02:  0x03  自己设置
//	if(timn==0||timn==7) 	                //定时器1或8   
//	{
//		 fclk = 72;                        //默认APB2 1倍频
//	}
//	else 
//	{
//	     fclk =72;						   //默认APB1 2倍频
//	} 
//******************************************************************************************
	if(timn==0)                        //定时器1
	{
	  RCC->APB2ENR |=1<<11;                 //高级定时器1时钟使能 
	  if(REMAP==0x00)
	  {
		  if(Channel==CAP_CH1)
		  {
		     gpio_init(PA8,GPI_DOWN,HIGH);            //输入下拉
			 PAout(8)=0;               
			 TIM1->CCMR1 |=0x01;                      //CC1S=1 CC1配置为输入 IC1映射到TI1上
			 TIM1->CCMR1 |=0x03<<4;                   //IC1F=3 配置滤波器以FCKint采样,8个事件有效(消除抖动)
			 TIM1->CCMR1 |=0x00<<2;                   //IC1PS=0  不分频
		  } 
		  else if(Channel==CAP_CH2)
		  {
		      gpio_init(PA9,GPI_DOWN,HIGH);            //输入下拉
			  PAout(9)=0; 
			  TIM1->CCMR1 |=0x01<<8;                    //CC2配置为输出 IC2映射到TI2上
			  TIM1->CCMR1 |=0x03<<12;                   //IC2F=3 配置滤波器以FCKint采样,8个事件有效(消除抖动)
			  TIM1->CCMR1 |=0x00<<10;                   //IC2PS=0  不分频
		  }
		  else if(Channel==CAP_CH3)
		  {
		     gpio_init(PA10,GPI_DOWN,HIGH);            //输入下拉
			 PAout(10)=0;               
			 TIM1->CCMR2 |=0x01;                      //01: CC3配置为输入 IC3映射到TI3上
			 TIM1->CCMR2 |=0x03<<4;                   //IC3F=3 配置滤波器以FCKint采样,8个事件有效(消除抖动)
			 TIM1->CCMR2 |=0x00<<2;                   //IC3PS=0  不分频
		  } 
		  else if(Channel==CAP_CH4)
		  {
		      gpio_init(PA11,GPI_DOWN,HIGH);            //输入下拉
			  PAout(11)=0; 
			  TIM1->CCMR2 |=0x01<<8;                      //01:CC4通道被配置为输入,IC4映射在TI4上;
			  TIM1->CCMR2 |=0x03<<12;                  //IC4F=3 配置滤波器以FCKint采样,8个事件有效(消除抖动)
			  TIM1->CCMR2 |=0x00<<10;                  //IC4PS=0  不分频
		  }
		  else
		  {
		   ASSERT(0); 
		  }
	   }
	                       //*******************************
	  else if(REMAP==0x01)
	  {
	      RCC->APB2ENR |= 1<<0;                       //使能I/O复用时钟
		  AFIO->MAPR   &=~(0x3<<6);                   //位7:6清零   
		  AFIO->MAPR   |= REMAP<<6;                   //TIM1部分映射
		  if(Channel==CAP_CH1)
		  {
		     gpio_init(PA8,GPI_DOWN,HIGH);            //输入下拉
			 PAout(8)=0;               
			 TIM1->CCMR1 |=0x01;                      //CC1S=1 CC1配置为输入 IC1映射到TI1上
			 TIM1->CCMR1 |=0x03<<4;                   //IC1F=3 配置滤波器以FCKint采样,8个事件有效(消除抖动)
			 TIM1->CCMR1 |=0x00<<2;                   //IC1PS=0  不分频
		  } 
		  else if(Channel==CAP_CH2)
		  {
		      gpio_init(PA9,GPI_DOWN,HIGH);            //输入下拉
			  PAout(9)=0; 
			  TIM1->CCMR1 |=0x01<<8;                    //CC2配置为输出 IC2映射到TI2上
			  TIM1->CCMR1 |=0x03<<12;                   //IC2F=3 配置滤波器以FCKint采样,8个事件有效(消除抖动)
			  TIM1->CCMR1 |=0x00<<10;                   //IC2PS=0  不分频
		  }
		  else if(Channel==CAP_CH3)
		  {
		     gpio_init(PA10,GPI_DOWN,HIGH);            //输入下拉
			 PAout(10)=0;               
			 TIM1->CCMR2 |=0x01;                      //01: CC3配置为输入 IC3映射到TI3上
			 TIM1->CCMR2 |=0x03<<4;                   //IC3F=3 配置滤波器以FCKint采样,8个事件有效(消除抖动)
			 TIM1->CCMR2 |=0x00<<2;                   //IC3PS=0  不分频
		  } 
		  else if(Channel==CAP_CH4)
		  {
		      gpio_init(PA11,GPI_DOWN,HIGH);            //输入下拉
			  PAout(11)=0; 
			  TIM1->CCMR2 |=0x01<<8;                      //01:CC4通道被配置为输入,IC4映射在TI4上;
			  TIM1->CCMR2 |=0x03<<12;                  //IC4F=3 配置滤波器以FCKint采样,8个事件有效(消除抖动)
			  TIM1->CCMR2 |=0x00<<10;                  //IC4PS=0  不分频
		  } 
		  
		  else
		  {
		   ASSERT(0); 
		  }	
	   }
	                         //**********************************
	  else if(REMAP==0x03)									   //完全映射
	  {
	     RCC->APB2ENR |= 1<<0;                       //使能I/O复用时钟
		 AFIO->MAPR   &=~(0x3<<6);                   //位7:6清零   
		 AFIO->MAPR   |= REMAP<<6;                   //TIM1完全映射
		 if(Channel==CAP_CH1)
		 {
		      gpio_init(PE9,GPI_DOWN,HIGH);            //输入下拉
		   	  PEout(9)=0;               
			  TIM1->CCMR1 |=0x01;                      //CC1S=1 CC1配置为输入 IC1映射到TI1上
			  TIM1->CCMR1 |=0x03<<4;                   //IC1F=3 配置滤波器以FCKint采样,8个事件有效(消除抖动)
			  TIM1->CCMR1 |=0x00<<2;                   //IC1PS=0  不分频
		 } 
		 else if(Channel==CAP_CH2)
		 {
		      gpio_init(PE11,GPI_DOWN,HIGH);            //输入下拉
			  PEout(11)=0; 
			  TIM1->CCMR1 |=0x01<<8;                    //CC2配置为输出 IC2映射到TI2上
			  TIM1->CCMR1 |=0x03<<12;                   //IC2F=3 配置滤波器以FCKint采样,8个事件有效(消除抖动)
			  TIM1->CCMR1 |=0x00<<10;                   //IC2PS=0  不分频
		 }
		 else if(Channel==CAP_CH3)
		 {
		     gpio_init(PE13,GPI_DOWN,HIGH);            //输入下拉
			 PEout(13)=0;               
			 TIM1->CCMR2 |=0x01;                      //01: CC3配置为输入 IC3映射到TI3上
			 TIM1->CCMR2 |=0x03<<4;                   //IC3F=3 配置滤波器以FCKint采样,8个事件有效(消除抖动)
			 TIM1->CCMR2 |=0x00<<2;                   //IC3PS=0  不分频
		 } 
		 else if(Channel==CAP_CH4)
		 {
		      gpio_init(PE14,GPI_DOWN,HIGH);            //输入下拉
			  PEout(14)=0; 
			  TIM1->CCMR2 |=0x01<<8;                      //01:CC4通道被配置为输入,IC4映射在TI4上;
			  TIM1->CCMR2 |=0x03<<12;                  //IC4F=3 配置滤波器以FCKint采样,8个事件有效(消除抖动)
			  TIM1->CCMR2 |=0x00<<10;                  //IC4PS=0  不分频
		 }
		 else
		 {
		   ASSERT(0); 
		 }	
	  } 
	                  //****************************************
	  else
	  {
	    ASSERT(0);
	  }
	}
  //**********************************************************************************************************
	else if(timn==1)                   //定时器2
	{
	//  REMAP=0x01;
	  RCC->APB1ENR |=1<<0;                  //定时器2时钟使能
	  if(REMAP==0x00)
	  {
		  if(Channel==CAP_CH1)
		  {
		     gpio_init(PA0,GPI_DOWN,HIGH);            //输入下拉
			 PAout(0)=0;               
			 TIM2->CCMR1 |=0x01;                      //CC1S=1 CC1配置为输入 IC1映射到TI1上
			 TIM2->CCMR1 |=0x03<<4;                   //IC1F=3 配置滤波器以FCKint采样,8个事件有效(消除抖动)
			 TIM2->CCMR1 |=0x00<<2;                   //IC1PS=0  不分频
		  } 
		  else if(Channel==CAP_CH2)
		  {
		      gpio_init(PA1,GPI_DOWN,HIGH);            //输入下拉
			  PAout(1)=0; 
			  TIM2->CCMR1 |=0x01<<8;                    //CC2配置为输出 IC2映射到TI2上
			  TIM2->CCMR1 |=0x03<<12;                   //IC2F=3 配置滤波器以FCKint采样,8个事件有效(消除抖动)
			  TIM2->CCMR1 |=0x00<<10;                   //IC2PS=0  不分频
		  }
		  else if(Channel==CAP_CH3)
		  {
		     gpio_init(PA2,GPI_DOWN,HIGH);            //输入下拉
			 PAout(2)=0;               
			 TIM2->CCMR2 |=0x01;                      //01: CC3配置为输入 IC3映射到TI3上
			 TIM2->CCMR2 |=0x03<<4;                   //IC3F=3 配置滤波器以FCKint采样,8个事件有效(消除抖动)
			 TIM2->CCMR2 |=0x00<<2;                   //IC3PS=0  不分频
		  } 
		  else if(Channel==CAP_CH4)
		  {
		      gpio_init(PA3,GPI_DOWN,HIGH);            //输入下拉
			  PAout(3)=0; 
			  TIM2->CCMR2 |=0x01<<8;                      //01:CC4通道被配置为输入,IC4映射在TI4上;
			  TIM2->CCMR2 |=0x03<<12;                  //IC4F=3 配置滤波器以FCKint采样,8个事件有效(消除抖动)
			  TIM2->CCMR2 |=0x00<<10;                  //IC4PS=0  不分频
		  }
		  else
		  {
		   ASSERT(0); 
		  }
	   }
	                       //*******************************
	  else if(REMAP==0x01)	     //部分映射
	  {
	      RCC->APB2ENR |= 1<<0;                       //使能I/O复用时钟
		  AFIO->MAPR   &=~(0x3<<8);                   //位9:8清零   
		  AFIO->MAPR   |= REMAP<<8;                   //TIM2部分映射 
		  if(Channel==CAP_CH1)
		  {
		     gpio_init(PA15,GPI_DOWN,HIGH);            //输入下拉
			 PAout(15)=0;               
			 TIM2->CCMR1 |=0x01;                      //CC1S=1 CC1配置为输入 IC1映射到TI1上
			 TIM2->CCMR1 |=0x03<<4;                   //IC1F=3 配置滤波器以FCKint采样,8个事件有效(消除抖动)
			 TIM2->CCMR1 |=0x00<<2;                   //IC1PS=0  不分频
		  } 
		  else if(Channel==CAP_CH2)
		  {
		      gpio_init(PB3,GPI_DOWN,HIGH);            //输入下拉
			  PBout(3)=0; 
			  TIM2->CCMR1 |=0x01<<8;                    //CC2配置为输出 IC2映射到TI2上
			  TIM2->CCMR1 |=0x03<<12;                   //IC2F=3 配置滤波器以FCKint采样,8个事件有效(消除抖动)
			  TIM2->CCMR1 |=0x00<<10;                   //IC2PS=0  不分频
		  }
		  else if(Channel==CAP_CH3)
		  {
		     gpio_init(PA2,GPI_DOWN,HIGH);            //输入下拉
			 PAout(2)=0;               
			 TIM2->CCMR2 |=0x01;                      //01: CC3配置为输入 IC3映射到TI3上
			 TIM2->CCMR2 |=0x03<<4;                   //IC3F=3 配置滤波器以FCKint采样,8个事件有效(消除抖动)
			 TIM2->CCMR2 |=0x00<<2;                   //IC3PS=0  不分频
		  } 
		  else if(Channel==CAP_CH4)
		  {
		      gpio_init(PA3,GPI_DOWN,HIGH);            //输入下拉
			  PAout(3)=0; 
			  TIM2->CCMR2 |=0x01<<8;                      //01:CC4通道被配置为输入,IC4映射在TI4上;
			  TIM2->CCMR2 |=0x03<<12;                  //IC4F=3 配置滤波器以FCKint采样,8个事件有效(消除抖动)
			  TIM2->CCMR2 |=0x00<<10;                  //IC4PS=0  不分频
		  } 
		  else
		  {
		   ASSERT(0); 
		  }	
	   }
	                         //*********************************
	  else if(REMAP==0x02)									   //部分映射
	  {
	     RCC->APB2ENR |= 1<<0;                       //使能I/O复用时钟
		 AFIO->MAPR   &=~(0x3<<8);                   //位9:8清零   
		 AFIO->MAPR   |= REMAP<<8;                   //TIM2部分映射 
		 if(Channel==CAP_CH1)
		 {
		      gpio_init(PA0,GPI_DOWN,HIGH);            //输入下拉
		   	  PAout(0)=0;               
			  TIM2->CCMR1 |=0x01;                      //CC1S=1 CC1配置为输入 IC1映射到TI1上
			  TIM2->CCMR1 |=0x03<<4;                   //IC1F=3 配置滤波器以FCKint采样,8个事件有效(消除抖动)
			  TIM2->CCMR1 |=0x00<<2;                   //IC1PS=0  不分频
		 } 
		 else if(Channel==CAP_CH2)
		 {
		      gpio_init(PA1,GPI_DOWN,HIGH);            //输入下拉
			  PAout(1)=0; 
			  TIM2->CCMR1 |=0x01<<8;                    //CC2配置为输出 IC2映射到TI2上
			  TIM2->CCMR1 |=0x03<<12;                   //IC2F=3 配置滤波器以FCKint采样,8个事件有效(消除抖动)
			  TIM2->CCMR1 |=0x00<<10;                   //IC2PS=0  不分频
		 }
		 else if(Channel==CAP_CH3)
		 {
		     gpio_init(PB10,GPI_DOWN,HIGH);            //输入下拉
			 PBout(10)=0;               
			 TIM2->CCMR2 |=0x01;                      //01: CC3配置为输入 IC3映射到TI3上
			 TIM2->CCMR2 |=0x03<<4;                   //IC3F=3 配置滤波器以FCKint采样,8个事件有效(消除抖动)
			 TIM2->CCMR2 |=0x00<<2;                   //IC3PS=0  不分频
		 } 
		 else if(Channel==CAP_CH4)
		 {
		      gpio_init(PB11,GPI_DOWN,HIGH);            //输入下拉
			  PBout(11)=0; 
			  TIM2->CCMR2 |=0x01<<8;                      //01:CC4通道被配置为输入,IC4映射在TI4上;
			  TIM2->CCMR2 |=0x03<<12;                  //IC4F=3 配置滤波器以FCKint采样,8个事件有效(消除抖动)
			  TIM2->CCMR2 |=0x00<<10;                  //IC4PS=0  不分频
		 }
		 else
		 {
		   ASSERT(0); 
		 }
	  }
	                         //**********************************
	  else if(REMAP==0x03)									   //完全映射
	  {
         RCC->APB2ENR |= 1<<0;                       //使能I/O复用时钟
		 AFIO->MAPR   &=~(0x3<<8);                   //位9:8清零   
		 AFIO->MAPR   |= REMAP<<8;                   //TIM2部分映射               
		 if(Channel==CAP_CH1)
		 {
		      gpio_init(PA15,GPI_DOWN,HIGH);            //输入下拉
		   	  PAout(15)=0;               
			  TIM2->CCMR1 |=0x01;                      //CC1S=1 CC1配置为输入 IC1映射到TI1上
			  TIM2->CCMR1 |=0x03<<4;                   //IC1F=3 配置滤波器以FCKint采样,8个事件有效(消除抖动)
			  TIM2->CCMR1 |=0x00<<2;                   //IC1PS=0  不分频
		 } 
		 else if(Channel==CAP_CH2)
		 {
		      gpio_init(PB3,GPI_DOWN,HIGH);            //输入下拉
			  PBout(3)=0; 
			  TIM2->CCMR1 |=0x01<<8;                    //CC2配置为输出 IC2映射到TI2上
			  TIM2->CCMR1 |=0x03<<12;                   //IC2F=3 配置滤波器以FCKint采样,8个事件有效(消除抖动)
			  TIM2->CCMR1 |=0x00<<10;                   //IC2PS=0  不分频
		 }
		 else if(Channel==CAP_CH3)
		 {
		     gpio_init(PB10,GPI_DOWN,HIGH);            //输入下拉
			 PBout(10)=0;               
			 TIM2->CCMR2 |=0x01;                      //01: CC3配置为输入 IC3映射到TI3上
			 TIM2->CCMR2 |=0x03<<4;                   //IC3F=3 配置滤波器以FCKint采样,8个事件有效(消除抖动)
			 TIM2->CCMR2 |=0x00<<2;                   //IC3PS=0  不分频
		 } 
		 else if(Channel==CAP_CH4)
		 {
		      gpio_init(PB11,GPI_DOWN,HIGH);            //输入下拉
			  PBout(11)=0; 
			  TIM2->CCMR2 |=0x01<<8;                      //01:CC4通道被配置为输入,IC4映射在TI4上;
			  TIM2->CCMR2 |=0x03<<12;                  //IC4F=3 配置滤波器以FCKint采样,8个事件有效(消除抖动)
			  TIM2->CCMR2 |=0x00<<10;                  //IC4PS=0  不分频
		 }
		 else
		 {
		   ASSERT(0); 
		 }	
	  } 
	                  //****************************************
	  else
	  {
	    ASSERT(0);
	  } 
	   
	}          
	//**************************************************************************************************************
    else if(timn==2)                   //定时器3
	{
	  RCC->APB1ENR |=1<<1;                  //定时器3时钟使能
	  if(REMAP==0x00)
	  {
		  if(Channel==CAP_CH1)
		  {
		     gpio_init(PA6,GPI_DOWN,HIGH);            //输入下拉
			 PAout(6)=0;               
			 TIM3->CCMR1 |=0x01;                      //CC1S=1 CC1配置为输入 IC1映射到TI1上
			 TIM3->CCMR1 |=0x03<<4;                   //IC1F=3 配置滤波器以FCKint采样,8个事件有效(消除抖动)
			 TIM3->CCMR1 |=0x00<<2;                   //IC1PS=0  不分频
		  } 
		  else if(Channel==CAP_CH2)
		  {
		      gpio_init(PA7,GPI_DOWN,HIGH);            //输入下拉
			  PAout(7)=0; 
			  TIM3->CCMR1 |=0x01<<8;                    //CC2配置为输出 IC2映射到TI2上
			  TIM3->CCMR1 |=0x03<<12;                   //IC2F=3 配置滤波器以FCKint采样,8个事件有效(消除抖动)
			  TIM3->CCMR1 |=0x00<<10;                   //IC2PS=0  不分频
		  }
		  else if(Channel==CAP_CH3)
		  {
		     gpio_init(PB0,GPI_DOWN,HIGH);            //输入下拉
			 PBout(0)=0;               
			 TIM3->CCMR2 |=0x01;                      //01: CC3配置为输入 IC3映射到TI3上
			 TIM3->CCMR2 |=0x03<<4;                   //IC3F=3 配置滤波器以FCKint采样,8个事件有效(消除抖动)
			 TIM3->CCMR2 |=0x00<<2;                   //IC3PS=0  不分频
		  } 
		  else if(Channel==CAP_CH4)
		  {
		      gpio_init(PB1,GPI_DOWN,HIGH);            //输入下拉
			  PBout(1)=0; 
			  TIM3->CCMR2 |=0x01<<8;                      //01:CC4通道被配置为输入,IC4映射在TI4上;
			  TIM3->CCMR2 |=0x03<<12;                  //IC4F=3 配置滤波器以FCKint采样,8个事件有效(消除抖动)
			  TIM3->CCMR2 |=0x00<<10;                  //IC4PS=0  不分频
		  }
		  else
		  {
		   ASSERT(0); 
		  }
	   }
	                       //*******************************
	  else if(REMAP==0x02)
	  {
	      RCC->APB2ENR |= 1<<0;                       //使能I/O复用时钟
		  AFIO->MAPR   &=~(0x3<<10);                   //位7:6清零   
		  AFIO->MAPR   |= REMAP<<10;                   //TIM3部分映射
		  if(Channel==CAP_CH1)
		  {
		     gpio_init(PB4,GPI_DOWN,HIGH);            //输入下拉
			 PBout(4)=0;               
			 TIM3->CCMR1 |=0x01;                      //CC1S=1 CC1配置为输入 IC1映射到TI1上
			 TIM3->CCMR1 |=0x03<<4;                   //IC1F=3 配置滤波器以FCKint采样,8个事件有效(消除抖动)
			 TIM3->CCMR1 |=0x00<<2;                   //IC1PS=0  不分频
		  } 
		  else if(Channel==CAP_CH2)
		  {
		      gpio_init(PB5,GPI_DOWN,HIGH);            //输入下拉
			  PBout(5)=0; 
			  TIM3->CCMR1 |=0x01<<8;                    //CC2配置为输出 IC2映射到TI2上
			  TIM3->CCMR1 |=0x03<<12;                   //IC2F=3 配置滤波器以FCKint采样,8个事件有效(消除抖动)
			  TIM3->CCMR1 |=0x00<<10;                   //IC2PS=0  不分频
		  }
		  else if(Channel==CAP_CH3)
		  {
		     gpio_init(PB0,GPI_DOWN,HIGH);            //输入下拉
			 PBout(0)=0;               
			 TIM3->CCMR2 |=0x01;                      //01: CC3配置为输入 IC3映射到TI3上
			 TIM3->CCMR2 |=0x03<<4;                   //IC3F=3 配置滤波器以FCKint采样,8个事件有效(消除抖动)
			 TIM3->CCMR2 |=0x00<<2;                   //IC3PS=0  不分频
		  } 
		  else if(Channel==CAP_CH4)
		  {
		      gpio_init(PB1,GPI_DOWN,HIGH);            //输入下拉
			  PBout(1)=0; 
			  TIM3->CCMR2 |=0x01<<8;                      //01:CC4通道被配置为输入,IC4映射在TI4上;
			  TIM3->CCMR2 |=0x03<<12;                  //IC4F=3 配置滤波器以FCKint采样,8个事件有效(消除抖动)
			  TIM3->CCMR2 |=0x00<<10;                  //IC4PS=0  不分频
		  } 
		  
		  else
		  {
		   ASSERT(0); 
		  }	
	   }
	                         //**********************************
	  else if(REMAP==0x03)									   //完全映射
	  {
	     RCC->APB2ENR |= 1<<0;                       //使能I/O复用时钟
		 AFIO->MAPR   &=~(0x3<<10);                   //位7:6清零   
		 AFIO->MAPR   |= REMAP<<10;                   //TIM1完全映射
		 if(Channel==CAP_CH1)
		 {
		      gpio_init(PC6,GPI_DOWN,HIGH);            //输入下拉
		   	  PCout(6)=0;               
			  TIM3->CCMR1 |=0x01;                      //CC1S=1 CC1配置为输入 IC1映射到TI1上
			  TIM3->CCMR1 |=0x03<<4;                   //IC1F=3 配置滤波器以FCKint采样,8个事件有效(消除抖动)
			  TIM3->CCMR1 |=0x00<<2;                   //IC1PS=0  不分频
		 } 
		 else if(Channel==CAP_CH2)
		 {
		      gpio_init(PC7,GPI_DOWN,HIGH);            //输入下拉
			  PCout(7)=0; 
			  TIM3->CCMR1 |=0x01<<8;                    //CC2配置为输出 IC2映射到TI2上
			  TIM3->CCMR1 |=0x03<<12;                   //IC2F=3 配置滤波器以FCKint采样,8个事件有效(消除抖动)
			  TIM3->CCMR1 |=0x00<<10;                   //IC2PS=0  不分频
		 }
		 else if(Channel==CAP_CH3)
		 {
		     gpio_init(PC8,GPI_DOWN,HIGH);            //输入下拉
			 PCout(8)=0;               
			 TIM3->CCMR2 |=0x01;                      //01: CC3配置为输入 IC3映射到TI3上
			 TIM3->CCMR2 |=0x03<<4;                   //IC3F=3 配置滤波器以FCKint采样,8个事件有效(消除抖动)
			 TIM3->CCMR2 |=0x00<<2;                   //IC3PS=0  不分频
		 } 
		 else if(Channel==CAP_CH4)
		 {
		      gpio_init(PC9,GPI_DOWN,HIGH);            //输入下拉
			  PCout(9)=0; 
			  TIM3->CCMR2 |=0x01<<8;                      //01:CC4通道被配置为输入,IC4映射在TI4上;
			  TIM3->CCMR2 |=0x03<<12;                  //IC4F=3 配置滤波器以FCKint采样,8个事件有效(消除抖动)
			  TIM3->CCMR2 |=0x00<<10;                  //IC4PS=0  不分频
		 }
		 else
		 {
		   ASSERT(0); 
		 }	
	  } 
	                  //****************************************
	  else
	  {
	    ASSERT(0);
	  }  
	}       
	//********************************************************************************************************************
	else if(timn==3)                   //定时器4
	{
	  RCC->APB1ENR |=1<<2;                  //定时器4时钟使能
	  if(REMAP==0x00)
	  {
		  if(Channel==CAP_CH1)
		  {
		     gpio_init(PB6,GPI_DOWN,HIGH);            //输入下拉
			 PBout(6)=0;               
			 TIM4->CCMR1 |=0x01;                      //CC1S=1 CC1配置为输入 IC1映射到TI1上
			 TIM4->CCMR1 |=0x03<<4;                   //IC1F=3 配置滤波器以FCKint采样,8个事件有效(消除抖动)
			 TIM4->CCMR1 |=0x00<<2;                   //IC1PS=0  不分频
		  } 
		  else if(Channel==CAP_CH2)
		  {
		      gpio_init(PB7,GPI_DOWN,HIGH);            //输入下拉
			  PBout(7)=0; 
			  TIM4->CCMR1 |=0x01<<8;                    //CC2配置为输出 IC2映射到TI2上
			  TIM4->CCMR1 |=0x03<<12;                   //IC2F=3 配置滤波器以FCKint采样,8个事件有效(消除抖动)
			  TIM4->CCMR1 |=0x00<<10;                   //IC2PS=0  不分频
		  }
		  else if(Channel==CAP_CH3)
		  {
		     gpio_init(PB8,GPI_DOWN,HIGH);            //输入下拉
			 PBout(8)=0;               
			 TIM4->CCMR2 |=0x01;                      //01: CC3配置为输入 IC3映射到TI3上
			 TIM4->CCMR2 |=0x03<<4;                   //IC3F=3 配置滤波器以FCKint采样,8个事件有效(消除抖动)
			 TIM4->CCMR2 |=0x00<<2;                   //IC3PS=0  不分频
		  } 
		  else if(Channel==CAP_CH4)
		  {
		      gpio_init(PB9,GPI_DOWN,HIGH);            //输入下拉
			  PBout(9)=0; 
			  TIM4->CCMR2 |=0x01<<8;                      //01:CC4通道被配置为输入,IC4映射在TI4上;
			  TIM4->CCMR2 |=0x03<<12;                  //IC4F=3 配置滤波器以FCKint采样,8个事件有效(消除抖动)
			  TIM4->CCMR2 |=0x00<<10;                  //IC4PS=0  不分频
		  }
		  else
		  {
		   ASSERT(0); 
		  }
	   }
	                       //*******************************
	  else if(REMAP==0x01)
	  {
	      RCC->APB2ENR |= 1<<0;                       //使能I/O复用时钟
		  AFIO->MAPR   &=~(0x1<<12);                   //位12清零   
		  AFIO->MAPR   |= REMAP<<12;                   //TIM4部分映射
		  if(Channel==CAP_CH1)
		  {
		     gpio_init(PD12,GPI_DOWN,HIGH);            //输入下拉
			 PDout(12)=0;               
			 TIM4->CCMR1 |=0x01;                      //CC1S=1 CC1配置为输入 IC1映射到TI1上
			 TIM4->CCMR1 |=0x03<<4;                   //IC1F=3 配置滤波器以FCKint采样,8个事件有效(消除抖动)
			 TIM4->CCMR1 |=0x00<<2;                   //IC1PS=0  不分频
		  } 
		  else if(Channel==CAP_CH2)
		  {
		      gpio_init(PD13,GPI_DOWN,HIGH);            //输入下拉
			  PDout(13)=0; 
			  TIM4->CCMR1 |=0x01<<8;                    //CC2配置为输出 IC2映射到TI2上
			  TIM4->CCMR1 |=0x03<<12;                   //IC2F=3 配置滤波器以FCKint采样,8个事件有效(消除抖动)
			  TIM4->CCMR1 |=0x00<<10;                   //IC2PS=0  不分频
		  }
		  else if(Channel==CAP_CH3)
		  {
		     gpio_init(PD14,GPI_DOWN,HIGH);            //输入下拉
			 PDout(14)=0;               
			 TIM4->CCMR2 |=0x01;                      //01: CC3配置为输入 IC3映射到TI3上
			 TIM4->CCMR2 |=0x03<<4;                   //IC3F=3 配置滤波器以FCKint采样,8个事件有效(消除抖动)
			 TIM4->CCMR2 |=0x00<<2;                   //IC3PS=0  不分频
		  } 
		  else if(Channel==CAP_CH4)
		  {
		      gpio_init(PD15,GPI_DOWN,HIGH);            //输入下拉
			  PDout(15)=0; 
			  TIM4->CCMR2 |=0x01<<8;                      //01:CC4通道被配置为输入,IC4映射在TI4上;
			  TIM4->CCMR2 |=0x03<<12;                  //IC4F=3 配置滤波器以FCKint采样,8个事件有效(消除抖动)
			  TIM4->CCMR2 |=0x00<<10;                  //IC4PS=0  不分频
		  } 
		  
		  else
		  {
		   ASSERT(0); 
		  }	
	  }  
	  else
	  {
	    ASSERT(0);
	  } 
	} 
	//*********************************************************************************************************  	              
    else if(timn==4)                   //定时器5
	{
	   RCC->APB1ENR |=1<<3;                  //定时器5时钟使能
	   if(Channel==CAP_CH1)
		  {
		     gpio_init(PA0,GPI_DOWN,HIGH);            //输入下拉
			 PAout(0)=0;               
			 TIM5->CCMR1 |=0x01;                      //CC1S=1 CC1配置为输入 IC1映射到TI1上
			 TIM5->CCMR1 |=0x03<<4;                   //IC1F=3 配置滤波器以FCKint采样,8个事件有效(消除抖动)
			 TIM5->CCMR1 |=0x00<<2;                   //IC1PS=0  不分频
		  } 
		  else if(Channel==CAP_CH2)
		  {
		      gpio_init(PA1,GPI_DOWN,HIGH);            //输入下拉
			  PAout(1)=0; 
			  TIM5->CCMR1 |=0x01<<8;                    //CC2配置为输出 IC2映射到TI2上
			  TIM5->CCMR1 |=0x03<<12;                   //IC2F=3 配置滤波器以FCKint采样,8个事件有效(消除抖动)
			  TIM5->CCMR1 |=0x00<<10;                   //IC2PS=0  不分频
		  }
		  else if(Channel==CAP_CH3)
		  {
		     gpio_init(PA2,GPI_DOWN,HIGH);            //输入下拉
			 PAout(2)=0;               
			 TIM5->CCMR2 |=0x01;                      //01: CC3配置为输入 IC3映射到TI3上
			 TIM5->CCMR2 |=0x03<<4;                   //IC3F=3 配置滤波器以FCKint采样,8个事件有效(消除抖动)
			 TIM5->CCMR2 |=0x00<<2;                   //IC3PS=0  不分频
		  } 
		  else if(Channel==CAP_CH4)
		  {
		      gpio_init(PA3,GPI_DOWN,HIGH);            //输入下拉
			  PAout(3)=0; 
			  TIM5->CCMR2 |=0x01<<8;                      //01:CC4通道被配置为输入,IC4映射在TI4上;
			  TIM5->CCMR2 |=0x03<<12;                  //IC4F=3 配置滤波器以FCKint采样,8个事件有效(消除抖动)
			  TIM5->CCMR2 |=0x00<<10;                  //IC4PS=0  不分频
		  } 
		  
		  else
		  {
		   ASSERT(0); 
		  }	

	}    
	//******************************************************************************************************   
	else  if(timn==7)
	{
	     RCC->APB2ENR |=1<<13;                  //定时器8时钟使能  
	     if(Channel==CAP_CH1)
		 {
		      gpio_init(PC6,GPI_DOWN,HIGH);            //输入下拉
		   	  PCout(6)=0;               
			  TIM8->CCMR1 |=0x01;                      //CC1S=1 CC1配置为输入 IC1映射到TI1上
			  TIM8->CCMR1 |=0x03<<4;                   //IC1F=3 配置滤波器以FCKint采样,8个事件有效(消除抖动)
			  TIM8->CCMR1 |=0x00<<2;                   //IC1PS=0  不分频
		 } 
		 else if(Channel==CAP_CH2)
		 {
		      gpio_init(PC7,GPI_DOWN,HIGH);            //输入下拉
			  PCout(7)=0; 
			  TIM8->CCMR1 |=0x01<<8;                    //CC2配置为输出 IC2映射到TI2上
			  TIM8->CCMR1 |=0x03<<12;                   //IC2F=3 配置滤波器以FCKint采样,8个事件有效(消除抖动)
			  TIM8->CCMR1 |=0x00<<10;                   //IC2PS=0  不分频
		 }
		 else if(Channel==CAP_CH3)
		 {
		     gpio_init(PC8,GPI_DOWN,HIGH);            //输入下拉
			 PCout(8)=0;               
			 TIM8->CCMR2 |=0x01;                      //01: CC3配置为输入 IC3映射到TI3上
			 TIM8->CCMR2 |=0x03<<4;                   //IC3F=3 配置滤波器以FCKint采样,8个事件有效(消除抖动)
			 TIM8->CCMR2 |=0x00<<2;                   //IC3PS=0  不分频
		 } 
		 else if(Channel==CAP_CH4)
		 {
		      gpio_init(PC9,GPI_DOWN,HIGH);            //输入下拉
			  PCout(9)=0; 
			  TIM8->CCMR2 |=0x01<<8;                   //01:CC4通道被配置为输入,IC4映射在TI4上;
			  TIM8->CCMR2 |=0x03<<12;                  //IC4F=3 配置滤波器以FCKint采样,8个事件有效(消除抖动)
			  TIM8->CCMR2 |=0x00<<10;                  //IC4PS=0  不分频
		 }
		 else
		 {
		   ASSERT(0); 
		 }	 
	}
	//********************************************************************************************************
    else
	{
		ASSERT(0); 
	}	
	                                      
    TIMx[timn]->PSC  = 71;                  //预分频值   Fclk=fclk/(71+1)   1MHZ
    TIMx[timn]->ARR  = 0xFFFF;			    //重新装载的值
    if(mode==0x00)                          //捕获低电平
	{
	   TIMx[timn]->CCER |= 0x3<<(4*Channel);   //下降沿捕获 捕获低电平 捕获使能  
	}
	else                                    //捕获高电平
	{
       TIMx[timn]->CCER |= 0x01<<(4*Channel);  //上升沿捕获 捕获高电平 捕获使能	  
	}

	TIMx[timn]->DIER |= 1<<(Channel+1);     //开启捕获比较中断  
    TIMx[timn]->DIER |= 1<<0;			    //允许更新中断   UIE=1;
	TIMx[timn]->CR1  |= 0<<4;               //DIR=0; 向上计数
   	TIMx[timn]->CR1  |= 1<<0;               //使能计数器 开始计数
    //中断优先级设置  

}

TIM_CAP_Init函数同时实现了高电平和低电平脉冲宽度的捕获。

2.2.2 TIM1/8溢出/捕获/比较中断

定时器1和定时器8都是高级定时器,拥有独立的溢出(更新)中断、以及捕获/比较中断事件。

接下来我们将会以高级定时器TIM1为例介绍这个脉冲宽度捕获是如何实现的,并且我们以捕获高电平为例进行讲解。

在中断处理函数中,先判断是否捕获成功,如果捕获成功了,说明是在脉冲低电平的阶段,什么都不需要做。

如果捕获没有成功,说明是在脉冲高电平的阶段,就需要执行不同的处理逻辑;

  • 在更新(溢出)中断中,表示此时高电平脉冲长度过长,TIM1CH1_CAP_STA1
  • 在捕获/比较中断中;
    • 判断是否是第一次捕获到(捕捉到的是上升沿),如果是,计数器当前值(TIM1_CNT)清零,TIM1CH1_CAP_VAL清零,同时标记第一次捕获到高电平,设置极性下降沿捕捉;
    • 判断是否是第二次捕获到(捕获到的是下降沿),如果是标记捕获完成,保存当前计数器(TIM1_CNT)的值到TIM1CH1_CAP_VAL,设置极性上升沿捕获。
2.2.2.1 TIM1_UP_IRQHandler

定时器1更新(溢出)中断TIM1_UP_IRQHandler实现;

/*******************************************************************************
* Function Name  : TIM1_UP_IRQHandler
* Description    : This function handles TIM1 overflow and update interrupt 
*                  request.
* Input          : None
* Output         : None
* Return         : None
*******************************************************************************/
void TIM1_UP_IRQHandler(void)				    //定时器1溢出中断
{
    u16 timsr;              //存放定时器标志位
	timsr = TIM1->SR; 
    if((TIM1CH1_CAP_STA&0x80)==0)            //还未成功捕获
	{
	   /****************************************/
	   if(timsr&0x01)                        //发生更新(溢出)中断
	   {
	      if(TIM1CH1_CAP_STA&0x40)                 //已经捕获到高/低电平
		  {
		     if((TIM1CH1_CAP_STA&0x3F)==0X3F)      //高/低电平太长了 强制捕获完成
			 {
			    TIM1CH1_CAP_STA |=0x80;            //标记成功捕获一次
				TIM1CH1_CAP_VAL  =0xFFFF;
			 }
			 else
			 {
			    TIM1CH1_CAP_STA++;                 //自增1
			 }
		  }
	    }
	 }
	    //***********************************************
	if((TIM1CH2_CAP_STA&0x80)==0)            //还未成功捕获
	{
	   /****************************************/
	   if(timsr&0x01)                        //发生更新(溢出)中断
	   {
	      if(TIM1CH2_CAP_STA&0x40)                 //已经捕获到高/低电平
		  {
		     if((TIM1CH2_CAP_STA&0x3F)==0X3F)      //高/低电平太长了 强制捕获完成
			 {
			    TIM1CH2_CAP_STA |=0x80;            //标记成功捕获一次
				TIM1CH2_CAP_VAL  =0xFFFF;
			 }
			 else
			 {
			    TIM1CH2_CAP_STA++;                 //自增1
			 }
		  }
	    }
	 }
	 //********************************************
	if((TIM1CH3_CAP_STA&0x80)==0)            //还未成功捕获
	{
	   /****************************************/
	   if(timsr&0x01)                        //发生更新(溢出)中断
	   {
	      if(TIM1CH3_CAP_STA&0x40)                 //已经捕获到高/低电平
		  {
		     if((TIM1CH3_CAP_STA&0x3F)==0X3F)      //高/低电平太长了 强制捕获完成
			 {
			    TIM1CH3_CAP_STA |=0x80;            //标记成功捕获一次
				TIM1CH3_CAP_VAL  =0xFFFF;
			 }
			 else
			 {
			    TIM1CH3_CAP_STA++;                 //自增1
			 }
		  }
	    }
	 }
	 //*********************************************
	if((TIM1CH4_CAP_STA&0x80)==0)            //还未成功捕获
	{
	   /****************************************/
	   if(timsr&0x01)                        //发生更新(溢出)中断
	   {
	      if(TIM1CH4_CAP_STA&0x40)                 //已经捕获到高/低电平
		  {
		     if((TIM1CH4_CAP_STA&0x3F)==0X3F)      //高/低电平太长了 强制捕获完成
			 {
			    TIM1CH4_CAP_STA |=0x80;            //标记成功捕获一次
				TIM1CH4_CAP_VAL  =0xFFFF;
			 }
			 else
			 {
			    TIM1CH4_CAP_STA++;                 //自增1
			 }
		  }
	    }
	 }
	//**********************自定义用户任务****************************//
    
    
	//*****************************************************************//
	TIM1->SR &=~(1<<0);                       //清中断标志   必须  (置0清 非写1)
 
}

在更新(溢出)中断处理函数中,先判断是否捕获成功,如果捕获成功了,什么都不需要做。如果捕获没有成功,就需要进行逻辑处理。

由于我们进行输入捕获,一旦捕捉到了上升沿,就设置计数器当前值为0,让它从0开始重新计数。

但是如果高脉冲的长度过于宽了,也就是说,从0开始计数到自动重加载值一个循环结束了,脉冲还是没有结束。这个情况下,显而易见不能只记录一下最后的计数器当前值。

解决的方法即使引入TIM1CH1_CAP_STATIM1CH1_CAP_STA是我们自己定义的全局变量,即自定义捕获状态寄存器;

/*********************************************************************************************************
 *
 *		   Description:  自定义捕获状态寄存器
                         bit7                bit6                     bit5~0
						 捕获完成标志        第一次捕获到高电平标志	  捕获高电平后定时器溢出次数
 *
 ********************************************************************************************************/
u8   TIM1CH1_CAP_STA=0;                    //定时器1通道1捕获状态
u16  TIM1CH1_CAP_VAL=0;					   //输入捕获值
u8   TIM1CH2_CAP_STA=0;                    //定时器1通道2捕获状态
u16  TIM1CH2_CAP_VAL=0;					   //输入捕获值
u8   TIM1CH3_CAP_STA=0;                    //定时器1通道3捕获状态
u16  TIM1CH3_CAP_VAL=0;					   //输入捕获值
u8   TIM1CH4_CAP_STA=0;                    //定时器1通道4捕获状态
u16  TIM1CH4_CAP_VAL=0;					   //输入捕获值
.......

位[5-0]为捕捉高电平后定时器溢出的次数,位6为捕捉到高电平标志,位7为捕获完标志。

这里定时器1向上计数为例,TIM1_CNT计数到自动加载值(TIMx_ARR),将会触发计数器溢出中断,

在溢出中断处理函数TIM1_UP_IRQHandler的任务就是统计高电平持续周期触发了多少次溢出中断。

2.2.2.2 TIM1_CC_IRQHandler

定时器1捕获/比较中断TIM1_CC_IRQHandler实现;

/*******************************************************************************
* Function Name  : TIM1_CC_IRQHandler        
* Description    : This function handles TIM1 capture compare interrupt request.
* Input          : None
* Output         : None
* Return         : None
*******************************************************************************/
void TIM1_CC_IRQHandler(void)				   //定时器1捕获比较中断
{
    u16 timsr;              //存放定时器标志位
	timsr = TIM1->SR; 
    if((TIM1CH1_CAP_STA&0x80)==0)            //还未成功捕获
	{
        if(timsr&0x02)                        //捕获1发生捕获事件
		{
		   if(TIM1CH1_CAP_STA&0X40)           //第二次捕获到
		   {
		     TIM1CH1_CAP_STA |=0X80;          //高/低电平捕获成功
			 TIM1CH1_CAP_VAL  =TIM1->CCR1;    //获取当前的捕获值	  
		   } 
		   else								 //第一次捕获到
		   {
		   	 TIM1CH1_CAP_VAL=0;
			 TIM1CH1_CAP_STA =0X40;			 //标记捕获到
			 TIM1->CNT   =0;                 //计数器清空
		   }
		   if( TIM1->CCER&(1<<1))		      //上次设置为下降沿
		   {
		   	  TIM1->CCER &=~(1<<1);           //清零
			  TIM1->CCER |=0<<1;              //CC1P设置为上升沿
		   }
		   else								  //上次设置为上升沿
		   {
		      TIM1->CCER &=~(1<<1);           //清零
			  TIM1->CCER |=1<<1;              //CC1P设置为下降沿
		   }
		   TIM1->SR &=~(1<<1);               //清中断标志   必须  (置0清 非写1)
		}     
	 }
	 //*******************************************************
    if((TIM1CH2_CAP_STA&0x80)==0)            //还未成功捕获
	{
        if(timsr&0x04)                        //捕获1发生捕获事件
		{
		   if(TIM1CH2_CAP_STA&0X40)          
		   {
		     TIM1CH2_CAP_STA |=0X80;          //高/低电平捕获成功
			 TIM1CH2_CAP_VAL  =TIM1->CCR2;    //获取当前的捕获值	   
		   } 
		   else								
		   {

		   	 TIM1CH2_CAP_VAL=0;
			 TIM1CH2_CAP_STA =0X40;			 //标记捕获到
			 TIM1->CNT   =0;                 //计数器清空
		   }
		   if( TIM1->CCER&(1<<5))		      //上次设置为下降沿
		   {
		   	  TIM1->CCER &=~(1<<5);           //清零
			  TIM1->CCER |=0<<5;              //CC2P设置为上升沿
		   }
		   else								  //上次设置为上升沿
		   {
		      TIM1->CCER &=~(1<<5);           //清零
			  TIM1->CCER |=1<<5;              //CC2P设置为下降沿
		   }
		   TIM1->SR &=~(1<<2);               //清中断标志   必须  (置0清 非写1)
		}     
	 }
	 //***********************************************************
	if((TIM1CH3_CAP_STA&0x80)==0)            //还未成功捕获
	{
        if(timsr&0x08)                        //捕获1发生捕获事件
		{
		   if(TIM1CH3_CAP_STA&0X40)         
		   {
		     TIM1CH3_CAP_STA |=0X80;          //高/低电平捕获成功
			 TIM1CH3_CAP_VAL  =TIM1->CCR3;    //获取当前的捕获值	 
		   } 
		   else								
		   {
		   	 TIM1CH3_CAP_VAL=0;
			 TIM1CH3_CAP_STA =0X40;			 //标记捕获到
			 TIM1->CNT   =0;                 //计数器清空
		   }
		   if( TIM1->CCER&(1<<9))		      //上次设置为下降沿
		   {
		   	  TIM1->CCER &=~(1<<9);           //清零
			  TIM1->CCER |=0<<9;              //CC3P设置为上升沿
		   }
		   else								  //上次设置为上升沿
		   {
		      TIM1->CCER &=~(1<<9);           //清零
			  TIM1->CCER |=1<<9;              //CC3P设置为下降沿
		   }
		   TIM1->SR &=~(1<<3);               //清中断标志   必须  (置0清 非写1)
		}     
	 }
	 //*******************************************8
	if((TIM1CH4_CAP_STA&0x80)==0)            //还未成功捕获
	{
        if(timsr&0x10)                        //捕获1发生捕获事件
		{
		   if(TIM1CH4_CAP_STA&0X40)          
		   {
		     TIM1CH4_CAP_STA |=0X80;          //高/低电平捕获成功
			 TIM1CH4_CAP_VAL  =TIM1->CCR4;    //获取当前的捕获值	
		   } 
		   else								
		   {
		   	 TIM1CH4_CAP_VAL=0;
			 TIM1CH4_CAP_STA =0X40;			 
			 TIM1->CNT   =0;                 //计数器清空
		   }
		   if( TIM1->CCER&(1<<13))		      //上次设置为下降沿
		   {
		   	  TIM1->CCER &=~(1<<13);           //清零
			  TIM1->CCER |=0<<13;              //CC4P设置为上升沿
		   }
		   else								  //上次设置为上升沿
		   {
		      TIM1->CCER &=~(1<<13);           //清零
			  TIM1->CCER |=1<<13;              //CC4P设置为下降沿
		   }
		   TIM1->SR &=~(1<<4);               //清中断标志   必须  (置0清 非写1)
		}     
	 }
    //**********************自定义用户任务****************************//



	//*****************************************************************//
}

在捕获/比较中断中;

  • 判断是否是第一次捕获到(捕捉到的是上升沿),如果是,计数器当前值(TIM1_CNT)清零,TIM1CH1_CAP_VAL清零,同时标记第一次捕获到高电平,设置极性下降沿捕捉;
  • 判断是否是第二次捕获到(捕获到的是下降沿),如果是标记捕获完成,保存当前计数器(TIM1_CNT)的值到TIM1CH1_CAP_VAL,设置极性上升沿捕获。
2.2.2.3 脉宽计算

接下来我们介绍一下高电平脉宽如何计算,以TIM1通道1为例:

\[TIM1CH1\_CAP\_STA[5:0] \times \frac {65536}{F_{clk}} + TIM1CH1\_CAP\_VAL \times \frac{1}{F_{clk}} \]

其中:\(F_{clk} = 72MHz\)

2.2.3 TIM2~5更新中断

定时器TIM2~5更新中断处理函数基本是一样的,这里以TIM2_IRQHandler为例。

由于定时器TIM2~5均是通用定时器,其不像高级定时器那样有单独的溢出中断、捕获/比较中断事件,其只有中断事件,对应的中断处理函数为TIMx_IRQHandler

/*******************************************************************************
* Function Name  : TIM2_IRQHandler
* Description    : This function handles TIM2 global interrupt request.
* Input          : None
* Output         : None
* Return         : None
*******************************************************************************/
void TIM2_IRQHandler(void)
{
    u16 timsr;              //存放定时器标志位
	timsr = TIM2->SR;
	//******************************************  通道1 ****************************************************************
	if((TIM2CH1_CAP_STA&0x80)==0)            //还未成功捕获
	{ 
	   /****************************************/
	   if(timsr&0x01)                        //发生更新(溢出)中断
	   {
	      if(TIM2CH1_CAP_STA&0x40)                 //已经捕获到高/低电平
		  {
		     if((TIM2CH1_CAP_STA&0x3F)==0X3F)      //高/低电平太长了 强制捕获完成
			 {
			    TIM2CH1_CAP_STA |=0x80;            //标记成功捕获一次
				TIM2CH1_CAP_VAL  =0xFFFF;
			 }
			 else
			 {
			    TIM2CH1_CAP_STA++;                 //自增1
			 }
		  }
	   }
		/***********************************************/
	   if(timsr&0x02)                        //捕获1发生捕获事件
		{
		   if(TIM2CH1_CAP_STA&0X40)           //第二次发生捕获
		   {
		     TIM2CH1_CAP_STA |=0X80;          //高电平/低电平捕获成功
			 TIM2CH1_CAP_VAL  =TIM2->CCR1;    //获取当前的捕获值		   
		   } 
		   else					  			  //第一次发生捕获
		   {					  
		   	 TIM2CH1_CAP_VAL=0;
			 TIM2CH1_CAP_STA =0X40;			  //标记捕获到上升沿/下降沿
			 TIM2->CNT   =0;                  //计数器清空
		   }
		   if( TIM2->CCER&(1<<1))		  //上次设置为下降沿
		   {
		   	  TIM2->CCER &=~(1<<1);           //清零
			  TIM2->CCER |=0<<1;              //CC1P设置为上升沿
		   }
		   else								  //上次设置为上升沿
		   {
		      TIM2->CCER &=~(1<<1);           //清零
			  TIM2->CCER |=1<<1;              //CC1P设置为下降沿
		   }
		}     
    }
		//***************************************  通道2   **************************************************************
	if((TIM2CH2_CAP_STA&0x80)==0)            //还未成功捕获
	{
	   /****************************************/
	   if(timsr&0x01)                        //发生更新(溢出)中断
	   {
	      if(TIM2CH2_CAP_STA&0x40)                 //已经捕获到高/低电平
		  {
		     if((TIM2CH2_CAP_STA&0x3F)==0X3F)      //高、低电平太长了 强制捕获完成
			 {
			    TIM2CH2_CAP_STA |=0x80;            //标记成功捕获一次
				TIM2CH2_CAP_VAL  =0xFFFF;
			 }
			 else
			 {
			    TIM2CH2_CAP_STA++;                 //自增1
			 }
		  }
		}
		/***********************************************/
		if(timsr&0x04)                        //捕获2发生捕获事件
		{
		   if(TIM2CH2_CAP_STA&0X40)           //标记第二次捕捉
		   {
		     TIM2CH2_CAP_STA |=0X80;          //高/低电平捕获成功
			 TIM2CH2_CAP_VAL  =TIM2->CCR2;    //获取当前的捕获值	   
		   } 
		   else								 //标记第一次捕捉
		   {
		   	 TIM2CH2_CAP_VAL=0;
			 TIM2CH2_CAP_STA =0X40;			 //标记第一次捕捉到
			 TIM2->CNT   =0;                 //计数器清空
		   }
		   if( TIM2->CCER&(1<<5))		      //上次设置为下降沿
		   {
		   	  TIM2->CCER &=~(1<<5);           //清零
			  TIM2->CCER |=0<<5;              //CC2P设置为上升沿
		   }
		   else								  //上次设置为上升沿
		   {
		      TIM2->CCER &=~(1<<5);           //清零
			  TIM2->CCER |=1<<5;              //CC2P设置为下降沿
		   }
		}   
	  
	}
	//***************************************  通道3   **************************************************************
	if((TIM2CH3_CAP_STA&0x80)==0)            //还未成功捕获
	{
	   /****************************************/
	   if(timsr&0x01)                        //发生更新(溢出)中断
	   {
	      if(TIM2CH3_CAP_STA&0x40)                 //已经捕获到高/低电平
		  {
		     if((TIM2CH3_CAP_STA&0x3F)==0X3F)      //高/低电平太长了 强制捕获完成
			 {
			    TIM2CH3_CAP_STA |=0x80;            //标记成功捕获一次
				TIM2CH3_CAP_VAL  =0xFFFF;
			 }
			 else
			 {
			    TIM2CH3_CAP_STA++;                 //自增1
			 }
		  }
		}
		/***********************************************/
		if(timsr&0x08)                        //捕获3发生捕获事件
		{
		   if(TIM2CH3_CAP_STA&0X40)           
		   {
		     TIM2CH3_CAP_STA |=0X80;          //高/低电平捕获成功
			 TIM2CH3_CAP_VAL  =TIM2->CCR3;    //获取当前的捕获值	   
		   } 
		   else								 
		   {
		   	 TIM2CH3_CAP_VAL=0;
			 TIM2CH3_CAP_STA =0X40;			 //标记捕获到
			 TIM2->CNT   =0;                 //计数器清空
		   }
		   if( TIM2->CCER&(1<<9))		      //上次设置为下降沿
		   {
		   	  TIM2->CCER &=~(1<<9);           //清零
			  TIM2->CCER |=0<<9;              //CC3P设置为上升沿
		   }
		   else								  //上次设置为上升沿
		   {
		      TIM2->CCER &=~(1<<9);           //清零
			  TIM2->CCER |=1<<9;              //CC3P设置为下降沿
		   }
		}   
	 }
	 //***************************************  通道4   **************************************************************
	if((TIM2CH4_CAP_STA&0x80)==0)            //还未成功捕获
	{
	   /****************************************/
	   if(timsr&0x01)                        //发生更新(溢出)中断
	   {
	      if(TIM2CH4_CAP_STA&0x40)                 //已经捕获到高/低电平
		  {
		     if((TIM2CH4_CAP_STA&0x3F)==0X3F)      //高、低电平太长了 强制捕获完成
			 {
			    TIM2CH4_CAP_STA |=0x80;            //标记成功捕获一次
				TIM2CH4_CAP_VAL  =0xFFFF;
			 }
			 else
			 {
			    TIM2CH4_CAP_STA++;                 //自增1
			 }
		  }
		}
		/***********************************************/
		if(timsr&0x10)                        //捕获4发生捕获事件
		{
		   if(TIM2CH4_CAP_STA&0X40)          
		   {
		     TIM2CH4_CAP_STA |=0X80;          //高/低电平捕获成功
			 TIM2CH4_CAP_VAL  =TIM2->CCR4;    //获取当前的捕获值		   
		   } 
		   else								 
		   {
		   	 TIM2CH4_CAP_VAL=0;
			 TIM2CH4_CAP_STA =0X40;			 //标记第一次捕获到
			 TIM2->CNT   =0;                 //计数器清空
		   }
		   if( TIM2->CCER&(1<<13))		      //上次设置为下降沿
		   {
		   	  TIM2->CCER &=~(1<<13);           //清零
			  TIM2->CCER |=0<<13;              //CC4P设置为上升沿
		   }
		   else								  //上次设置为上升沿
		   {
		      TIM2->CCER &=~(1<<13);           //清零
			  TIM2->CCER |=1<<13;              //CC4P设置为下降沿
		   }
		}   
	}  

	//**********************自定义用户任务****************************//




	//*****************************************************************//
	TIM2->SR =0;                       //清中断标志	   更新中断和比较捕获中断
}
2.3 功能实现

接下来我们以TIM3通道1(PA6引脚)为例进行输入捕获测试,我们将PC7模拟成PWM输出,高电平持续大约时间为258us,低电平持续时间为500us

2.3.1 main函数实现
int main()
{
    u32 temp = 0;
    STM32_Clock_Init(9);                              //系统时钟初始化

    gpio_init(PC7,GPO_SpeedMax_50,HIGH);

    STM32_NVIC_Init(2,USART1_IRQn,0,1);		        //串口中断优先级初始化,其中包括中断使能
    usart_init(USART_1,115200);				        //串口1初始化,波特率115200 映射到PA9 PA10

    STM32_NVIC_Init(2,TIM3_IRQn,0,1);  		       //定时器3中断使能

    TIM_CAP_Init(TIMER3,CAP_CH1,1);	               //定时器3通道1输入捕获 PA6
    while(1)
    {
        //把PC7和PA6相连,测量PA6高电平脉宽
        PCout(7)=1;
	    delay_us(258);
	    PCout(7)=0;
	    delay_ms(500);
	    while(TIM3CH1_CAP_STA&0X80)
	    {
	        temp = TIM3CH1_CAP_STA&0X3F;
	        temp *=65536;
	        temp +=TIM3CH1_CAP_VAL;
			printf("PA6 high level time: %d us\n",temp);
	        TIM3CH1_CAP_STA=0;
	    }
   }
}
2.3.2 测试

编译程序并下载,我们需要将PC7引脚连接到PA6引脚;

可以看到高电平时间大概为262us,比延时时间258us略长一些,这是因为我们程序执行也会消耗一定时间,可以看到这个测量结果还是比较准的。

三、源码下载

源码下载路径:stm32f103

参考文章

[1] STM32通用定时器的输入捕获(实例:输入捕获)

#include "led.h" #include "delay.h" #include "key.h" #include "sys.h" #include "exti.h" #include "timer.h" #include "usart.h" #include "IWDG.h" //int main(void) //中断 //{ ////delay_init(); //LED_Init(); ////KEY_Init(); ////NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); ////EXTIX_Init(); //LED=0; //while(1); //} //int main(void) //定时器中断 //{ // NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); // delay_init(); // LED_Init(); // // TIM3_Int_Init(1999,7199);//((1+7199)/72M)*(1+9999)=1秒*/反 // while(1); //} //int main(void) //pwm //{ // u16 ledpwmval=0; // u8 dir=1; // delay_init(); // NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); // uart_init(115200); // LED_Init (); // // TIM3_PWM_Init(199,7199);//50Hz // while(1) // { // delay_ms(10); // if(dir)ledpwmval++; // else ledpwmval --; // if(ledpwmval >1000) // dir=0; // if(ledpwmval ==0) // dir=1; // TIM_SetCompare2(TIM3,5); // delay_ms(500); // TIM_SetCompare2(TIM3,10); // delay_ms(500); // TIM_SetCompare2(TIM3,15); // delay_ms(500); // TIM_SetCompare2(TIM3,20); // delay_ms(500); // TIM_SetCompare2(TIM3,25); // delay_ms(500); // } //} //int main() //串口 //{ // u16 t; // u16 len; // u16 times=0; // delay_init(); // NVIC_PriorityGroupConfig (NVIC_PriorityGroup_2 ); // uart_init(115200); // LED_Init(); // KEY_Init(); // while(1) // { // if(USART_RX_STA&0x8000) // { // len=USART_RX_STA&0x3fff;//得到此次接收的数据长度 // printf("\r\n您发送的消息为:\r\n\r\n"); // for(t=0;t<len;t++) // { // USART_SendData(USART1,USART_RX_BUF[t]); // while(USART_GetFlagStatus(USART1,USART_FLAG_TC)!=SET); // } // printf("\r\n\r\n");//插入换行 // USART_RX_STA=0; // } // else // { // times++; // if(times%500000==0) // { // LED=!LED; // } // } // } //} extern void TIM4_Cap_Init(u16 arr,u16 psc); extern u8 TIM4CH1_CAPTURE_STA; //输入捕获状态 输入捕获实验 extern u16 TIM4CH1_CAPTURE_VAL; //输入捕获值 int main(void) { u32 temp=0; delay_init(); //延时函数初始化 NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //设置NVIC中断分组2:2位抢占优先级,2位响应优先级 uart_init(115200); //串口初始化为115200 LED_Init(); //LED端口初始化 // TIM3_PWM_Init(899,0); //不分频。PWM频率72000/(899+1)=80Khz TIM4_Cap_Init(0XFFFF,72-1); //以1Mhz的频率计数 while(1) { delay_ms(10); TIM_SetCompare2(TIM3,TIM_GetCapture2(TIM3)+1); if(TIM_GetCapture2(TIM3)==300) TIM_SetCompare2(TIM3,0); if(TIM4CH1_CAPTURE_STA&0X80)//成功捕获到了一次上升沿 { temp=TIM4CH1_CAPTURE_STA&0X3F; temp*=65536; //溢出时间总和 temp+=TIM4CH1_CAPTURE_VAL;//得到总的高电平时间 printf("HIGH:%d us\r\n",temp);//打印总的高点平时间 TIM4CH1_CAPTURE_STA=0;//开启下一次捕获 } } }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Graceful_scenery

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值