STM32外部中断模拟输入捕获来测频率

由于功能添加且板子已经定型的原因,在原来没有定时器输入捕获的引脚上添加频率检测,便使用了STM32的外部中断与定时器的配合来做简单测量。

一、步骤:

1、初始化引脚的外部中断,我这里用了PA11和PA12两个引脚,void EXTI_PA11_PA12_Config(void),需要注意的是频率检测只使用上升沿触发即可,如果测量占空比,则采用双边沿检测;
2、初始化两个定时器,TIM4和TIM6, GENERAL_TIM4_Mode_Config(); BASIC_TIM6_Mode_Config();
这里需要注意的是:
(1)定时器的最小采样时间是根据时钟的分频系数相关的,比如时钟现在是72000000HZ,定时器分频系数是72-1,则分频后的定时器时钟为1000000HZ(即1us);
(2)最大采样间隔(即超过这个时间还没有采样到一个脉冲)是跟定时器的中断间隔相关的,定时器产生溢出中断后计数值CNT会自动清0,定时器的中断间隔由分频系数Prescaler和自动重装载寄存器Period决定,分频系数前面已经确定,那最大采样间隔只需要考虑自动重装载寄存器Period的设置,比如频分析系数72-1,自动重装寄存器值10000-1,则 中断间隔=72000000/72/10000=100HZ,即最大采样间隔10ms,如果10ms内没有检测到一个脉冲,则这么设定间隔是不合理的,必须想办法牺牲最小的采样时间1us(扩大分频系数)或者扩大自动重装寄存器值(16位,<65535)来增加定时器中断间隔,也可以编写自己的应用函数来计算溢出的定时时间。
3.编写外部中断函数void EXTI15_10_IRQHandler(void);
来一次脉冲上升沿则会触发一次外部中断,定时器的时钟一直运行着,CNT计数值++,计算两次的CNT差值然后根据定时器时钟即可算出频率;
4.编写定时器中断函数,这部分主要是应用,根据项目的要求,在没有接收到脉冲后1s需要清零计数值,这里清零的地方正好放在定时器中断中处理。

仿真:
在这里插入图片描述
信号发生器:
在这里插入图片描述

二、代码:

TimeInput.c

/**
  ******************************************************************************
  * @file    TimeInput.c
  * @author  davidysw
  * @version V1.0
  * @date    2019-12-xx
  * @brief   定时器输入捕获
  * @brief	 
  ******************************************************************************
**/

#include "TimeInput.h"

