Forum: Analoge Elektronik und Schaltungstechnik MSP430F1612_ISR für Spannung weg (Batteriebetrieb)


von Mathias U. (munter)


Angehängte Dateien:

Lesenswert?

Hallo,

ich hab mal wieder eine Frage bzgl. MSP430.

Es ist ein MSP430F1612
Software ist IAR 3.20A in der Sprache C.

Ich habe ein Gerät gebaut, welches soweit ganz gut funktioniert.
Es ist eine Uhrzeit implementiert (per TI Bibliotheken...).
Weiterhin nutze ich die AD-Wandler, hab nen PGA per SPI dran und auch 
eine SD-Card.
Ein LC-Dsiplay hängt auch noch dran...

Der MSP und die weiteren Baugruppen werden von nem Netzteil mit Spannung 
versorgt. Der MSP bekommt 3,3V.

Dadurch, dass ich eine Uhrzeit brauche, habe ich eine externe 
Lithium-zelle mit dran.(siehe Schaltplan)
Der Interrupt-Eingang geht an P2.7 des MSP.

Was jetzt mein riesiges Problem ist, ist folgendes:
Wird das Gerät ausgeschalten, ist ja die Spannung weg. Alle Baugruppen 
(Filter, PGA, Effektivwertbilder usw. sind dann aus.) Der MSP muss aber 
anbleiben, weil die Uhrzeit ja weiterlaufen soll. --> Deshalb auch die 
Batterie.

Den Interrupt-Eingang habe ich vorgesehen, damit der MSP weiss, wann die 
Spannung weg ist.
Dann soll er in einen LPM fahren, und halt nur noch die Zeit 
weiterlaufen lassen.
Welcher LMP wäre da sinnvoll? Ich würde dem LPM3 nehmen...
Wie baue ich solch eine ISR auf? Wie muss sowas aussehen?

Ich hoffe mal, dass alle Variablen, die während des Programmablaufes 
geändert wurden, erhalten bleiben, also die Werte?

Das Problem ist auch, was muss gemacht werden, wenn das Gerät wieder 
Spannung hat?
Sicher muss doch das LCD wieder initialisiert werden?

Müssen die Timer auch neu initialisiert werden? (habe nur Timer A in 
Betrieb, der mir alle 125ms nen "Tick" erzeugt...aus diesem Tick bekomme 
ich auch die Uhrzeit raus...
Wenn ich nach dem Einschalten wieder die Timer neu initialisiere, dann 
stimmt doch die Zeit nicht mehr, oder?

Die Port-Definitionen müssen doch sicher nicht neu initialisiert werden, 
oder?

Was ist mit den Einstellungen für den DCO?

Was ist mit den Sachen für das SPI?

In meinem Programm, in der main() wird am Anfang einmal die init_mcu() 
aufgerufen, die mir oben genannte Sachen einstellt.
Wenn jetzt einige Sachen, wie z.b. Timer nicht noch einmal neu 
eingestellt werden müssen, wie mache ich DAS dem MSP klar? Ist nen bissl 
schlecht zu erklären, was ich meine...

An welcher Stelle würde denn der MSP weitermachen, wenn die ISR "nach" 
dem erneuten Einschalten fertig ist? Fängt der dann ganz von vorne an, 
bei der main().
Das wäre nämlich dämlich, weil ja am Anfang die init_mcu() kommt...

Hat jemand soetwas schonmal gemacht? Wie sieht so eine ISR aus?
Irgendwie muss ich ja nen Interrupt erzeugen, wenn sich die Spannung an 
P2.7 ändert. Aber wie mache ich das am schlauesten?

Bei bedarf kann ich ja mal meine init_mcu(), und meine main.c anhängen.
Vielen Dank schonmal.

(mit Interrupt Service Routinen hab ich wenig bis keine Ahnung...hab ja 
bisher nur die eine gemacht, die mir vom TimerA alle 125ms nen Int 
erzeugt...)

von Falk B. (falk)


Lesenswert?

@ Mathias U. (munter)

>Den Interrupt-Eingang habe ich vorgesehen, damit der MSP weiss, wann die
>Spannung weg ist.
>Dann soll er in einen LPM fahren, und halt nur noch die Zeit
>weiterlaufen lassen.
>Welcher LMP wäre da sinnvoll? Ich würde dem LPM3 nehmen...

Ja.

>Wie baue ich solch eine ISR auf? Wie muss sowas aussehen?

Nix besonderes. ODrt muss einfach ein Zähler hochgezählt werden. Ein 
Timer hängt mit ACLK an einem 32 kHz Quarz, den du wahrscheinlich schon 
hast. BEi jedem Overflow wird eins hochgezählt. Fertig. Und natürlich 
noch geprüft, wen die Spannung wieder da ist, dann muss ein LPM3_exit(); 
mit rein ;-)

