首页 > 其他分享 >输入捕获原理与配置

输入捕获原理与配置

时间:2022-10-18 15:00:07浏览次数:48  
标签:定时器 HAL TIM5 捕获 TIM Handler 原理 输入

一、通用定时器输入捕获概述

1.STM32 输入捕获工作过程

2.STM32 输入捕获工作过程(通道1为例)

通过检测TIMx_CHx上的边沿信号,在边沿信号发生跳变(比如上升沿/下降沿)的时候,将当前定时器的值(TIMx_CNT)存放到对应的捕获/比较寄存器(TIMx_CCRx)里面,完成一次捕获。

1)步骤1:设置输入捕获滤波器(通道1为例)

2)步骤2:设置输入捕获极性(通道1为例)

3)步骤三:设置输入捕获映射通道(通道1为例)

4)步骤四:设置输入捕获分频器(通道1为例)

5)步骤五:捕获到有效信号可以开启中断

6)定时器通道对应引脚TIM5为例

二、常用寄存器和库函数配置

1.通用定时器基本函数和定义所在文件

Stm32fxxx_hal_tim.c
位置:工程文件 - HALLIB - Stm32fxxx_hal_tim.c
Stm32fxxx_hal_tim.h
位置:工程文件 - HALLIB - Stm32fxxx_hal_tim.c - Stm32fxxx_hal_tim.h

2.定时器输入捕获功能常用函数

位置:工程文件 - HALLIB - Stm32fxxx_hal_tim.c - Stm32fxxx_hal_tim.h

1)定时器输入捕获时基参数初始化函数:

HAL_StatusTypeDef HAL_TIM_IC_Init(TIM_HandleTypeDef *htim)
位置:工程文件 - HALLIB - Stm32fxxx_hal_tim.c

该函数和HAL_TIM_Base_Init/HAL_TIM_PWM_Init函数作用一样,不同的是引导调用不同的回调函数。

typedef struct
{
	uint32_t Prescaler; 						//预分频系数
	uint32_t CounterMode; 				//计数模式:向上/下
	uint32_t Period; 							//自动装载值
	uint32_t ClockDivision; 				//时钟分频因子:定时器时钟与数字滤波器分频比
	uint32_t RepetitionCounter; 		//重复计数次数:高级定时器使用
} TIM_Base_InitTypeDef;

2)定时器输入捕获时基参数初始化回调函数

void HAL_TIM_IC_MspInit(TIM_HandleTypeDef *htim);
位置:工程文件 - HALLIB - Stm32fxxx_hal_tim.c

主要用来编写定时器时钟使能,通道IO配置以及中断优先级设置等。

__HAL_RCC_TIM5_CLK_ENABLE();		//定时器3时钟使能

3)输入捕获通道参数配置函数

HAL_StatusTypeDef HAL_TIM_IC_ConfigChannel(TIM_HandleTypeDef htim,TIM_IC_InitTypeDef sConfig, uint32_t Channel);
位置:工程文件 - HALLIB - Stm32fxxx_hal_tim.c

typedef struct
{
	uint32_t ICPolarity; 			//捕获极性
	uint32_t ICSelection; 		//输入映射
	uint32_t ICPrescaler;		 //输入分频
	uint32_t ICFilter; 				//输入滤波器
} TIM_IC_InitTypeDef

4)使能定时器并使能输入捕获通道

HAL_StatusTypeDef HAL_TIM_IC_Start (TIM_HandleTypeDef *htim, uint32_t Channel);
位置:工程文件 - HALLIB - Stm32fxxx_hal_tim.c

HAL_StatusTypeDef HAL_TIM_IC_Start_IT (TIM_HandleTypeDef *htim, uint32_t Channel);
位置:工程文件 - HALLIB - Stm32fxxx_hal_tim.c

该函数同时还使能了捕获中断。

5)捕获中断回调函数

void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim)
位置:工程文件 - HALLIB - Stm32fxxx_hal_tim.c

类似中断服务函数,我们可以在里面编写与捕获相关的函数逻辑

6)读取捕获值

uint32_t HAL_TIM_ReadCapturedValue(TIM_HandleTypeDef *htim,uint32_t Channel);
位置:工程文件 - HALLIB - Stm32fxxx_hal_tim.c

3.输入捕获的一般配置关键步骤:

①使能定时器时钟和通道IO口时钟。

②配置IO口复用映射:HAL_GPIO_Init();

③初始化输入捕获时基参数:HAL_TIM_IC_Init();

④初始化输入捕获通道参数:HAL_TIM_IC_ConfigChannel();

⑤使能定时器(中断),设置优先级:HAL_TIM_IC_Start_IT();

⑥编写中断服务回调函数:HAL_TIM_IC_CaptureCallback();

三、输入捕获实验
1.实验目的:测量信号的脉冲宽度

