Forum: Mikrocontroller und Digitale Elektronik for-loop iterator den Interrupt überleben lassen


von Seb A. (aslmx)


Lesenswert?

Hi zusammen,

Vielleicht sollte ich hier erwähnen, das ich das mit CodeWarrior im 
Simulator programmiere. Auf einem Simulierten Motorola 68HC08 
Microcontroller.

Vielleicht liegt es also am COmpiler das er das nicht mitmacht, aber ich 
hab auch nicht so viel C-Erfahrung...

Und zwar Versuche ein Lauflicht zu bauen das Interrupt getriggert 
startet und anhält. Läuft ganz okay, allerdings... ich poste mal ein 
bisscen code ;)

die ISR toggelt ledon.
1
#pragma TRAP_PROC 
2
void ISR_LED (void) {
3
4
ledon = !ledon;  // Toggle LED
5
6
KBSCR_ACKK = 1;  // Keyboard Acknowledge Bit löschen   
7
  
8
}

Aus dem infinite Loop in main() rufe ich immer folgende Funktion auf
1
static void LightShow (void){
2
  
3
 for (i = 1; i > 0; i <<=1){
4
5
 // Bevor Lauflicht aktualisiert wird, prüfen ob es überhaupt angeschaltet ist
6
 
7
 if (ledon > 0) { 
8
   
9
  PTB = i;
10
  
11
 } 
12
 
13
  Delay();
14
15
 }
16
 
17
}

So wie klappt das mit dem stoppen und starten, aber das Lauflicht läuft 
ja eigentlich weiter, es wird nur nicht aktualisiert.. (weil PTB nicht 
neu gesetzt wird).

wenn ich das so schreibe

1
static void LightShow (void){
2
3
 // Bevor Lauflicht aktualisiert wird, prüfen ob es überhaupt angeschaltet ist
4
 if (ledon > 0) {   
5
6
 for (i = 1; i > 0; i <<=1){
7
  
8
  PTB = i;
9
  
10
 } 
11
 
12
  Delay();
13
14
 }
15
 
16
}

Dann läuft das Licht natürlich erst einmal Eine Runde zu Ende und 
reagiert nicht so fort (je nach Delay() kann das lange sein...).

Was ich jetzt eigentlich vorhatte, aber irgendwie nicht auf die Kette 
bekomme ist, folgendes

1
static void LightShow (void){
2
  
3
static unsigned int i;
4
5
 for (i = i; i > 0; i <<=1){
6
7
8
 // Bevor Lauflicht aktualisiert wird, prüfen ob es überhaupt angeschaltet ist
9
 
10
 if (ledon > 0) { 
11
   
12
  PTB = i;
13
  
14
 }
15
else
16
{ break; } 
17
 
18
  Delay();
19
20
 }
21
 
22
}

Ich erhoffte mir damit, das das i den Funktionsaufruf überlebt und die 
for-Schleife mit i=i wieder da weitermacht wo sie aufgehört hat.
Aber das scheint nicht zu gehen.
Auch wenn ich
1
 for (; i > 0; i <<=1){

das erste Feld einfach leer lasse, machts die Kiste nicht...

Bin ich der Lösung irgendwie schon nahe, oder muss ich auf die 
For-Schleife verzichten und ein anderes Konstrukt wählen um den 
Schleifeneinstieg beim wieder starten der des Lauflichts frei definieren 
zu können?

Danke für eure Hilfe :-)

vgs

von nocheinGast (Gast)


Lesenswert?

> static unsigned int i;
Welchen Wert hat i?
Die Schleife wird natürlich nicht ausgeführt, wenn i <= 0 ist.

von Mark B. (markbrandis)


Lesenswert?

nocheinGast schrieb:
>> static unsigned int i;
> Welchen Wert hat i?
> Die Schleife wird natürlich nicht ausgeführt, wenn i <= 0 ist.

Kleiner als Null wird bei unsigned etwas schwierig. ;-)

: Bearbeitet durch User
von nocheinGast (Gast)


Lesenswert?

> Kleiner als Null wird bei unsigned etwas schwierig. ;-)
Du weißt was ich gemeint hab... aber mal ernsthaft: Beim ersten Aufruf 
der Funktion wird i initialisiert. Wenn man keinen Wert angibt, ist i 
undefiniert oder 0?

von nocheinGast (Gast)


Lesenswert?

Ich beantwort mir die Frage mal selber:
>If an object that has static storage duration is not
>initialized explicitly, then:
>if it has arithmetic type, it is initialized to (positive or unsigned) zero;

Somit kannst du dir sicher sein, dass deine Schleife nie ausgeführt 
wird.

