23_定时器输入捕获实验

目录

STM32输入捕获工作过程

输入捕获滤波器

设置输入捕获极性

设置捕获映射通道

设置输入捕获分频器

捕获到有效信号可以开启中断

频率计算:

输入捕获结构体详解

输入捕获相关函数

输入捕获的一般配置步骤:

实验代码:


STM32输入捕获工作过程

23_定时器输入捕获实验_第1张图片

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

23_定时器输入捕获实验_第2张图片

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

输入捕获滤波器

23_定时器输入捕获实验_第3张图片

 23_定时器输入捕获实验_第4张图片

 输入捕获1滤波器ICIF[3:0],这个用来设置输入采样频率和数字滤波器长度。其中,fck_INT是定时器的输入频率(TIMxCLK),一般为72Mhz,而fDTS则是根据TIMx_CRI的CKD[1:0]的设置来确定的,如果CKD[1:0]设置为00,那么fors=fck_INT。N值就是滤波长度

设置输入捕获极性

23_定时器输入捕获实验_第5张图片

 23_定时器输入捕获实验_第6张图片

 设置捕获映射通道

23_定时器输入捕获实验_第7张图片

 23_定时器输入捕获实验_第8张图片

如果CC1S设置为00通道1就被设置成输出.01就是CC1通道被配置位输入,映射到TI1上。

一般情况下我们都是通道1就是映射到IC1上,通道2就是映射到IC2上。

设置输入捕获分频器

23_定时器输入捕获实验_第9张图片

 23_定时器输入捕获实验_第10张图片

 捕获到有效信号可以开启中断

23_定时器输入捕获实验_第11张图片

简单说明:STM32的输入捕获,简单的说就是通过检测TIMx_CHx上的边沿信号,在边沿信号发生跳变(比如上升沿/下降沿)的时候,将当前定时器的值(TIMx_CNT)存放到对应的通道的捕获/比较寄存器(TIMx_CCRx)里面,完成一次捕获。先设置输入捕获为上升沿检测,记录发生上升沿的时候 TIMx_CNT 的值。然后配置捕获信号为下降沿捕获,当下降沿到来时,发生捕获,并记录此时的 TIMx_CNT 值。这样,前后两次 TIMx_CNT 之差,就是高电平的脉宽,同时 TIMx 的计数频率我们是知道的,从而可以计算出高电平脉宽的准确时间。

频率计算:

将捕获的模式设置为下降沿/上升沿捕获,当第一次捕获到上升沿/下降沿,则会触发中断,在中断中,把当前的计数值记录下来Value1;第二次捕获到上升沿/下降沿,再一次触发中断,在中断中我们把当前的计数值记录下来Value2。所以第二次捕获和第一次捕获之间的时间就是波的周期了。假设定时器的时钟被设置为72MHz,那么得到的波的频率应该为72MHz/(Value2 - Value1)。

输入捕获结构体详解

typedef struct
{
uint16_t TIM_Channel; //捕获通道1-4
uint16_t TIM_ICPolarity; //捕获极性
uint16_t TIM_ICSelection; //映射关系
uint16_t TIM_ICPrescaler; //分频系数
uint16_t TIM_ICFilter; //滤波器
}TIM_ICInitTypeDef;

输入捕获相关函数

输入捕获通道初始化函数

void TIM_ICInit(TIM_TypeDef* TIMx, TIM_ICInitTypeDef* TIM_ICInitStruct);

通道极性设置独立函数

void TIM_OCxPofarityConfig(TIM_TypeDef* TIMx, uint16_1 TIM_OCPolarity);

获取通道捕获值

uint32_t  TIM GetCapture 1(TIM_ TypeDef* TIMx):

输入捕获的一般配置步骤:

1.初始化定时器和通道对应IO的时钟。

2.初始化IO口,模式位输入:

GPIO_Init();

GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPD; //下拉输入

3.初始化定时器ARR,PSC

TIM_TimeBaselnit();

4.初始化输入捕获通道

TIM ICInit();

5.如果要开启捕获中断

TIM_ITConfig();

NVIC Init();

6.使能定时器

TIM_Cmd();

7.编写中断服务函数

TIMx_IRQHandler();

实验代码:

检测GPIOA.0引脚的高电平时间

/**
  ******************************************************************************
  * @file           : user_rcc_config.c
  * @brief          : V1.00
  ******************************************************************************
  * @attention
  *
  ******************************************************************************
  */

/* Include 包含---------------------------------------------------------------*/
#include "user_rcc_config.h"
/* Typedef 类型----------------------------------------------------------------*/
/* Define  定义----------------------------------------------------------------*/
/* Macro   宏------------------------------------------------------------------*/
/* Variables 变量--------------------------------------------------------------*/
/* Constants 常量--------------------------------------------------------------*/
/* Function  函数--------------------------------------------------------------*/

