MSP430无法处理双倍

时间:2012-03-27 18:47:18

标签: msp430

我正在尝试使用简单的“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
}

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

4 个答案:

答案 0 :(得分:2)

您的问题看起来像是将数据发送到MSP的方式。

根据您的代码,来自MATLAB的通信是一系列4个二进制字节值,然后您可以从串行端口获取并将其直接转换为double。进入的值将在-128到+127之间。

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

真正重要的问题是你在浮动点上做了什么 - 在一个16位整数处理器上(许多版本)都有整数乘法器硬件。

答案 1 :(得分:1)

正如Ian所说,你正在采用一个8位的值(UCA0RXBUF无论如何只有8位宽),并希望得到一个32位或64位的值。

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

与Ian一样,我也会质疑在低功耗嵌入式微控制器中进行浮点运算的智慧。这类任务更适合DSP。

至少你应该使用定点数学,参见wikipedia(即使在DSP中你也会使用定点运算)。

答案 2 :(得分: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)

答案 3 :(得分:0)

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

最好的是构建一个FIFO缓冲区,其中包含可合理数量的输入值。 USCI例程填充FIFO,而主程序一直在查找其中的数据并在它们可用时进行处理。

这样,在处理数据时,USCI可以中断处理新的输入字节。

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

在这种情况下,请务必声明 volatile 在中断例程和主进程之间共享的每个变量。