stm32TIM比较捕获

框图

stm32TIM比较捕获_第1张图片
stm32TIM比较捕获_第2张图片
框图分析
1.举例通道1输入波形设置采样频率,通过 边沿检测器吗,设置CC1P确定边沿检测方式(上升沿,下降沿,双边沿),设置输入通道映射,设置捕获分频,是能捕获,产生捕获后的信号。
2.捕获产生的信号ICIPS=1 CC1E=1(捕获使能),通过与门为1,与CC1G软件产生捕获事件通过或门。CC1S(模式配置配置为输入)经过或门为1,CCR1捕获比较值读完后为0。下边与门产生捕获信号将 计数器的值写入信号将捕获/比较影子寄存器中,通过与门产生capture_transfer信号将捕获/比较影子寄存器中的值写到捕获/比较预装载寄存器中。就能读到CCR1 的值也就是这个电平的时长。

通用定时器输入捕获测量脉宽的原理

stm32TIM比较捕获_第3张图片
分析:
原理:比如可以设置开始为上升沿检测,当检测到上升沿时,此时定时器清零失能后使能重新计数,同时设置为下降沿检测,当产生下降沿时读到CCRx2,CCRx2表示高电平时间。(这里是计数时间,和实际时间之间还要换算。)
递增计数模式下CNT==ARR 时产生溢出。
分两类情况
1.脉宽很小,在ARR范围内不产生溢出
即CCRx2比ARR还小 这时直接计算就行了。
2.脉宽很大在ARR范围内产生溢出
需要记录脉宽次数N(通过溢出更新中断+1记录N)。从而产生上图公式。

例程

stm32TIM比较捕获_第4张图片
这里以f407为例子PSC为84-1 ARR=65535 但是我的板子这里电平按下去为地弹上来为高
代码:

#include "tim_ic.h"
#include "usart.h"
#include "stdio.h"


uint8_t g_timxchy_cap_sta = 0;    /* 输入捕获状态 */
uint16_t g_timxchy_cap_val = 0;   /* 输入捕获值 */


TIM_HandleTypeDef g_timx_handle={0};
void MX_base_time_Init(uint16_t arr,uint16_t psc)
{
	TIM_IC_InitTypeDef tim_ic_cap_chy={0};//这里初始化结构体为0为了是防止一些没有设置的成员为随机变量
	g_timx_handle.Instance=TIM5;
	g_timx_handle.Init.CounterMode=TIM_COUNTERMODE_UP;
	//预分频值
	g_timx_handle.Init.Prescaler=arr;
	//重装载值
	g_timx_handle.Init.Period=psc;
	HAL_TIM_IC_Init(&g_timx_handle);
  
	tim_ic_cap_chy.ICPolarity = TIM_ICPOLARITY_RISING;//配置上升沿捕获
	tim_ic_cap_chy.ICSelection = TIM_ICSELECTION_DIRECTTI;//连接到TI1上
	tim_ic_cap_chy.ICPrescaler =TIM_ICPSC_DIV1;//设置分频值,这里的分频值是比如多少个上升沿触发一个事件
	tim_ic_cap_chy.ICFilter= 0;// 配置滤波器This parameter can be a number between Min_Data = 0x0 and Max_Data = 0xF 
	HAL_TIM_IC_ConfigChannel(&g_timx_handle,&tim_ic_cap_chy,TIM_CHANNEL_1);//配置输入通道1
	
	__HAL_TIM_ENABLE_IT(&g_timx_handle,TIM_IT_UPDATE);//使能更新中断
	HAL_TIM_IC_Start_IT(&g_timx_handle,TIM_CHANNEL_1);//以中断模式开启捕获
}


void HAL_TIM_IC_MspInit(TIM_HandleTypeDef *htim)
{
	if(htim->Instance==g_timx_handle.Instance)
	{
		//使能时钟
		__HAL_RCC_TIM5_CLK_ENABLE();
		__HAL_RCC_GPIOA_CLK_ENABLE();
		GPIO_InitTypeDef gpio_init_struct={0};
		gpio_init_struct.Pin=GPIO_PIN_0;
		gpio_init_struct.Mode=GPIO_MODE_AF_PP;//虽然是输入但是这里是复用推完
		gpio_init_struct.Pull=GPIO_PULLDOWN;
		gpio_init_struct.Speed=GPIO_SPEED_FREQ_VERY_HIGH;
		gpio_init_struct.Alternate=GPIO_AF2_TIM5;
		HAL_GPIO_Init(GPIOA,&gpio_init_struct);
		
		HAL_NVIC_SetPriority(TIM5_IRQn,1,0);
		HAL_NVIC_EnableIRQ(TIM5_IRQn);
		//配置NVIC

	}
}

void TIM5_IRQHandler(void)
{
	HAL_TIM_IRQHandler(&g_timx_handle);
}

