Forum: Mikrocontroller und Digitale Elektronik MSP430 Capture eine Frequenz


von MiGu (Gast)


Lesenswert?

Hallo alle zusammen,

habe folgendes kleines Programm geschrieben. Es läuft auf dem 430F149. 
So weit so gut. Am Capture-Pin CCI2A habe ich eine quarzstabile 
Eingangsfrequenz von 32.786kHz angeschlossen. Diese wird auch nach 200 
Capture-Durchläufen und Mittelwertbildung angezeigt - der Clou ist aber, 
dass im Code noch irgendwo eine Schwachstelle ist. In den Array's summe 
und buffer habe ich mal 10 aufeinanderfolgende Messungen anzeigen 
lassen. Es sind öfter (aber nicht immer) Werte darunter, die um genau 
0xFFFF höher zu liegen scheinen. Irgendow ist da noch ein bug drin. Hat 
jemand eine Idee???

Danke euch, MG.

Der Code:


#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <msp430x14x.h>
#include <main.h>
#include <math.h>

volatile unsigned int LastValue;
char fCAP;
unsigned int count=0;
volatile unsigned long sum=0;
unsigned int CountTC;
float freq;
float buffer[10];
unsigned long summe[10];
int b=0;

void InitOsc(void)    // MCLK is the source (8MHz)
{
  unsigned int i;
  WDTCTL = WDTPW | WDTHOLD;             // stop watchdog timer
  BCSCTL1 &= ~XT2OFF;                   // XT2 = HF XTAL
  do{
    IFG1 &= ~OFIFG;                       // Clear OSCFault flag
    for (i = 0xFF; i > 0; i--);           // Time for flag to set
  }
  while ((IFG1 & OFIFG) != 0);          // OSCFault flag still set?
  BCSCTL2 |= SELM1 | SELS;              // MCLK = XT2 (safe) and SMCLK


  TACTL = TASSEL1 | TAIE | TACLR;
  TACTL |= MC1;
  TACCTL2 |= CM0 | CAP | CCIE | SCS;     // rising edge, CCI2A, sync, 
capture mode

  _EINT();                                  // Enable interrupts

}                                       // amplitude is OK)

void TimerA1_Interrupt(void) __interrupt[TIMERA1_VECTOR]
{
 TACCTL2 &= ~COV;
 switch(TAIV){
//----------------------------------------------------------
  case 0x0A:{     // timer 2 overflow
//++++++++++++++++++++++++++++++++++++++++
   if(LastValue==0) LastValue = 0xFFFF;
   sum+=0xFFFF-LastValue;
   LastValue=0;
   TACCTL2 |= CCIE;
//++++++++++++++++++++++++++++++++++++++++
    break;}
//----------------------------------------------------------
  case 0x04:{     // capture 2 interrupt
//++++++++++++++++++++++++++++++++++++++++

  if(fCAP == 1){
     LastValue = TACCR2;
     sum=0;
     fCAP = 0;
     TACCTL2 |= CCIE;
  }else{
     sum+=TACCR2-LastValue;
     LastValue = TACCR2;
     TACCTL2 |= CCIE;
     if(CountTC==199){
     freq =(200/(1e-6 * sum)*8);
     buffer[b] = freq;
     summe[b]=sum;
     b++;
     if(b==10){
       b=0;
     }
       fCAP = 1;
       P3OUT ^= 0x02;
       CountTC = 0;
       sum = 0;
       LastValue = 0;
      }else
       CountTC++;
  }

  /*
  if(TACCTL2 & 0x0002){
    TACCTL2 &= ~COV;
  }
*/
//++++++++++++++++++++++++++++++++++++++++
    break;}
 }
}

void main(void)
{
 int i;
  InitOsc();

  // Port Definition
  P3SEL = 0;
  P3OUT = 0;
  P3DIR = 0xFF;

  P1SEL = 0xff;
  P1OUT = 0;
  P1DIR = 0x01;

  fCAP = 1;
  CountTC=0;
 while(1){
 i++;i++;
  };
}

von MiGu (Gast)


Lesenswert?

Hallo allerseits,

habe den Fehler anscheinend gefunden: der Code in

  case 0x0A:{     // timer 2 overflow
//++++++++++++++++++++++++++++++++++++++++
   if(LastValue==0) LastValue = 0xFFFF;      // Zeile 1
   sum+=0xFFFF-LastValue;                    // Zeile 2
   LastValue=0;                              // Zeile 1
   TACCTL2 |= CCIE;
//++++++++++++++++++++++++++++++++++++++++
    break;}

muss wohl weg. Die Zeilen 1..3 kann man wohl auskommentieren und nur das 
setzen des IE-Flags lassen. Habe mal ein paar 10er Durchläufe so 
durchgespielt. Ist zwar etwas unlogisch aber naja. Wie verhält man sich 
beim aufsummieren, wenn ein Timerüberlauf das TACCR2-Register wieder auf 
null setzt und von dort aus weiterzählt....? Naja, werde mal weiter 
testen.

Greez, MG.

PS: Diese kleine Bsp. zum Capture mit MSP hat schon lange im Forum 
gefehlt :-)))

von MiGu (Gast)


Lesenswert?

Hallo alle zusammen,

habe mich mit der Capturei noch ein bisschen weiter beschäftigt und noch 
folgende Verbesserung zu vermerken. Folgender Code sollte an die Stelle 
mit der Frequenzberechnung ausgetauscht/eingefügt werden:

//############# snip ##############
TACTL &= ~MC1;                // Timer anhalten
TACCTL2 &= ~CM0;              // Capture anhalten

     freq =(200/(1e-6 * sum)*8);   // Berechnung wie oben

TACCTL2 &= ~COV;             // falls Capture Overflow, löschen
TACCTL2 |= CM0;              // Captuer starten
TACTL |= MC1;                // ... und dann Timer an
//################################

Es werden hier der Timer und das Capture explizit angehalten (AUCH DAS 
CAPTURE!!!). Dann erfolgt der zeitaufwendige Schrunz... Und dann beides 
wieder einschalten. Somit bekommt die ganze Zähleinheit nicht 
durcheinander. Läuft soweit super.

Bis denne,
MG.

von MiGu (Gast)


Lesenswert?

Ich noch ma,


also beim Capturen und den Timern sollte man die ganze 
Interrupt-Geschichte nicht ausser Acht lassen. Besonders der 
Capture-Interrupt kann feuern - auch wenn man noch in der 
Interrupt-Routine ist. Somit wird das COV-Flag gesetzt aber danach kann 
die Int-Routine gleich wieder starten - also bei Berechnungen unbedingt 
den Timer und Capture AUSSCHALTEN und danach wieder ein.

MG.

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.