>Ich hoffe mal, dass alle Variablen, die während des Programmablaufes
>geändert wurden, erhalten bleiben, also die Werte?

Sicher, der MSP läuf "normal" weiter.

>Sicher muss doch das LCD wieder initialisiert werden?

Ja.

>Müssen die Timer auch neu initialisiert werden? (habe nur Timer A in

Nein.

>Die Port-Definitionen müssen doch sicher nicht neu initialisiert werden,
>oder?

Der MSP, läuft normal weier, nur halt im Sleep Mode.

>Was ist mit den Einstellungen für den DCO?

Muss nix geändert werden.

>Was ist mit den Sachen für das SPI?

Dito.

MSP bleibt, alles andere ausserhalb muss neu initialisiert werden.

>In meinem Programm, in der main() wird am Anfang einmal die init_mcu()
>aufgerufen, die mir oben genannte Sachen einstellt.

Dort kommst du gar nciht hin. Es wird KEIN Reset ausgeführt.

>An welcher Stelle würde denn der MSP weitermachen, wenn die ISR "nach"
>dem erneuten Einschalten fertig ist?

Nach der LPM3() Anweisung.

>Hat jemand soetwas schonmal gemacht? Wie sieht so eine ISR aus?

Ja, siehe oben.

>Irgendwie muss ich ja nen Interrupt erzeugen, wenn sich die Spannung an
>P2.7 ändert. Aber wie mache ich das am schlauesten?

Über einen Pin Change Interrupt?

>Bei bedarf kann ich ja mal meine init_mcu(), und meine main.c anhängen.
>Vielen Dank schonmal.

Nöö, lass mal. Lies mal was über Sleep Mode.

MFG
Falk

von Mathias U. (munter)


Lesenswert?

Hallo Falk,

ich hab mich etwas eingelesen, hab aber trotzdem noch die ein oder 
andere Frage.
Das mit dem Zähler hochzähler, was Du am Anfang geschrieben hast, 
bezieht sich sicher auf das Weiterlaufen der uhrzeit, oder? Ansonsten 
weis ich nicht, was Du damit meinst.
Ich habe ja Wie gesagt schon eine ISR für meinen TimerA, wo genau das 
passiert.

>Sicher, der MSP läuf "normal" weiter.

Damit meinst Du aber sicher nicht, dass das Programm normal weiterläuft, 
oder?
Wenn ich jetzt bspw. in einer Endlosschleife im "Normalbetrieb" eine 
Variable hochzähle, dann wird er, wenn er im LPMx ist, nicht damit 
weitermachen, oder?
Wäre ja auch dämlich, wenn er mit den ganzen Berechnungen weitermacht.
Die Variablen-Werte bleiben erhalten...
So hab ich das verstanden.

Ich habe mal weiter im Forum gesucht nach dem Thema und auch etwas 
gefunden...
Auch im User-Guide und in die TI-Beispiele hab ich geschaut.

Was ich evtl. noch nicht ganz verstanden habe, ist folgendes:

Das Flag P2IES kann entweder 0 sein, dann wird das IFG bei einer low --> 
high änderung eines Pins gesetzt.
Oder es kann 1 sein, dann wird das IFG bei einer high --> low Änderung 
gesetzt. Ist das soweit richtig?

Jetzt brauche ich aber am P2.7 beide Änderungen...
Einmal, wenn die Spannung weg geht, dann soll er auf high-->low 
reagieren.
Und einmal andersherum.
Kann ich das so wie im unteren Code machen?

Nächste Frage: Das P2IE |= 0x01; heisst, dass der gesamte Port2 oder nur 
P2.1 als Interrupt enable gemacht wurde?
Ich habe an den anderen Pins noch was dran. Und diese Pins können 
durchaus auch mal nen Flankenwechsel haben. Was dann etwas hinderlich 
wäre.
Obwohl, eigentlich frage ich ja das (P2IFg & INTERRUPT_P2_7) ab...also 
sollte das schon so gehen.
Ich möchte erstmal nicht, dass wenn der MSP nichts zu tun hat, autom. in 
den LMP3 geht.
Sondern nur über den Pegelwechsel an P2.7.

1
// die sachen hier kommen in die init_mcu() mit rein
2
P2IE   |= 0x01;
3
P2IES  |= 0x01;    // P2IFG wird gesetzt bei high --> low
4
_BIS_SR(GIE);             // allgemeiner Interrupt an
5
6
// die sache kommt hinter die main() in die main.c mit rein, hinter die ISR für TimerA
7
#pragma vector=PORT2_VECTOR
8
__interrupt void Port2_Interrupt (void)
9
{
10
  // wenn high --> low
11
  // INTERRUPT_P2_7 ist als 0x80 defined
12
  if((P2IFG & INTERRUPT_P2_7) == 1)
13
  {
14
    //if (protokoll_laeuft == 1) Protokoll_laeuft = 0;
15
    //if (kalibrierung_laeuft == 1) kalibrierung_laeuft = 0;
16
    P2IES |= 0x00;    // P2IFG wird gesetzt bei low --> high
17
    LMP3();
18
  }
19
  
20
  // wenn low --> high
21
  if((P2IFG & INTERRUPT_P2_7) == 1)
22
  {
23
    LPM3_exit();
24
    P2IES  |= 0x01;  // P2IFG wird gesetzt bei high --> low
25
    LCD_Init();      // LCD initialisieren ...
26
    LCD_Clear();     // ...loeschen, cursor an anfang
27
  }
28
29
  P2IFG = 0;      // Flag wird zurueckgesetzt
30
}

Dankeschön

von Falk B. (falk)


Lesenswert?

@  Mathias U. (munter)

>Das mit dem Zähler hochzähler, was Du am Anfang geschrieben hast,
>bezieht sich sicher auf das Weiterlaufen der uhrzeit, oder? Ansonsten

Ja.

>>Sicher, der MSP läuf "normal" weiter.

>Damit meinst Du aber sicher nicht, dass das Programm normal weiterläuft,
>oder?

Nein, die CPU steht still. Aber die Spannung liegt weiter an und alles 
Register halten ihren Wert. Der Timer läuft auch noch.

>Wenn ich jetzt bspw. in einer Endlosschleife im "Normalbetrieb" eine
>Variable hochzähle, dann wird er, wenn er im LPMx ist, nicht damit
>weitermachen, oder?

Logisch.

>Das Flag P2IES kann entweder 0 sein, dann wird das IFG bei einer low -->
>high änderung eines Pins gesetzt.
>Oder es kann 1 sein, dann wird das IFG bei einer high --> low Änderung
>gesetzt. Ist das soweit richtig?

Ja.

>Jetzt brauche ich aber am P2.7 beide Änderungen...
>Einmal, wenn die Spannung weg geht, dann soll er auf high-->low
>reagieren.
>Und einmal andersherum.
>Kann ich das so wie im unteren Code machen?

Ganz einfach. nach dem Reset wartest du auf eine fallende Flanke, wenn 
nämlich die Sapnnung weggeht. Wenn das passiert wird umkonfiguriert. 
Dann wird der Interrupt bei der steigenden Flanke (Spannung wieder da) 
ausgelöst.

>Nächste Frage: Das P2IE |= 0x01; heisst, dass der gesamte Port2 oder nur
>P2.1 als Interrupt enable gemacht wurde?

Nöö, nur Bit #0.

>Ich möchte erstmal nicht, dass wenn der MSP nichts zu tun hat, autom. in
>den LMP3 geht.
<Sondern nur über den Pegelwechsel an P2.7.

Na dann muss die Umschaltung in die passende ISR rein.

MfG
Falk

von Christian R. (supachris)


Lesenswert?

Schau dir am besten mal das hier bei TI an: 
http://focus.ti.com/mcu/docs/mcusupporttechdocsc.tsp?sectionId=96&tabId=1502&abstractName=slaa294a
Das ist super erklärt, wie man die Low Power Modes effektiv einsetzt. 
Ich mach das nur noch so, mein Prozessor ist sogut wie immer im LPM3, 
alle Aktionen werden per Interrupt gestartet, in der ISR ein Flag 
gesetzt, was in der Main-Schleife dann ausgewertet wird. Ist die 
Funktion beendet wird das entsprechende Flag gelöscht. Sind alle Flags 
gelöscht, main-loop in den LPM3. Am Ende jeder ISR muss natürlich dann 
ein exit_lpm3() stehn, damit die main-loop weiterläuft, wenn die ISR 
beendet ist.
Sehr energieeffizient und übersichtlich.

von Mathias U. (munter)


Lesenswert?

Hallo,

danke erstmal.
Kann mal bitte einer über den Code oben drüberschauen, ob dass soweit 
geht?
Evtl. ist da ja ein grobe Fehler drin, den ich jetzt nicht sehe.

Ich müsste doch nur statt
1
P2IE |= 0x01;
1
P2IE |= 0x80;
machen, damit ich den Int für P2.7 aktiviere.
Und das mit "P2IES" müsste doch genau so gehen, wie ich es brauche, 
oder?

@Christian: den Text werde ich mir noch mal einverleiben...danke

von Falk B. (falk)


Lesenswert?

@ Mathias U. (munter)

>P2IE |= 0x80;

>machen, damit ich den Int für P2.7 aktiviere.

ja.

>Und das mit "P2IES" müsste doch genau so gehen, wie ich es brauche,
>oder?

ja.

MfG
Falk

von Mathias U. (munter)


Lesenswert?

Sorry, dass ich nochmal frage, aber KANN das denn so überhaupt gehen?
1
P2IE   |= 0x80;                                   // interrupt an P2.7 an
2
P2IES  |= 0x01;                                   // P2IFG wird gesetzt bei high --> low
3
_BIS_SR(GIE);                                     // allgemeiner Interrupt an
4
5
6
7
#pragma vector=PORT2_VECTOR
8
__interrupt void Port2_Interrupt (void)
9
{
10
  // wenn high --> low
11
  if((P2IFG & INTERRUPT_P2_7) == 1)
12
  {
13
    if (protokoll_laeuft == 1) Protokoll_laeuft = 0;
14
    if (kalibrierung_laeuft == 1) kalibrierung_laeuft = 0;
15
    P2IES |= 0x00;                                  // P2IFG wird gesetzt bei low --> high
16
    LPM3;
17
  }
18
  
19
  // wenn low --> high
20
  if((P2IFG & INTERRUPT_P2_7) == 1)
21
  {
22
    LPM3_EXIT;
23
    P2IES  |= 0x01;                                 // P2IFG wird gesetzt bei high --> low
24
    Mode = 1;                                       // line-mode an
25
    Wichtung = 1;                                   // a-wichtung an
26
    Seite = 0;                                      // erste seite an
27
    LCD_Init();                                     // LCD initialisieren ...
28
    LCD_Clear();                                    // ...loeschen, cursor an anfang
29
  }
30
  P2IFG = 0;                                        // Flag wird zurueckgesetzt
31
}

Wird die zweite if () anweisung durchlaufen, wenn der MSP in der ersten 
if in den LPM3 geschickt wird...
Die "ifs" sind ja gleich...
Oder sollte ich nicht besser das P2IFG in beiden if-Anweisungen 
zurücksetzen...statt am Ende ausserhalb der ifs?
Was sagen die Profis dazu? Ich bin etwas verwirrt...weil wenn die ISR 
beendet wird (nach dem Aufruf LPM3; ) dann setzt er ja auch das P2IFG 
nicht zurück, was am Ende steht...
Ich komme leider heute nicht mehr dazu die Sache zu Testen, aber morgen 
fahr ich nochmal an die Uni...
Danke

von Falk B. (falk)


Lesenswert?

@ Mathias U. (munter)

>Sorry, dass ich nochmal frage, aber KANN das denn so überhaupt gehen?

>P2IE   |= 0x80;                                   // interrupt an P2.7 an
>P2IES  |= 0x01;                                   // P2IFG wird gesetzt

Das soll doch bestimmt heissen

P2IES  |= 0x80;

>Die "ifs" sind ja gleich...

Was schonmal Unsinn ist. Eher so.
1
#pragma vector=PORT2_VECTOR
2
__interrupt void Port2_Interrupt (void)
3
{
4
  uit8_t tmp;
5
6
  tmp = P2IFG; 
7
  P2IFG = 0;                                        // Flag wird zurueckgesetzt
8
 
9
  // wenn high --> low
10
  if((tmp & INTERRUPT_P2_7) == 1) {
11
    if (protokoll_laeuft == 1) {
12
      Protokoll_laeuft = 0;
13
      if (kalibrierung_laeuft == 1) kalibrierung_laeuft = 0;
14
      P2IES |= 0x00;                                  // P2IFG wird gesetzt bei low --> high
15
      LPM3;
16
    }
17
    else {
18
      LPM3_EXIT;
19
      P2IES  |= 0x01;                                 // P2IFG wird gesetzt bei high --> low
20
      Mode = 1;                                       // line-mode an
21
      Wichtung = 1;                                   // a-wichtung an
22
      Seite = 0;                                      // erste seite an
23
      LCD_Init();                                     // LCD initialisieren ...
24
      LCD_Clear();                                    // ...loeschen, cursor an anfang
25
    }
26
  }
27
}

>Was sagen die Profis dazu? Ich bin etwas verwirrt...weil wenn die ISR
>beendet wird (nach dem Aufruf LPM3; )

Nein. Das ist ein wenig tricky. LPM3_EXIT ist ein Makro. Das setzt NICHT 
direkt den Sleep Mode im CPU Statusregister sondern die gespeicherte 
Version auf dem Stack. Dadurch wird LPM3 erst aktiv, wenn der Interrupt 
beendet wird. LPM3 hingegen schaltet sofort in LPM3 Modus. Ob das aber 
direkt in einer ISR so gut ist, glaub ich nicht so ganz.

MfG
Falk

von S. Z. (szimmi)


Lesenswert?

Falk Brunner wrote:
> @ Mathias U. (munter)
>
>>Sorry, dass ich nochmal frage, aber KANN das denn so überhaupt gehen?
>
>>P2IE   |= 0x80;                                   // interrupt an P2.7 an
>>P2IES  |= 0x01;                                   // P2IFG wird gesetzt
>
> Das soll doch bestimmt heissen
>
> P2IES  |= 0x80;
>
>>Die "ifs" sind ja gleich...
>
> Was schonmal Unsinn ist. Eher so.
>
>
1
> #pragma vector=PORT2_VECTOR
2
> __interrupt void Port2_Interrupt (void)
3
> {
4
>   uit8_t tmp;
5
> 
6
>   tmp = P2IFG;
7
>   P2IFG = 0;                                        // Flag wird
8
> zurueckgesetzt
9
> 
10
>   // wenn high --> low
11
>   if((tmp & INTERRUPT_P2_7) == 1) {
12
>     if (protokoll_laeuft == 1) {
13
>       Protokoll_laeuft = 0;
14
>       if (kalibrierung_laeuft == 1) kalibrierung_laeuft = 0;
15
>       P2IES |= 0x00;                                  // P2IFG wird
16
> gesetzt bei low --> high
17
>       LPM3;
18
>     }
19
>     else {
20
>       LPM3_EXIT;
21
>       P2IES  |= 0x01;                                 // P2IFG wird
22
> gesetzt bei high --> low
23
>       Mode = 1;                                       // line-mode an
24
>       Wichtung = 1;                                   // a-wichtung an
25
>       Seite = 0;                                      // erste seite an
26
>       LCD_Init();                                     // LCD
27
> initialisieren ...
28
>       LCD_Clear();                                    // ...loeschen,
29
> cursor an anfang
30
>     }
31
>   }
32
> }
33
>
Hmmm. Scheint mir noch größerer Unsinn zu sein. In den else-Zweig geht 
er doch niemals nicht.
Wie wäre es mit Variante 3:
1
pragma vector=PORT2_VECTOR
2
__interrupt void Port2_Interrupt (void)
3
{
4
  P2IFG = 0;      // Flag wird zurueckgesetzt
5
 
6
  // wenn high --> low freigegeben (es geht zuende mit dem Saft)
7
  if((P2IES & INTERRUPT_P2_7)) {
8
9
    // mache die notwendigen Operationen für den Shutdown
10
    // setze ein Flag für main, um dort in den LPM3 zu schalten
11
     P2IES &= ~INTERRUPT_P2_7;   // P2IFG wird gesetzt bei low --> high
12
  }
13
  else {
14
    // mache die notwendigen Operationen für den WakeUp
15
     P2IES |= INTERRUPT_P2_7;   // P2IFG wird gesetzt bei high --> low
16
     LPM3_EXIT;
17
  }
18
}



>
>>Was sagen die Profis dazu? Ich bin etwas verwirrt...weil wenn die ISR
>>beendet wird (nach dem Aufruf LPM3; )
>
> Nein. Das ist ein wenig tricky. LPM3_EXIT ist ein Makro. Das setzt NICHT
> direkt den Sleep Mode im CPU Statusregister sondern die gespeicherte
> Version auf dem Stack. Dadurch wird LPM3 erst aktiv, wenn der Interrupt
> beendet wird. LPM3 hingegen schaltet sofort in LPM3 Modus. Ob das aber
> direkt in einer ISR so gut ist, glaub ich nicht so ganz.
>
> MfG
> Falk

von Mathias U. (munter)


Lesenswert?

Hmmm, ich glaube jetzt habe ich nen Fehler gemacht, Du Falk aber auch.

Es muss natürlich
1
P2IE   |= 0x01;
heissen, denn PxIE kann ja nur 0(für int disable) und 1(für int enable) 
sein. siehe User-Guide Seite 9-6.
Damit stimmt Deine Aussage von vorhin auch nicht, oder?
>P2IE |= 0x80;
>machen, damit ich den Int für P2.7 aktiviere.
>>ja.

>Das soll doch bestimmt heissen
>P2IES  |= 0x80;

Nee, kann ja nicht, denn auch PxIES kann nur 0 oder 1 sein. Entweder für 
low-to-high transition (0) oder für high-to-low transition (1).
Siehe User-Guide gleiche Seite.

Was jetzt Deinen Code angeht, komme ich damit gar nicht klar.
Was passiert denn:

Das Gerät hat Spannung vom Netz. P2IES ist auf high --> low Flanke 
eingestellt.
Die Spannung geht weg...
--> ein Port2_Interrupt wird ausgelöst und P2IFG auf 1 gesetzt.
--> er geht in die ISR, setzt P2IFG auf tmp und geht dann in die erste 
if-Anweisung

P2IES ist jetzt auf low-->high Flanke eingestellt.
Die Netzspannung ist wieder da.
--> ein Port2_Interrupt wird ausgelöst und P2IFG auf 1 gesetzt.
--> er geht in die ISR, setzt wieder P2IFG auf tmp und geht wieder in 
die if-Anweisung. In die else geht er doch NIE, oder?

Evtl. wäre es doch besser, nicht das P2IFG abzufragen, sondern direkt 
den Zustand an P2.7??

Was hab ich an der Sache nur falsch verstanden?
Danke soweit erstmal!

von Falk B. (falk)


Lesenswert?

@ S. Z. (szimmi)

>Hmmm. Scheint mir noch größerer Unsinn zu sein. In den else-Zweig geht
>er doch niemals nicht.

Klar, wenn protokoll_laeuft == 0

>Wie wäre es mit Variante 3:

Sieht gut aus.

MfG
Falk

von S. Z. (szimmi)


Lesenswert?

Mathias U. wrote:
>
> Nee, kann ja nicht, denn auch PxIES kann nur 0 oder 1 sein. Entweder für
> low-to-high transition (0) oder für high-to-low transition (1).
> Siehe User-Guide gleiche Seite.
Natürlich hat Falk recht. Du arbeitest doch nur mit P2.7. Das ist Bit 7 
in allen betreffenden Registern. Es muss also immer 0x80 heissen und 
nicht 0x01. Wenn Du mit P2.6 arbeiten würdest, dann 0x40 usw...

von S. Z. (szimmi)


Lesenswert?

Falk Brunner wrote:
> @ S. Z. (szimmi)
>
>
> Klar, wenn protokoll_laeuft == 0
Oerks, sorry, hatte eine Klammer übersehen. Ich nehme (fast) alles 
zurück und behaupte das Gegenteil :-)

