ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

STM32单片机-输入捕获、FFT测频

2026/8/26 13:34:22 拓冰建站 浏览量
STM32单片机-输入捕获、FFT测频 目录一、硬件连接1、电压信号处理电路仿真2、单片机连接二、代码部分1、通过STM32输入捕获2、通过FFT实现3、屏显驱动介绍三、测频法计算频率1、外部中断统计跳变沿个数2、定时器外部计数的方法一、硬件连接1、电压信号处理电路仿真图1.1.1 Proteus仿真图(使用教程)2、单片机连接▼主控 MCUSTM32F103ZET6(STM32的介绍)LM293输出连接在 PB0 上检测电压信号的频率如图1.1.1 与图1.2.1 所示。图1.2.1 原理图截图图1.2.2 管脚功能截图▲如图1.2.2 所示注意其中的TIM3_CH2N 是 PWM 捕获比较输出TIM3_CH3 才是输入捕获。图1.2.3 内部高级控制定时器框图二、代码部分这里通过 STM32 输入捕获或 FFT 转换两种方式实现频率的测量在实际工程中都已实现。 STM32 输入捕获信号幅度小于 2V 时单片机检测不到跳变沿需硬件对信号适当处理(如图1.1.1)。PB0/ADC8 也可用 ADC 读信号电压值ADC 值为0时进行记录再次为0就相当于经过了半个周期。计算两次 ADC 为0的时间差就可以计算出信号的频率这种方法不会受限于信号幅度的限制。1、通过STM32输入捕获下面的程序采集 PB0口(图1.2.1)的电压信号因频率较低且要求继电器出口时间小于 35ms采用测周法计算频率。给出主要部分定时器配置与定时器中断程序。因上升沿示波器测试并不陡峭(图1.1.1 仿真图也可看出)故取一周波两次下降沿。▼注意后期的处理程序必须捕获到两个下降沿的前提下才能作相应的处理。采集程序未完成此时处理会出错。图2.1.1 示波器信号1定时器配置void adc_TIM_Init(void) { TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure; //定时器 GPIO_InitTypeDef GPIO_InitStructure; //端口 TIM_ICInitTypeDef TIM_ICInitStructure; //输入捕获 //初始化GPIO口 GPIO_InitStructure.GPIO_ModeGPIO_Mode_IN_FLOATING; //浮空输入模式 GPIO_InitStructure.GPIO_PinGPIO_Pin_0; GPIO_Init(GPIOB,GPIO_InitStructure); GPIO_SetBits(GPIOB,GPIO_Pin_0); //使能时钟 RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3,ENABLE); //TIM3 RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB|RCC_APB2Periph_AFIO,ENABLE); //初始化TIM3定时 TIM_TimeBaseStructInit(TIM_TimeBaseStructure); TIM_TimeBaseStructure.TIM_Prescaler 17; //1MHz计数脉冲 1us TIM_TimeBaseStructure.TIM_Period 65535; TIM_TimeBaseStructure.TIM_ClockDivision 0x0; TIM_TimeBaseStructure.TIM_CounterMode TIM_CounterMode_Up; //向上计数 TIM_TimeBaseInit(TIM3, TIM_TimeBaseStructure); TIM_TimeBaseStructInit(TIM_TimeBaseStructure); //初始化TIM3 Channel3输入捕获IC(Input Capture) TIM_ICInitStructure.TIM_ChannelTIM_Channel_3; TIM_ICInitStructure.TIM_ICPolarityTIM_ICPolarity_Falling; //下降沿捕获 TIM_ICInitStructure.TIM_ICSelectionTIM_ICSelection_DirectTI; //管脚与寄存器一一对应 TIM_ICInitStructure.TIM_ICPrescalerTIM_ICPSC_DIV1; //有下降沿就捕获不分频 TIM_ICInitStructure.TIM_ICFilter0x00; //不打开输入捕获滤波器 TIM_ICInit(TIM3,TIM_ICInitStructure); TIM_ITConfig(TIM3,TIM_IT_Update,ENABLE); //允许定时中断 TIM_ITConfig(TIM3,TIM_IT_CC3,ENABLE); //允许CC3捕获中断 TIM_Cmd(TIM3,ENABLE); ………… }2定时溢出与输入捕获中断void TIM3_IRQHandler(void) //TIM3 { static u8 CapStatus 0; //捕获状态CapStatus0未捕获到第1个下降沿CapStatus1捕获到第1个下降沿 static u8 TIM3_CH3_Capture 0; //总的计数次数 u32 FrequencyTemp 0; if(TIM_GetITStatus(TIM3,TIM_IT_Update)) //TIM3定时溢出更新中断 { TIM_ClearITPendingBit(TIM3,TIM_IT_Update); //清除中断标志位 if(CapStatus) TIM3_CH3_Capture; } if(TIM_GetITStatus(TIM3,TIM_IT_CC3)) //RB0输入捕获中断 { TIM_ClearITPendingBit(TIM3,TIM_IT_CC3); //清除中断标志位 if(!CapStatus) { CapStatus 1; TIM_SetCounter(TIM3,0); //计数器清零 } else if(CapStatus) //已经捕获到第1个下降沿 { CapStatus 0; FrequencyTempTIM_GetCapture3(TIM3)TIM3_CH3_Capture*65536;//计算两个下降沿总计数 TIM3_CH3_Capture 0; //溢出次数清零 TIM_SetCounter(TIM3,0); //计数器清零 FrequencyValue 400000000/FrequencyTemp;//计算频率比如5000单位0.01Hz } } }图2.1.2 继保频率设置图2.1.3 实际测量值2、通过FFT实现1概述▼下面是采集 PC1口 (图1.2.1)的小通道电流信号计算频率其固件具ST官方DSP库实现FFT试用测试固件移步FFT(具ST官方DSP库实现)。图2.2.1 实际测量值2数据采集使用 STM32F103 自带的 12位 ADC 进行数据采集定时器触发 ADC 采集DMA 搬运定时器时间自行设置采样频率已知。此部分相关内容移步ADC转换汇总(采样原理、取平均、精度等)。3功能介绍▼通过 FFT 可以准确测量电压值、电流值互感器二次值精确到小数点后 2位无压力电流范围大硬件增加大小通道、程序分别采集涌流二次谐波含量最多故可实现二次谐波制动谐波的相关介绍移步电力-涌流抑制与谐波。三段式保护移步继电保护原理1.1-电流、方向保护反时限移步继电保护原理1.2-反时限过流保护重合闸移步继电保护原理4-自动重合闸之第五章、自动重合闸。1已实现FFT控制板图2.2.2 主控板正面图2.2.3 主控板反面2GSM短信功能▼介绍移步SIM7600CE模块(GSM/GPRS)调试。图2.2.4 4G短信试验板3GPRS 数据功能介绍移步STM32-GPRS模块连接系统主站可以采用映翰通工业数据终端做透明传输。4以太网功能板▼本方案基于 W5500详细的介绍移步网络知识汇总(基于W5500以太网)。图2.2.5以太网主控板图2.2.6 以太网接口板3、屏显驱动介绍▼非常详细的液晶屏内容请移步12864液晶显示原理(C代码)。图2.3.1 英文显示三、测频法计算频率网上找的资料不保证正确性没有实际测试过仅供参考。通过在一定时间内检测跳变沿的个数可计算出频率频率 上升沿或下降沿个数/统计时间。1、外部中断统计跳变沿个数配置一个定时器每隔一定时间对频率进行计算部分代码如下。void exti_init(void) //外部中断初始化函数 { GPIO_InitTypeDef GPIO_InitStructure; EXTI_InitTypeDef EXTI_InitStructure; NVIC_InitTypeDef NVIC_InitStructure; RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE); RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC,ENABLE); GPIO_InitStructure.GPIO_PinGPIO_Pin_2; GPIO_InitStructure.GPIO_ModeGPIO_Mode_IN_FLOATING; GPIO_InitStructure.GPIO_SpeedGPIO_Speed_50MHz; GPIO_Init(GPIOC,GPIO_InitStructure); GPIO_EXTILineConfig(GPIO_PortSourceGPIOC, GPIO_PinSource2); //选择GPIO引脚用作外部中段线路 //此处一定要记住给端口管脚加上中断外部线路 EXTI_InitStructure.EXTI_LineEXTI_Line2; EXTI_InitStructure.EXTI_ModeEXTI_Mode_Interrupt; EXTI_InitStructure.EXTI_TriggerEXTI_Trigger_Falling; //下降沿进中断 EXTI_InitStructure.EXTI_LineCmd ENABLE; EXTI_Init(EXTI_InitStructure); NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1); NVIC_InitStructure.NVIC_IRQChannel EXTI2_IRQn; //打开EXTI2的全局中断 NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority 1; //设置优先级 NVIC_InitStructure.NVIC_IRQChannelSubPriority 1; NVIC_InitStructure.NVIC_IRQChannelCmd ENABLE; //使能 NVIC_Init(NVIC_InitStructure); }外部中断函数void EXTI2_IRQHandler(void) { if(EXTI_GetITStatus(EXTI_Line2)SET) { EXTI_ClearITPendingBit(EXTI_Line0);//清中断 if(GPIO_ReadInputDataBit(GPIOC,GPIO_Pin_2)Bit_RESET) //确定沿 { cnt; } } }定时器中断函数void TIM3_IRQHandler(void) { frequent cnt; //定时器设置时间为1s时 cnt 0; //清零计数cnt TIM_ClearITPendingBit(TIM3,TIM_IT_Update); //清标志位 }2、定时器外部计数的方法采用定时器外部计数的方法另外一个定时器负责每隔一段时间计算频率部分代码如下。void time_init(void) { GPIO_InitTypeDef GPIO_InitStructure; TIM_TimeBaseInitTypeDef TIM2_TimeBaseInitStructure; TIM_TimeBaseInitTypeDef TIM3_TimeBaseInitStructure; NVIC_InitTypeDef NVIC_InitStructure; RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE); RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3,ENABLE); RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE); GPIO_InitStructure.GPIO_PinGPIO_Pin_0; GPIO_InitStructure.GPIO_ModeGPIO_Mode_IPU; GPIO_InitStructure.GPIO_SpeedGPIO_Speed_50MHz; GPIO_Init(GPIOA,GPIO_InitStructure); TIM_ClearITPendingBit(TIM2,TIM_IT_Update);//清除TIM2中断标志位 TIM2_TimeBaseInitStructure.TIM_Period 0xFFFF;//设置自动重装载值 TIM2_TimeBaseInitStructure.TIM_Prescaler 0;//设置分频 TIM2_TimeBaseInitStructure.TIM_ClockDivision TIM_CKD_DIV1; TIM2_TimeBaseInitStructure.TIM_CounterMode TIM_CounterMode_Up;//向上计数 TIM_TimeBaseInit(TIM2,TIM2_TimeBaseInitStructure); TIM_ETRClockMode1Config(TIM2, TIM_ExtTRGPSC_OFF,TIM_ExtTRGPolarity_NonInverted, 0x00); //设置为采用外部时钟计数,可设定滤波参数消除信号干扰 TIM_Cmd(TIM2,ENABLE); TIM_ClearITPendingBit(TIM3,TIM_IT_Update); TIM3_TimeBaseInitStructure.TIM_Period 999; TIM3_TimeBaseInitStructure.TIM_Prescaler 3599; TIM3_TimeBaseInitStructure.TIM_ClockDivision TIM_CKD_DIV1; TIM3_TimeBaseInitStructure.TIM_CounterMode TIM_CounterMode_Up; TIM_TimeBaseInit(TIM3,TIM3_TimeBaseInitStructure); TIM_Cmd(TIM3,ENABLE); TIM_ITConfig(TIM3, TIM_IT_Update, ENABLE ); NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1); NVIC_InitStructure.NVIC_IRQChannelTIM3_IRQn; NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority0; NVIC_InitStructure.NVIC_IRQChannelSubPriority0; NVIC_InitStructure.NVIC_IRQChannelCmd ENABLE; NVIC_Init(NVIC_InitStructure); }定时器中断函数void TIM3_IRQHandler(void) { static u8 i; static u32 frequent_sum; TIM_ClearITPendingBit(TIM3,TIM_IT_Update); //清中断 if(i19) { cnt TIM_GetCounter(TIM2); //获取计数器的值累加减少误差 TIM_SetCounter(TIM2,0); //计数器清零 i; } else { cnt TIM_GetCounter(TIM2); TIM_SetCounter(TIM2,0); cnt cnt*0.000025; //根据实际情况修改系数线性补偿 frequent cnt; i 0; cnt 0; } }首先要有一个具体目标那些所有你认为必须前置的知识都可以在完成目标的过程中学到。觉得不错动动发财的小手点个赞哦