在开发板中用wake_up按键来模拟脉冲,然后用输入捕获来测量高电平持续时间,并通过串口打印输出

步骤如下
①使能定时器时钟和通道IO口时钟。

②配置IO口复用映射:HAL_GPIO_Init();

③初始化输入捕获时基参数:HAL_TIM_IC_Init();

④初始化输入捕获通道参数:HAL_TIM_IC_ConfigChannel();

⑤使能定时器(中断),设置优先级:HAL_TIM_IC_Start_IT();

⑥编写中断服务回调函数:HAL_TIM_IC_CaptureCallback();

2.timer.c文件解读

位置:工程文件 - HARDWARE - timer.c
代码如下:

#include "timer.h"
#include "led.h"

TIM_HandleTypeDef TIM3_Handler;         //定时器3PWM句柄 
TIM_OC_InitTypeDef TIM3_CH4Handler;	    //定时器3通道4句柄

/***************************************************************************
****************************************************************************
  下面是PWM输出实验相关函数源码
****************************************************************************
****************************************************************************/
//TIM3 PWM部分初始化 
//PWM输出初始化
//arr:自动重装值
//psc:时钟预分频数
void TIM3_PWM_Init(u16 arr,u16 psc)
{ 
    TIM3_Handler.Instance=TIM3;            //定时器3
    TIM3_Handler.Init.Prescaler=psc;       //定时器分频
    TIM3_Handler.Init.CounterMode=TIM_COUNTERMODE_UP;//向上计数模式
    TIM3_Handler.Init.Period=arr;          //自动重装载值
    TIM3_Handler.Init.ClockDivision=TIM_CLOCKDIVISION_DIV1;
    HAL_TIM_PWM_Init(&TIM3_Handler);       //初始化PWM
    
    TIM3_CH4Handler.OCMode=TIM_OCMODE_PWM1; //模式选择PWM1
    TIM3_CH4Handler.Pulse=arr/2;            //设置比较值,此值用来确定占空比,
                                            //默认比较值为自动重装载值的一半,即占空比为50%
    TIM3_CH4Handler.OCPolarity=TIM_OCPOLARITY_LOW; //输出比较极性为低 
    HAL_TIM_PWM_ConfigChannel(&TIM3_Handler,&TIM3_CH4Handler,TIM_CHANNEL_4);//配置TIM3通道4
    HAL_TIM_PWM_Start(&TIM3_Handler,TIM_CHANNEL_4);//开启PWM通道4
}

//定时器底层驱动,时钟使能,引脚配置
//此函数会被HAL_TIM_PWM_Init()调用
//htim:定时器句柄
void HAL_TIM_PWM_MspInit(TIM_HandleTypeDef *htim)
{
    GPIO_InitTypeDef GPIO_Initure;
		
	__HAL_RCC_TIM3_CLK_ENABLE();			//使能定时器3
    __HAL_RCC_GPIOB_CLK_ENABLE();			//开启GPIOB时钟
	
    GPIO_Initure.Pin=GPIO_PIN_1;           	//PB1
    GPIO_Initure.Mode=GPIO_MODE_AF_PP;  	//复用推完输出
    GPIO_Initure.Pull=GPIO_PULLUP;          //上拉
    GPIO_Initure.Speed=GPIO_SPEED_HIGH;     //高速
	GPIO_Initure.Alternate= GPIO_AF2_TIM3;	//PB1复用为TIM3_CH4
    HAL_GPIO_Init(GPIOB,&GPIO_Initure);
}

//设置TIM通道4的占空比
//compare:比较值
void TIM_SetTIM3Compare4(u32 compare)
{
	TIM3->CCR4=compare;
}

//获取TIM捕获/比较寄存器值
u32 TIM_GetTIM3Capture4(void)
{
	return  HAL_TIM_ReadCapturedValue(&TIM3_Handler,TIM_CHANNEL_4);
}


/***************************************************************************
****************************************************************************
  下面是输入捕获相关源码实验相关函数源码
****************************************************************************
****************************************************************************/
TIM_HandleTypeDef TIM5_Handler;         //定时器5句柄