void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim)
{
	if(htim->Instance==TIM5)
	{
		if((g_timxchy_cap_sta & 0x80)==0)//还没有捕获过
		{
			if(g_timxchy_cap_sta & 0x40) //检验是否标记捕获到上升沿标记捕获到上升沿
			{
				g_timxchy_cap_sta |=0x80;//标记捕获过了
				g_timxchy_cap_val=HAL_TIM_ReadCapturedValue(&g_timx_handle,TIM_CHANNEL_1);//读出捕获值
				TIM_RESET_CAPTUREPOLARITY(&g_timx_handle,TIM_CHANNEL_1);//清除原有设置
				TIM_SET_CAPTUREPOLARITY(&g_timx_handle,TIM_CHANNEL_1,TIM_ICPOLARITY_RISING);//设置为上升沿捕获
			}
		
		else
		{
			//这是第一次捕获高电平  捕捉到上升沿开始计数
				g_timxchy_cap_sta=0;//清零
				g_timxchy_cap_val=0;
				g_timxchy_cap_sta|=0x40;//标记捕获到上升沿
				__HAL_TIM_DISABLE(&g_timx_handle);//失能定时器
				__HAL_TIM_SET_COUNTER(&g_timx_handle,0);// Set the TIM Counter Register value on runtime.计数器清零
				TIM_RESET_CAPTUREPOLARITY(&g_timx_handle,TIM_CHANNEL_1);//清除原来的设置
				TIM_SET_CAPTUREPOLARITY(&g_timx_handle,TIM_CHANNEL_1,TIM_CHANNEL_1);//定时器5设置为下降沿捕获
				__HAL_TIM_ENABLE(&g_timx_handle);//使能定时器5
			
		}
	}
	
	}
}


void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
	if(htim->Instance==TIM5)//定时器5产生溢出更新中断
	{
		if((g_timxchy_cap_sta&0x80)==0)//判读是不是捕获过了
		{
			if(g_timxchy_cap_sta&0x40)//判断是否捕获到高电平
			{
					if((g_timxchy_cap_sta&0x3F)==0x3F)//高电平时间 太长超出最大计数值:最大计数值为2^6*65536+65525=4194303us
					{
						TIM_RESET_CAPTUREPOLARITY(&g_timx_handle,TIM_CHANNEL_1);//清除设置
						TIM_SET_CAPTUREPOLARITY(&g_timx_handle,TIM_CHANNEL_1,TIM_ICPOLARITY_RISING);//重新设置为定时器5通道1上升沿检测
						g_timxchy_cap_sta |=0x80;//标记成功捕获一次
						g_timxchy_cap_val=0xFFFF;//计数值为最大值
					}
					else
					{
						g_timxchy_cap_sta++;//高电平时间没有超出最大计数值  溢出次数累计+1
			}
		
		}
	}
}
}

main

int main(void)
{
	uint32_t temp = 0;

  HAL_Init();

  /* USER CODE BEGIN Init */

  /* USER CODE END Init */

  /* Configure the system clock */
  SystemClock_Config();


  MX_GPIO_Init();
	usart_Init();
	MX_base_time_Init(0XFFFF, 84 - 1);
  /* USER CODE BEGIN 2 */

  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
	printf("demo!!!\r\n");
  while (1)
  {
			if(g_timxchy_cap_sta&0x80)
			{
				temp=g_timxchy_cap_sta&0x3F;
				temp*=65536;
				temp+=g_timxchy_cap_val;
			  printf("HIGH:%d us\r\n", temp);
				 g_timxchy_cap_sta = 0;   
				
			}
			HAL_Delay(10);
  }
  /* USER CODE END 3 */
}

总结

1、先配置时基MX_base_time_Init(uint16_t arr,uint16_t psc) 配置定时器基地址,预分频值,自动重装载值,计数模式
	HAL_TIM_IC_Init()调用这个函数初始化
2、配置输入模式
	声明这个结构体TIM_IC_InitTypeDef tim_ic_cap_chy={0};//这里初始化结构体为0为了是防止一些没有设置的成员为随机变量
	tim_ic_cap_chy.ICPolarity = TIM_ICPOLARITY_RISING;//配置上升沿捕获
	tim_ic_cap_chy.ICSelection = TIM_ICSELECTION_DIRECTTI;//连接到TI1上
	tim_ic_cap_chy.ICPrescaler =TIM_ICPSC_DIV1;//设置分频值,这里的分频值是比如多少个上升沿触发一个事件
	tim_ic_cap_chy.ICFilter= 0;// 配置滤波器This parameter can be a number between Min_Data = 0x0 and Max_Data = 0xF 
	HAL_TIM_IC_ConfigChannel(&g_timx_handle,&tim_ic_cap_chy,TIM_CHANNEL_1);//配置输入通道1
	__HAL_TIM_ENABLE_IT(&g_timx_handle,TIM_IT_UPDATE);//使能更新中断
	HAL_TIM_IC_Start_IT(&g_timx_handle,TIM_CHANNEL_1);//以中断模式开启捕获,这两个中断都会到TIM5_IRQHandler函数中去通过HAL_TIM_IRQHandler(&g_timx_handle);判断是哪种中断进而执行哪种回调函数

	回调函数处理MSPINIT 配置NVIC GPIO等
				void HAL_TIM_IC_MspInit(TIM_HandleTypeDef *htim)
		{
			if(htim->Instance==g_timx_handle.Instance)
			{
				//使能时钟
				__HAL_RCC_TIM5_CLK_ENABLE();
				__HAL_RCC_GPIOA_CLK_ENABLE();
				GPIO_InitTypeDef gpio_init_struct={0};
				gpio_init_struct.Pin=GPIO_PIN_0;
				gpio_init_struct.Mode=GPIO_MODE_AF_PP;//虽然是输入但是这里是复用推完
				gpio_init_struct.Pull=GPIO_PULLDOWN;
				gpio_init_struct.Speed=GPIO_SPEED_FREQ_VERY_HIGH;
				gpio_init_struct.Alternate=GPIO_AF2_TIM5;
				HAL_GPIO_Init(GPIOA,&gpio_init_struct);
				
				HAL_NVIC_SetPriority(TIM5_IRQn,1,0);
				HAL_NVIC_EnableIRQ(TIM5_IRQn);
				//配置NVIC
		
			}
		}

