精华内容
下载资源
问答
  • 运用TIMER ETR的外部脉冲捕获方式,3通道定时器去采集脉冲数值,K值为脉冲数,用的是ZET6芯片,亲可行 频率范围:1-50khz 误差:1-50khz ±1HZ 50-100KZH ±4HZ 100KZH-500KZH ±20HZ
  • stm32 测频率外部中断(低频)输入捕获模式(中高频)外部计数器模式(高频) 准备电赛的过程中,尝试了几种测量频率的方法,也参考了一些博主,没有一种可以测量范围很广的方法,那就都尝试一下,需要什么就用什么...


    准备电赛的过程中,尝试了几种测量频率的方法,也参考了一些博主,没有一种可以测量范围很广的方法,那就都尝试一下,需要什么就用什么吧。

    下面的代码都是我运行成功的,可以测量

    平台:stm32F407

    外部中断(低频)

    第一个想到的就是外部中断,也是最简单的方式,在每一个上升沿或者下降沿进入一次中断,定时统计进入中断的次数,即可算出频率,如果需要计算出占空比,可以在用另外一个定时器测量上升沿和下降沿的时间就可以啦,
    下面贴出外部中断和定时器的代码,在低频时很不错,但是50KHZ之后太不行了,误差好大,频繁进入中断,只能测测低频啦

    下面展示一些 内联代码片
    TIM4_Int_Init(10000-1,8400-1);//*外部中断测频率 PA0

    // A code block
    /**
      * @brief 外部中断测频率
      * @param  
      * @retval 
      */
    void TIM4_Int_Init(u16 arr,u16 psc)
    {
    	TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;
    	NVIC_InitTypeDef NVIC_InitStructure;
    	
    	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4,ENABLE);  ///使能TIM3时钟
    	
      TIM_TimeBaseInitStructure.TIM_Period = arr; 	//自动重装载值
    	TIM_TimeBaseInitStructure.TIM_Prescaler=psc;  //定时器分频
    	TIM_TimeBaseInitStructure.TIM_CounterMode=TIM_CounterMode_Up; //向上计数模式
    	TIM_TimeBaseInitStructure.TIM_ClockDivision=TIM_CKD_DIV1; 
    	
    	TIM_TimeBaseInit(TIM4,&TIM_TimeBaseInitStructure);//初始化TIM2
    	
    	TIM_ITConfig(TIM4,TIM_IT_Update,ENABLE); //允许定时器2更新中断
    	TIM_Cmd(TIM4,ENABLE); //使能定时器3
    	
    	NVIC_InitStructure.NVIC_IRQChannel=TIM4_IRQn; //定时器3中断
    	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=0x01; //抢占优先级1
    	NVIC_InitStructure.NVIC_IRQChannelSubPriority=0x03; //子优先级3
    	NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE;
    	NVIC_Init(&NVIC_InitStructure);
    	
    }
    
    void TIM4_IRQHandler(void)
    {
    	
    	if(TIM_GetITStatus(TIM4,TIM_IT_Update)==SET) //溢出中断
    	{
      	LCD_ShowNum(60,60,freq,8,16);
    		freq=0;
    
    	}
    	
    	TIM_ClearITPendingBit(TIM4,TIM_IT_Update);  //清除中断标志位
    }
    
    
    // An highlighted block
    //外部中断初始化程序
    void EXTIX_Init(void)
    {
    	NVIC_InitTypeDef   NVIC_InitStructure;
    	EXTI_InitTypeDef   EXTI_InitStructure;
    	KEY_Init(); //按键对应的IO口初始化
    	RCC_APB2PeriphClockCmd(RCC_APB2Periph_SYSCFG, ENABLE);//使能SYSCFG时钟
    	
    	
    	
    	GPIO_InitTypeDef  GPIO_InitStructure;
    	RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);
       GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
    	GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IN;
    	GPIO_InitStructure.GPIO_Speed=GPIO_High_Speed;
      GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_DOWN ;
      GPIO_Init(GPIOA, &GPIO_InitStructure);
    	SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOA, EXTI_PinSource0);
    	/* 配置EXTI_Line0 */
      EXTI_InitStructure.EXTI_Line = EXTI_Line0;//LINE0
      EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;//中断事件
      EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising; //上升沿触发 
      EXTI_InitStructure.EXTI_LineCmd = ENABLE;//使能LINE0
      EXTI_Init(&EXTI_InitStructure);//配置
    		NVIC_InitStructure.NVIC_IRQChannel = EXTI0_IRQn;//外部中断0
      NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x02;//抢占优先级2
      NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x02;//子优先级2
      NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;//使能外部中断通道
      NVIC_Init(&NVIC_InitStructure);//配置
    }
    
    //外部中断0服务程序
    void EXTI0_IRQHandler(void)
    {
    	 
    //   if(GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_0) == 1){
    //	    GPIO_ResetBits(GPIOA,GPIO_Pin_6 | GPIO_Pin_7);
    //	 }
    	 freq++;
    	 EXTI_ClearITPendingBit(EXTI_Line0); //清除LINE0上的中断标志位 
    }	
    
    

    输入捕获模式(中高频)

    既然是测频率,自然会想到定时器的输入捕获模式,本以为这个还不错,但是超过100KHZ误差就很大了,测中高频是可以的。
    这个我参考了野火的程序
    输入捕获可以对输入信号的上升沿、下降沿、双边沿进行捕获,用于测量脉宽、频率、占空比
    当相应的 ICx 信号检测到跳变沿后,将使用捕获/比较寄存器(TIMx_CCRx)来锁存计数器的值。通过检测 TIMx_CHx 上的边沿信号,在边沿信号发生跳变(比如上升沿/下降沿)的时候,将当前定时器的值(TIMx_CNT)存放到对应的通道的捕获/比较寄存(TIMx_CCRx)里面,完成一次捕获。同时还可以配置捕获时是否触发中断/DMA 等。通过对上升沿下降沿捕获的值来计算需要的值
    下面展示一些 内联代码片
    // TIM8_Configuration();//输入捕获模式测频率

    
    // A code block
    **
      * @brief 定时器输入捕获模式
      * @param  
      * @retval 
      */
    /**
      * @brief  配置TIM复用输出PWM时用到的I/O
      * @param  无
      * @retval 无
      */
    static void TIMx_GPIO_Config(void) 
    {
    	/*定义一个GPIO_InitTypeDef类型的结构体*/
    	GPIO_InitTypeDef GPIO_InitStructure;
    
    	/*开启LED相关的GPIO外设时钟*/
    	RCC_AHB1PeriphClockCmd (GENERAL_OCPWM_GPIO_CLK, ENABLE); 
    	RCC_AHB1PeriphClockCmd (ADVANCE_ICPWM_GPIO_CLK, ENABLE); 	
    
    	/* 定时器复用引脚 */
    	GPIO_PinAFConfig(GENERAL_OCPWM_GPIO_PORT,GENERAL_OCPWM_PINSOURCE,GENERAL_OCPWM_AF); 
    	GPIO_PinAFConfig(ADVANCE_ICPWM_GPIO_PORT,ADVANCE_ICPWM_PINSOURCE,ADVANCE_ICPWM_AF); 
    	
    	/* 通用定时器PWM输出引脚 */															   
    	GPIO_InitStructure.GPIO_Pin = GENERAL_OCPWM_PIN;	
    	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;    
    	GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
    	GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
    	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz; 
    	GPIO_Init(GENERAL_OCPWM_GPIO_PORT, &GPIO_InitStructure);
    	
    	/* 高级控制定时器PWM输入捕获引脚 */
    	GPIO_InitStructure.GPIO_Pin = ADVANCE_ICPWM_PIN;	
    	GPIO_Init(ADVANCE_ICPWM_GPIO_PORT, &GPIO_InitStructure);
    }
    
     /**
      * @brief  高级控制定时器 TIMx,x[1,8]中断优先级配置
      * @param  无
      * @retval 无
      */
    static void TIMx_NVIC_Configuration(void)
    {
        NVIC_InitTypeDef NVIC_InitStructure; 
        // 设置中断组为0
        NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);		
    		// 设置中断来源
        NVIC_InitStructure.NVIC_IRQChannel = ADVANCE_TIM_IRQn; 	
    		// 设置抢占优先级
        NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;	 
    	  // 设置子优先级
        NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;	
        NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
        NVIC_Init(&NVIC_InitStructure);
    	  NVIC_InitStructure.NVIC_IRQChannel = TIM5_IRQn;
    	 NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;	
    	 NVIC_Init(&NVIC_InitStructure);
     	
    }
    static void TIM_PWMOUTPUT_Config(void)
    {
    	TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
      TIM_OCInitTypeDef  TIM_OCInitStructure;
    	
    	// 开启TIMx_CLK,x[2,3,4,5,12,13,14] 
      RCC_APB1PeriphClockCmd(GENERAL_TIM_CLK, ENABLE); 
    
      /* 累计 TIM_Period个后产生一个更新或者中断*/		
      //当定时器从0计数到9999,即为10000次,为一个定时周期
      TIM_TimeBaseStructure.TIM_Period = 10000-1;       
    	
    	// 通用定时器2时钟源TIMxCLK = HCLK/2=84MHz 
    	// 设定定时器频率为=TIMxCLK/(TIM_Prescaler+1)=100KHz
      TIM_TimeBaseStructure.TIM_Prescaler = 840-1;	
      // 采样时钟分频
      TIM_TimeBaseStructure.TIM_ClockDivision=TIM_CKD_DIV1;
      // 计数方式
      TIM_TimeBaseStructure.TIM_CounterMode=TIM_CounterMode_Up;
    	
    	// 初始化定时器TIMx, x[1,8]
    	TIM_TimeBaseInit(GENERAL_TIM, &TIM_TimeBaseStructure);
    	
    	/* PWM输出模式配置 */
    	/* 配置为PWM模式1 */
      TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;	    
      TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;	
    	/* PWM脉冲宽度 */
      TIM_OCInitStructure.TIM_Pulse = 3000-1;
      TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;
    	/* 使能通道1 */
      TIM_OC1Init(GENERAL_TIM, &TIM_OCInitStructure);	
    	/*使能通道1重载*/
    	TIM_OC1PreloadConfig(GENERAL_TIM, TIM_OCPreload_Enable);
    	// 使能定时器
    	TIM_Cmd(GENERAL_TIM, ENABLE);	
    }
    
    static void TIM_PWMINPUT_Config(void)
    {
    	TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
    	TIM_ICInitTypeDef  TIM_ICInitStructure;
    	
    	// 开启TIMx_CLK,x[1,8] 
      RCC_APB2PeriphClockCmd(ADVANCE_TIM_CLK, ENABLE); 
    	
    	TIM_TimeBaseStructure.TIM_Period = 0xFFFF-1; 	
    	// 高级控制定时器时钟源TIMxCLK = HCLK=168MHz 
    	// 设定定时器频率为=TIMxCLK/(TIM_Prescaler+1)=100KHz
      TIM_TimeBaseStructure.TIM_Prescaler = 168-1;	
      // 计数方式
      TIM_TimeBaseStructure.TIM_CounterMode=TIM_CounterMode_Up;	
    	// 初始化定时器TIMx, x[1,8]
    	TIM_TimeBaseInit(ADVANCE_TIM, &TIM_TimeBaseStructure);
    	
    	/* IC1捕获:上升沿触发 TI1FP1 */
      TIM_ICInitStructure.TIM_Channel = ADVANCE_IC1PWM_CHANNEL;
      TIM_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising;
      TIM_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI;
      TIM_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1;
      TIM_ICInitStructure.TIM_ICFilter = 0x0;
      TIM_PWMIConfig(ADVANCE_TIM, &TIM_ICInitStructure);
    	
    	/* IC2捕获:下降沿触发 TI1FP2 */	
    	TIM_ICInitStructure.TIM_Channel = ADVANCE_IC2PWM_CHANNEL;
      TIM_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Falling;
      TIM_ICInitStructure.TIM_ICSelection = TIM_ICSelection_IndirectTI;
      TIM_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1;
      TIM_ICInitStructure.TIM_ICFilter = 0x0;
      TIM_PWMIConfig(ADVANCE_TIM, &TIM_ICInitStructure);
    	
    	/* 选择定时器输入触发: TI1FP1 */
      TIM_SelectInputTrigger(ADVANCE_TIM, TIM_TS_TI1FP1);		
    
      /* 选择从模式: 复位模式 */
      TIM_SelectSlaveMode(ADVANCE_TIM, TIM_SlaveMode_Reset);
      TIM_SelectMasterSlaveMode(ADVANCE_TIM,TIM_MasterSlaveMode_Enable);
    
      /* 使能高级控制定时器 */
      TIM_Cmd(ADVANCE_TIM, ENABLE);
    
      /* 使能捕获/比较2中断请求 */
      TIM_ITConfig(ADVANCE_TIM, TIM_IT_CC1, ENABLE);
    }
    
    
    /**
      * @brief  初始化高级控制定时器定时,1ms产生一次中断
      * @param  无
      * @retval 无
      */
    void TIM8_Configuration(void)
    {
    	TIMx_GPIO_Config();
    	
    	TIMx_NVIC_Configuration();	
      
      TIM_PWMOUTPUT_Config();
    	
    	TIM_PWMINPUT_Config();
    	printf("TIMx_Configuration_ok\n");
    }
    void  ADVANCE_TIM_IRQHandler (void)
    {
    
      TIM_ClearITPendingBit(ADVANCE_TIM, TIM_IT_CC1);
    
      IC1Value = TIM_GetCapture1(ADVANCE_TIM);
      IC2Value = TIM_GetCapture2(ADVANCE_TIM);	
    //printf("IC1Value = %d  IC2Value = %d ",IC1Value,IC2Value);
    //		LCD_ShowNum(0,60,IC1Value,8,16);
    //		LCD_ShowNum(70,70,IC1Value,8,16);
      if (IC1Value != 0)
      {
        
        DutyCycle = (float)(IC2Value * 100) / IC1Value;
    
        Frequency = 168000000/168/(float)IC1Value;
    		printf("占空比:%0.2f%%   频率:%0.2fHz\n",DutyCycle,Frequency);
    		LCD_ShowNum(10,20,DutyCycle,8,16);
    		LCD_ShowNum(60,40,Frequency,8,16);
      }
      else
      {
        DutyCycle = 0;
        Frequency = 0;
      }
    }
    
    // An highlighted block
    
     void PWM1_Intput_Mode_Config(void);
     /* 通用定时器PWM输出 */
    /* PWM输出引脚 */
    #define GENERAL_OCPWM_PIN             GPIO_Pin_5              
    #define GENERAL_OCPWM_GPIO_PORT       GPIOA                      
    #define GENERAL_OCPWM_GPIO_CLK        RCC_AHB1Periph_GPIOA
    #define GENERAL_OCPWM_PINSOURCE				GPIO_PinSource5
    #define GENERAL_OCPWM_AF							GPIO_AF_TIM2
    
    /* 通用定时器 */
    #define GENERAL_TIM           		    TIM2
    #define GENERAL_TIM_CLK       		    RCC_APB1Periph_TIM2
    
    /* 高级控制定时器PWM输入捕获 */
    /* PWM输入捕获引脚 */
    #define ADVANCE_ICPWM_PIN             GPIO_Pin_6            
    #define ADVANCE_ICPWM_GPIO_PORT       GPIOC                      
    #define ADVANCE_ICPWM_GPIO_CLK        RCC_AHB1Periph_GPIOC
    #define ADVANCE_ICPWM_PINSOURCE				GPIO_PinSource6
    #define ADVANCE_ICPWM_AF							GPIO_AF_TIM8
    #define ADVANCE_IC1PWM_CHANNEL        TIM_Channel_1
    #define ADVANCE_IC2PWM_CHANNEL        TIM_Channel_2
    
    /* 高级控制定时器 */
    #define ADVANCE_TIM           		    TIM8
    #define ADVANCE_TIM_CLK       		    RCC_APB2Periph_TIM8
    
    /* 捕获/比较中断 */
    #define ADVANCE_TIM_IRQn					    TIM8_CC_IRQn
    #define ADVANCE_TIM_IRQHandler        TIM8_CC_IRQHandler
    
    

    外部计数器模式(高频)

    原本我还不知道有这种用法,后来看到有人这样用,真的能测到很高100khz-15Mhz误差0.01%——0.02%,频率过于大存在一定的误差,总体还不错。
    外部计数器可以用于脉冲数计数
    下面展示一些 内联代码片

    // A code block
    void TIM2_Cnt_Init(void)
    {
            GPIO_InitTypeDef GPIO_InitStructure;
            TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
            NVIC_InitTypeDef NVIC_InitStructure;
            TIM_DeInit(TIM2);
            TIM_DeInit(TIM7);
            RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2|RCC_APB1Periph_TIM7,ENABLE);     
            RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE);            
            GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3; //GPIOA0
            GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
            GPIO_InitStructure.GPIO_Speed = GPIO_Speed_25MHz;      
            GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; 
            GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
            GPIO_Init(GPIOB,&GPIO_InitStructure); //初始化PA0
            GPIO_PinAFConfig(GPIOB,GPIO_PinSource3,GPIO_AF_TIM2); 
            TIM_TimeBaseStructure.TIM_Prescaler=0; 
            TIM_TimeBaseStructure.TIM_CounterMode=TIM_CounterMode_Up; 
            TIM_TimeBaseStructure.TIM_Period=0xFFFFFFFF;  
            TIM_TimeBaseStructure.TIM_ClockDivision=TIM_CKD_DIV1; 
            TIM_TimeBaseInit(TIM2,&TIM_TimeBaseStructure);
            TIM_TIxExternalClockConfig(TIM2,TIM_TIxExternalCLK1Source_TI2,TIM_ICPolarity_Rising,0);
            TIM_TimeBaseStructure.TIM_Prescaler=18000-1; 
            TIM_TimeBaseStructure.TIM_CounterMode=TIM_CounterMode_Up; 
            TIM_TimeBaseStructure.TIM_Period=1000-1; 
            TIM_TimeBaseStructure.TIM_ClockDivision=TIM_CKD_DIV1; 
      NVIC_InitStructure.NVIC_IRQChannel = TIM7_IRQn;
            NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=0;
            NVIC_InitStructure.NVIC_IRQChannelSubPriority =0;         
            NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;                 
            NVIC_Init(&NVIC_InitStructure);       
            TIM_ITConfig(TIM7,TIM_IT_Update,ENABLE); 
     
            TIM_Cmd(TIM7,ENABLE );        
            TIM_Cmd(TIM2,ENABLE );       
    }
    u32 TIM7_LastCnt;
    u32 TIM_ExtCntFreq;
    //频率为TIM_ExtCntFreq 
    void TIM7_IRQHandler(void)
    {
             char        str[32];
            TIM_ExtCntFreq=(TIM2->CNT-TIM7_LastCnt)*(1/0.1);
    	     // printf("%3.3f\n",TIM_ExtCntFreq/1.0/2.128);
            TIM7_LastCnt=TIM2->CNT;
            TIM_ClearITPendingBit(TIM7,TIM_IT_Update);
    }
    

    借鉴了一些别人的做法,从中学到了经验,非常感谢__,把自己的学习过程记录一下,也是一个巩固的好方法。如果有错误,请大家指正

    展开全文
  • 使用stm32f103进行频率测量,使用TFT-LCD屏进行显示,在上升沿进行检测,只能检测方波的频率,如果想要正弦波,要搭正弦波转方波电路。
  • stm32测频率

    热门讨论 2013-03-09 08:42:07
    stm32测频率,利用定时器的捕获模式测量信号的频率
  • 基于STM32F407ZGT6的输入捕获测量频率以及占空比的完整工程,可直接使用
  • 基于stm32频率测量 ,只需将c h文件加入工程中即可,初始化后,通过 GetFreq()函数获得测量的频率,已和安捷伦频率发生器对比过,测量非常精准,最高可以 量到400k左右。并且稍加修改可同时测量占空比。
  • 本例程主要实现STM32测量外部脉冲的频率和PWM波占空比,例程中频率测量是TIMER4 ,主要看定时器4的中断函数。
  • 关于stm32测频率与占空比的几种方法,有助于stm32开发
  • 使用STM32F407芯片,测试300KHz内频率,40KHz频段内精度和稳定性较高,高频段有做相应补偿;
  • STM32 检测信号频率

    千次阅读 2021-05-25 15:13:24
    STM32 检测信号频率目标 目标 信号:500kHz±50Hz方波信号,占空比50%,低... 用STM32定时器测量信号频率——测频法和周法 2. 使用 STM32 测量频率和占空比的几种方法 [1]: https://www.cnblogs.com/helesheng/p/141

    STM32 检测信号频率

    目标

    信号:500kHz±50Hz方波信号,占空比50%,低电平:0V,高电平:3.3V
    检测:信号的频率,采样率100Hz,记录频率值

    分析

    信号周期2μm,高电平、低电平各持续1μm;
    采样频率100Hz,即每10ms记录一次频率值,计数范围:5000±50(4950~5050);
    使用STM32F103单片机,外部晶振8MHz,内部时钟倍频最高到72MHz:

    • 外部中断:每次一个上升沿/下降沿进入一次中断记录脉冲次数。低频(<10KHz)时可以使用,缺点是频繁进入中断,占用大量时间,不能用于测量高频
    • PWM输入模式:直接使用STM32硬件PWM输入模式来采集频率
    • 输入捕获模式:上升沿触发,记录开始时间,下一次上升沿时记录第二次时间,两个时间差就是一个周期。<100KHz时效果很好,速度再快反复进出中断会导致检测精度下降
    • 外部时钟计数器:使用两个时钟,一个时钟用于精准及时采用,一个时钟用于计数,检测固定时间内的脉冲个数。比如一个时钟精准定时10ms,另一个时钟用于记录10ms内脉冲的个数cnt,那么频率f=cnt/10ms。此方法要使用两个单独的定时器,可以检测2MHz的信号。

    测频法原理

    测频法的思路如下图所示,在一固定时间Tc1内,对被测信号脉冲进行计数得到N1。如果标准信号的频率为fc,那么被测信号的频率fx = N1*fc
    测频法

    参考:1. 用STM32定时器测量信号频率——测频法和测周法
    2. 使用 STM32 测量频率和占空比的几种方法
    [1]: https://www.cnblogs.com/helesheng/p/14107012.html

    展开全文
  • STM32测输入信号频率

    2018-03-21 08:14:34
    STM32测输入信号频率,通过输入捕获的方式测量信号频率(学习定时器的输入捕获功能)
  • stm32 测量频率代码

    2014-11-06 09:07:23
    STM32 编写代码 测频频率 采用库函数编写,能够成功
  • stm32实现高精度频率测定 捕获法(可精确到0.001Hz) 定时器中断法(可精确到0.1Hz)
  • 利用STM32F1主控芯片,实现对信号为10HZ到15KHZ内的信号频率进行测量,该文档包含详细的硬件电路,MULTISIM仿真电路和代码
  • 基于STM32F103ZET6的外部时钟触发测频率,理论可达35-36M,采用正点原子的TFTLCD屏幕显示。
  • 看清楚没有proteus仿真。
  • 通过输入捕获测量频率程序源码,测量,串口输出显示,STM32F103
  • STM32F1输入捕获测频率

    2017-10-24 21:23:20
    使用STM32F1平台实现了输入捕获测频率的功能,能够在2.8寸TFT液晶上显示汉字及测频数值,以及输入捕获计算值。
  • STM32F103测频率

    热门讨论 2013-07-29 18:26:53
    使用STM32内部的定时器的捕获模式采集输入的PWM波的频率,测量范围在大约1K~100K,精度到整数位
  • 基于STM32频率检测,采用自带ADC通过使用定时器。仅供学习参考,严禁商用。
  • 本资料有完整的原理图PCB和代码,成功到150KHz,可满足课设要求
  • STM32定时器输入捕获模式测频率
  • 使用STM32F4系列单片机(本次使用的是STM32F429,此程序F4全系列使用,只需注意修改好主频就行了)加陶晶驰3.5寸T0系列串口屏,由触摸屏上的按键开启测量,然后显示信号峰峰值,频率,画出波形,判断波形。对频率...
  • 基于STM32高精度频率计的设计。 这是我自己采用STM32的定时器外部计数模式,考虑到了计数溢出中断。开设1s的时钟窗口。数据均通过MATLAB二次拟合处理过,以纠正误差。理论上可以到1hz-无穷的频率范围(但在本实验...
  • stm32测量信号频率及占空比

    千次阅读 多人点赞 2019-12-07 22:18:28
    基于stm32f103单片机对信号频率、占空比的测量。 最近开始仪器仪表方面的学习了,计划后期做一个示波器。...说到用stm32测频率,都会想到用定时器的输入捕获模式,只需要一个定时器和一个IO口即...

    基于stm32f103单片机对信号频率、占空比的测量。

    最近开始仪器仪表方面的学习了,计划后期做一个示波器。所以这周就在stm32f103上面做了一个测量频率、占空比的小设计。总体上精度还是比较高的,测量频率量程在35Hz—190KHz。频率可以精确到小数点后四位,占空比测量的精度也比较高,可以到小数点后两位。
    说到用stm32测频率,都会想到用定时器的输入捕获模式,只需要一个定时器和一个IO口即可,前几天在论坛上看到还有一种是用两个定时器测频率,一个定时器用来检测信号跳变沿,另外一个用来精准定时,比如说用TIM1检测跳变沿(假设为上升沿),TIM2开一个1s的定时器中断,这个1s就比较准确,在1s内TM1检测到了多少个上升沿改信号的频率就是多少。这种方法我本周二试过,精度比输入捕获模式下的高,而且还比较稳定,缺点是用到了两个定时器,占用的cpu资源较多。考虑到我后面任务需要,定时器可能会不够用,故还是用的输入捕获模式。

    实验平台:stm32f103zet6
    定时器及通道:TIM2的通道2
    IO口:PA1

    定时器及输入捕获模式的配置:

    u8 Edge_Flag;  //高低电平的标志位
    u16 Rising,Falling,Rising_Last;   
    
    //定时器2输入捕获中断初始化
    void TIM2_Cap_Init()
    {
    	GPIO_InitTypeDef GPIO_InitStruct;   
    	TIM_TimeBaseInitTypeDef TIM_InitStruct;
    	TIM_ICInitTypeDef TIM_ICInitStruct;
    	NVIC_InitTypeDef NVIC_InitStruct;
    	
    	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
    	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE);
    	
    	GPIO_InitStruct.GPIO_Pin=GPIO_Pin_1;
    	GPIO_InitStruct.GPIO_Mode=GPIO_Mode_IN_FLOATING;   //浮空
    	GPIO_InitStruct.GPIO_Speed=GPIO_Speed_50MHz;
    	GPIO_Init(GPIOA,&GPIO_InitStruct);
    	
    	TIM_InitStruct.TIM_ClockDivision=TIM_CKD_DIV1;
    	TIM_InitStruct.TIM_CounterMode=TIM_CounterMode_Up;  //向上计数
    	TIM_InitStruct.TIM_Period=0xffff;
    	TIM_InitStruct.TIM_Prescaler=0;                //分频系数 当分频系数越大时,可测量频率最小值越小
    	TIM_TimeBaseInit(TIM2,&TIM_InitStruct);
    	
    	TIM_ICInitStruct.TIM_Channel=TIM_Channel_2;
    	TIM_ICInitStruct.TIM_ICFilter=0x00;         //不滤波
    	TIM_ICInitStruct.TIM_ICPolarity=TIM_ICPolarity_Rising;     //第一次是检测上升沿进入中断
    	TIM_ICInitStruct.TIM_ICPrescaler=TIM_ICPSC_DIV1;
    	TIM_ICInitStruct.TIM_ICSelection=TIM_ICSelection_DirectTI; //直接映射
    	TIM_ICInit(TIM2,&TIM_ICInitStruct);
    	TIM_ITConfig(TIM2,TIM_IT_CC2,ENABLE);
    	
    	NVIC_InitStruct.NVIC_IRQChannel=TIM2_IRQn;
    	NVIC_InitStruct.NVIC_IRQChannelCmd=ENABLE;
    	NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority=0x00;    //抢占优先级
    	NVIC_InitStruct.NVIC_IRQChannelSubPriority=0x01;          //响应优先级
    	NVIC_Init(&NVIC_InitStruct);
    	
    	TIM_Cmd(TIM2,ENABLE);     //使能
    }
    

    定时器2的中断服务函数:

    void TIM2_IRQHandler(void)
    { 
    	if(TIM_GetITStatus(TIM2,TIM_IT_CC2)!=RESET)    //捕获到上升沿
    	{
    		if(Edge_Flag==1)
    		{
    			Rising=TIM2->CCR2;    //第一次检测到下降沿
    			TIM_OC2PolarityConfig(TIM2,TIM_ICPolarity_Rising);  //再次改为上升沿触发
    			Edge_Flag++; 
    		}
    		else if(Edge_Flag==2)
    		{
    			Rising_Last=TIM2->CCR2;
    			TIM_OC2PolarityConfig(TIM2,TIM_ICPolarity_Rising);
    			Edge_Flag=0;     //标志位清0
    			TIM_SetCounter(TIM2,0); //定时器清0
    		}
    		else
    		{
    			Falling=TIM2->CCR2;     //第一次检测到上升沿
    			TIM_OC2PolarityConfig(TIM2,TIM_ICPolarity_Falling);    //将上升沿触发改为下降沿触发
    			Edge_Flag++;
    		}
    	}
    	TIM_ClearITPendingBit(TIM2,TIM_IT_CC2);    //清除标志位
    }
    

    输入捕获模式下,中断服务函数里面处理的内容要尽量少,所以在记录定时器捕获到值时,直接将TIM2的CCR2寄存器里面的值赋值给相应变量。

    主函数:

    int main(void)
    {	
    	delay_init();    //延时函数初始化	  
    	
    	OLED_Init();  //oled屏幕初始化
    	OLED_On();
    	OLED_Clear();
    	
    	TIM2_Cap_Init();   //定时器初始化
    
        while(1)
    	{			
    		OLED_ShowString(0,0,"Freq:",16);
    		OLED_ShowString(100,0,"Hz",16);
    		OLED_ShowNum(50,0,72000000/(Rising_Last-Falling),6,16);
    		OLED_ShowString(0,2,"Duty:",16);
    		OLED_ShowString(95,2,"%",16);
    		OLED_Showdecimal(50,2,(float)(Rising-Falling)/(float)(Rising_Last-Falling)*100,2,3,16);
    		delay_ms(100);
    	}		
    }
    

    变量Rising_Last为第二次检测到上升沿捕获到的值,Falling为第一次捕获到的值,两者之差为定时器计数的数值差,根据TIM_Prescaler=0(即不分频),主频为72M,频率f=72M/(Rising_Last-Falling)。而Rising-Falling为高电平的时间,除以一个周期就是占空比了。

    实验现象
    频率10K,占空比60%

    在这里插入图片描述
    频率102.56K,占空比33%
    在这里插入图片描述
    可见效果还是挺不错的,但是这种办法包括上面讲到的双定时器法都有一个缺点,那就是当信号幅度小于2v时,单片机就检测不到跳变沿。外部还需要硬件对信号进行适当放大。也是前几天,在论坛上看到有人提出一个测频率的叫过零检测法,用ADC读信号电压值,ADC值为0时进行记录,再次为0就相当于经过了半个周期。计算两次ADC为0的时间差,就可以计算出信号的频率,这种方法不会受限于信号幅度大小。原理也比较简单,相关程序我也正在写,等测试没问题后我再发出来和大家分享!

    展开全文
  • STM32F4系列单片机使用输入捕获、外部计数的方式进行交流信号频率、占空比的测量,很适合初学者学习
  • timx可以定时,可以进行输入捕获,输入捕获可以测频率可测脉冲宽度,这就是这个实验要用到的功能。测量脉冲个数:每一个TIM都一个自己的计数器,和一个自己的预装载寄存器ARR.这里既然这是为了计数,那么设置ARR的值...
  • 这个是根据正点原子的输入捕获代码稍稍改了一下,可用。测量范围与误差没有具体试过,还是要看单片机的性能吧。
  • 根据原子修改STM32f103战舰板可直接用。检测脉冲周期即高低的总时间。需自己间接的求频率频率为周期分之1)。 操作说明:pb5连接pa0 打开xcom(串口软件)观察周期时间 利用软件仿真,不断改变定时器3的频率,对照...
  • 不过由于STM32F4本身的限制,信号频率大于200K之后误差就会有所增加。我这里是用的7针OLED屏显示的参数。F4系列的板子几乎都可以拿来使用。程序略显复杂,大家有什么疑问可以评论区留言。目前程序我已经用在了项目里...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 9,903
精华内容 3,961
关键字:

stm32测频率