//定时器5通道1输入捕获配置
//arr:自动重装值(TIM2,TIM5是32位的!!)
//psc:时钟预分频数
void TIM5_CH1_Cap_Init(u32 arr,u16 psc)
{  
    TIM_IC_InitTypeDef TIM5_CH1Config;  
    
    TIM5_Handler.Instance=TIM5;                         	 //通用定时器5
    TIM5_Handler.Init.Prescaler=psc;                    	 //分频系数
    TIM5_Handler.Init.CounterMode=TIM_COUNTERMODE_UP;   	 //向上计数器
    TIM5_Handler.Init.Period=arr;                        	 //自动装载值
    TIM5_Handler.Init.ClockDivision=TIM_CLOCKDIVISION_DIV1;	 //时钟分频因子
    HAL_TIM_IC_Init(&TIM5_Handler);							 //初始化输入捕获时基参数
    
    TIM5_CH1Config.ICPolarity=TIM_ICPOLARITY_RISING;    	//上升沿捕获
    TIM5_CH1Config.ICSelection=TIM_ICSELECTION_DIRECTTI;	//映射到TI1上
    TIM5_CH1Config.ICPrescaler=TIM_ICPSC_DIV1;          	//配置输入分频,不分频
    TIM5_CH1Config.ICFilter=0;                          	//配置输入滤波器,不滤波
    HAL_TIM_IC_ConfigChannel(&TIM5_Handler,&TIM5_CH1Config,TIM_CHANNEL_1);//配置TIM5通道1
	
    HAL_TIM_IC_Start_IT(&TIM5_Handler,TIM_CHANNEL_1);  		 //开启TIM5的捕获通道1,并且开启捕获中断
    __HAL_TIM_ENABLE_IT(&TIM5_Handler,TIM_IT_UPDATE);   	 //使能更新中断
}

//定时器5底层驱动,时钟使能,引脚配置
//此函数会被HAL_TIM_IC_Init()调用
//htim:定时器5句柄
void HAL_TIM_IC_MspInit(TIM_HandleTypeDef *htim)
{
    GPIO_InitTypeDef GPIO_Initure;				//初始化GPIO
	if(htim -> Instance == TIM5)				//判断定时器5是否触发中断
	{
		__HAL_RCC_TIM5_CLK_ENABLE();            //使能TIM5时钟
		__HAL_RCC_GPIOA_CLK_ENABLE();			//开启GPIOA时钟
		
		GPIO_Initure.Pin=GPIO_PIN_0;            //PA0
		GPIO_Initure.Mode=GPIO_MODE_AF_PP;      //复用推挽输出
		GPIO_Initure.Pull=GPIO_PULLDOWN;        //下拉
		GPIO_Initure.Speed=GPIO_SPEED_HIGH;     //高速
		GPIO_Initure.Alternate=GPIO_AF2_TIM5;   //PA0复用为TIM5通道1
		HAL_GPIO_Init(GPIOA,&GPIO_Initure);

		HAL_NVIC_SetPriority(TIM5_IRQn,2,0);    //设置中断优先级,抢占优先级2,子优先级0
		HAL_NVIC_EnableIRQ(TIM5_IRQn);          //开启ITM5中断通道  
	}
}

//捕获状态
//[7]:0,没有成功的捕获;1,成功捕获到一次.
//[6]:0,还没捕获到低电平;1,已经捕获到低电平了.
//[5:0]:捕获低电平后溢出的次数(对于32位定时器来说,1us计数器加1,溢出时间:4294秒)
u8  TIM5CH1_CAPTURE_STA=0;	//输入捕获状态		    				
u32	TIM5CH1_CAPTURE_VAL;	//输入捕获值(TIM2/TIM5是32位)

//定时器5中断服务函数
void TIM5_IRQHandler(void)
{
	HAL_TIM_IRQHandler(&TIM5_Handler);//定时器共用处理函数
}
 
//定时器更新中断(计数溢出)中断处理回调函数, 该函数在HAL_TIM_IRQHandler中会被调用
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)//更新中断(溢出)发生时执行
{
	
	if((TIM5CH1_CAPTURE_STA&0X80)==0)//还未成功捕获
	{
			if(TIM5CH1_CAPTURE_STA&0X40)//已经捕获到高电平了
			{
				if((TIM5CH1_CAPTURE_STA&0X3F)==0X3F)//高电平太长了
				{
					TIM5CH1_CAPTURE_STA|=0X80;		//标记成功捕获了一次
					TIM5CH1_CAPTURE_VAL=0XFFFFFFFF;
				}else TIM5CH1_CAPTURE_STA++;
			}	 
	}		
}

