www.mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik MSP430 LaunchPad - Anfänger Probleme


Important announcement: there is an English version of this forum on EmbDev.net. Posts you create there will be displayed on Mikrocontroller.net and EmbDev.net.
Autor: PhilllihP (Gast)
Datum:

Diesen Beitrag bewerten:
lesenswert
nicht lesenswert
Hi Leute,

ich bin ein totaler Programmieranfänger und habe mir vor kurzem das TI 
MSP430 LaunchPad Rev. 1.4 besorgt und nun versuche ich meine ersten 
Schritte, die aber leider nicht so klappen wollen.

Zum Programmieren nutze ich Code Composer Studio 5.2 und zurzeit 
versuche ich gerade mal eine LED per Taster zum leuchten zu bringen.

Die LED ist am Port 1.0 angeschlossen und der Taser an Port 1.3
Der Taster wird als Pullup betrieben und ist über 47k an VCC.

Mein Programm sieht wie folgt aus:
/*
 * main.c
 */

#include  <msp430g2231.h>

//********************************
// Hauptprogramm

int main(void)    // Main program
{
  WDTCTL = WDTPW + WDTHOLD;  // Watchdog Timer ausschalten

  P1DIR = 0x01;  // Port P1.0 als output
  P1SEL = 0x00;  // Port 1 als GPIO nutzen
  P1IE  = 0x00;  // interrupt ausmachen
  P1OUT = 0x00;  // initial LED aus


    if ((P1IN & 0x08) == 0)
    {
      P1OUT=0x01;
    }

}

Das Problem ist nur nachdem Debugen läuft es irgendwie nicht an... erst 
wenn ich das Board vom USB trenne und wieder anschließe aber die LED 
leuchtet dann dauerhaft und nicht erst nach drücken des Tasters.

Meine eigentlich Frage ist was an meinem Code falsch ist das die Lampe 
nicht durch Tastendruck leuchtet und wieso das Board erst anläuft 
nachdem man den USB getrennt und erneute verbunden hat.

Danke schon mal für eure Hilfe :)

Autor: Helmut Lenzen (helmi1)
Datum:

Diesen Beitrag bewerten:
lesenswert
nicht lesenswert
Dein Program bearbeitet der Controller ruck-zuck und laeuft dann ins 
leere.
Mach da mal eine Endlosschleife um dein Programm. Ausserdem wird der 
Port nur gesetzt aber nie mehr zurueckgesetzt.

Autor: ucWriter (Gast)
Datum:

Diesen Beitrag bewerten:
lesenswert
nicht lesenswert
Nach der Initialisierung kommt i.d.R. eine Endlosschleife in der dein 
Hauptprogramm abgearbeitet wird.
while(1)
{
    if ((P1IN & 0x08) == 0)
    {
      P1OUT=0x01;
    }
}

Autor: DSausW (Gast)
Datum:

Diesen Beitrag bewerten:
lesenswert
nicht lesenswert
Für Fans von blinkenden LEDs und mehr
gibt es bei TI den sample code der MSP430G2XXXX-family.
Blinken im polling, oder mit interrupt- alles da.

Einfach einmal anschauen.
Praktisch ist es dann auch sich gleich die APPN
des Debuggers anzuschauen.

Autor: PhilllihP (Gast)
Datum:

Diesen Beitrag bewerten:
lesenswert
nicht lesenswert
Jetzt funktioniert es wunderbar
Danke :)

Autor: Test (Gast)
Datum:

Diesen Beitrag bewerten:
lesenswert
nicht lesenswert
LED = Taster
while(1)
{
    if ((P1IN & 0x08) == 0)
    {
      P1OUT |= 0x01;
    }
    else
      P1OUT &= ~0x01;
}

Autor: ArneN (Gast)
Datum:

Diesen Beitrag bewerten:
lesenswert
nicht lesenswert
Hallo zusammen!

Ich habe auch vor kurzem angefangen ein wenig mit dem MSP430 zu 
arbeiten. An sich komme ich sehr gut mit ihm zurecht, aber ich komme bei 
einer Sache einfach nicht weiter und habe bislang auch nichts 
hilfreiches zu meinem Problem finden können.

Ich möchte gerne eine Uhr mit dem MSP430G2231 bauen. Allerdings komme 
ich nicht dahinter, wie ich den uC so einstelle, dass er nach jeder 
Sekunde die Variable "sekunde" um eins inkrementiert.

In manchen Threads, die ich hier gelesen habe wird geschrieben, dass man 
das mit dem Watchdog-Timer irgendwie machen kann. Aber auch dahinter 
komme ich nicht wirklich und das Programm funktioniert teilweise gar 
nicht, wenn ich es auf den uC übertrage.

