STM32F103C8_DMA方式2路ADC采集双声道音频FFT变换显示频谱
这是一个完整的项目,没有加狗
关键点在于多路采集,FFT库函数应用,这个FFT函数用汇编优化,速度比较快。
当然,本系统速度瓶颈在画点显示。后期我采用直接写显存,就比较快了。
上段忙,这也是我对同道的一点小小的贡献
单片机源程序如下:
- #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)
|