STM32——输入捕获

输入捕获简介:
STM32F4除了基本定时器TIM6和TIM7,其他定时器都具有输入捕获功能。输入捕获可以对输入的信号的上升沿,下降沿或者双边沿进行捕获,通常用于测量输入信号的脉宽、测量 PWM 输入信号的频率及占空比。输入捕获的工作原理比较简单,在输入捕获模式下,当相应的 ICx 信号检测到跳变沿后,将使用捕获/比较寄存器(TIMx_CCRx)来锁存计数器的值。简单的说就是通过检测TIMx_CHx上的边沿信号,在边沿信号发生跳变(比如上升沿/下降沿)的时候,将当前定时器的值(TIMx_CNT)存放到对应的通道的捕获/比较寄存(TIMx_CCRx)里面,完成一次捕获。同时还可以配置捕获时是否触发中断/DMA 等。
在这里插入图片描述
最开始设置的捕获极性如果是上升沿的话,当捕获到上升沿的时候将计数器cnt置0,计数器开始计数,再设置捕获为下降沿捕获,当捕获到下降沿的时候将cnt的值给CCRx2中,在整个高电平的过程中cnt会产生溢出,溢出后又从0开始计数,所以需要几率溢出次数。
CNT计数的次数等于:N*ARR+CCRx2,有了这个计数次数,再乘以 CNT 的计数周期,即可得到 t2-t1 的时间长度,即高电平持续时间。
输入捕获配置步骤:
(1)使能定时器及端口时钟,并设置引脚复用器映射和引脚模式等

RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM5,ENABLE); 
GPIO_PinAFConfig(GPIOA,GPIO_PinSource0,GPIO_AF_TIM5);
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AF; //复用输出模式

在这里插入图片描述
(2)初始化定时器参数,包含自动重装值,分频系数,计数方式等

voidTIM_TimeBaseInit(TIM_TypeDef*TIMx,TIM_TimeBaseInitTypeDef* TIM_TimeBaseInitStruct);

(3)设置通用定时器的输入捕获参数,开启输入捕获功能

void TIM_ICInit(TIM_TypeDef* TIMx, TIM_ICInitTypeDef* 
TIM_ICInitStruct);
typedef struct
{
	uint16_t TIM_Channel; //通道
	uint16_t TIM_ICPolarity; //捕获极性
	uint16_t TIM_ICSelection;//映射
	uint16_t TIM_ICPrescaler;//分频系数
	uint16_t TIM_ICFilter; //滤波器长度
} TIM_ICInitTypeDef;
TIM_OC1PolarityConfig(TIM5,TIM_ICPolarity_Rising);

(4)开启捕获和定时器溢出(更新)中断

void TIM_ITConfig(TIM_TypeDef* TIMx, uint16_t TIM_IT, FunctionalState NewState)TIM_ITConfig(TIM5,TIM_IT_Update|TIM_IT_CC1,ENABLE);

(5)设置定时器中断优先级,使能定时器中断通道
NVIC初始化库函数是NVIC_Init()

(6)编写定时器中断服务函数

TIM5_IRQHandler
ITStatus TIM_GetITStatus(TIM_TypeDef* TIMx, uint16_t TIM_IT);
void TIM_ClearITPendingBit(TIM_TypeDef* TIMx, uint16_t TIM_IT);
TIM_SetCounter(TIM5,0); //定时器初值为0

(7)使能定时器

void TIM_Cmd(TIM_TypeDef* TIMx, FunctionalState NewState);

使用TIM5的CH1检测输入信号高电平脉宽,将检测的高电平脉宽时间通过printf函数打印出来,同时让D1指示灯不
断闪烁表示系统正常运行。由于TIM5的CH1与KEY_UP共用一个管脚,所以可以使用KEY_UP来产生输入信号。

input.c

#include "input.h"

u8 TIM5_CH1_CAPTURE_STA=0; //输入捕获的状态  在源文件中声明过的全局变量
u32 TIM5_CH1_CAPTURE_VAL=0;//输入捕获值(TIM2/TIM5是32位)