/*!
	\brief		定时器初始化
	\param[in]	none
	\param[in]	none
	\retval 	none
*/
void Rcc_config(void)
{	
	/*使能GPIOA时钟*/
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
	/*使能UART1时钟*/
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE);
	/*使能定时器5时钟*/
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM5,ENABLE);
	
	
}

/************************************************************** END OF FILE ****/
/**
  ******************************************************************************
  * @file           : user_gpio.c
  * @brief          : V1.00
  ******************************************************************************
  * @attention
  *
  ******************************************************************************
  */

/* Include 包含---------------------------------------------------------------*/
#include "user_gpio.h"
/* Typedef 类型----------------------------------------------------------------*/
/* Define  定义----------------------------------------------------------------*/
/* Macro   宏------------------------------------------------------------------*/
/* Variables 变量--------------------------------------------------------------*/
/* Constants 常量--------------------------------------------------------------*/
/* Function  函数--------------------------------------------------------------*/

/*!
	\brief		GPIO初始化函数
	\param[in]	none
	\param[out]	none
	\retval 	none
*/
void Gpio_Init(void)
{	
	/*GPIO结构体*/
	GPIO_InitTypeDef GPIO_InitTypeDefstruct;
	
	/*UART1发送引脚配置*/
	GPIO_InitTypeDefstruct.GPIO_Mode  = GPIO_Mode_AF_PP;//推挽复用输出
	GPIO_InitTypeDefstruct.GPIO_Pin   = GPIO_Pin_9;
	GPIO_InitTypeDefstruct.GPIO_Speed =	GPIO_Speed_10MHz;
	/*写入结构体到GPIOA*/
	GPIO_Init(GPIOA,&GPIO_InitTypeDefstruct);
	
	/*UART1接收引脚配置*/
	GPIO_InitTypeDefstruct.GPIO_Mode  = GPIO_Mode_IN_FLOATING;//浮空输入
	GPIO_InitTypeDefstruct.GPIO_Pin   = GPIO_Pin_10;
	GPIO_InitTypeDefstruct.GPIO_Speed =	GPIO_Speed_10MHz;
	/*写入结构体到GPIOA*/	
	GPIO_Init(GPIOA,&GPIO_InitTypeDefstruct);
	
	/*初始化PA0*/
	GPIO_InitTypeDefstruct.GPIO_Mode  = GPIO_Mode_IPD;//下拉输入
	GPIO_InitTypeDefstruct.GPIO_Pin   = GPIO_Pin_0;	
	/*写入结构体到GPIOA*/
	GPIO_Init(GPIOA,&GPIO_InitTypeDefstruct);
	
	/*设置为下拉输入*/
	GPIO_ResetBits(GPIOA,GPIO_Pin_0);
}

/************************************************************** END OF FILE ****/
/**
  ******************************************************************************
  * @file           : user_uart.c
  * @brief          : V1.00
  ******************************************************************************
  * @attention
  *
  ******************************************************************************
  */

/* Include 包含---------------------------------------------------------------*/
#include "user_uart.h"
/* Typedef 类型----------------------------------------------------------------*/
/* Define  定义----------------------------------------------------------------*/
/* Macro   宏------------------------------------------------------------------*/
/* Variables 变量--------------------------------------------------------------*/

extern uint16_t USART_RX_STA;
extern uint8_t USART_RX_BUF[200];


/* Constants 常量--------------------------------------------------------------*/
/* Function  函数--------------------------------------------------------------*/


#if 1
#pragma import(__use_no_semihosting)  
/*实现Printf代码*/
struct __FILE 
{ 
	int handle; 

}; 
FILE __stdout;       

void _sys_exit(int x) 
{ 
	x = x; 
} 
//重定义fputc函数 
int fputc(int ch, FILE *f)
{      
	while((USART1->SR&0X40)==0);//循环发送,直到发送完毕   
    USART1->DR = (u8) ch;      
	return ch;
}
#endif 





/*!
	\brief		UART1初始化
	\param[in]	none
	\param[out]	none
	\retval 	none
*/

void Uart1_Init(u32 bound)
{
	/*UART结构体*/
	USART_InitTypeDef USART_InitTypeDefstruct;
	
	/*UART结构体配置*/
	USART_InitTypeDefstruct.USART_BaudRate = bound; //波特率
	USART_InitTypeDefstruct.USART_HardwareFlowControl =USART_HardwareFlowControl_None; //不使用硬件流
	USART_InitTypeDefstruct.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;//发送接收使能
	USART_InitTypeDefstruct.USART_Parity = USART_Parity_No; //不使用奇偶校验
	USART_InitTypeDefstruct.USART_StopBits = USART_StopBits_1; //1个停止位
	USART_InitTypeDefstruct.USART_WordLength = USART_WordLength_8b; //8个数据位
	/*写入USART1*/
	USART_Init(USART1,&USART_InitTypeDefstruct);
	
	/*使能串口1*/
	USART_Cmd(USART1,ENABLE);

}