float FrequencyPA11;	//输入脉冲的频率HZ
float FrequencyPA12;	//输入脉冲的频率HZ
uint16_t PA11_Counter1=0;
uint16_t PA12_Counter1=0;
uint16_t ClearPA11Count=0;//用来计数,2s内不在有脉冲进入则清零 测速值
uint16_t ClearPA12Count=0;//用来计数,2s内不在有脉冲进入则清零 测速值
/***************************************************
//中断优先级配置
*****************************************************/
static void GENERAL_TIM4_NVIC_Config(void)
{
    NVIC_InitTypeDef NVIC_InitStructure; 
    // 设置中断组为0
    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);		
		// 设置中断来源
    NVIC_InitStructure.NVIC_IRQChannel = GENERAL_TIM4_IRQ ;	
		// 设置主优先级为 0
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 3;	 
	  // 设置抢占优先级为3
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;	
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init(&NVIC_InitStructure);
}
/***************************************************
//定时器配置
*****************************************************/
static void GENERAL_TIM4_Mode_Config(void)
{
	TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
	
	GENERAL_TIM4_NVIC_Config();	
		// 开启定时器时钟,即内部时钟CK_INT=72M
    GENERAL_TIM4_APBxClock_FUN(GENERAL_TIM4_CLK, ENABLE);	
		// 自动重装载寄存器的值,累计TIM_Period+1个频率后产生一个更新或者中断
    TIM_TimeBaseStructure.TIM_Period=GENERAL_TIM4_Period;
	  // 时钟预分频数
    TIM_TimeBaseStructure.TIM_Prescaler= GENERAL_TIM4_Prescaler;	
		// 时钟分频因子 ,没用到不用管
    TIM_TimeBaseStructure.TIM_ClockDivision=TIM_CKD_DIV1;		
		// 计数器计数模式,设置为向上计数
    TIM_TimeBaseStructure.TIM_CounterMode=TIM_CounterMode_Up; 		
		// 重复计数器的值,没用到不用管
	TIM_TimeBaseStructure.TIM_RepetitionCounter=0;	
	  // 初始化定时器
    TIM_TimeBaseInit(GENERAL_TIM4, &TIM_TimeBaseStructure);
	
		// 清除计数器中断标志位
    TIM_ClearFlag(GENERAL_TIM4, TIM_FLAG_Update);
	  
		// 开启计数器中断
    TIM_ITConfig(GENERAL_TIM4,TIM_IT_Update,ENABLE);
		
		// 使能计数器
    TIM_Cmd(GENERAL_TIM4, ENABLE);
}
/***************************************************
//中断优先级配置
*****************************************************/
static void BASIC_TIM6_NVIC_Config(void)
{
    NVIC_InitTypeDef NVIC_InitStructure; 
    // 设置中断组为0
    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);		
		// 设置中断来源
    NVIC_InitStructure.NVIC_IRQChannel = BASIC_TIM6_IRQ ;	
		// 设置主优先级为 0
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;	 
	  // 设置抢占优先级为3
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;	
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init(&NVIC_InitStructure);
}
/***************************************************
//定时器配置
*****************************************************/
static void BASIC_TIM6_Mode_Config(void)
{
    TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
		
	BASIC_TIM6_NVIC_Config();
		// 开启定时器时钟,即内部时钟CK_INT=72M
    BASIC_TIM6_APBxClock_FUN(BASIC_TIM6_CLK, ENABLE);
	
		// 自动重装载寄存器的值,累计TIM_Period+1个频率后产生一个更新或者中断
    TIM_TimeBaseStructure.TIM_Period = BASIC_TIM6_Period;	

	  // 时钟预分频数为
    TIM_TimeBaseStructure.TIM_Prescaler= BASIC_TIM6_Prescaler;
	
		// 时钟分频因子 ,基本定时器没有,不用管
    //TIM_TimeBaseStructure.TIM_ClockDivision=TIM_CKD_DIV1;
		
		// 计数器计数模式,基本定时器只能向上计数,没有计数模式的设置
    //TIM_TimeBaseStructure.TIM_CounterMode=TIM_CounterMode_Up; 
		
		// 重复计数器的值,基本定时器没有,不用管
		//TIM_TimeBaseStructure.TIM_RepetitionCounter=0;
	
	  // 初始化定时器
    TIM_TimeBaseInit(BASIC_TIM6, &TIM_TimeBaseStructure);
		
		// 清除计数器中断标志位
    TIM_ClearFlag(BASIC_TIM6, TIM_FLAG_Update);
	  
		// 开启计数器中断
    TIM_ITConfig(BASIC_TIM6,TIM_IT_Update,ENABLE);
		
		// 使能计数器
    TIM_Cmd(BASIC_TIM6, ENABLE);	
}

/***************************************************
//引脚输入初始化
*****************************************************/	
void GPIO_NVIC_Configuration(void)
{
  NVIC_InitTypeDef NVIC_InitStructure;
  
  /* 配置NVIC为优先级组1 */
  NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0);
  
  /* 配置中断源:PA11、PA12 */
  NVIC_InitStructure.NVIC_IRQChannel = EXTI15_10_IRQn;
  /* 配置抢占优先级 */
  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
  /* 配置子优先级 */
  NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
  /* 使能中断通道 */
  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
	
  NVIC_Init(&NVIC_InitStructure);
}

 /**
  * @brief  配置 IO为EXTI中断口,并设置中断优先级
  * @param  无
  * @retval 无
  */
void EXTI_PA11_PA12_Config(void)
{
	GPIO_InitTypeDef GPIO_InitStructure; 
	EXTI_InitTypeDef EXTI_InitStructure;

	/*开启GPIO口的时钟*/
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_AFIO,ENABLE);
									
	/* 配置 NVIC 中断*/
	GPIO_NVIC_Configuration();
	