von Mathias U. (munter)


Lesenswert?

Argh, die Klammer hab ich auch nicht gesehen...blöde Formatierung.

Ich glaub jetzt hat es ein wenig klick gemacht:
PxIFG, PxIE und PxIES sind ALLES 8bit lange Register?

Dann habt Ihr natürlich recht mit dem P2IES |= 0x80;

@S.Z.: deine Variante werde ich mir gleich mal anschauen...

von Martin (Gast)


Lesenswert?

Wäre es nicht besser, wenn am Interrupt-Eingang noch ein Widerstand 
gegen
Masse ist?
Die Dioden sind doch nicht so ideal, schon kleinste Leckströme ziehen
das Potential des Interrupt-Pins hoch.

von Falk B. (falk)


Lesenswert?

@ Mathias U. (munter)

>Ich glaub jetzt hat es ein wenig klick gemacht:
>PxIFG, PxIE und PxIES sind ALLES 8bit lange Register?

Ja was denn sonst? Und PxIE und PXIES haben pro IO-Pin ein Bit.
Aber an der Stelle ist die Doku von TI wirklich schwach. Da ist nix 
gezeigt, nur Text. Ein bild sagt mehr als tausend Worte.

@ Martin (Gast)

>Wäre es nicht besser, wenn am Interrupt-Eingang noch ein Widerstand
>gegen Masse ist?