Kann mir da jemand helfen? Mit einem kleinen Programm, dass einfach jede 
Sekunde eine Variable erhöht, wäre mir schon sehr geholfen.

Vielen Dank im Vorraus!

Gruß
Arne

Autor: ucWriter (Gast)
Datum:

Diesen Beitrag bewerten:
lesenswert
nicht lesenswert
Also Du könntest Dir die Beispielprogramme zum Timer anschauen. Da wirst 
Du fündig.

Autor: Jörg S. (joerg-s)
Datum:

Diesen Beitrag bewerten:
lesenswert
nicht lesenswert
Die Ti Beispiele kennst du?
Wenn nein:
http://www.ti.com/lit/zip/slac463

Beispiel msp430g2xx1_wdt_01.c ist so ungefähr das was du willst.

Autor: ArneN (Gast)
Datum:

Diesen Beitrag bewerten:
lesenswert
nicht lesenswert
Vielen Dank für die schnellen Antworten. Ich habe mir mal das 
Code-Beispiel von TI schon vor kurzem angeschaut. Das Problem dabei ist, 
dass die LED dann sehr schnell blinkt.

Ich habe mir auch mal das Beispiel von microcontroller.net angeschaut:
http://www.mikrocontroller.net/articles/MSP430_Cod...

Das habe ich dann versucht einzubauen:
#include  <msp430g2231.h>


int main(void)    // Main program
{
  WDTCTL = WDTPW + WDTHOLD;  // Watchdog Timer ausschalten

  P1DIR = 0x01;  // Port P1.0 als output
  P1SEL = 0x00;  // Port 1 als GPIO nutzen
  P1IE  = 0x00;  // interrupt ausmachen
  P1OUT = 0x00;  // initial LED aus
  
  void init_TimerA();

}


void init_TimerA(unsigned int cycles )
  {
     TACTL = TASSEL1 + TACLR;              // SMCLK, clear TAR
     CCTL0 = CCIE;                         // CCR0 interrupt enabled
     CCR0 = cycles;
     TACTL |= MC_2;                         // Start Timer_A in continuous mode
     _EINT();                              // interrupt enable
  }
 
  // Timer A0 interrupt service routine
interrupt (TIMERA0_VECTOR) Timer_A(void)
  {
    P1OUT ^= 0x01;                        // Toggle P1.0
    CCR0 += 50000;                        // Add Offset to CCR0
  }


Error[Pe079]: expected a type specifier
Error[Pe260]: explicit type is missing ("int" assumed)
Error[Pe141]: unnamed prototyped parameters not allowed when body is 
present
Error[Pe130]: expected a "{"


Wo habe ich etwas falsch gemacht bzw. übersehen?

Autor: ucWriter (Gast)
Datum:

Diesen Beitrag bewerten:
lesenswert
nicht lesenswert
1) Die Code-Zeile
void init_TimerA();
in deiner main() ist nicht richtig.


2) Weiterhin fehlt immer noch (!) eine Endlosschleife.

3) Ich dachte immer beim Code Composer (habe V4.x). werden 
Interrupt-Handler wie z.B. folgenderweise
#pragma vector=ADC10_VECTOR
__interrupt void ADC10_ISR (void)
{
}

definiert. Hat sich das geändert?

4) Funktionsprototypen

5) Es gibt zum Launchpad eine Demo-Anwendung. Hast Du diese mal 
angeschaut und verstanden? Irgendetwas zusammenkopieren hilft Dir nicht.

Autor: Test (Gast)
Datum:

Diesen Beitrag bewerten:
lesenswert
nicht lesenswert
hier mal das TI Demo mit kleiner Erweiterung
#include <msp430g2231.h>

volatile unsigned int wdt_intr = 0;

void main(void)
{
  WDTCTL = WDT_MDLY_32;                     // Set Watchdog Timer interval to ~30ms
  IE1 |= WDTIE;                             // Enable WDT interrupt
  P1DIR |= 0x01;                            // Set P1.0 to output direction

  _BIS_SR(LPM0_bits + GIE);                 // Enter LPM0 w/ interrupt
}

// Watchdog Timer interrupt service routine
#pragma vector=WDT_VECTOR
__interrupt void watchdog_timer(void)
{
  if(wdt_intr++ >= 31)
  {
    wdt_intr = 0;  
    P1OUT ^= 0x01;                            // Toggle P1.0 using exclusive-OR
  }
}

ucWriter schrieb:
> Weiterhin fehlt immer noch (!) eine Endlosschleife.
Braucht man hier nicht, da nur low power Schlaf oder ISR.

