MSP430 LaunchPad - Anfänger Probleme

Gast #2618785
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 :)
Gast #2618826
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.
Gast #2626494
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
Gast #2626636
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?
Gast #2626733
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.
Gast #2626829
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.
Gast #2626985
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?
#2627126
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.
Gast #2627263
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?
Gast #2627862
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?
#2628299
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.
Gast #2628392
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.
Gast #2628470
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.
Gast #2628600
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
Gast #6165646
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?

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren