Datum:
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 :)
Datum:
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.
Datum:
Nach der Initialisierung kommt i.d.R. eine Endlosschleife in der dein Hauptprogramm abgearbeitet wird.
while(1) { if ((P1IN & 0x08) == 0) { P1OUT=0x01; } } |
Datum:
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.
Datum:
Jetzt funktioniert es wunderbar Danke :)
Datum:
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
Datum:
Also Du könntest Dir die Beispielprogramme zum Timer anschauen. Da wirst Du fündig.
Datum:
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.
Datum:
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?
Datum:
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.
Datum:
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.
Datum:
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:
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

und

anschließen. Wie baue ich das ganze aber jetzt in das Interrupt ein?
Datum:
Gab es schon: Beitrag "MSP430 Timer Uhr sekundentakt" Und fürs Board: http://www.ti.com/litv/pdf/slau318b
Datum:
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.
Datum:
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?
Datum:
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.
Datum:
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?
Datum:
@ArneN: Hol' dir die Datenblätter, Dokumentation und Beispielprojekte und arbeite diese durch --> Hilfe zur Selbsthilfe.
Datum:
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.
Datum:
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.
Datum:
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.
Datum:
> If-Schleife
Nicht schon wieder!
SCNR
Datum:
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