/*!
	\brief		UART1中断服务函数
	\param[in]	none
	\param[out]	none
	\retval 	none
*/

void USART1_IRQHandler(void)
{

}
	

/************************************************************** END OF FILE ****/
 
/**
  ******************************************************************************
  * @file           : user_timer.c
  * @brief          : V1.00
  ******************************************************************************
  * @attention
  *
  ******************************************************************************
  */

/* Include 包含---------------------------------------------------------------*/
#include "user_timer.h"
/* Typedef 类型----------------------------------------------------------------*/
/* Define  定义----------------------------------------------------------------*/
/* Macro   宏------------------------------------------------------------------*/
/* Variables 变量--------------------------------------------------------------*/
/*
因为捕获的高电平不知道是多久
有可能超过了定时器的时间还是
高电平所以弄了一个字节来记录
捕获完成、捕获到高电平、和定时器溢出次数
这样可以算出我们捕获的时间是多少
TIM5CH1_CAPTURE_STA
bit7   捕获完成标志 
bit6   捕获到高电平标志
bit5~0 捕获高电平定时器溢出的次数
*/
u8  TIM5CH1_CAPTURE_STA=0;	//输入捕获状态		    				
u16	TIM5CH1_CAPTURE_VAL;	//输入捕获值
/* Constants 常量--------------------------------------------------------------*/
/* Function  函数--------------------------------------------------------------*/

/*!
	\brief		定时器初始化
	\param[in]	装载值
	\param[in]	分频系数
	\retval 	none
*/
void Tim5_Input_Init(uint16_t arr, uint16_t psc)
{	
	/*定时器结构体*/
	TIM_TimeBaseInitTypeDef TIM_TimeBaseInitTypeDefstruct;
	/*定时器5输入捕获结构体*/
	TIM_ICInitTypeDef  TIM5_ICInitStructure;
	/*中断控制器结构体*/
   	NVIC_InitTypeDef NVIC_InitStructure;
	
	/*定时器初始化配置*/
	TIM_TimeBaseInitTypeDefstruct.TIM_Period = arr; //自动装载值
	TIM_TimeBaseInitTypeDefstruct.TIM_Prescaler = psc; //分频系数
	TIM_TimeBaseInitTypeDefstruct.TIM_CounterMode = TIM_CounterMode_Up;//向上计数模式
	TIM_TimeBaseInitTypeDefstruct.TIM_ClockDivision = TIM_CKD_DIV1;//时钟分频
	/*写入定时器5*/
	TIM_TimeBaseInit(TIM5,&TIM_TimeBaseInitTypeDefstruct);

	/*初始化定时器5输入捕获参数*/
	TIM5_ICInitStructure.TIM_Channel = TIM_Channel_1; //CC1S=01 选择输入端 IC1映射到TI1上
  	TIM5_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI; //映射到TI1上  	
	TIM5_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising;	//上升沿捕获
  	TIM5_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1;//配置输入分频,不分频就是有上升沿捕获,如果是分频2的话就是2次上升沿才开始捕获 
  	TIM5_ICInitStructure.TIM_ICFilter = 0x00;//IC1F=0000 配置输入滤波器 不滤波,不采集
  	
	/*写入定时器5输入捕获通道里面*/
	TIM_ICInit(TIM5, &TIM5_ICInitStructure);
	
	/*中断分组初始化*/
	NVIC_InitStructure.NVIC_IRQChannel = TIM5_IRQn; //TIM5中断
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2;//抢占优先级2
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; //子优先0级
	NVIC_InitStructure.NVIC_IRQChannelCmd =ENABLE; //使能输入捕获
	
	/*写入中断控制器中*/
	NVIC_Init(&NVIC_InitStructure);
	
	/*使能更新、允许CCC1IE捕获中断*/
	TIM_ITConfig(TIM5,TIM_IT_Update|TIM_IT_CC1,ENABLE);
	/*使能定时器*/
	TIM_Cmd(TIM5,ENABLE);
	
	
}

/*!
	\brief		TIM5_IRQHandler
	\param[in]	none
	\param[in]	none
	\retval 	none
*/

