Forum: Mikrocontroller und Digitale Elektronik MSP430 Interrupt-Routine, Rücksprung


von Philip.J (Gast)


Lesenswert?

Hallo,

bei mir soll durch einen Schalter der Programmcounter erhöht werden. Das 
Programm selbst befindet sich in einer Funktion. Der Programmcounter 
selbst wird in der ISR erhöht.

Ich möchte allerdings, dass das Programm nach der ISR nicht wieder in 
die Funktion hereinspringt, sondern zu dem Punkt in der Main, wo diese 
zuletzt verlassen wurde (beim Funktionsaufruf). Gibt es dafür nun eine 
elegante Möglichkeit oder springt die ISR sowieso in die Main zurück ? 
Falls nicht, mag ich allerdings auch nicht mit goto arbeiten.

von Programmierer (Gast)


Lesenswert?

Philip.J schrieb:
> bei mir soll durch einen Schalter der Programmcounter erhöht werden.

?! Der PC wird normalerweise durch die HW selbst erhöht.

> Ich möchte allerdings, dass das Programm nach der ISR nicht wieder in
> die Funktion hereinspringt, sondern zu dem Punkt in der Main, wo diese
> zuletzt verlassen wurde (beim Funktionsaufruf).

?! Die ISR unterbricht das "reguläre" Programm irgendwo. Der 
Programmfluss wird unterbrochen, die ISR abgearbeitet, dann geht's 
wieder da weiter, wo die ISR unterbrochen hatte.

> mag ich allerdings auch nicht mit goto arbeiten.

Gott bewahre! goto allein ist schon gefährlich (virtueller Waffenschein 
ist Voraussetzung) - aus der ISR ins Irgendwo ist dann verordneter 
Selbstmord.

von dummschwaetzer (Gast)


Lesenswert?

Beim Einsprung in deine ISR wird eine Kopie des PC auf dem Stack 
abgelegt.
Diese musst du manipulieren!
Ist aber sehr schlechter CodeStyle!!!

Altenativ: du meinst mit "Programmcounter" nicht das was man so unter 
Programmcounter versteht.

von Philip.J (Gast)


Lesenswert?

#include <msp430g2152.h>

int pc = 0;

void time_1ms(int dlms)
{
  while (dlms--)
  {
    __delay_cycles(1000);
  }
}

void program(int st, int dl, int bs, int pn, int steps, int lights)
{
  P1OUT = pn;
  time_1ms(1000);
  P1OUT = 0x01;

  while(1)
  {
    int i = 0;
    int j = 0;

    for (j = 0; j < steps; j++)
    {
      do
      {
        for (i = 0; i < lights; i++)  // total 0.5s -1s
        {
          if (i == 0 && j == 0)
          {
            P1OUT = 0x01;
            time_1ms(dl);
          }
          else if (i == 0)
          {
            P1OUT = 0x01;
            P1OUT = P1OUT << j;
            time_1ms(dl);
          }
          else
          {
            P1OUT = P1OUT << bs;
            time_1ms(dl);
          }
        }
      }while(1==1);            // time < 0.5s - 1s (timer)
    }
  }
}

#pragma vector = PORT2_VECTOR
__interrupt void Port_2(void)
{
  if (pc > 3)          // program + 1
  {
    pc = 1;
  }
  else
  {
    pc = pc+1;
  }

  P2IFG &= ~0x01;          // P2.0 IFG cleared
}

void main(void)
{
  WDTCTL = WDTPW + WDTHOLD;

  if (CALBC1_1MHZ == 0xFF || CALDCO_1MHZ == 0xFF)
  {
    while(1);
  }

  BCSCTL1 = CALBC1_1MHZ;    // else dco-default ~800kHz
  DCOCTL = CALDCO_1MHZ;

  P1SEL = 0;          // P1.x I/O
  P1DIR = 0xff;        // P1.x output
  P1OUT = 0x00;

  P2SEL = 0;          // P2.x I/O
  P2DIR = 0xfe;        // P2.0 input, else output

  P2REN |= 0x01;        // ( ) P2.0 pullup
  P2IES |= 0x01;        // P2.0 high/low
  P2IFG &= ~0x01;        // P2.0 IFG clear
  P2IE |= 0x01;        // P2.0 int enabled
  //_EINT();

  while(1)
  {
    switch(pc)
    {
      case 1: program(1,1,1,1,1,1);
      break;
      case 2: program(1,10,1,2,1,1);
      break;
      case 3: program(1,1,2,4,1,1);
      break;
      case 4: program(2,2,2,8,1,1);
      break;
      default: _NOP();
    }
  }
}

Ich hätte wohl doch gleich den Quelltext posten sollen :)
Ablauf ist: Program -> delay -> Program -> delay usw.
-> Taster -> ISR -> PC + 1 -> ISR Ende -> ? Gewünscht wäre natürlich in 
die While-Schleife der Main. Ich mag die Switch-Funktion allerdings auch 
nicht irgendwo in die Program-Funktion einbauen, allerdings soll die 
Umschaltung nach dem Taster recht schnell von statten gehen, nur wie ?
Wenn ich eine Abfrage in die delay-Funktion einbaue, dann lande ich ja 
trotzdem erst wieder in der Funktion Program, zumal ich jetzt auch nicht 
wüsste, wie ich elegant 'springen' kann.