Ja, so 100K-1M.

MfG
Falk

von Mathias U. (munter)


Lesenswert?

Ich werde die Sache morgen einfach mal so testen...
1
P2IE   |= 0x80;                                  // interrupt an P2.7 an
2
P2IES  |= 0x80;                                  // P2IFG wird gesetzt bei high --> low
3
_BIS_SR(GIE);                                    // allgemeiner Interrupt an
4
5
6
pragma vector=PORT2_VECTOR
7
__interrupt void Port2_Interrupt (void)
8
{
9
  P2IFG = 0;              // Flag wird zurueckgesetzt
10
 
11
  
12
  if((P2IES & INTERRUPT_P2_7) == 1)    // wenn high --> low
13
  {
14
    // mache die notwendigen Operationen für den Shutdown
15
    // setze ein Flag für main, um dort in den LPM3 zu schalten
16
    // z.B.
17
    // gehe_in_LPM3 = 1;
18
    P2IES &= ~INTERRUPT_P2_7;       // P2IFG wird gesetzt bei low --> high
19
  }
20
  else
21
  {
22
    LPM3_EXIT;
23
    P2IES |= INTERRUPT_P2_7;         // P2IFG wird gesetzt bei high --> low
24
    // mache die notwendigen Operationen für den WakeUp
25
    // hier wieder:
26
    // gehe_in_LPM3 = 0;    
27
  }
28
}
Ich habe mal das LPM3_EXIT vorne angestellt, weil der MSP doch erstmal 
aufwachen muss, um Variablen oder Register neu zu setzen,oder?

