Forum: Mikrocontroller und Digitale Elektronik Interruptbehandlung MSP430


von Daniel S. (nasenschleim)


Lesenswert?

Hallo,

ich bin noch ziemlich neu auf dem Gebiet "uC" und habe mich jetzt mal 
mit dem MSP430f169 auseinander gesetzt.
Die TI-Beispiele habe ich mir auch schon angeschaut.

Kurz gesagt geht es darum über USART1 etwas über USB zu empfangen 
(benutze dazu den CP2103 (USB-Seriell-Chip)) und dadurch den uC zu 
steuern. Zum Beispiel eine Messung mit ein oder zwei Sensoren 
anzustoßen. Die Messwerte sollen anschließend über die USART 
Schnittstelle zum PC transferiert werden. Im einzelnen funktioniert die 
Kommunikation...

Nun wollte ich die Kommunikation Interruptgesteuert ausführen. Also wenn 
der PC einen Befehl an den uC schickt, soll dieser in die ISR wechseln 
und erstmal die ankommenden Daten aufnehmen. Dies klappt aber nur wenn 
ich den uC in den LP Modus setze (als Beispiel LPM0), dann nimmt er die 
Daten, welche gesendet werden auf und verarbeitet diese durch einer 
Switch-Case Anweisung.

Meine Frage warum, funktioniert dies nur in einem LPM Mode und nicht 
ganz normal aus dem Mainprogramm heraus. Ich dachte mir das er auch in 
die ISR springen kann, wenn er zum Beispiel gerade die Analogauswertung 
bearbeitet!?

Ich hoffe ihr könnt mir bei meinem Problem weiterhelfen.
Schon mal danke.

Hier mal noch der C-Code:

// MSP430 Programm

#include  "msp430f169.h"

char string1[8];
char Auswahl;
char test,Ende1;
int j,i;
int a=0;

void delay(unsigned int a);          // Wartezeitfunktion initialisiert


void main(void)
{
// Allgemeine Einstellung
  WDTCTL = WDTPW + WDTHOLD;             // WatchDogTimer anhalten

// Einstellung ADC
  P6SEL |= 0x01;                       // Pin 6.0 mit AD Funktion nutzen
  ADC12CTL0 = ADC12ON+SHT0_8+REFON+MSC;     // ADC12 einschalten
  ADC12CTL1 = SHP+CONSEQ_2;
  ADC12MCTL0 = SREF_1+INCH_0;         // Referenzspgquelle zugewiesen + 
Daten in ADC12MEM0 schreiben
  ADC12IE = 0x01;                     // Interrupt einschalten für ADC 0
  ADC12CTL0 |= ENC;                   // ADC Konfiguration abgeschlossen

// Einstellung USART1
  P3SEL |= 0xC0;                      // Port P3.6,7 = USART1
  ME2 |= UTXE1 + URXE1;               // Einschalten USART1 Modul
  UCTL1 |= CHAR;                      // USART 8Bit (Char)
  UTCTL1 |= SSEL0;                    // UCLK = ACLK
  UBR01 = 0x03;                       // 32k/9600 - 3.41
  UBR11 = 0x00;                       // UBR11 = Baud Rate 1
  //UMCTL1 = 0x4A;                    // Modulation Control (Korrektur 
der Baudratendivision)
  UMCTL1 = 0x49;              // Verbesserung der Korrektur bei 9600 
Baud
  UCTL1 &= ~SWRST;                    // SRST = USART Software Reset
  IE2 |= UTXIE1;                      // Enable USART1 TX-Interrupt
  IE2 |= URXIE1;                      // Enable USART1 RX-Interrupt
  IFG2 &= ~UTXIFG1;                   // initales interrupt-flag 
loeschen
  IFG2 &= ~URXIFG1;                   // initales interrupt-flag 
loeschen

  P4DIR = 0xFF;                // Port 4 als Output (LEDs)
  P4SEL = 0x00;                // Ports als GPIO benutzen (=0)
  P4OUT = 0x00;                // Initialisierung Port4 (Low=0)

  j=0;


  for(;;)            // Main-loop (Endlosschleife)
  {

  _BIS_SR(LPM0_bits + GIE);               // in den LPM0 wechseln

/*
// ADC_Konvertierung starten
  ADC12CTL0 |= ADC12SC;                     // Konvertierung starten


// Umformen vom ADC12MEM0 und senden der Ergebnisse
  unsigned char Part1,Part2;
  Part1 = ADC12MEM0;
  Part2 = (ADC12MEM0 >> 8);

     while (!(IFG2 & UTXIFG1));  // warten, bis USART1 TX-Buffer 
sendebereit
   TXBUF1= Part2;
     while (!(IFG2 & UTXIFG1));    // warten, bis USART1 TX-Buffer 
sendebereit
   TXBUF1= Part1;
     while (!(IFG2 & UTXIFG1));    // warten, bis USART1 TX-Buffer 
sendebereit
   TXBUF1= '/';             // Zeichen 1von2 Uebermittlung Ende
     while (!(IFG2 & UTXIFG1));    // warten, bis USART1 TX-Buffer 
sendebereit
   TXBUF1= '0';              // Zeichen 2von2 Uebermittlung Ende

 // Wartefunktion noch durch Timer ersetzen
  delay(60000);                // Wartefunktion

 */


 // Empfangenen String vergleichen
  if ((string1[0] == 'S') && (string1[1] == 'E') && (string1[2] == 'N') 
&& (string1[3] == '1'))
  { Auswahl = '1';}

  if ((string1[0] == 'S') && (string1[1] == 'E') && (string1[2] == 'N') 
&& (string1[3] == '2'))
  { Auswahl = '2';}

  if ((string1[0] == '0') && (string1[1] == 'S') && (string1[2] == 'E') 
&& (string1[3] == 'N'))
  { Auswahl = '0';}

  if ((string1[0] == '2') && (string1[1] == 'S') && (string1[2] == 'E') 
&& (string1[3] == 'N'))
  { Auswahl = '3';}

    switch(Auswahl)
      {
      case '0':
          test='a';
          break;
      case '1':
          test='b';
          break;
      case '2':
          test='c';
          break;
      case '3':
          test='d';
          break;

      default:
           test='0';
           break;

      }
  }
}

