栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > C/C++/C#

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

C/C++/C# 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

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

本内容介绍基于STM32F103VET6的一个实际工程中添加采集A相电压信号或B相电流信号频率的小功能,分别通过输入捕获与FFT实现,均测试可用。紫色文字是超链接,点击自动跳转至相关博文。持续更新,原创不易!

目录:

一、硬件连接

1、电压信号处理电路仿真

2、单片机连接

二、程序部分

1、通过STM32输入捕获

1)定时器配置   2)定时溢出和输入捕获中断处理

2、通过FFT实现

3、屏显驱动介绍

附录1:测频法计算频率 ----------------------------------------------------------------------------------------------------------------- 一、硬件连接 1、电压信号处理电路仿真

图1.1.1 ----------------------------------------------------------- 2、单片机连接 主控MCU:STM32F103ZET6,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_Mode=GPIO_Mode_IN_FLOATING; //浮空输入模式    GPIO_InitStructure.GPIO_Pin=GPIO_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_Channel=TIM_Channel_3;    TIM_ICInitStructure.TIM_ICPolarity=TIM_ICPolarity_Falling; //下降沿捕获    TIM_ICInitStructure.TIM_ICSelection=TIM_ICSelection_DirectTI; //管脚与寄存器一一对应    TIM_ICInitStructure.TIM_ICPrescaler=TIM_ICPSC_DIV1; //有下降沿就捕获,不分频    TIM_ICInitStructure.TIM_ICFilter=0x00; //不打开输入捕获滤波器    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; //捕获状态,CapStatus=0未捕获到第1个下降沿,CapStatus=1捕获到第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;          FrequencyTemp=TIM_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实现 下面是采集PC1口(图1.2.1)的小通道电流信号,计算频率,其固件具ST官方DSP库实现FFT,测试固件移步:FFT(具ST官方DSP库实现)。 -------------------------------- 1)用STM32F103自带的12位ADC进行数据采集,定时器触发ADC采集,DMA搬运,定时器时间自行设置,采样频率已知。此部分相关内容移步:AD转换汇总(STM32、取平均、过采样)。 -------------------------------- 2)通过FFT可以准确测量电压值、电流值、有功功率、无功功率、频率、谐波分量(比如显示2~32次谐波)、相角(电压与电流夹角)。互感器二次值精确到小数点后2位无压力,电流范围大,硬件增加大小通道、程序分别采集即可;涌流二次谐波含量最多,故可实现二次谐波制动,相关介绍移步:电力-涌流抑制与谐波。

图2.2.1 ----------------------------------------------------------- 3、屏显驱动介绍 移步:12864液晶显示原理(C程序)。 ----------------------------------------------------------------------------------------------------------------- 附录1:测频法计算频率 网上找的资料,不保证正确性,没有实际测试过,仅供参考。 通过在一定时间内检测跳边沿的个数可计算出频率 频率=上升沿或下降沿个数/统计时间。 ----------------------------------------------------------- 方法1:利用外部中断统计跳边沿个数,配置一个定时器每隔一定时间对频率进行计算。部分代码如下。 void exti_init()  //外部中断初始化函数 { 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_Pin=GPIO_Pin_2; GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IN_FLOATING; GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz; GPIO_Init(GPIOC,&GPIO_InitStructure);   GPIO_EXTILineConfig(GPIO_PortSourceGPIOC, GPIO_PinSource2);//选择GPIO引脚用作外部中段线路 //此处一定要记住给端口管脚加上中断外部线路   EXTI_InitStructure.EXTI_Line=EXTI_Line2; EXTI_InitStructure.EXTI_Mode=EXTI_Mode_Interrupt; EXTI_InitStructure.EXTI_Trigger=EXTI_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()     { if(EXTI_GetITStatus(EXTI_Line2)==SET) {     EXTI_ClearITPendingBit(EXTI_Line0);//清中断 if(GPIO_ReadInputDataBit(GPIOC,GPIO_Pin_2)==Bit_RESET)    //确定沿 { cnt++; }  } } 定时器中断函数 void TIM3_IRQHandler()    { frequent=cnt; //定时器设置时间为1s时 cnt=0;  //清零计数cnt TIM_ClearITPendingBit(TIM3,TIM_IT_Update);    //清标志位 } ----------------------------------------------------------- 方法2:采用定时器外部计数的方法,另外一个定时器负责每隔一段时间计算频率,部分代码如下。 void time_init() { 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_Pin=GPIO_Pin_0; GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IPU; GPIO_InitStructure.GPIO_Speed=GPIO_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_IRQChannel=TIM3_IRQn;  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=0; NVIC_InitStructure.NVIC_IRQChannelSubPriority=0;   NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; NVIC_Init(&NVIC_InitStructure); } 定时器中断函数 void TIM3_IRQHandler()   { static u8 i; static u32 frequent_sum; TIM_ClearITPendingBit(TIM3,TIM_IT_Update);   //清中断 if(i<19) { 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; } } -----------------------------------------------------------------------------------------------------------------
转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/869594.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号