void TIM5_CH1_Input_Init(u32 arr,u16 psc)
{
	TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;//定时器参数结构体
	TIM_ICInitTypeDef TIM_ICInitStructure;//输入捕获结构体
	NVIC_InitTypeDef NVIC_InitStructure;//NVIC初始化结构体
	GPIO_InitTypeDef GPIO_InitStructure;//端口结构体
	
	RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA,ENABLE);//使能端口A时钟
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM5,ENABLE);//使能TIM5时钟
	
	GPIO_PinAFConfig(GPIOA,GPIO_PinSource0,GPIO_AF_TIM5);//管脚复用,将PA0映射到TIM5上
	
    //初始化PA0端口
	GPIO_InitStructure.GPIO_Pin=GPIO_Pin_0;//管脚设置
	GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AF; //复用输出模式
	GPIO_InitStructure.GPIO_Speed=GPIO_Speed_100MHz;//速度为100M
	GPIO_InitStructure.GPIO_OType=GPIO_OType_PP;//推挽输出
	GPIO_InitStructure.GPIO_PuPd=GPIO_PuPd_DOWN;//下拉
	GPIO_Init(GPIOA,&GPIO_InitStructure); //初始化结构体
	
	//初始化定时器参数
	TIM_TimeBaseInitStructure.TIM_Period=arr;   //自动装载值,定时器5是32位的注意形参大小
	TIM_TimeBaseInitStructure.TIM_Prescaler=psc; //分频系数
	TIM_TimeBaseInitStructure.TIM_ClockDivision=TIM_CKD_DIV1;  //时钟分割,时钟分频 通常不需要修改
	TIM_TimeBaseInitStructure.TIM_CounterMode=TIM_CounterMode_Up; //设置向上计数模式
	TIM_TimeBaseInit(TIM5,&TIM_TimeBaseInitStructure);	//初始化定时器5
	
	//设置通用定时器的输入捕获参数,开启输入捕获功能
	TIM_ICInitStructure.TIM_Channel=TIM_Channel_1; PA0是定时器5通道1
	TIM_ICInitStructure.TIM_ICFilter=0x00;  //不使用,直接设置成0
	TIM_ICInitStructure.TIM_ICPolarity=TIM_ICPolarity_Rising;//设置为上升沿捕获
	TIM_ICInitStructure.TIM_ICPrescaler=TIM_ICPSC_DIV1; //不分频,设置成1分频
	TIM_ICInitStructure.TIM_ICSelection=TIM_ICSelection_DirectTI;//直接映射到TI1
	TIM_ICInit(TIM5,&TIM_ICInitStructure);//初始化输入捕获结构体

	//配置溢出中断
	TIM_ITConfig(TIM5,TIM_IT_Update|TIM_IT_CC1,ENABLE);//开启更新和通道1捕获中断
	
	//配置中断通道
	NVIC_InitStructure.NVIC_IRQChannel = TIM5_IRQn;//中断通道
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=2;//抢占优先级
	NVIC_InitStructure.NVIC_IRQChannelSubPriority =0;		//子优先级
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;			//IRQ通道使能
	NVIC_Init(&NVIC_InitStructure);//根据指定的参数初始化VIC寄存器
		
	TIM_Cmd(TIM5,ENABLE); //使能定时器
}

//中断服务函数
void TIM5_IRQHandler(void)
{
	if((TIM5_CH1_CAPTURE_STA&0x80)==0) //最高位代表上升沿捕获完成,但是最开始肯定没有上升沿,所以为0
	{
		if(TIM_GetITStatus(TIM5,TIM_IT_Update)) //读取更新中断状态标志,读取溢出次数
		{
			if(TIM5_CH1_CAPTURE_STA&0X40)//捕获到了高电平
			{
				if((TIM5_CH1_CAPTURE_STA&0x3f)==0x3f) //高电平时间太长,说明后6位全部为1,累计到最大值
				{
					TIM5_CH1_CAPTURE_STA|=0x80; //标志一次捕获成功,时间过长强制让其捕获完成
					TIM5_CH1_CAPTURE_VAL=0xffffffff;
				}
				else
				{
					TIM5_CH1_CAPTURE_STA++;//没有累计到最大值,让其累加1
				}
			}
		}
		if(TIM_GetITStatus(TIM5,TIM_IT_CC1)) //发生捕获中断
		{
			if(TIM5_CH1_CAPTURE_STA&0X40)//捕获到了低电平,//次高位为表示已经捕获
			{
				TIM5_CH1_CAPTURE_STA|=0x80; //成功捕获一次高电平
				TIM5_CH1_CAPTURE_VAL=TIM_GetCapture1(TIM5);  //读取通道1ccrx的值
				TIM_OC1PolarityConfig(TIM5,TIM_ICPolarity_Rising); //设置上升沿捕获,//最开始肯定没有被捕获TIM5_CH1_CAPTURE_STA次高位肯定为0,进入else,进入上升沿捕获
			}
			else
			{
				TIM5_CH1_CAPTURE_STA=0;//置0防止干扰
				TIM5_CH1_CAPTURE_VAL=0;
				TIM5_CH1_CAPTURE_STA|=0x40; //捕获到高电平 标志   //设置次高位为1,让其为已经捕获的状态
				TIM_Cmd(TIM5,DISABLE);    //关闭定时器
				TIM_SetCounter(TIM5,0); //定时器初值置0
				TIM_OC1PolarityConfig(TIM5,TIM_ICPolarity_Falling); //设置下降沿捕获
				TIM_Cmd(TIM5,ENABLE);   //开启定时器
			}
		}
	}
	TIM_ClearITPendingBit(TIM5,TIM_IT_CC1|TIM_IT_Update);//清空中断标志位
}



input.h

#ifndef __input_H
#define __input_H

#include "system.h"

extern u8 TIM5_CH1_CAPTURE_STA;//保存输入捕获状态的标志,最高是否捕获成功,次高位是否捕获到上升沿,低六位累计溢出次数
extern u32 TIM5_CH1_CAPTURE_VAL; //保存输入捕获的值CCRx

void TIM5_CH1_Input_Init(u32 arr,u16 psc);
void TIM5IRQHandler(void);

#endif

main

#include "system.h"
#include "SysTick.h"
#include "led.h"
#include "usart.h"
#include "input.h"

int main()
{
	u8 i=0;
	long long indata=0;
	
	SysTick_Init(168);
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);  //中断优先级分组 分2组
	LED_Init();
	USART1_Init(9600);

	TIM5_CH1_Input_Init(0xffffffff,83);  //以1M频率计数
	
	while(1)
	{
		if(TIM5_CH1_CAPTURE_STA&0x80) //成功捕获
		{
			indata=TIM5_CH1_CAPTURE_STA&0x3f;
			indata*=0xffffffff; //溢出次数乘以一次的计数次数时间 us
			indata+=TIM5_CH1_CAPTURE_VAL;//加上高电平捕获的时间
			printf("高电平持续时间:%lld us\r\n",indata); //总的高电平时间
			TIM5_CH1_CAPTURE_STA=0; //开始下一次捕获
		}
		
		i++;
		if(i%20==0)
		{
			led1=!led1;
		}
		myDelay_ms(10);
	}
}

		 


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值