von S. R. (svenska)


Lesenswert?

Du versuchst, eine for-Schleife unterbrechbar zu gestalten. Das ist 
äußerst unschön. Baue die relevanten Teile einfach selbst nach:
1
void DoLauflicht(void) {
2
  static unsigned char muster = 1; /* 8 LEDs an einem Port */
3
  PTB = muster;
4
  muster <<= 1;
5
  if(!muster) muster = 1;
6
}

Der Code nutzt aus, dass das eine Bit irgendwann komplett rausgeshiftet 
ist, und re-initialisiert dann die Variable. Ach so, und ist ungetestet.

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

nocheinGast schrieb:
> Wenn man keinen Wert angibt, ist i undefiniert oder 0?

static-Variablen sind immer mit 0 vordefiniert, wenn man keinen Wert 
angibt. Das ist in C garantiert.

von Klaus W. (mfgkw)


Lesenswert?

Frank M. schrieb:
> static-Variablen sind immer mit 0 vordefiniert, wenn man keinen Wert
> angibt. Das ist in C garantiert.

Soweit sich der Compiler an den Standard hält.
Bei Controllern würde ich mir lieber noch mal die Doku zum Compiler 
anschauen sicherheitshalber...

von Seb A. (aslmx)


Lesenswert?

S. R. schrieb:
> Du versuchst, eine for-Schleife unterbrechbar zu gestalten. Das ist
> äußerst unschön. Baue die relevanten Teile einfach selbst nach:

Ja... ich dachte mir das schon.

Werde nachher nochmal etwas experimentieren. Die Aufgabenstellung war 
ein vorhandenes Lauflicht (das eigentlich nur aus dieser for-Schleife 
besteht) so zu erweitern, dass es Interrupt getriggert gestartet und 
gestoppt werden kann. Das habe ich soweit eigentlich erreicht, das 
Starten und Stoppen funktioniert per Interrupt. Allerdings suchte ich 
gestern Abend noch einen Weg das etwas eleganter zu machen und eben 
nicht entweder nur die Anzeige ein/auszuschalten oder den 
Schleifenzyklus for dem Ein/Ausschlaten abwarten zu müssen.

Werde nachher mal mit einem anderen Konstrukt experimentieren das 
sauberer arbeitet, wird dann vermutlich keine for-schleife werden.

War gestern Abend schon spät, sorry für die Rechtschreibfehler und die 
etwas unklare Beschreibung ;-)

Danke auch für die anderen Antworten!

vgs

: Bearbeitet durch User
von Georg G. (df2au)


Lesenswert?

Du solltest dir bei der Gelegenheit auch das Stichwort "volatile" 
vornehmen. Wenn eine globale Variable in einer Interrupt Routine 
geändert wird, geht das u.U. dem Hauptprogramm am Allerwertesten vorbei. 
Da optimiert der Compiler mal schnell was weg.

von Seb A. (aslmx)


Angehängte Dateien:

Lesenswert?

Georg G. schrieb:
> Du solltest dir bei der Gelegenheit auch das Stichwort "volatile"
> vornehmen. Wenn eine globale Variable in einer Interrupt Routine
> geändert wird, geht das u.U. dem Hauptprogramm am Allerwertesten vorbei.
> Da optimiert der Compiler mal schnell was weg.

Danke für den Hinweis. Ich ändere den Iterator i jedoch nicht aus der 
ISR. Da wird nur ledon getoggelt. Auf i wird nur während ledon==1 ist 
ein LeftShit gemacht damit die LED sich nach links bewegt.

habs jetzt so gebaut
1
(...)
2
3
unsigned char i = 1; // i = 1, damit das Lauflicht direkt beginnen kann.
4
5
(...)
6
7
8
static void LightShow (void){
9
  
10
while (ledon == 1){  // while ledon == 1 -> LED == enabled
11
    PTB = i; // animate DIL-LED
12
    i <<=1; // shift left  
13
  if (i==0){
14
    i++;    // Wenn i 0 wird muss es auf 1 erhöht 
15
  }       //werden damit es von vorne beginnt
16
  Delay();
17
     __RESET_WATCHDOG();  // Falls Lauflicht lange an ist muss der Hund gefüttert werden   
18
  }
19
  
20
}
21
22
(...)
23
24
main()
25
26
(...)
27
28
29
for(;;){
30
  LightShow(); // Run LightShow()
31
       __RESET_WATCHDOG(); // Falls Lauflicht lange aus ist Watchdog zurücksetzen
32
}
33
34
(...)