void TIM5_IRQHandler(void)
{
	/*判断是不是捕获到了一个高电平,是0的时候我们才开始有效计数,否则退出中断*/
	if((TIM5CH1_CAPTURE_STA & 0x80) == 0) //还未捕获完成
	{	/*判断是不是定时器到*/
		if (TIM_GetITStatus(TIM5, TIM_IT_Update) != RESET)		 
		{	 /*已经捕获到高电平了*/   
			if(TIM5CH1_CAPTURE_STA&0X40)
			{	/*高电平太长了,计数次数已经满了,直接强制标志成*/
				if((TIM5CH1_CAPTURE_STA&0X3F)==0X3F)
				{
					TIM5CH1_CAPTURE_STA|=0X80;//标记成功捕获了一次
					TIM5CH1_CAPTURE_VAL=0XFFFF;
				}
				else
				{	/*计数器更新事件加1,用于计算高电平时间
					TIM5CH1_CAPTURE_STA*定时器设定+TIM5CH1_CAPTURE_VAL =高平时间
					*/
					TIM5CH1_CAPTURE_STA++;
					
				} 

			}	 
		}
	}
	
	
	/*判断是不是捕获发生*/
	if (TIM_GetITStatus(TIM5, TIM_IT_CC1) != RESET)
	{	/*判断上一次是不是捕获到了高电平,如果上一次
		是高电平则这次就是捕获到了低电平
		*/
		if(TIM5CH1_CAPTURE_STA&0X40)		//捕获到一个下降沿 		
		{	  			
			TIM5CH1_CAPTURE_STA|=0X80;		//标记成功捕获到一次高电平脉宽
			TIM5CH1_CAPTURE_VAL=TIM_GetCapture1(TIM5); //把捕获比较寄存器的值保存起来用于计算时间
		   	TIM_OC1PolarityConfig(TIM5,TIM_ICPolarity_Rising); //CC1P=0 设置为上升沿捕获
		}else  		
		{	
			/*捕获到高电平*/
			TIM5CH1_CAPTURE_STA=0;	//清空
			TIM5CH1_CAPTURE_VAL=0;
	 		TIM_SetCounter(TIM5,0); //设置定时器计数为0开始记录高电平时间
			TIM5CH1_CAPTURE_STA|=0X40;		//标记捕获到了上升沿
		   	TIM_OC1PolarityConfig(TIM5,TIM_ICPolarity_Falling);		//CC1P=1 设置为下降沿捕获
		}		    
	}
	
	/*清除中断标志位*/
	TIM_ClearITPendingBit(TIM5, TIM_IT_CC1|TIM_IT_Update); 
}


/************************************************************** END OF FILE ****/

/**
  ******************************************************************************
  * @file           : user_mian.h
  * @brief          : V1.00
  ******************************************************************************
  * @attention
  *
  ******************************************************************************
  */

/* Include 包含---------------------------------------------------------------*/
#include "stm32f10x.h"
#include 
#include "user_gpio.h"
#include "user_delay.h"
#include "user_rcc_config.h"
#include "user_uart.h"
#include "user_timer.h"


/* Typedef 类型----------------------------------------------------------------*/
/* Define  定义----------------------------------------------------------------*/
/* Macro   宏------------------------------------------------------------------*/
/* Variables 变量--------------------------------------------------------------*/
//最多一次接收200个字节
uint8_t USART_RX_BUF[200];
//接收状态
//bit15,	接收完成标志
//bit14,	接收到0x0d
//bit13~0,	接收到的有效字节数目
uint16_t USART_RX_STA=0;       //接收状态标记	
extern u8  TIM5CH1_CAPTURE_STA;		//输入捕获状态		    				
extern u16	TIM5CH1_CAPTURE_VAL;	//输入捕获值	
/* Constants 常量--------------------------------------------------------------*/
/* Function  函数--------------------------------------------------------------*/


 int main(void)
 {	
	u32 temp=0;
	 
	/*配置系统中断分组为2位抢占2位响应*/
	 NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
	 /*延时函数初始化*/
	 delay_init();
	/*RCC配置*/
	 Rcc_config();
	/*GPIO初始化*/ 
	 Gpio_Init();
	/*USART1初始化*/
	 Uart1_Init(9600);
	 /*定时器5初始化*/
	 Tim5_Input_Init(0xFFFF,72-1); //以1Mhz的频率计数  计数器从0计数到FFFF才会溢出 一个时钟周期就是1us
	/*死循环*/ 
	 while(1){
			delay_ms(10);
		 /*成功捕获到了完成*/
		if(TIM5CH1_CAPTURE_STA&0X80)
		{	/*取溢出多少次*/
			temp=TIM5CH1_CAPTURE_STA&0X3F;
			/*因为每次计数器时间到都是FFFF换算成10进制就是65535*/
			temp*=65536;//溢出时间总和
			temp+=TIM5CH1_CAPTURE_VAL;//最后一次捕获到的+溢出时间总和 = 得到总的高电平时间 
			printf("HIGH:%d ms\r\n",temp/1000);//打印总的高点平时间
			TIM5CH1_CAPTURE_STA=0;//开启下一次捕获
		}

	 } 
		

}
 
 /************************************************************** END OF FILE ****/

 23_定时器输入捕获实验_第12张图片

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