2012-03-27 63 views
0

我想编写一个简单的“FIR滤波器”程序的MSP430,看起来像以下:MSP430无法处理双

#include "msp430x22x4.h" 
#include "legacymsp430.h" 

#define FILTER_LENGTH 4 
#define TimerA_counter_value 12000    // 12000 counts/s -> 12000 counts ~ 1 Hz 

int i; 
double x[FILTER_LENGTH+1] = {0,0,0,0,0}; 
double y = 0; 
double b[FILTER_LENGTH+1] = {0.0338, 0.2401, 0.4521, 0.2401, 0.0338}; 

signed char floor_and_convert(double y); 

void setup(void) 
{ 
WDTCTL = WDTPW + WDTHOLD;      // Stop WDT 
BCSCTL1 = CALBC1_8MHZ;       // Set DCO 
DCOCTL = CALDCO_8MHZ; 

/* Setup Port 3 */ 
P3SEL |= BIT4 + BIT5;       // P3.4,5 = USART0 TXD/RXD 
P3DIR |= BIT4;         // P3.4 output direction 

/* UART */ 
UCA0CTL1 = UCSSEL_2;       // SMCLK 
UCA0BR0 = 0x41;         // 9600 baud from 8Mhz 
UCA0BR1 = 0x3; 
UCA0MCTL = UCBRS_2;      
UCA0CTL1 &= ~UCSWRST;       // **Initialize USCI state machine** 
IE2 |= UCA0RXIE;        // Enable USCI_A0 RX interrupt 

/* Setup TimerA */ 
BCSCTL3 |= LFXT1S_2;       // LFXT1S_2: Mode 2 for LFXT1 = VLO 
               // VLO provides a typical frequency of 12kHz 
TACCTL0 = CCIE;         // TACCR0 Capture/compare interrupt enable 
TACCR0 = TimerA_counter_value;     // Timer A Capture/Compare 0: -> 25 Hz 
TACTL = TASSEL_1;        // TASSEL_1: Timer A clock source select: 1 - ACLK 

TACTL |= MC_1;         // Start Timer_A in up mode 
__enable_interrupt(); 
} 

void main(void)         // Beginning of program 
{ 
setup();          // Call Function setup (see above) 
_BIS_SR(LPM3_bits);       // Enter LPM0 
} 


/* USCIA interrupt service routine */ 
               /*#pragma vector=USCIAB0RX_VECTOR;*/ 
               /*__interrupt void USCI0RX_ISR(void)*/ 
interrupt (USCIAB0RX_VECTOR) USCI0RX_ISR(void) 
{ 

TACTL |= MC_1;         // Start Timer_A in up mode 

x[0] = (double)((signed char)UCA0RXBUF);  // Read received sample and perform type casts 
y = 0; 
for(i = 0;i <= FILTER_LENGTH;i++)   // Run FIR filter for each received sample 
{ 
    y += b[i]*x[i]; 
}  
for(i = FILTER_LENGTH-1;i >= 0;i--)   // Roll x array in order to hold old sample inputs 
{ 
    x[i+1] = x[i]; 
} 

while (!(IFG2&UCA0TXIFG));      // Wait until USART0 TX buffer is ready? 
UCA0TXBUF = (signed char) y; 
TACTL |= TACLR;         // Clear TimerA (prevent interrupt during receive) 
} 

/* Timer A interrupt service routine */ 
               /*#pragma vector=TIMERA0_VECTOR;*/ 
               /*__interrupt void TimerA_ISR (void)*/ 
interrupt (TIMERA0_VECTOR) TimerA_ISR(void) 
{ 
for(i = 0;i <= FILTER_LENGTH;i++)   // Clear x array if no data has arrived after 1 sec 
{ 
    x[i] = 0; 
} 
TACTL &= ~MC_1;         // Stops TimerA 
} 

程序与MATLAB代码,发送200个双打交互到MSP,在FIR滤波器中进行处理。我的问题是,MSP无法处理双打。 我正在使用MSPGCC来编译代码。当我发送一个int到MSP时,它会响应再次发送一个int。

+0

尽量简化代码*很多*。如果问题出在数学处理上,你的例子不需要所有的中断处理代码。另外,告诉我们你期望得到什么以及你实际得到了什么。 – Lindydancer 2012-03-27 19:54:51

+0