3、中断处理函数
							void TIM5_IRQHandler(void)
						{
							HAL_TIM_IRQHandler(&g_timx_handle);
						}
					4、回调函数实现功能	
							void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim)
				{
					if(htim->Instance==TIM5)
					{
						if((g_timxchy_cap_sta & 0x80)==0)//还没有捕获过
						{
							if(g_timxchy_cap_sta & 0x40) //检验是否标记捕获到上升沿标记捕获到上升沿
							{
								g_timxchy_cap_sta |=0x80;//标记捕获过了
								g_timxchy_cap_val=HAL_TIM_ReadCapturedValue(&g_timx_handle,TIM_CHANNEL_1);//读出捕获值
								TIM_RESET_CAPTUREPOLARITY(&g_timx_handle,TIM_CHANNEL_1);//清除原有设置
								TIM_SET_CAPTUREPOLARITY(&g_timx_handle,TIM_CHANNEL_1,TIM_ICPOLARITY_RISING);//设置为上升沿捕获
							}
						
						else
						{
							//这是第一次捕获高电平  捕捉到上升沿开始计数
								g_timxchy_cap_sta=0;//清零
								g_timxchy_cap_val=0;
								g_timxchy_cap_sta|=0x40;//标记捕获到上升沿
								__HAL_TIM_DISABLE(&g_timx_handle);//失能定时器
								__HAL_TIM_SET_COUNTER(&g_timx_handle,0);// Set the TIM Counter Register value on runtime.计数器清零
								TIM_RESET_CAPTUREPOLARITY(&g_timx_handle,TIM_CHANNEL_1);//清除原来的设置
								TIM_SET_CAPTUREPOLARITY(&g_timx_handle,TIM_CHANNEL_1,TIM_CHANNEL_1);//定时器5设置为下降沿捕获
								__HAL_TIM_ENABLE(&g_timx_handle);//使能定时器5
							
						}
					}
					
					}
				}

				void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
			{
				if(htim->Instance==TIM5)//定时器5产生溢出更新中断
				{
					if((g_timxchy_cap_sta&0x80)==0)//判读是不是捕获过了
					{
						if(g_timxchy_cap_sta&0x40)//判断是否捕获到高电平
						{
								if((g_timxchy_cap_sta&0x3F)==0x3F)//高电平时间 太长超出最大计数值:最大计数值为2^6*65536+65525=4194303us
								{
									TIM_RESET_CAPTUREPOLARITY(&g_timx_handle,TIM_CHANNEL_1);//清除设置
									TIM_SET_CAPTUREPOLARITY(&g_timx_handle,TIM_CHANNEL_1,TIM_ICPOLARITY_RISING);//重新设置为定时器5通道1上升沿检测
									g_timxchy_cap_sta |=0x80;//标记成功捕获一次
									g_timxchy_cap_val=0xFFFF;//计数值为最大值
								}
								else
								{
									g_timxchy_cap_sta++;//高电平时间没有超出最大计数值  溢出次数累计+1
						}
					
					}
				}
			}
			}

4.main 调用处理
int main(void)
{
uint32_t temp = 0;

	  HAL_Init();
	
	  /* USER CODE BEGIN Init */
	
	  /* USER CODE END Init */
	
	  /* Configure the system clock */
	  SystemClock_Config();
	
	
	  MX_GPIO_Init();
		usart_Init();
		MX_base_time_Init(0XFFFF, 84 - 1);
	  /* USER CODE BEGIN 2 */
	
	  /* USER CODE END 2 */
	
	  /* Infinite loop */
	  /* USER CODE BEGIN WHILE */
		printf("demo!!!\r\n");
	  while (1)
	  {
				if(g_timxchy_cap_sta&0x80)
				{
					temp=g_timxchy_cap_sta&0x3F;
					temp*=65536;
					temp+=g_timxchy_cap_val;
				  printf("HIGH:%d us\r\n", temp);
					 g_timxchy_cap_sta = 0;   
					
				}
				HAL_Delay(10);
	  }
	  /* USER CODE END 3 */
	}

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