0

次のような単純な「FIRフィルター」プログラムを使用して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
}

プログラムは、FIRフィルターで処理するためにMSPに200のdoubleを送信するMatLabコードと対話します。私の問題は、MSPがダブルスを処理できないことです。私はMSPGCCを使用してコードをコンパイルしています。私がintをMSPに送信すると、MSPはintを再度送信するように応答します。

4

4 に答える 4

2

問題は、データが MSP に送信される方法にあるようです。

MATLAB からの通信は、コードによると、4 つのバイナリ バイト値のシーケンスであり、シリアル ポートから取得して double に直接キャストします。入力される値の範囲は -128 から +127 です。

ソース データが他のデータ サイズである場合、プログラムは壊れます。データ ソースがバイナリの「double」データを提供している場合、各値は内部データ表現に応じて 4 バイトまたは 8 バイトの長さになります。これらの値の 1 つをシリアル ポート経由で送信すると、MSP によって 4 つの入力サンプルの完全なセットとして解釈され、一連の回答が完全にガベージになります。

本当に大きな問題は、なぜ地球上でこれを浮動小数点で行うのかということです-(多くのバージョンで)整数乗算器ハードウェアを備えた16ビット整数プロセッサ上で。

于 2012-03-28T07:11:31.877 に答える
1

イアンが言ったように、あなたは 8 ビットの値を取り (とにかく UCA0RXBUF は 8 ビット幅しかありません)、そこから 32 ビットまたは 64 ビットの値を取得することを期待しています。

適切なサンプルを取得するには、UCA0RXBUF を複数回読み取り、各 8 ビット値を 32/64 ビットに連結してから double にキャストする必要があります。

Ian のように、低消費電力の組み込みマイクロコントローラーで浮動小数点演算を行うことの賢明さにも疑問を投げかけます。このタイプのタスクは、DSP に適しています。

少なくとも、固定小数点演算を使用する必要があります。wikipediaを参照してください (DSP でも固定小数点演算を使用します)。

于 2012-07-23T13:27:47.227 に答える
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)
于 2012-03-28T10:59:40.027 に答える
0

また、割り込みの待ち時間に影響を与えるため、割り込みルーチンで長い処理ルーチンを実行し続けることもお勧めしません。シリアル ポートでのバッファ オーバーランが原因で、PC からのバイトが簡単に失われる可能性があります。

妥当な数の入力値を保持する FIFO バッファを構築するのが最善です。USCI ルーチンは、メイン プログラムが FIFO 内のデータを探し続け、利用可能になったときにそれらを処理する間、FIFO をいっぱいにします。

このようにして、データが処理されている間、USCI は新しい受信バイトを処理するために中断できます。

FIFO が空の場合、電力を節約するためにメイン プロセスを適切な LPM モードにすることができます (これがMSP430の最良の機能です)。USCI ルーチンは、データの準備ができると CPU を起動します (MSPGCC を使用している場合は、USCI ハンドラに WAKEUP 属性を設定するだけです)。

このようなシナリオでは、割り込みルーチンとメイン プロセスの間で共有されるすべての変数を必ずvolatile宣言してください。

于 2014-10-13T13:45:02.977 に答える