我期望得到与MATLAB代码中FIR滤波器产生的值相匹配的返回值。我试图分析从MSP返回的内容,我确实得到了一些值,但不是它发送给MSP(200)的那么多。我试图在Windows机器上编译AIR中的代码,当这样做时,代码工作正常。 – Kaspersoerensen 2012-03-28 15:44:23

回答

2

你的问题看起来是在数据被发送到MSP的方式。

从MATLAB的通信,根据你的代码,4个二进制字节值,你再从串口取直投它的双序列。进来的价值将有一个-128到+127的范围。

如果源数据为任何其他数据大小那么你的程序将被打破。如果您的数据源提供二进制“双倍”数据,则根据其内部数据表示形式,每个值可能为4或8个字节。通过串口发送这些值中的一个将被MSP解释为一组完整的4个输入样本,导致对于一组答案的绝对垃圾。

真正的大问题是,究竟为什么要这样的浮点 - 一个16位整数处理器(多种类型)具有整数倍数的硬件。

0

嗯。实际上,代码是由我的老师,我只是试图让我的Mac上,而不是在AIR工作:-)

MATLAB代码是这样的:

function FilterTest(comport) 
Fs = 100;   % Sampling Frequency 
Ts = 1/Fs;   % Sampling Periode 
L = 200;    % Number of samples 

N = 4;     % Filter order 
Fcut = 5;    % Cut-off frequency 
B = fir1(N,Fcut/(Fs/2)) % Filter coefficients in length N+1 vector B 

t = [0:L-1]*Ts;   % time array 
A_m = 80;    % Amplitude of main component 
F_m = 5;    % Frequency of main component 
P_m = 80;    % Phase of main component 

y_m = A_m*sin(2*pi*F_m*t - P_m*(pi/180)); 

A_s = 40;    % Amplitude of secondary component 
F_s = 40;    % Frequency of secondary component 
P_s = 20;    % Phase of secondary component 

y_s = A_s*sin(2*pi*F_s*t - P_s*(pi/180)); 

y = round(y_m + y_s); % sum of main and secondary components (rounded to integers) 

y_filt = round(filter(B,1,y)); % filtered data (rounded to integers) 

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 
Serial_port_object = serial(comport);   % create Serial port object 
set(Serial_port_object,'InputBufferSize',L)  % set InputBufferSize to length of data 
set(Serial_port_object,'OutputBufferSize',L) % set OutputBufferSize to length of data 
fopen(Serial_port_object)      % open Com Port 
fwrite(Serial_port_object,y,'int8');   % send out data 
data = fread(Serial_port_object,L,'int8');  % read back data 
fclose(Serial_port_object)      % close Com Port 
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 

subplot(2,1,1) 
hold off 
plot(t,y) 
hold on 
plot(t,y_filt,'r') 
plot(t,y_filt,'ro') 
plot(t,data,'k.') 
ylabel('Amplitude') 
legend('y','y filt (PC)','y filt (PC)','y filt (muP)') 

subplot(2,1,2) 
hold off 
plot(t,data'-y_filt) 
hold on 
xlabel('time') 
ylabel('muP - PC') 
figure(1) 
1

正如伊恩说,你需要一个8位的值(反正UCA0RXBUF只有8位宽),并期望得到一个32位或64位的值。

为了得到正确的样本,您需要多次读取UCA0RXBUF,然后将每个8位值连接成32/64位,然后将其转换为双精度值。

像伊恩我也质疑在低功耗的嵌入式微控制器执行浮点运算的智慧。这种类型的任务更适合于DSP。

至少你应该使用定点数学,见wikipedia(即使在DSP中你将使用定点算术)。

0

也不建议保持中断例程执行长处理例程,因为这会影响中断延迟。由于串口上的缓冲区溢出,来自PC的字节很容易丢失。

最好是建立一个FIFO缓冲器保持输入值的合理的数量。 USCI例程填充FIFO,而主程序不断查找其中的数据并在它们可用时处理它们。

这样,当数据正在处理时,USCI可以中断来处理新的包含字节。

当FIFO为空时,可以将主进程置于合适的LPM模式以节省功耗(这是MSP430的特性)。当数据准备就绪时,USCI例程会唤醒CPU(如果使用MSPGCC,只需在USCI处理程序中放置WAKEUP属性)。

在这种情况下,一定要声明易失性中断例程和主进程之间共享的每个变量。