Ein VerständnisProblem habe ich noch:
An welcher stelle in der main() macht denn der MSP weiter, wenn er die 
ISR verlassen hat? (wenn die Spannung weg ist, und das Flag zum in den 
LPM3 schalten, gesetzt ist)
Wenn er normal weitermachen würde, bis er irgendwann mal zu der Abfrage 
des Flags kommt, dann könnten doch meine Operationen zum Vorbereiten des 
Shutdowns schon wieder aufgehoben ode verändert worden sein, oder?

Wenn ich in meiner main() dann sowas habe:
1
void main(void)
2
{
3
...funktionsaufrufe...
4
  if (gehe_in_LPM3 == 1)
5
  {
6
    LPM3;
7
  }
8
}
Reicht das dann?
Danke, cool, dass sich um diese Uhrzeit noch Leute finden, die einem bei 
solchen Problemen helfen!

edit: Widerstand wird noch eingelötet. Danke für den Hinweiß!
@Falk, na wenigstens bin ich nicht der einzige, der diesen Teil der Doku 
schwach findet ;-) Bei den anderen Registern sind doch auch Bildchen...

von Falk B. (falk)


Lesenswert?

@ Mathias U. (munter)

>Ich habe mal das LPM3_EXIT vorne angestellt, weil der MSP doch erstmal
>aufwachen muss, um Variablen oder Register neu zu setzen,oder?

