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.
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.
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.
#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.
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.
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.
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.
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
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 ?
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.
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 !
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.