// Interruptbehandlung bei einkommenden Daten(RX)
#pragma vector=USART1RX_VECTOR
__interrupt void usart1_rx (void)
{
        string1[j++] = RXBUF1;
        if (RXBUF1==92)
          {a=1;}
        if ((RXBUF1=='0') && (a))
          {j=0;
           a=0;}

    _BIC_SR_IRQ(LPM0_bits);
}

von Stefan (Gast)


Lesenswert?

1.) Halte Dich an die Reihenfolge im User Guide:
Note: Initializing or Re-Configuring the USART Module
The required USART initialization/re-configuration process is:
1) Set SWRST (BIS.B #SWRST,&UxCTL)
2) Initialize all USART registers with SWRST = 1 (including UxCTL)
3) Enable USART module via the MEx SFRs (URXEx and/or UTXEx)
4) Clear SWRST via software (BIC.B #SWRST,&UxCTL)
5) Enable interrupts (optional) via the IEx SFRs (URXIEx and/or UTXIEx)
Failure to follow this process may result in unpredictable USART 
behavior.

2.) Möglicherweise ärgert Dich folgender Bug:
US14 USART0, USART1 Module
Function Lost character start edge
Description When using the USART in UART mode with UxBR0 = 0x03 and 
UxBR1 = 0x00, the start edge of received characters may be ignored due 
to internal timing conflicts within the UART state machine. This 
condition does not apply when UxBR0 > 0x03.
Workaround None

3.) Setze Deinen Code in [ c ]...[ /c ]. (Leerzeichen weglassen!)
Dann kann man's auch lesen ;-)

4.) Soll das heißen, Dein geposteter Code funktioniert und sobald Du
1
_BIS_SR(LPM0_bits + GIE);               // in den LPM0 wechseln
durch
1
_BIS_SR(GIE);
ersetzt, geht's nicht mehr?

von Daniel S. (nasenschleim)


Lesenswert?

zu 3.

was meinst du damit?
Soll ich die Leerzeichen in den Anweisungen weglassen oder meinst du nur 
die vielen Freiräume zwischen Anweisung und Kommentar, welche hier durch 
den Zeilenumbruch schnell zu einem kleinen Chaos mutieren?


zu 4.

ja, der Code funktioniert soweit. Ich sehe die Änderung des Strings und 
der Variablen im DebugModus des CodeComposers.
Er funktioniert nicht mehr wenn ich
_BIS_SR(LPM0_bits + GIE);
und
_BIC_SR_IRQ(LPM0_bits);
auskommentiere. (Ich war die ganze Zeit der Meinung, das ich die 
Interruptbehandlung durch die anfangs gemachten Einstellungen schon 
aktiviert hatte und somit die Sache dann von alleine läuft.

Ich habe die ganze Zeit gedacht das ich durch die erste Anweisung in den 
LPM0, inklusive eingeschalteten Interrupt wechsle und durch die 2. 
Anweisung (_BIC_SR_IRQ(LPM0_bits);) nach einer ISR wieder in den LPM 
wechsle...

Habe ebend mal nur die Anweisung (_BIS_SR(GIE);) probiert und es funzt, 
so wie ich es mir vorstelle.
Also muß ich diese Anweisung verwenden um endgültig  die 
Interruptbehandlung zu aktivieren?



Noch mal sorry für die vermeintlich blöden Fragen...

von Stefan (Gast)


Lesenswert?

Daniel S. schrieb:
> zu 3.
>
> was meinst du damit?
> Soll ich die Leerzeichen in den Anweisungen weglassen oder meinst du nur
> die vielen Freiräume zwischen Anweisung und Kommentar, welche hier durch
> den Zeilenumbruch schnell zu einem kleinen Chaos mutieren?
Du sollst Deinen Code formatieren, so dass man ihn hier besser lesen 
kann:
http://www.mikrocontroller.net/articles/Formatierung_im_Forum

> zu 4.
> Er funktioniert nicht mehr wenn ich
> _BIS_SR(LPM0_bits + GIE);
> und
> _BIC_SR_IRQ(LPM0_bits);
> auskommentiere.
Die Antwort hast Du Dir ja selbst schon gegeben:

> Habe ebend mal nur die Anweisung (_BIS_SR(GIE);) probiert und es funzt,


> Also muß ich diese Anweisung verwenden um endgültig  die
> Interruptbehandlung zu aktivieren?
Ja sicher, mit dem G(lobal) I(nterrupt) E(nable) gibst Du die einzelnen 
Interrupts überhaupt erst global frei!

von Daniel S. (nasenschleim)


Lesenswert?

Okay, vielen Dank.
Hat mir sehr geholfen.
Es sind halt immer die Kleinigkeiten die man vergisst.

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.