stm32 测频率(1HZ 您所在的位置:网站首页 stm32f407最高主频 stm32 测频率(1HZ

stm32 测频率(1HZ

2024-07-14 16:30| 来源: 网络整理| 查看: 265

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

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



【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有