Ich habe den Iterator jetzt im globalen Teil definiert, da scheint er 
den Interrupt zu überleben. Falls ledon lange Zeit == 0 ist, wird auch 
im infite-loop innerhalb von main() noch der Watchdog "gefüttert"...

Bin so eigentlich zufrieden, aber wie ich das Forum kenne kommt bestimmt 
noch jemand mit etwas um die Ecke was ich noch nicht kenne, wofür ich 
auch dankbar wäre :-)

PS: ich hab mal für die, die es nicht kennen einen Screenshot von der 
"Simulation" angefügt, falls sich einer über das DIL-LED im Komentar 
wundert. Da wird (nach Aufgabenstellung!) ein 8-Bit DIL Switch als 
Lauflicht missbraucht... optisch passts ja ;)
Das XP lauft in einer VM... Die XP VM nimmt auf dem Linux Laptop einfach 
weniger Platz weg als eine Win7 VM ;)

von Bernd (Gast)


Lesenswert?

Sebastian J. schrieb:
> habs jetzt so gebaut

Bitte gewöhn Dir an Deinen Code ordentlich zu formatieren bevor Du ihn 
postest. Wenn alles nur so lieblos hingekotzt und kreuz und quer 
verstreut ist ohne sichtbare Struktur dann wird dem Leser schon nach 5 
Sekunden übel und er hat keine Lust mehr sich nach Feierabend noch mit 
Deinem Problem zu beschäftigen.

von S. R. (svenska)


Lesenswert?

Was war denn an meinem Code so schlecht? :-(

Wenn du eine Variable innerhalb einer Funktion als "static" 
deklarierst, dann verhält sie sich wie eine globale Variable, ist aber 
nur innerhalb dieser Funktion sichtbar. Eine globale Variable "i" wird 
dir (oder anderen) noch viel Ärger bereiten.

Mal abgesehen davon, dass die ganze Logik etwas arg verquer ist. Du 
trennst die "Programmlogik" (Timing, wann was zu tun ist) nicht von der 
"Problemlogik" (wie ein Problem zu lösen ist). Oder du erkennst das 
Problem nicht korrekt, was aber auch keine Rolle spielt.

von Bernd K. (prof7bit)


Lesenswert?

S. R. schrieb:
> Was war denn an meinem Code so schlecht?

Nicht Dein Code sondern der von S.J. Der ist formatiert wie Kraut und 
Rüben. Ich will da jetzt keine Diskussion lostreten, ich wollte es nur 
als Tipp am Rande für die Zukunft loswerden. Kollegen und andere 
Projektteilnehmer werden stets dankbar sein wenn sie nicht einen 
durchgewürfelten Buchstabenhaufen vorgesetzt bekommen sondern etwas was 
zumindest schonmal rein optisch so aussieht als hätte es eine gewisse 
Struktur damit das Auge beim Lesen sinnvolle Konturen findet an denen es 
sich festhalten und orientieren kann.

von S. R. (svenska)


Lesenswert?

Da haben wir uns beim Posten überschnitten. Ich habe mich nur gewundert, 
warum der TO einen guten Ansatz ignoriert hat und dann schlecht 
formatierten, wenig durchdachten Code präsentiert hat.

Naja, man kann nicht alles haben.

von Seb A. (aslmx)


Lesenswert?

Ja sorry das ich die 5 relevanten Zeilen mit der eigentlichen Logik 
nicht schöner präsentiert habe...

Ich bitte ja auch nur darum das sich das einer nach Feierabend antut, 
ich verlange es nicht und zwinge niemanden.


Mea culpa! Beim nächsten mal wirds schöner...


Ich sehe leider erst jetzt das dein (S.R. (svenskas)) Ansatz ganz ohne 
Schleife auskommt, sofern die Prüfung ob das Lauflicht laufen soll oder 
nicht ausserhalb geschieht.

Ich hatte mir erstmal nur deinen Ratschlag zu Herzen genommen auf die 
For-Schleife zu verzichten, damit bin ich ja auch schonmal ein gutes 
Stück weiter gekommen.

Danke fürs helfen!



edit: typo

: Bearbeitet durch User
von S. R. (svenska)


Lesenswert?

Ja, in der ISR brauchst du dann nur die Funktion DoLauflicht() aufrufen, 
die dann einen Schritt weitergeht. Wenn das Lauflicht nicht laufen soll, 
dann rufst du die Funktion eben nicht auf.

Damit ist die Programmlogik (wann soll das Lauflicht laufen, und wie 
schnell) von der Problemlogik (wie lasse ich ein Lauflicht unterbrechbar 
laufen) entkoppelt.

;-)

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.