标题:
STM32F1DMA方式ADC采集双声道音频FFT变换显示频谱 源程序
[打印本页]
作者:
新洲罗远
时间:
2021-1-21 15:48
标题:
STM32F1DMA方式ADC采集双声道音频FFT变换显示频谱 源程序
STM32F103C8_DMA方式2路ADC采集双声道音频FFT变换显示频谱
这是一个完整的项目,没有加狗
关键点在于多路采集,FFT库函数应用,这个FFT函数用汇编优化,速度比较快。
当然,本系统速度瓶颈在画点显示。后期我采用直接写显存,就比较快了。
上段忙,这也是我对同道的一点小小的贡献
51hei图片20210121160005.jpg
(130.86 KB, 下载次数: 83)
下载附件
2021-1-21 16:00 上传
单片机源程序如下:
#include "stm32f10x.h"
#include "usart.h"
#include "adc.h"
#include "delay.h"
#include "Lcd_Driver.h"
#include "LCD_Config.h"
#include "stm32_dsp.h"
#include "math.h"
#define NPT 256 //FFT采样点数
long lBUFMAG[NPT+NPT]; //存储求模后的数据[NPT+NPT/2]
long lBUFOUT[NPT]; //FFT输出序列NPT=256
long lBUFIN0[NPT]; //FFT输入系列
long lBUFIN1[NPT]; //FFT输入系列
void dsp_column0(void);
void dsp_column1(void);
void powerMag(long nfill);//计算频点幅值
void dsp_column_1(void);
void OLED_Fill(u8 x1,u8 y1,u8 x2,u8 y2,u16 dot);
extern __IO uint16_t ADC_ConvertedValue[NOFCHANEL];
// 局部变量,用于保存转换计算后的电压值
float ADC_ConvertedValueLocal[NOFCHANEL];
int main(void)
{
u16 i;
uart_init(115200);
ADCx_Init();
delay_init();
Lcd_Init();//初始化硬件SPI
Lcd_Clear(BLUE); //清屏函数
while(1)
{
ADC_SoftwareStartConvCmd(ADC_x, ENABLE);
while(!DMA_GetFlagStatus(DMA1_FLAG_TC1));
DMA_ClearFlag(DMA1_FLAG_TC1);
ADC_SoftwareStartConvCmd(ADC1, DISABLE);
ADC_ConvertedValueLocal[0] =(float) ADC_ConvertedValue[0]/4096*3.3;
ADC_ConvertedValueLocal[1] =(float) ADC_ConvertedValue[1]/4096*3.3;
printf("CH0 = %f V \r\n",ADC_ConvertedValueLocal[0]);
printf("CH1 = %f V \r\n",ADC_ConvertedValueLocal[1]);
for(i=0;i<NPT;i++)
{// 由于没有采用外部触发,所以使用软件触发ADC转换
ADC_SoftwareStartConvCmd(ADC_x, ENABLE);
while(!DMA_GetFlagStatus(DMA1_FLAG_TC1));
DMA_ClearFlag(DMA1_FLAG_TC1);
ADC_SoftwareStartConvCmd(ADC1, DISABLE);
lBUFIN0[i] =(float) ADC_ConvertedValue[0];
lBUFIN1[i] =(float) ADC_ConvertedValue[1];
}
cr4_fft_256_stm32(lBUFOUT,lBUFIN1,NPT);//调用STM32的DSP库作FFT变换
powerMag(NPT);//计算频点幅值
dsp_column1();//显示x根柱条。
cr4_fft_256_stm32(lBUFOUT,lBUFIN0,NPT);//调用STM32的DSP库作FFT变换
//(FFT输出序列,输入序列,NPT=256)
powerMag(NPT);//计算频点幅值
dsp_column0();//显示x根柱条。
}
}
//显示各频点的柱条
void dsp_column0(void)
{
u8 i,j=80;
for(i=1;i<161;i+=2)
{ OLED_Fill(i,0,i,128,0x0000); //填充区域的对角坐标
OLED_Fill(i,0,i,lBUFMAG[j],RED); //填充区域的对角坐标
j --;
}
}
//显示各频点的柱条
void dsp_column1(void)
{
u8 i,j=80;
for(i=0;i<160;i+=2)
{ OLED_Fill(i,0,i,128,0x0000); //填充区域的对角坐标
OLED_Fill(i,0,i,lBUFMAG[j],GREEN); //填充区域的对角坐标
j --;
}
}
//x1,y1,x2,y2 填充区域的对角坐标
//确保x1<=x2;y1<=y2 0<=x1<=127 0<=y1<=63
//dot:0,清空;1,填充
void OLED_Fill(u8 x1,u8 y1,u8 x2,u8 y2,u16 dot) //可以快
{
u8 x,y;
for(x=x1;x<=x2;x++)
{
for(y=y1;y<=y2;y++) Gui_DrawPoint(x,y,dot);//画一个点
}
}
////////////////////////////////////////////
//计算各频点的模值
void powerMag(long nfill) //计算频点幅值
{ int32_t lX,lY;
uint32_t i,j;
for (i=0; i < nfill; i++) //256
{
lX= (lBUFOUT[i]<<16)>>16; /* sine_cosine --> cos */
lY= (lBUFOUT[i] >> 16); /* sine_cosine --> sin */
{
float X= 64*((float)lX)/32768;
float Y = 64*((float)lY)/32768;
float Mag = sqrt(X*X+ Y*Y)/nfill; // 先平方和,再开方sqrt
j= (long)(Mag*65536); //存储求模后的数据
if(j>128) j=128;//避免显示越界
lBUFMAG[i] =j;
}
}
}
复制代码
所有程序51hei提供下载:
DMA2通道ADC_FFT.7z
(216.08 KB, 下载次数: 169)
2021-1-21 16:46 上传
点击文件名下载附件
下载积分: 黑币 -5
作者:
杨雪飞
时间:
2021-1-21 19:09
虽然不懂stm32,还是强烈支持一下。
作者:
liesnake
时间:
2021-1-22 20:12
这个不错的,很好的东西。
作者:
wangsh
时间:
2021-1-27 23:06
thank you very much!!!!!!!!!
作者:
罗程峰8200
时间:
2021-1-28 08:14
加油,虽然我不会玩,看看也好
作者:
VB老哥
时间:
2021-1-28 20:36
谢谢提供思路
欢迎光临 (http://www.51hei.com/bbs/)
Powered by Discuz! X3.1