基于MSP430F6638的信号采集与分析系统试验
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
信号采集与分析系统实验一、实验目的本实验目的是利用实验箱构建一个信号采集和分析系统。
二、实验内容
放大模块(备选扩展)信号发生器(器产生单频模DD号,测试根据按键,生不同单频采集模A寸液晶3.单片机核心(也可用单片显示频FPG核心代替内A显示按键LE显块,不LE代表输入为不频点正弦信
三、实验步骤–编写单片机程序,控制按键,控制灯的亮、键盘及LED的设计与制作1 LED 灭,测试所有能控制的按键和–测试在液晶屏上显示波形和数据2、液晶屏显示的设计与制作16个指示灯代表以16个单频点,频点3、以信号发生器输入单频正弦波,在200Hz ~ 10kHz任选,信号发生器每次产生一种频点正弦波,AD采集,对应频点的指示灯会亮;
4、把指示灯显示频点改成用液晶显示
5、液晶屏同时显示频谱和时域波形
四、实验原理
1、AD采样模块
在这个模块中,每过一段时间,AD采样器采集一个数据存入数组中,并将存储的二进制数转换成对应的电压值,通过代码:collect0[t].real =
实现。
采集满N个值之后,令标志变量flag=1,表示ADC12MEM0*3.0 / 0x03ff;变换。
我们将信号发生器输出的模FFT一组数据采集完毕,进入下一模块,即.
,这是因为:若电压值太大,会导致结果波形失真;0V~2V 拟电压范围设定为若出现负电压,则因为AD模块不支持负电压的采集,结果可能会出现错误。
2、FFT处理模块LCD该模块将采集进来的数据进行FFT变换,变换后的实部即为频谱,用于变的频谱绘制。
绘制时,以各频点的幅频值与最大幅频值的相对大小进行绘制;频fre表示,便于屏幕及LED换后模值最大的频点对应的频率即为待测频率,用fre,可求得若干函数值,用于LCD的时域波形绘制。
率显示;根据求得的液晶屏显示模块LCD3、该模块用于显示时域波形、频谱、学号、所测频率等内容。
关键语句:清屏:清屏etft_AreaSet(0,0,239,319,0);//显示:,fre);
(buffer, ?敲畱湥祣???穈sprintf etft_DisplayString(buffer, 0, 32, 0xFFFF,
0x0000);//显示频率
同时,在模块中加入了延时语句,使得波形可以保持一定的时间。
时间到后,LCD
会进行刷新,重新显示波形和数据。
4、LED灯显示模块
LED1作为采样指示灯,ADC模块每采一次样闪烁一次,由于采样频率极高,但中断调用间隔较长,实际显示为每次进入ADC采样中断LED1闪烁一下。
使用LED2、LED3、LED4、LED5显示频率,标号分别为5.7、4.7、4.6、4.5。
受LED灯数目的限制,当用LED显示频率时(二进制表示),只能精确到1kHz。
如当1500<=fre<2500时,用2kHz表示,灯显示为0010;当5500<=fre<6500时,用6kHz表示,灯显示为0110,其余类似。
通过以上模块,可以实现以下功能:AD模块采集N个数据后,FFT模块对数据进行处理,FFT变换后,实部为频谱,用于LCD的频谱绘制;模值最大的频点为所求频率,在LED和LCD上显示;再求得一些采样点的函数值,在LCD上绘制时域波形。
最终,频率显示在LED灯和LCD上,波形和频谱显示在LCD 上。
图像保持一段时间后,LCD会进行刷新,重新显示波形和数据。
附录:{
&P4IN, &P4OUT, &P4DIR, 1、键盘及LED的设计与制作
&P4REN, &P4SEL
#include <msp430.h>
}; #include <stdint.h>
#include <stdio.h>
const GPIO_TypeDef GPIO5 = #include dr_i2c.h
{
#include dr_tft.h
&P5IN, &P5OUT, &P5DIR,
&P5REN, &P5SEL
#define TEMP_ADDR 0x2A
}; #define TEMP_LOCAL 0x00
#define TEMP_REMOTE 0x01
const GPIO_TypeDef GPIO8 = #define TEMP_CONFIG1 0x09
{
TEMP_CONFIG2 #define
&P8IN, &P8OUT, 0x0A
&P8DIR,
&P8REN, &P8SEL
TEMP_NCORR #define
}; 0x21
GPIO_TypeDef* #define BATT_ADDR 0x55 const
{&GPIO4, LED_GPIO[5] #define BATT_VOLTAGE =
&GPIO5, &GPIO4, 0x04
&GPIO4,
&GPIO8};
#define BATT_CURRENT
= 0x10
uint8_t LED_PORT[5] const
{BIT5, BIT6, BIT7, BIT7, BIT0};
#define BATT_SOC 0x1C
#define BATT_CAPA 0x0C
void initClock() #define BATT_FLAG 0x06
{
while(BAKCTL & LOCKIO) int TEMP_LOCAL_INDEX;
// Unlock XT1 pins for operation
int TEMP_REMOTE_INDEX;
&= BAKCTL int BATT_VOLTAGE_INDEX;
~(LOCKIO);
int BATT_CURRENT_INDEX;
//int BATT_SOC_INDEX; ~XT1OFF; UCSCTL6 &=
XT1
int BATT_CAPA_INDEX; 启动BIT3; int BATT_FLAG_INDEX; |= BIT2 + P7SEL //XT2typedef struct 引脚功能选择//&= ~XT2OFF; UCSCTL6 {
XT2
const volatile uint8_t* PxIN; 启动
OFIFG) & volatile uint8_t* PxOUT; while (SFRIFG1
与DCO volatile uint8_t* PxDIR; 稳定XT1{ //等待、XT2&= UCSCTL7 volatile uint8_t* PxREN;
~(DCOFFG+XT1LFOFFG+XT2OFvolatile uint8_t* PxSEL;
FG);
} GPIO_TypeDef;
SFRIFG1 &= ~OFIFG;
}
const GPIO_TypeDef GPIO4 =
initTFT();
= UCSCTL4
SELA__XT1CLK +
SELS__XT2CLK + etft_AreaSet(0,0,319,239,0);
int i;
SELM__XT2CLK; //避免DCO调for(i=0;i<5;++i)
整中跑飞*LED_GPIO[i]->PxDIR |=
LED_PORT[i]; UCSCTL1 = DCORSEL_5; //设置各LED灯所在端口为输出方向//6000kHz~23.7MHz
/ UCSCTL2 = 20000000
(4000000 / 16); //XT2频率较高,分P4REN |= 0x1F; //使能按键端口上的上下拉电阻频后作为基准可获得更高的精度
P4OUT |= 0x1F; //上拉状态UCSCTL3 =
SELREF__XT2CLK +
FLLREFDIV__16; //XT2进行16分uint8_t last_btn = 0x1F,
cur_btn, temp;
频后作为基准
while (SFRIFG1 & OFIFG) while(1)
稳定{
XT2{ //等待XT1、与DCO UCSCTL7 &= int temp1, temp2;
~(DCOFFG+XT1LFOFFG+XT2OF char buffer[41];
FG);
cur_btn = P4IN & 0x1F;
SFRIFG1 &= ~OFIFG; temp = (cur_btn ^ last_btn)
& last_btn; }
//找出刚向下跳变的按键= UCSCTL5 DIV A__1 +
设定几个DIVS__1 + DIVM__1; //last_btn = cur_btn;
int i;
的分频CLK
for(i=0;i<5;++i) UCSCTL4 =
+ {
SELA__XT1CLK
if(temp & (1 << i)) SELS__DCOCLK +
几设//定个{ SELM__DCOCLK;
CLK的时钟源
*LED_GPIO[i]->PxOUT } ^=
LED_PORT[i]; //翻转对应的LED
__delay_cycles(3276); //int main( void ) 延时大约{
100ms
timer Stop // watchdog to temp1=7-i;
prevent time out reset
temp2=5-i;
+ WDTPW = WDTCTL sprintf(buffer,
Switch %d LED WDTHOLD;
%d, temp1,
temp2);
etft_DisplayString(buffer, 0, 0,
0xFFFF, 0x0000);
initClock();
sprintf(buffer,
initI2C();
emp %d, temp);
UCSCTL4 = SELA__XT1CLK +
SELS__XT2CLK + SELM__XT2CLK;
//避免DCO调整中跑飞etft_DisplayString(buffer, 0, 16, UCSCTL1 0xFFFF, 0x0000);
= DCORSEL_5;
//6000kHz~23.7MHz
}
UCSCTL2 = 20000000 }
/ (4000000 /
16); //XT2频率较高,分频后作为基准__delay_cycles(2000000); 可获得更高的精度}
UCSCTL3 }
= SELREF__XT2CLK +
FLLREFDIV__16; //XT2进行16分频后作为基准
while (SFRIFG1 & OFIFG)
{ //等待XT1 2、信号采集与显示、XT2与DCO稳定
#include <msp430f6638.h> UCSCTL7 &=
~(DCOFFG+XT1LFOFFG+XT2OFFG)#include <stdint.h>
;
#include <stdio.h>
#include math.h SFRIFG1 &= ~OFIFG;
}
#include dr_tft.h
UCSCTL5 = DIV A__1 + DIVS__1 +
DIVM__1; //设定几个CLK的分频
//FFT#define N 256 点数UCSCTL4 = SELA__XT1CLK + SELS__DCOCLK + SELM__DCOCLK; #define PI 3.14159265327 // 设定几个CLK的时钟源
} volatile long IntDegF;
volatile long IntDegC;
struct compx
{ void initClock()
{
float real,imag;
};
while(BAKCTL & LOCKIO) //
struct compx collect[N],collect0[N]; Unlock XT1 pins for operation
BAKCTL &= ~(LOCKIO);
采集到的值//AD
fs unsigned long = 28500; 启~XT1OFF; &= UCSCTL6 //动
//采样频率XT1
int i,j,fre;
P7SEL |= BIT2 + BIT3; //XT2 引脚功float temp_frc,z;
能选择unsigned int t=0,k=0,flag=0,n=0,c=0; 动//~XT2OFF; &= UCSCTL6 启XT2
/*
while (SFRIFG1 & OFIFG)
EE(struct 数稳定DCO与XT2XT1等待{ // 、函原compx struct 型:compx
b1,struct compx b2)
UCSCTL7 &=
~(DCOFFG+XT1LFOFFG+XT2OFFG)函数功能:对两个复数进行乘法运算输入参数:两个以联合体定义的复数;
a,b
SFRIFG1 &= ~OFIFG;
以联合体的的乘积,b和a输出参数:}
形式输出//把最高位变成0
k=k/2; */
//k/2,比较次高位,依次类推,逐个比struct compx EE(struct compx a,struct
较,直到某个位为0 compx b)
} {
j=j+k; struct compx c;
//把0改为1
c.real=a.real*b.real-a.imag*b.imag; }
c.imag=a.real*b.imag+a.imag*b.rea
l;
f=N;
for(l=1;(f=f/2)!=1;l++) return(c); //计算l的值,即计算蝶形级数}
;
/*
for(m=1;m<=l;m++) // 控制蝶形结级数函数原型:void FFT(struct compx *xin)
函数功能:对输入的复数组进行快速{ //m表示第m级蝶形,l为蝶
形级总数l=log(FFT傅里叶变换()2)N
le=2<<(m-1); *xin输入参数:复数结构体组的首地//le蝶形结距离,即第m型址指针,struct 级蝶形的蝶形结相距le点*/
lei=le/2; //void FFT(struct compx *xin) 同一蝶形结中参加运算的两点的距离{
u.real=1.0; int f,m,nv2,nm1,i,k,l,j=0; //u为蝶形结运算系数,初始值为1 struct compx u,w,t;
int le,lei,ip; 运u.imag=0.0; //FFT w.real=cos(PI/lei); 运算算核,使用蝶形运算完成FFT //w为系数商,即当前系数与前一个系数的商nv2=N/2; //变址运算,即把自然顺w.imag=-sin(PI/lei);
序变成倒位序,采用雷德算法for(j=0;j<=lei-1;j++) //控制计算不同种蝶形结,即计算系数不nm1=N-1;
同的蝶形结for(i=0;i<nm1;i++)
{
{
for(i=j;i<=N-1;i=i+le) // 如果//控制同if(i<j)
一蝶形结运算,即计算系数相同蝶形i<j,即进行变址结{
t=xin[j]; {
ip=i+lei; xin[j]=xin[i]; //i,ip分别表示参加蝶形运算的两个节点xin[i]=t;
t=EE(xin[ip],u); }
的下一个倒j// k=nv2; 求//蝶形运算,详见公式位序
xin[ip].real=xin[i].real-t.real; while(k<=j)
1 的最高位为j表示如果//k<=j,
xin[ip].imag=xin[i].imag-t.imag; {
j=j-k;
xin[i].real=xin[i].real+t.real; char buffer[81];
etft_AreaSet(0,0,239,319,0);//清屏
xin[i].imag=xin[i].imag+t.imag; sprintf(buffer, Name:Zhao
Zhenqi); }
//改变系数,进行下etft_DisplayString(buffer, 0, 0, u=EE(u,w);
0xFFFF, 0x0000); 一个蝶形运算} sprintf(buffer, Student
Number:22920132203719); }
etft_DisplayString(buffer, 0, 16, }
0xFFFF, 0x0000);
void main( void )
while(1) {
float y[N]; {
// Stop watchdog timer to prevent
time out reset
ADC12CTL0 |= ADC12SC; + WDTCTL = WDTPW //
Sampling and conversion start WDTHOLD;
__bis_SR_register(LPM4_bits +
GIE); initClock(); // LPM0 with interrupts
enabled initTFT();
__no_operation();
REFCTL0 &= ~REFMSTR; if(flag==1)
处理//FFT // Reset REFMSTR to hand over control {
to 模块FFT(collect); // ADC12_A ref
control registers
求变换后结; ADC12CTL0 = 0x0050 // for(i=0;i<N;i++)
果的模值,存入复数的实部部分// Internal ref = 1.5V
ADC12SHP; ADC12CTL1 =
collect[i].real=sqrt(collect[i].real*collect// enable sample timer
[i].real+collect[i].imag*collect[i].imag); ADC12MCTL0 =
temp_frc=collect[1].real; ch ADC ADC12INCH_13; // i/p
fre=1; A10 = temp sense i/p
for(i=2;i<N/2;i++) 0x001; ADC12IE =
{ ADC_IFG // upon conv
result-ADCMEMO
求出最__delay_cycles(75); if(collect[i].real>temp_frc)// // 75us delay to allow Ref to settle 大幅值对应的频点{ ADC12CTL0 |= ADC12ENC;
temp_frc=collect[i].real; P8DIR |= BIT0;
fre=i; P5DIR |= BIT7;
} P4DIR |= BIT5+BIT6+BIT7;
}
fre=fre*fs/N;//所测频率else if(fre>=1500&&fre<2500)
for(i=0;i<80;i++) {
P4OUT &= ~BIT5; {
y[i]=sin((float)i*PI*fre/2/fs); P4OUT |= BIT6;
} P4OUT &= ~BIT7;
P5OUT
&= ~BIT7; //LCD 液晶屏显示模块etft_AreaSet(32,0,239,319,0);//}
清屏
else if(fre>=2500&&fre<3500)
{
Frequency: ] sprintf(buffer,
Hz,fre);
P4OUT |= BIT5;
etft_DisplayString(buffer, 0, 32, P4OUT |= BIT6;
0xFFFF, 0x0000); P4OUT &= ~BIT7;
P5OUT &= ~BIT7;
sprintf(buffer,.); }
for(i=0;i<80;i++) else if(fre>=3500&&fre<4500)
{ {
P4OUT &= ~BIT6; etft_DisplayString(buffer,(i)*4,(int)((y[i] P4OUT |= 波绘+1)*10+90),0xFFFF,0x0000);//制BIT7;
形P5OUT &= ~BIT7;
} }
else if(fre>=4500&&fre<5500)
{
sprintf(buffer,*);
for(j=1;j<319;j++) P4OUT |= BIT5;
{ P4OUT &= ~BIT6;
P4OUT |= BIT7;
i=14-(int)(collect[j].real/(temp_frc/1 P5OUT &= ~BIT7;
0)*14);//扫频,频谱高度由该频点与中}
心频点的相对值决定else if(fre>=5500&&fre<6500)
{
P4OUT &= ~BIT5;
etft_DisplayString(buffer,j,200+i,0x P4OUT |= BIT6;
绘制频谱FFFF,0x0000);// P4OUT |= BIT7;
} P5OUT &= ~BIT7;
}
灯显示模块//LEDelse if(fre>=6500&&fre<7500)
if(fre>=500&&fre<1500) {
{
P4OUT |= BIT7;
P4OUT |= 点亮灯BIT5;//P4OUT |= BIT6;
熄灭灯P4OUT &= ~BIT6;// P4OUT |= BIT5;
P4OUT &= ~BIT7; P5OUT &= ~BIT7;
P5OUT &= ~BIT7; }
else if(fre>=7500&&fre<8500)
}
{
case 4: break; //Vector 4:
ADC转换时间溢出中断P4OUT &= ~BIT7;
P4OUT &= ~BIT6; case 6:
P4OUT &= ~BIT5; collect0[t].imag = 0;
collect0[t].real = ADC12MEM0*3.0 P5OUT |= BIT7; /
0x03ff; }
else if(fre>=8500&&fre<9500) t++;
{
if(t==N)//采满N个值
{
P4OUT |= BIT7;
P4OUT &= ~BIT5; flag=1;
P5OUT |= BIT7; for(k=0;k<N;k++)
}
{
collect[k]=collect0[k]; else if(fre>=9500&&fre<10500) {
}
}
P4OUT &= ~BIT7;
P4OUT |= BIT6; P8OUT ^=BIT0;
P4OUT &= ~BIT5;
P5OUT |= BIT7;
}
__bic_SR_register_on_exit(LPM0_bits); flag=0;
break; // 退出低功耗模式0
__delay_cycles(2*MCLK_FREQ);//
case 8: break; 延时} case 10: break;
} case 12: break;
} case 14: break;
case 16: break;
//AD 采样模块case 18: break;
vector #pragma = case 20: break;
ADC12_VECTOR
case 22: break;
__interrupt void ACD12_ISR(void) case 24: break; { case 26: break;
case 28: break;
switch(__even_in_range(ADC12IV, case 30: break; 34))
case 32: break;
{
case 34: break;
0: //Vector 0: case break; default: break;
无中断}
}
break; case 2: 2: //Vector
ADC溢出中断。