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


von PhilllihP (Gast)


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:
1
/*
2
 * main.c
3
 */
4
5
#include  <msp430g2231.h>
6
7
//********************************
8
// Hauptprogramm
9
10
int main(void)    // Main program
11
{
12
  WDTCTL = WDTPW + WDTHOLD;  // Watchdog Timer ausschalten
13
14
  P1DIR = 0x01;  // Port P1.0 als output
15
  P1SEL = 0x00;  // Port 1 als GPIO nutzen
16
  P1IE  = 0x00;  // interrupt ausmachen
17
  P1OUT = 0x00;  // initial LED aus
18
19
20
    if ((P1IN & 0x08) == 0)
21
    {
22
      P1OUT=0x01;
23
    }
24
25
}

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 :)

von Helmut L. (helmi1)


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.

von ucWriter (Gast)


Lesenswert?

Nach der Initialisierung kommt i.d.R. eine Endlosschleife in der dein 
Hauptprogramm abgearbeitet wird.
1
while(1)
2
{
3
    if ((P1IN & 0x08) == 0)
4
    {
5
      P1OUT=0x01;
6
    }
7
}

von DSausW (Gast)


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.

von PhilllihP (Gast)


Lesenswert?

Jetzt funktioniert es wunderbar
Danke :)

von Test (Gast)


Lesenswert?

LED = Taster
1
while(1)
2
{
3
    if ((P1IN & 0x08) == 0)
4
    {
5
      P1OUT |= 0x01;
6
    }
7
    else
8
      P1OUT &= ~0x01;
9
}

von ArneN (Gast)


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

von ucWriter (Gast)


Lesenswert?

Also Du könntest Dir die Beispielprogramme zum Timer anschauen. Da wirst 
Du fündig.

von Jörg S. (joerg-s)


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.

von ArneN (Gast)


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_Codebeispiele#Initialisierung_des_Timers_A

Das habe ich dann versucht einzubauen:
1
#include  <msp430g2231.h>
2
3
4
int main(void)    // Main program
5
{
6
  WDTCTL = WDTPW + WDTHOLD;  // Watchdog Timer ausschalten
7
8
  P1DIR = 0x01;  // Port P1.0 als output
9
  P1SEL = 0x00;  // Port 1 als GPIO nutzen
10
  P1IE  = 0x00;  // interrupt ausmachen
11
  P1OUT = 0x00;  // initial LED aus
12
  
13
  void init_TimerA();
14
15
}
16
17
18
void init_TimerA(unsigned int cycles )
19
  {
20
     TACTL = TASSEL1 + TACLR;              // SMCLK, clear TAR
21
     CCTL0 = CCIE;                         // CCR0 interrupt enabled
22
     CCR0 = cycles;
23
     TACTL |= MC_2;                         // Start Timer_A in continuous mode
24
     _EINT();                              // interrupt enable
25
  }
26
 
27
  // Timer A0 interrupt service routine
28
interrupt (TIMERA0_VECTOR) Timer_A(void)
29
  {
30
    P1OUT ^= 0x01;                        // Toggle P1.0
31
    CCR0 += 50000;                        // Add Offset to CCR0
32
  }

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?

von ucWriter (Gast)


Lesenswert?

1) Die Code-Zeile
1
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.

von Test (Gast)


Lesenswert?

hier mal das TI Demo mit kleiner Erweiterung
1
#include <msp430g2231.h>
2
3
volatile unsigned int wdt_intr = 0;
4
5
void main(void)
6
{
7
  WDTCTL = WDT_MDLY_32;                     // Set Watchdog Timer interval to ~30ms
8
  IE1 |= WDTIE;                             // Enable WDT interrupt
9
  P1DIR |= 0x01;                            // Set P1.0 to output direction
10
11
  _BIS_SR(LPM0_bits + GIE);                 // Enter LPM0 w/ interrupt
12
}
13
14
// Watchdog Timer interrupt service routine
15
#pragma vector=WDT_VECTOR
16
__interrupt void watchdog_timer(void)
17
{
18
  if(wdt_intr++ >= 31)
19
  {
20
    wdt_intr = 0;  
21
    P1OUT ^= 0x01;                            // Toggle P1.0 using exclusive-OR
22
  }
23
}

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

von ArneN (Gast)


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
 ist, stellt sich für mich die Frage, wie ich einen Quarz einbaue. Auf 
dieser Seite habe ich gefunden, wie man diesen initialisiert:
1
void init_XT2(void)
2
{
3
  unsigned int i;
4
  WDTCTL = WDTPW + WDTHOLD;             // Stop WDT
5
  BCSCTL1 &= ~XT2OFF;                   // XT2 = HF XTAL
6
  do 
7
  {
8
    IFG1 &= ~OFIFG;                       // Clear OSCFault flag
9
    for (i = 0xFF; i > 0; i--);           // Time for flag to set
10
  }
11
  while ((IFG1 & OFIFG) != 0);          // OSCFault flag still set?                
12
  BCSCTL2 |= SELM1;                     // MCLK = XT2 (safe)
13
}

Und meines Wissens nach, muss ich den Quarz dann an
 und
 anschließen.

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

von nightwatch (Gast)


Lesenswert?


von Jörg S. (joerg-s)


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.

von ArneN (Gast)


Lesenswert?

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

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

von Jörg S. (joerg-s)


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.

von ArneN (Gast)


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?

von nigthwatch (Gast)


Lesenswert?


von ucWriter (Gast)


Lesenswert?

@ArneN:

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

von Jörg S. (joerg-s)


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.

von ArneN (Gast)


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.
1
#include <msp430g2231.h>
2
volatile unsigned int wdt_intr = 0;
3
volatile unsigned int halbesekunde = 0;
4
5
void main(void)
6
{
7
  // nicht so wichtig ...
8
  _BIS_SR(LPM0_bits + GIE);                 // Enter LPM0 w/ interrupt
9
  if(halbesekunde == 1)
10
    {
11
     halbesekunde = 0;
12
    }
13
}
14
15
__interrupt void watchdog_timer(void)
16
{
17
  if(wdt_intr++ >= 2)
18
  {
19
    wdt_intr = 0; 
20
    P1OUT ^= 0x01;                            // Toggle P1.0 using exclusive-OR
21
    halbesekunde++;
22
  }
23
}

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.

von Stefan (Gast)


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.

von Lötlackl *. (pappnase) Benutzerseite


Lesenswert?

> If-Schleife

Nicht schon wieder!
SCNR

von ArneN (Gast)


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

von Wurzel (Gast)


Lesenswert?

Hey

habe neuerdings folgendes Problem:

habe schon einige Projekte erstellt, die auch reibungslos funktionieren. 
Habe mir über ein Terminalprogramm strings ausspucken lassen und die 
beiden LEDs meines msp430 haben immer das gemacht, was ich wollte (um es 
stumpf zu formulieren). Aber auf einmal arbeitet der MSP nicht mehr wie 
er soll. Wenn ich ein Programm starte, leuchten beide LEDs auf, es 
werden auch keine Strings mehr ausgegeben. Hat jmd soetwas ähnliches 
schon gehabt?

von MaWin (Gast)


Lesenswert?

Nachdem ich jahrelang mit meinem Auto gefahren bin, es fuhr immer, fährt 
es jetzt nicht mehr. Keinen Meter.

Hat jemand so etwas ähnliches schon gehabt? ?

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.