#include <stm32f10x_lib.h>
#include<math.h>
#include "sys.h"
#include "delay.h"
#include "led.h"
#include "lcd.h"
#include "adc.h"
#define FFT_N 128 //定义福利叶变换的点数
#define PI 3.1415926535897932384626433832795028841971 //定义圆周率值
struct compx {float real,imag;}; //定义一个复数结构
struct compx s[FFT_N]; //FFT输入和输出:从S[0]开始存放,根据大小自己定义
float SIN_TAB[FFT_N/2]; //定义正弦表的存放空间
float mod[FFT_N]; //用于存储FFT结果的模值
u16 adc_buffer[FFT_N]; //用于存储ADC的结果,为整数
u8 hight[16]; //用于存储矩形的高度
u8 top_hight[16]; //用于存储矩形上漂浮物的高度
/*************此函数的功能是把ADC的结果转换为电压值,然后存到s数组的实部******************/
void adc_to_s()
{
u16 i;
for(i=0;i<FFT_N;i++) //给结构体赋值
{
s.real= (float)(adc_buffer*(3.3/4096));
s.imag=0; //虚部为0
}
}
/***********此函数的功能为把FFT的模值转换为矩形柱的高度,不超过屏的宽度****************/
void mod_hight()
{
u8 i;
for(i=0;i<16;i++)
if((u8)(mod[10+3*i]*100)<=238) //必须避免高度超过最高值(屏宽值,限制为238),否则从下部溢出,致使屏上出线莫名其妙的线条
hight=(u8)(mod[10+3*i]*100);
else
hight=238;
}
/**************显示矩形柱函数*****************/
void display()
{
u8 i;
LCD_Fill(Chnl_N*18+10+4,0,(Chnl_N+1)*18+10,235,LGRAY); //显示前我都进行一次模拟刷屏,也就是对每一个立柱做背景填充,并非真正刷屏
for(i=0;i<16;i++)
Show_rctgl(i, hight); //显示矩形柱函数,一共16段
for(i=0;i<16;i++)
Show_top(i,top_hight); //显示矩形柱上的漂浮物
}
int main(void)
{
u16 adcx; //记录ADC的转换结果
u16 num=0,i=0; //记录采样点的个数
create_sin_tab(SIN_TAB); //创建正弦表,FFT函数要调用
Stm32_Clock_Init(9);//系统时钟设置
delay_init(72); //延时初始化
LED_Init();
LCD_Init();
Adc_Init();
LCD_Clear(LGRAY);//清屏,每次清屏等效于设置背景色
  OINT_COLOR=BROWN;//设置字体颜色
for(i=0;i<16;i++) //漂浮物高度值清零
top_hight=0;
while(1)
{
delay_us(5); //采样周期,每隔5us执行一次AD转换
adcx=Get_Adc(ADC_CH0);
adc_buffer[num]=adcx;
num++; //采样点个数自加
if(num==FFT_N) //如果采样满128点
{
num=0; //计数器清零
adc_to_s();//将ADC的值转换为电压值 ,存放到s的实部
FFT(s);//做fft运算
for(i=0;i<FFT_N;i++) //求变换后结果的模值,存放于mod数组中
mod=sqrt(s.real*s.real+s.imag*s.imag);
mod_hight();//将傅里叶变换后的模值转换为彩色立柱的高度
for(i=0;i<16;i++) //计算漂浮物应该显示的高度,漂浮物宽度为五个像素点
if(top_hight<=hight) //如果矩形柱的高度大于漂浮物,则漂浮的高度值取矩形柱的高度
top_hight=hight;
else if((top_hight-5)>0) //否则,漂浮物的高度自减5,也就是每刷一次屏,漂浮物落下5个点
top_hight=top_hight-5; //当然要保证漂浮物高度不下溢,否则显示会出现混乱
else
top_hight=0;
display(); //此函数为显示立柱,显示前我都进行一次模拟刷屏,也就是对每一个立柱做背景填充,并非真正刷屏
LCD_ShowString(80,20,"Made by GreenHand");
LCD_ShowString(80,40," 2012/8/7");
// delay_ms(1); 此处延时我也将它省略掉
LED0=!LED0; //指示灯,指示FFT运算所花的时间
}
}
}
本人是个初学者,也许代码存在很多漏洞,恳请大家批评指正
这是一个很简单的频谱分析仪,我为了减少硬件错误,就直接分析mini
板子上现成的AD转换数据的频谱,视频中可以看到有矩形柱显示时采样的
是PA0口的悬空电压,因此乱七八糟,当我用杜邦线接上GND后显示为零。
这里我参照了原子建议,显示前不再清屏,而是用填充颜色法做模拟
清屏,但是效果还是很不好,视频中可以明显分辨出led等在闪烁,led等
闪烁频率就是lcd的显示频率。
|