von Programmierer (Gast)


Lesenswert?

dummschwaetzer schrieb:
> Beim Einsprung in deine ISR wird eine Kopie des PC auf dem Stack
> abgelegt.
> Diese musst du manipulieren!

Und was ist mit allfälligen Stack-Frames? Woher weisst du in der ISR, 
wie "tief" du in den Unterprogrammen steckst? Der Stack wird im nu 
explodieren, also vergiss die Idee ganz schnell wieder...


> Ist aber sehr schlechter CodeStyle!!!

Ack.

von Programmierer (Gast)


Lesenswert?

Philip.J schrieb:
> void program

Die Funktionalität von program() gehört in eine ISR, die du alle ms mal 
aufrufst und dann in Abhängigkeit von dem State (denn hier hast du eine 
State Machine) irgendwas machst. Korrekt implementiert kannst du 
komplett auf time_1ms() verzichten.

Mit dem Taster veränderst du einfach den Folgestate.

von Philip.J (Gast)


Lesenswert?

Mmh, ich und programmieren ^^

Wenn ich die Funktion in einer ISR ausführe (z.B. TimerA), dann bräuchte 
ich ja trotzdem noch die andere ISR für den Programmwechsel. Außerdem 
müsste ich auch wissen, wann genau der Durchlauf vorbei wäre, um nicht 
mitten drin abzubrechen (ich will ja alle Lichteffekte komplett 
ausführen), ergo für mich wenig praktikabel.
Gibt es sonst noch andere aktionsbezogene Interrupts ? Bei mir ist da 
bisher keiner weiter hängen gebliben, außer halt P1 und P2.

von Erik (Gast)


Lesenswert?

wenn das richtig verstehe ,

taste drücken  dann 1-10 als "Zählerstand"

danach in das enstsprechende UnterProgramm (bzw. zur Sprungadresse 
gehen) ausführen ? je nach Zählerstand lieg ich da richtig ?

IDEE :am schleifenabfang "Zählerstand" auwerten und dorthin springen ,
zwischendrin testen ob "Zählerstand" noch gültig ist

kann leider bloß Assembler
mfg Erik

von Philip.J (Gast)


Lesenswert?

Nach einigen weiteren Versuchen bin ich mittlerweile ein kleines Stück 
weiter gekommen. Funktioniert hat bisher schon, alle Programme mittels 
P2.0 durchzuschalten, allerdings mit der Einschränkung, dass die 
Programme nur jeweils 1x gelaufen sind und nicht dauerhaft.
Funktioniert hat auch schon, das ich mittels Taster von Nichts ins 
Programm 1 schalten konnte, welches dann dauerhaft lief, allerdings 
konnte ich das Programm dann nicht unterbrechen, um ins Programm 2 
schalten zu können (ich dachte eig. dafür wäre ein Interrupt da ?)

void program(int lights, ...)
{
  x = 0;
  while(P2IFG > 0)
  {
    P1OUT = lights;
    __delay_cycles(50000);
    P1OUT = 0;
    __delay_cycles(50000);
  }

Nach meinem Verständnis hätte ich P2IFG == 0 als Bedingung nehmen 
müssen, da ich das Flag ja in der ISR wieder zurücksetze, aber damit 
funktionierte gar nichts. So wie gepostet, läuft Programm 1 dauerhaft, 
ohne das ich es umschalten kann.

Schön wäre es auch gewesen, wenn das Programm in die While-Schleife am 
Ende der Main-Funktion eingreifen könnte, aber dort hatte der Taster gar 
keine Funktion, sodass ich diese derzeitig durch den lpm4 ersetzt habe.

@Erik: Jetzt werte ich den Zählerstand ja in der ISR aus und springe 
dann, zumal ich ja auch die verschiedenen Variablen mit übergeben muss, 
was nach meinem Verständnis nach dem Sprung schlecht geht ?

von endlos (Gast)


Lesenswert?

1
void program(int st, int dl, int bs, int pn, int steps, int lights)
2
{
3
...
4
  while(1)
5
  {
6
...
7
      do
8
      {
9
...
10
     }while(1==1);            // time < 0.5s - 1s (timer)
11
    }
12
  }
13
}

also das gehst schon einmal gar nicht!

Mach dir Gedanken übr deine Programmstruktur. Ich empfehle ab Kapitel 1 
deines Lehrbuches anzufangen.

von Philip.J (Gast)


Lesenswert?

Geht schon ;) Hatte allerdings einen anderen Sinn. Die do-while-Schleife 
war für mich zu dem Zeitpunkt einfach nur ein Platzhalter gewesen. Sieht 
man auch gut an der Kommentierung dahinter.
Die While(1)-Schleife beruhte auf einem Gedankenfehler, der mittlerweile 
behoben wurde.

Mein Fehler lag übrigens darin, dass ich das _EINT() vergessen hatte. 
Mittlerweile funktioniert alles.
Danke für die Hilfen !

von endlos (Gast)


Lesenswert?

Philip.J schrieb:
> Geht schon ;)

ich kann mein Auto auch schieben!

endlos schrieb:
> also das gehst schon einmal gar nicht!

heißt: das Programm ist sch...limm!

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.