Der ist doch an der Stelle schon wach. Lies dir das naochml in den 
TI-Dokumenten durch.

>An welcher stelle in der main() macht denn der MSP weiter, wenn er die
>ISR verlassen hat? (wenn die Spannung weg ist, und das Flag zum in den
>LPM3 schalten, gesetzt ist)

Dort wo er unterbrochen wurde.

>Wenn er normal weitermachen würde, bis er irgendwann mal zu der Abfrage
>des Flags kommt, dann könnten doch meine Operationen zum Vorbereiten des
>Shutdowns schon wieder aufgehoben ode verändert worden sein, oder?

Wenns falsch programmiert ist.

>Reicht das dann?

Ja, wenn sichergestellt ist, dass die Abfrage unter allen Bedingungen in 
wenigen (Dutzend) Millisekunden erreicht wird.

MfG
Falk

von Mathias U. (munter)


Lesenswert?

Das heisst:

1) Der MSP wird allein durch den Interrupt an P2.7 aufgeweckt, und 
LPM3_EXIT brauche ich nur, um dem MSP zu sagen, wo er weitermachen soll, 
mit dem Programmablauf, wenn die Spannung wieder da ist?

2) Ich müsste meine main() so machen?
1
void main(void)
2
{
3
  for(;;)
4
  {
5
  if (gehe_in_LPM3 != 1) funktion_1();
6
  else LPM3;
7
8
  if (gehe_in_LPM3 != 1) funktion_2();
9
  else LPM3;
10
11
  if (gehe_in_LPM3 != 1) funktion_3();
12
  else LPM3;
13
14
  if (gehe_in_LPM3 != 1) funktion_4();
15
  else LPM3;
16
  ...
17
  }
18
}

