2012-03-27 93 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屬性)。

在這種情況下,一定要聲明易失性中斷例程和主進程之間共享的每個變量。