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
}

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

4

4 回答 4

2

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

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

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

真正的大问题是你为什么要在浮点中执行此操作 - 在(许多版本)具有整数乘法器硬件的 16 位整数处理器上。

于 2012-03-28T07:11:31.877 回答
1

正如 Ian 所说,您正在获取 8 位值(UCA0RXBUF 无论如何只有 8 位宽)并期望从中获得 32 位或 64 位值。

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

像 Ian 一样,我也会质疑在低功耗嵌入式微控制器中进行浮点数学运算是否明智。这种类型的任务更适合 DSP。

至少您应该使用定点数学,请参阅维基百科(即使在 DSP 中,您也会使用定点算术)。

于 2012-07-23T13:27:47.227 回答
0

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

最好的办法是构建一个 FIFO 缓冲区来保存合理数量的输入值。USCI 例程填充 FIFO,而主程序继续在其中查找数据并在可用时对其进行处理。

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

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

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

于 2014-10-13T13:45:02.977 回答
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 回答