【STM32】(9) 输入捕获实验(含输入捕获简介和代码及分析)

一、实验目的

用TIM5的通道1(PA0)来做输入捕获,捕获PA0上高电平的脉宽(用KEY_UP按键输入高电平),通过串口打印高电平脉宽时间。

二、输入捕获简介

三、代码及分析

timer.c

#include "timer.h"

TIM_HandleTypeDef  TIM5_Handler;      // 定时器5句柄

// arr 自动重装载值(TIM5、TIM2是32位的)
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时基参数
	// 设置TIM5输入捕获参数
	
	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);
	
	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()调用

void HAL_TIM_IC_MspInit(TIM_HandleTypeDef *htim)
{
	GPIO_InitTypeDef GPIO_Initure;
	if(htim->Instance==TIM5)
	{
	
     __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_CH1
	HAL_GPIO_Init(GPIOA,&GPIO_Initure);	   	//初始化PA0
		
	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,溢出时间:4294s)

u8 TIM5CH1_CAPTURE_STA = 0;  //	输入捕获状态
u32 TIM5CH1_CAPTURE_VAL;   //输入捕获值(TIM5/TIM2是32位)

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
			}		    
	}	
}

main.c


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

int main(void)
{
    long long temp=0;   
    Cache_Enable();                 //打开L1-Cache
    HAL_Init();				        //初始化HAL库
    Stm32_Clock_Init(432,25,2,9);   //设置时钟,216Mhz 
    delay_init(216);                //延时初始化
	uart_init(115200);		        //串口初始化
    LED_Init();                     //初始化LED
    
    TIM5_CH1_Cap_Init(0XFFFFFFFF,108-1); //以1MHZ的频率计数
    while(1)
    {
               
        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;          //开启下一次捕获
		}
    } 
}

(1)自己定义一个 TIM5_CH1_Cap_Init(u32 arr, u16 psc)函数,调用函数HAL_TIM_IC_Init(&TIM5_Handler)进行时基部分的初始化。再调用HAL_TIM_IC_ConfigChannel(&TIM5_Handler,&TIM5_CH1Config,TIM_CHANNEL_1)设置TIM5输入捕获参数初始化。HAL_TIM_IC_Start_IT(&TIM5_Handler, TIM_CHANNEL_1); //开启TIM5的捕获通道1,并且开启捕获中断__HAL_TIM_ENABLE_IT(&TIM5_Handler, TIM_IT_UPDATE);//使能更新中断

(2)编写 HAL_TIM_IC_MspInit(TIM_HandleTypeDef *htim)函数,此函数会被HAL_TIM_IC_Init()调用。进行定时器5底层驱动,时钟使能,引脚配置。并开启TIM5中断,设置中断优先级。

(3)编写中断服务函数TIM5_IRQHandler (void),此函数内部又会调用 HAL_TIM_IRQHandler (&TIM5_Handler);//定时器公用处理函数

(4)此函数HAL_TIM_IRQHandler (&TIM5_Handler) 内部会对中断类型进行判断,会调用HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim)//定时器输入捕获中断处理回调函数和HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)//定时器更新中断(计数溢出)中断处理回调函数。而真正的逻辑会在这两个中断回调函数中编写。

在定时器更新中断(计数溢出)中断处理回调函数中:

(TIM5CH1_CAPTURE_STA&0X80)==0 为真,表示位[7] 位0,没有成功捕获;

TIM5CH1_CAPTURE_STA&0X40为真,则表示位[6] 位1,已经捕获到高电平;

(TIM5CH1_CAPTURE_STA&0X3F)==0X3F为真,则说明高电平太长了,定时器一直在溢出。然后TIM5CH1_CAPTURE_STA|=0X80;    标记成功捕获了一次。把输入捕获的值设为TIM5CH1_CAPTURE_VAL=0XFFFFFFFF;

在定时器输入捕获中断处理回调函数中:

若还未开始,第一次捕获到上升沿,首先把状态标识为和输入捕获的值清零。

TIM5CH1_CAPTURE_STA=0;     

TIM5CH1_CAPTURE_VAL=0;

标记捕获了上升沿:TIM5CH1_CAPTURE_STA|=0X40;   

此时,关闭定时器5:__HAL_TIM_DISABLE(&TIM5_Handler);        
 计数器的值设为0:              __HAL_TIM_SET_COUNTER(&TIM5_Handler,0);
 一定要先清除原来的设置:   TIM_RESET_CAPTUREPOLARITY(&TIM5_Handler,TIM_CHANNEL_1);  
定时器5通道1设置为下降沿捕获:                TIM_SET_CAPTUREPOLARITY(&TIM5_Handler,TIM_CHANNEL_1,TIM_ICPOLARITY_FALLING);
 使能定时器5  :             __HAL_TIM_ENABLE(&TIM5_Handler);

若 (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上升沿捕获

在主函数中:

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;                       //开启下一次捕获
        }

  • 4
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值