Autor: ArneN (Gast)
Datum:

Diesen Beitrag bewerten:
lesenswert
nicht lesenswert
Vielen Dank für den Code.
Wenn ich das richtig sehe, wird jetzt alle ~30ms die Variable erhöht.

Das heißt also, dass das Interrupt 33 mal durchgelaufen sein muss, damit 
ich eine Sekunde durch habe.
Folglich kann ich nun eine Variable "Sekunde" einfügen, die nach jeder 
Sekunde erhöht wird.
Richtig?

Da meine Uhr dadurch aber nicht exakt laufen würde, da
33 \cdot 30ms = 990ms
 ist, stellt sich für mich die Frage, wie ich einen Quarz einbaue. Auf 
dieser Seite habe ich gefunden, wie man diesen initialisiert:
void init_XT2(void)
{
  unsigned int i;
  WDTCTL = WDTPW + WDTHOLD;             // Stop WDT
  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;                     // MCLK = XT2 (safe)
}

Und meines Wissens nach, muss ich den Quarz dann an
X_{in}
 und
X_{out}
 anschließen.

Wie baue ich das ganze aber jetzt in das Interrupt ein?

Autor: nightwatch (Gast)
Datum:

Diesen Beitrag bewerten:
lesenswert
nicht lesenswert

Autor: Jörg S. (joerg-s)
Datum:

Diesen Beitrag bewerten:
lesenswert
nicht lesenswert
ArneN schrieb:
> Wenn ich das richtig sehe, wird jetzt alle ~30ms die Variable erhöht.
Ja

> Das heißt also, dass das Interrupt 33 mal durchgelaufen sein muss, damit
> ich eine Sekunde durch habe.
> Folglich kann ich nun eine Variable "Sekunde" einfügen, die nach jeder
> Sekunde erhöht wird.
> Richtig?
Ja

> Da meine Uhr dadurch aber nicht exakt laufen würde, da 33 \cdot
> 30ms = 990ms ist, stellt sich für mich die Frage, wie ich einen
> Quarz einbaue.
Entweder einen 32kHz Quarz für den Watchdog Timer, oder du benutzt halt 
einen Timer und den DCO Takt.