/*--------------------------配置-----------------------------*/
	/* 选择按键用到的GPIO */	
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11;
  /* 配置为浮空输入 */	
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
  GPIO_Init(GPIOA, &GPIO_InitStructure);

	/* 选择EXTI的信号源 */
  GPIO_EXTILineConfig(GPIO_PortSourceGPIOA, GPIO_PinSource11); 
  EXTI_InitStructure.EXTI_Line = EXTI_Line11;
	
	/* EXTI为中断模式 */
  EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
	/* 上升沿中断 */
  EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising;
  /* 使能中断 */	
  EXTI_InitStructure.EXTI_LineCmd = ENABLE;
  EXTI_Init(&EXTI_InitStructure);
	
  /*--------------------------配置-----------------------------*/
	/* 选择按键用到的GPIO */	
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12;
  /* 配置为浮空输入 */	
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
  GPIO_Init(GPIOA, &GPIO_InitStructure);

	/* 选择EXTI的信号源 */
  GPIO_EXTILineConfig(GPIO_PortSourceGPIOA, GPIO_PinSource12); 
  EXTI_InitStructure.EXTI_Line = EXTI_Line12;
	
	/* EXTI为中断模式 */
  EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
	/* 下降沿中断 */
  EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising;
  /* 使能中断 */	
  EXTI_InitStructure.EXTI_LineCmd = ENABLE;
  EXTI_Init(&EXTI_InitStructure);
}
	
	
/***************************************************
//定时器初始化,定时10us
*****************************************************/
	
void TIME_INPUT_Init(void)
{
	GENERAL_TIM4_Mode_Config();
	BASIC_TIM6_Mode_Config();
	EXTI_PA11_PA12_Config();
}	


/***************************************************
//PA11、PA12外部中断,上升沿检测,计数脉冲精度1us,与定时器分频有关,最大脉冲间隔与定时器计数值有关,10000即10ms
*****************************************************/	
void EXTI15_10_IRQHandler(void)
{
  //确保是否产生了EXTI Line中断
	if(EXTI_GetITStatus(EXTI_Line11) != RESET) 
	{	  
		FrequencyPA11=1000000/(TIM4->CNT-PA11_Counter1);
		TIM4->CNT=0;
		PA11_Counter1=TIM4->CNT;
    	ClearPA11Count=0;
		EXTI_ClearITPendingBit(EXTI_Line11); //清除中断标志位    
	} 
	
	if(EXTI_GetITStatus(EXTI_Line12) != RESET) 
	{	
		FrequencyPA12=1000000/(TIM6->CNT-PA12_Counter1);
		TIM6->CNT=0;
		PA12_Counter1=TIM6->CNT;
    	ClearPA12Count=0;
		EXTI_ClearITPendingBit(EXTI_Line12);//清除中断标志位     
	} 	
}
/***************************************************
//定时器中断
*****************************************************/	
void  TIM4_IRQHandler (void)
{
	if ( TIM_GetITStatus( GENERAL_TIM4, TIM_IT_Update) != RESET ) 
	{	
			ClearPA11Count++;
			if(ClearPA11Count>100)//1s
			{
				ClearPA11Count=0;
				PA11_Counter1=0;
				FrequencyPA11=0;
			}
			TIM_ClearITPendingBit(GENERAL_TIM4 , TIM_FLAG_Update);  		 
	}		 	
}	

void  TIM6_IRQHandler (void)
{
	if ( TIM_GetITStatus( BASIC_TIM6, TIM_IT_Update) != RESET ) 
	{		
			
			ClearPA12Count++;
			if(ClearPA12Count>100)	//1s
			{
				ClearPA12Count=0;
				PA12_Counter1=0;
				FrequencyPA12=0;
			}
		TIM_ClearITPendingBit(BASIC_TIM6 , TIM_FLAG_Update);  		 
	}		 	
}	

TimeInput.h

#ifndef _TIMEINPUT_H
#define _TIMEINPUT_H

#include "stm32f10x.h"

#define            GENERAL_TIM4                   TIM4
#define            GENERAL_TIM4_APBxClock_FUN     RCC_APB1PeriphClockCmd
#define            GENERAL_TIM4_CLK               RCC_APB1Periph_TIM4
#define            GENERAL_TIM4_Period            (10000-1)
#define            GENERAL_TIM4_Prescaler         72-1
#define            GENERAL_TIM4_IRQ               TIM4_IRQn
#define            GENERAL_TIM4_IRQHandler        TIM4_IRQHandler

#define            BASIC_TIM6                   TIM6
#define            BASIC_TIM6_APBxClock_FUN     RCC_APB1PeriphClockCmd
#define            BASIC_TIM6_CLK               RCC_APB1Periph_TIM6
#define            BASIC_TIM6_Period            10000-1
#define            BASIC_TIM6_Prescaler         71
#define            BASIC_TIM6_IRQ               TIM6_IRQn
#define            BASIC_TIM6_IRQHandler        TIM6_IRQHandler

extern void TIME_INPUT_Init(void);
#endif

  • 7
    点赞
  • 58
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值