Das ist aber ziemlich häßlich, vor allem, wenn er bei Spannungsausfall 
noch  in einer Funktion hängt, dann wird die ja noch bis zum Ende 
durchgezogen, eh die Flag-Abfrage kommt...

von Falk B. (falk)


Lesenswert?

@ Mathias U. (munter)

>1) Der MSP wird allein durch den Interrupt an P2.7 aufgeweckt, und
>LPM3_EXIT brauche ich nur, um dem MSP zu sagen, wo er weitermachen soll,
>mit dem Programmablauf, wenn die Spannung wieder da ist?

Ja.

>2) Ich müsste meine main() so machen?

Nein, wenigstens so
1
void main(void)
2
{
3
  for(;;)
4
  {
5
  if (gehe_in_LPM3 != 1) {
6
    funktion_1();
7
    gehe_in_LPM3=0;
8
  }
9
  else LPM3;

>Das ist aber ziemlich häßlich, vor allem, wenn er bei Spannungsausfall
>noch  in einer Funktion hängt, dann wird die ja noch bis zum Ende
>durchgezogen, eh die Flag-Abfrage kommt...

Ja. Da muss man mal genauer nachlesen und probieren. Vielleicht kann man 
auch im Interrupt den LPM3 anschalten, sodass er nach verlassen der ISR 
aktiv wird, so wie LPM3_exit. Weiss ich jetzt nicht genau. Such mal die 
Makros im Compilerhandbuch, dort gibt es welche zur direkten 
CPU-Statusregistermanipulation, so wie sie auch LPM3_EXIT() nutzt.

MfG
Falk

von Mathias U. (munter)


Lesenswert?

Wozu machst Du im if-Zweig "gehe_in_LPM3=0;"? Die Variable ist doch eh 
0, wenn der if-Zweig durchlaufen wird...
Das Zurücksetzen von gehe_in_LPM3 mache ich doch in der ISR...

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.