Einen Interrupt brauchst du auch nicht zwingend (Nur beim Watchdog 
geht's glaub ich nicht anders). Der macht dann sinn wenn du extrem Strom 
sparen willst. Für den Anfang wäre das wohl noch nicht notwendig und 
verkompliziert dein Vorhaben nur unnötig.

Autor: ArneN (Gast)
Datum:

Diesen Beitrag bewerten:
lesenswert
nicht lesenswert
So wie ich das verstanden habe müsste ich den Quarz einfach nur zwischen 
Xin und Xout anschließen und dann folgendes eingeben:
WDTCTL = WDT_ADLY_250;                    // WDT 250ms, ACLK, interval timer

Dann müsste nach 4 durchläufen 1 Sekunde vergangen sein. Richtig?

Autor: Jörg S. (joerg-s)
Datum:

Diesen Beitrag bewerten:
lesenswert
nicht lesenswert
Wenn du vorher den Quarz eingeschaltet hast, schon ja.
Wobei es da auch ein WDT_ADLY_1000 geben müsste, also das du direkt 1 
Sekunde hast.

Autor: ArneN (Gast)
Datum:

Diesen Beitrag bewerten:
lesenswert
nicht lesenswert
Wenn ich WDT_ADLY_1000 verwende, dann blinkt meine LED nicht jede 
Sekunde, sondern nur jede 2. Sekunde, zumindest wenn ich den Code von 
oben verwende, deshalb habe ich mich für WDT_ADLY_250 entschieden.
Eine Frage:
Es handelt sich ja dabei um ein Interrupt, das heißt, dass das 
Hauptprogramm in diesem Fall jede viertel Sekunde unterbrochen wird. 
Folglich kann ich im Hauptprogramm dann die Überprüfungen machen, ob 60 
Sekunden, 60 Minuten oder 24 Stunden erreicht wurden. Die Überprüfung 
kann man aber auch innerhalb des Interrupts machen.
Wäre es sinnvoller das ganze in das Interrupt zu packen oder in das 
Hauptprogramm?

Autor: nigthwatch (Gast)
Datum:

Diesen Beitrag bewerten:
lesenswert
nicht lesenswert
Eine gute Beschreibung von Anfang an:
http://tina.bu.edu/ec450s11/CourseDocuments/Resour...

Autor: ucWriter (Gast)
Datum:

Diesen Beitrag bewerten:
lesenswert
nicht lesenswert
@ArneN:

Hol' dir die Datenblätter, Dokumentation und Beispielprojekte und 
arbeite diese durch --> Hilfe zur Selbsthilfe.

Autor: Jörg S. (joerg-s)
Datum:

Diesen Beitrag bewerten:
lesenswert
nicht lesenswert
ArneN schrieb:
> Wenn ich WDT_ADLY_1000 verwende, dann blinkt meine LED nicht jede
> Sekunde, sondern nur jede 2. Sekunde,
Evt. hat der ACLK noch einen 2-fach Teiler drin?


> Wäre es sinnvoller das ganze in das Interrupt zu packen oder in das
> Hauptprogramm?
Kommt darauf an was du noch machen willst. Wenn der MSP sonst nichts zu 
tun hat kann man das auch in den Interrupt mit reinpacken.

Autor: ArneN (Gast)
Datum:

Diesen Beitrag bewerten:
lesenswert
nicht lesenswert
Ich habe jetzt mal versucht die Überprüfungen, ob 1 Minute oder eine 
Stunde vergangen sind, in das Hauptprogramm zu verlagern. Dabei bin ich 
leider auf ein kleines Problem gestoßen:
Wenn ich eine Variable im Interrupt erhöhe, wird dies anscheinend nicht 
im Hauptprogramm registriert.
#include <msp430g2231.h>
volatile unsigned int wdt_intr = 0;
volatile unsigned int halbesekunde = 0;

void main(void)
{
  // nicht so wichtig ...
  _BIS_SR(LPM0_bits + GIE);                 // Enter LPM0 w/ interrupt
  if(halbesekunde == 1)
    {
     halbesekunde = 0;
    }
}

__interrupt void watchdog_timer(void)
{
  if(wdt_intr++ >= 2)
  {
    wdt_intr = 0; 
    P1OUT ^= 0x01;                            // Toggle P1.0 using exclusive-OR
    halbesekunde++;
  }
} 

Also wenn im Interrupt "halbesekunde" erhöht wird, wird dies nicht im 
Hauptprogramm wahrgenommen, da die Bedingung der If-Schleife nie erfüllt 
wird.

Was muss ich verändern, damit dies möglich ist? Denn ansonsten müsste 
ich die Überprüfungen alle in das Interrupt legen und auch später die 
Routinen, die dafür zuständig sind, dass auf den 7-Seg. Anzeigen die 
richtige Uhrzeit angezeigt wird, im Interrupt platzieren.

Autor: Stefan (Gast)
Datum:

Diesen Beitrag bewerten:
lesenswert
nicht lesenswert
ArneN schrieb:
> Wenn ich WDT_ADLY_1000 verwende, dann blinkt meine LED nicht jede
> Sekunde, sondern nur jede 2. Sekunde
Klar, wenn du den Portpin jede Sekunde toggelst geht die LED jede zweite 
Sekunde für eine Sekunde an.

ArneN schrieb:
> Also wenn im Interrupt "halbesekunde" erhöht wird, wird dies nicht im
> Hauptprogramm wahrgenommen, da die Bedingung der If-Schleife nie erfüllt
> wird.

Die If-Schleife wird nie erreicht und die Bedingung damit nie geprüft da 
du den Controller direkt davor schlafen legst. Zur Interruptbearbeitung 
wird er jeweils kurz geweckt, am Ende der Interruptroutine aber 
automatisch wieder schlafen gelegt. Wenn der Controller nach einem 
Interrupt wachbleiben soll muss in der Interruptroutine das auf dem 
Stack gesicherte Statusregister entsprechend verändert werden.

Autor: ** Lötlackl (pappnase) Benutzerseite
Datum:

Diesen Beitrag bewerten:
lesenswert
nicht lesenswert
> If-Schleife

Nicht schon wieder!
SCNR

Autor: ArneN (Gast)
Datum:

Diesen Beitrag bewerten:
lesenswert
nicht lesenswert
Stefan schrieb:
> Wenn der Controller nach einem
> Interrupt wachbleiben soll muss in der Interruptroutine das auf dem
> Stack gesicherte Statusregister entsprechend verändert werden.

Vielen Dank für diesen Hinweis. Die Uhr läuft jetzt problemlos.

Vielen Dank an alle, die mir ein wenig unter die Arme gegriffen haben.


Gruß
Arne

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel




Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder GIF-Format hochladen.
Siehe Bildformate
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken erkennst du die Nutzungsbedingungen an.

webmaster@mikrocontroller.netImpressumNutzungsbedingungenWerbung auf Mikrocontroller.net