//定时器输入捕获中断处理回调函数,该函数在HAL_TIM_IRQHandler中会被调用
void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim)//捕获中断发生时执行
{
	if((TIM5CH1_CAPTURE_STA&0X80)==0)//还未成功捕获
	{
		if(TIM5CH1_CAPTURE_STA&0X40)		//捕获到一个下降沿 		
			{	  			
				TIM5CH1_CAPTURE_STA|=0X80;		//标记成功捕获到一次高电平脉宽
                TIM5CH1_CAPTURE_VAL=HAL_TIM_ReadCapturedValue(&TIM5_Handler,TIM_CHANNEL_1);//获取当前的捕获值.
                TIM_RESET_CAPTUREPOLARITY(&TIM5_Handler,TIM_CHANNEL_1);   //一定要先清除原来的设置!!
                TIM_SET_CAPTUREPOLARITY(&TIM5_Handler,TIM_CHANNEL_1,TIM_ICPOLARITY_RISING);//配置TIM5通道1上升沿捕获
			}else  								//还未开始,第一次捕获上升沿
			{
				TIM5CH1_CAPTURE_STA=0;			//清空
				TIM5CH1_CAPTURE_VAL=0;
				TIM5CH1_CAPTURE_STA|=0X40;		//标记捕获到了上升沿
				__HAL_TIM_DISABLE(&TIM5_Handler);        //关闭定时器5
				__HAL_TIM_SET_COUNTER(&TIM5_Handler,0);
				TIM_RESET_CAPTUREPOLARITY(&TIM5_Handler,TIM_CHANNEL_1);   //一定要先清除原来的设置!!
				TIM_SET_CAPTUREPOLARITY(&TIM5_Handler,TIM_CHANNEL_1,TIM_ICPOLARITY_FALLING);//定时器5通道1设置为下降沿捕获
				__HAL_TIM_ENABLE(&TIM5_Handler);//使能定时器5
			}		    
	}		
}

可见代码分为了两个部分,上面一段为PWM部分,下面为输入捕获相关代码,下面重点讲解输入捕获相关代码。

1)定时器5通道1输入捕获配置

这里的设置和普通定时器设置一样,具体可回看前面的笔记
TIM5_Handler.Init.Prescaler=psc; //分频系数
这段确定了输入捕获的采样频率,因为F429的基频为90Mhz,
这里输入捕获的采样频率=基频为90Mhz/(分频系数+1)

TIM5_Handler.Init.Period=arr; //自动装载值
确定定时器溢出时间,写入自动装载值后,计数器从0计数到自动装载值后会产生一个中断

下面是输入捕获通道参数配置代码:
TIM5_CH1Config.ICPolarity=TIM_ICPOLARITY_RISING; //上升沿捕获
设置捕获极性,即捕获上升沿还是下降沿

TIM5_CH1Config.ICSelection=TIM_ICSELECTION_DIRECTTI; //映射到TI1
把捕获到的指令映射到哪个通道上,F429共有TI1、TI2、TI3、TI4 四个通道

TIM5_CH1Config.ICPrescaler=TIM_ICPSC_DIV1; //配置输入分频,不分频
这里分频的意思是捕获到几个事件触发一次中断,具体对应寄存器在本文:一、2. 4)设置输入捕获分频器(通道1为例)

TIM5_CH1Config.ICFilter=0; //配置输入滤波器,不滤波

HAL_TIM_IC_ConfigChannel(&TIM5_Handler,&TIM5_CH1Config,TIM_CHANNEL_1);//配置TIM5通道1

2)输入捕获回调函数编写

注意,这里PA0设置的是下拉模式,即没有响应捕获的时候输出的是低电平

3)中断服务函数、定时器更新中断

因为按键按下不松开,计数器会一直进行计数,而计数器装载数值有限可能会产生溢出,所以我们要对定时器中断进行更新中断,程序如上图

3.main.c文件解读

#include "sys.h"
#include "delay.h"
#include "usart.h"
#include "led.h"
#include "timer.h"

extern u8  TIM5CH1_CAPTURE_STA;		//输入捕获状态		    				
extern u32	TIM5CH1_CAPTURE_VAL;	//输入捕获值 

int main(void)
{
    long long temp=0;  
    HAL_Init();                     	//初始化HAL库   
    Stm32_Clock_Init(360,25,2,8);   	//设置时钟,180Mhz
    delay_init(180);               	 	//初始化延时函数
    uart_init(115200);             		//初始化USART
    LED_Init();                     	//初始化LED 
    TIM3_PWM_Init(500-1,90-1);      	//90M/90=1M的计数频率,自动重装载为500,那么PWM频率为1M/500=2kHZ
    TIM5_CH1_Cap_Init(0XFFFFFFFF,90-1); //以1MHZ的频率计数
    while(1)
    {
        delay_ms(10);
		TIM_SetTIM3Compare4(TIM_GetTIM3Capture4()+1); 
		if(TIM_GetTIM3Capture4()==300)TIM_SetTIM3Compare4(0);        
        if(TIM5CH1_CAPTURE_STA&0X80)        //成功捕获到了一次高电平
		{
			temp=TIM5CH1_CAPTURE_STA&0X3F; 
			temp*=0XFFFFFFFF;		 	    //溢出时间总和
			temp+=TIM5CH1_CAPTURE_VAL;      //得到总的高电平时间
			printf("HIGH:%lld us\r\n",temp);//打印总的高点平时间
			TIM5CH1_CAPTURE_STA=0;          //开启下一次捕获
		}
    }
}

至此,输入捕获实验代码讲解完毕

标签:定时器,HAL,TIM5,捕获,TIM,Handler,原理,输入
From: https://www.cnblogs.com/L707/p/16802579.html

相关文章