2012-03-27 2 views
0

내가처럼 보이는 간단한 "FIR 필터"프로그램으로 MSP430을 프로그램하려고 다음MSP430 수없는 이중

프로그램은 200 복식을 보내는 MATLAB 코드와 상호 작용
#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에 전달합니다. 내 문제는 MSP가 복식을 다룰 수 없다는 것입니다. MSPGCC를 사용하여 코드를 컴파일하고 있습니다. int를 MSP로 보내면 int를 다시 전송하는 것으로 응답합니다.

+0

* * 많이 * 코드를 단순화하십시오. 문제가 수학 처리에있는 경우 예제에 모든 인터럽트 전달 코드가 필요하지는 않습니다. 또한 얻으려는 내용과 실제로 얻은 내용을 알려주십시오. – Lindydancer

+0

MATLAB 코드의 FIR 필터가 생성하는 값과 일치하는 결과를 얻을 것으로 예상됩니다. 나는 MSP에서 돌아온 것을 분석하려고 시도했지만 MSP (200)에 보내는 것처럼 값을 얻지 만 많지는 않습니다. Windows 컴퓨터에서 AIR의 코드를 컴파일하려고 시도했는데 코드가 제대로 작동합니다. – Kaspersoerensen

답변

2

데이터가 MSP로 전송되는 방식에 문제가있는 것처럼 보입니다.

MATLAB의 통신은 코드에 따라 직렬 포트에서 가져온 연속 4 개의 2 진수 바이트 값을 연속적으로 double로 변환합니다. 들어오는 값의 범위는 -128에서 +127입니다.

원본 데이터가 다른 데이터 크기이면 프로그램이 손상됩니다. 데이터 소스가 2 진 "이중"데이터를 제공하면 각 값은 내부 데이터 표현에 따라 4 또는 8 바이트가 될 수 있습니다. 직렬 포트를 통해이 값들 중 하나를 보내면 MSP에 의해 4 개의 입력 샘플로 해석되어 결과 집합에 절대적인 가비지가 발생합니다.

정말로 큰 질문은 부동 소수점에서이 작업을 수행하는 이유입니다. (많은 버전) 정수 배율 하드웨어가있는 16 비트 정수 프로세서에서.

0

흠. 실제로 코드가 선생님으로 구성되어, 나는 그냥

MATLAB 코드 :-), 그리고 AIR 내 Mac에서 작동하도록 노력하고있어 다음과 같이이다 :

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 비트로 연결해야합니다. 그러면이 값을 double로 변환합니다.

Ian과 마찬가지로 저전력 임베디드 마이크로 컨트롤러에서 부동 소수점 연산을 수행하는 지혜를 묻습니다. 이러한 유형의 작업은 DSP에 훨씬 더 적합합니다.

고정 소수점 연산을 사용해야합니다 (wikipedia 참조). 고정 소수점 연산을 사용하는 DSP에서도 마찬가지입니다.

0

인터럽트 지연에 영향을주기 때문에 긴 처리 루틴을 수행하는 인터럽트 루틴을 유지하는 것도 권장되지 않습니다. 직렬 포트의 버퍼 오버런으로 인해 PC에서 오는 바이트가 쉽게 손실 될 수 있습니다.

가장 좋은 방법은 매력적인 수의 입력 값을 유지하는 FIFO 버퍼를 만드는 것입니다. USCI 루틴은 FIFO를 채우지 만 주 프로그램은 내부의 데이터를 계속 찾고 사용 가능한 상태로 처리합니다.

이렇게하면 데이터가 처리되는 동안 USCI가 새로운 수신 바이트를 처리하기 위해 인터럽트 할 수 있습니다.

FIFO가 비어있는 경우 전원을 절약하기 위해 주 프로세스를 적절한 LPM 모드로 설정할 수 있습니다.이 메시지는 인데 가장 좋은 MSP430 기능입니다. USCI 루틴은 데이터가 준비되면 CPU를 깨울 것입니다 (MSPGCC를 사용하는 경우 USCI 핸들러에 WAKEUP 속성을 입력하십시오).

그런 시나리오에서는 인터럽트 루틴과 주 프로세스간에 공유되는 모든 변수을 휘발성으로 선언해야합니다.