Forum: Mikrocontroller und Digitale Elektronik Wait Timer optimierbar?


von Emitter (Gast)


Lesenswert?

Ich habe in meinem Programm einen Wait Timer, der mit Hilfe von 
Interrupts zählt.

1
void vSetWaitTimer(UI uiWaitValue)
2
{
3
  // initialize requested time
4
  __disable_interrupt();          // disable interrupt
5
  guiWaitTimer = uiWaitValue;
6
  __enable_interrupt();           // enable interrupt
7
  
8
  // wait until time is expired
9
  while (guiWaitTimer > 0)
10
  {
11
    // wait <-SCHLECHT?
12
  }
13
}

Die gewünschte Zeit (in ms), die das Programm pausieren soll wird mit 
der Variable uiWaitValue in die Funktion übergeben. Mein Problem ist 
jedoch die Zeile mit dem "// wait", in der while-Schleife passiert 
NICHTS, eine gefährliche Situation? Oder "darf" man das so realisieren?
Wie kann ich das vermeiden? Ich hatte an einen Scheduler im 
Hauptprogramm gedacht, aber dann kann icht die Wartezeit nicht 
universell per Funktion überall im Programm nutzen...

Weiß jemand Rat? Würde mich freuen.

Zugehöriger Interrupt:
1
#pragma vector=TIMER0_COMPA_vect
2
__interrupt void TIMER0_COMPA_int (void)
3
{
4
  if (guiWaitTimer > 0)                   
5
  {
6
    guiWaitTimer--;                  // reduce counter every 1 ms
7
  }
8
}

Prozessor: Atmel Atmega 328p
Compiler: IAR Embedded Workbench 5.5

: Verschoben durch User
von Läubi .. (laeubi) Benutzerseite


Lesenswert?

Emitter schrieb:
> in der while-Schleife passiert NICHTS, eine gefährliche Situation?

Was soll daran "gefährlich" sein?

Emitter schrieb:
> Wie kann ich das vermeiden?

Mach doch einfach nebenbei was anderes bis der Timer "abgelaufen" ist.

von Emitter (Gast)


Lesenswert?

Vielen Dank für die schnelle Antwort.

Läubi .. schrieb:
> Emitter schrieb:
>> in der while-Schleife passiert NICHTS, eine gefährliche Situation?
>
> Was soll daran "gefährlich" sein?

Ja, ich dachte mal gesagt bekommen zu haben, dass ich nicht "nichts" in 
einer Schleife machen soll. Weil das Programm während der Wartezeit 
quasi in der Endlosschleife hängt und im Fehlerfall, falls guiWaitTimer 
vom Interrupt nicht korrekt auf Null herunter gezählt wurde, das 
Programm sich komplett aufhängen würde, weil die Schleife dann niemals 
verlassen werden kann.

Läubi .. schrieb:
>
> Mach doch einfach nebenbei was anderes bis der Timer "abgelaufen" ist.

Und "was anderes machen", ja mhh nur was?


Ich dachte nur man könnte das besser implementieren...

Achja, vergessen oben zu definieren:
Programmiersprache: C

von Läubi .. (laeubi) Benutzerseite


Lesenswert?

Emitter schrieb:
> Und "was anderes machen", ja mhh nur was?

Keine Ahnung... wenn es eh nix anderes zu tun gibt bringt 
interruptgesteuertes Warten nur Komplexität aber keinen Nutzen.

Emitter schrieb:
> Weil das Programm während der Wartezeit quasi in der Endlosschleife
> hängt und im Fehlerfall,

Im Fehlerfall hilft es auch nicht irgendwas zu tun, du könntest 
natürlich einen Timeout einbauen, das macht aber nur Sinn, wenn du auf 
eine externes Signal wartest, ein Timeout bei einer Zeitwarteschleife 
ist etwas unsinnig.

von Ulrich (Gast)


Lesenswert?

Wenn es nur darum geht zu warten könnte man ggf. den Timer per Vorteiler 
langsamer laufen lassen und dann mit nur einem Interrupt auskommen. Die 
Zeit ist dabei allerdings gerade mit dem 8 Bit Timer nicht so genau 
einzustellen. Während des Wartens könnte man dann µC in einen 
Stromsparmodus (z.B. Idel) versetzen.

von Peter R. (peterfido)


Lesenswert?

Wozu das Disable und Enable?

In eine leere "Schleife" packe ich immer ein NOP. Ist aber nicht 
notwendig.

von Emitter (Gast)


Lesenswert?

Peter R. schrieb:
> Wozu das Disable und Enable?
>
> In eine leere "Schleife" packe ich immer ein NOP. Ist aber nicht
> notwendig.

Naja, um die globale Variable, welche im Interrupt dekrementiert wird, 
zu beschreiben, muss natürlich der Interrupt pausiert werden, da ich 
ansonsten nicht sauber reinschreiben kann. Deswegen zuerst disable 
interrupt und dann wieder enable interrupt.

von Karl H. (kbuchegg)


Lesenswert?

Emitter schrieb:

> Ich dachte nur man könnte das besser implementieren...

Kommt auf die Situation an.
Ausser bei ganz kurzen Warteschleifen bzw. wenn das Programm ausser 
Warten nichts zu tun hat, ist der ganze Ansazu mit Warten schon der 
falsche Weg. Also faktisch gesehen, ist es fast immer der falsche Weg. 
Ob jetzt mit Timer oder mit Prozessortakte verplempern (was im Grunde 
dasselbe ist, nur die Basis ist eine andere)

Der saubere Ansatz besteht darin, zu realisieren, dass µC meistens mit 
Eventsteuerung am einfachsten realisiert werden. In der Hauptschleife 
werden alle möglichen Eventquellen nacheinander abgeklappert, ob der 
Event eingetreten ist und wenn ja, wird er behandelt. Der Ablauf eines 
Timers ist dann auch nichts anderes als ein Event.
In letzter Konsequenz bringt einen ein derartiges Vorgehen dann meistens 
in die Richtung von Zustandsmaschinen.

von Falk B. (falk)


Lesenswert?


von Emitter (Gast)


Lesenswert?

Karl Heinz Buchegger schrieb:
> Der saubere Ansatz besteht darin, zu realisieren, dass µC meistens mit
> Eventsteuerung am einfachsten realisiert werden. In der Hauptschleife
> werden alle möglichen Eventquellen nacheinander abgeklappert, ob der
> Event eingetreten ist und wenn ja, wird er behandelt. Der Ablauf eines
> Timers ist dann auch nichts anderes als ein Event.
> In letzter Konsequenz bringt einen ein derartiges Vorgehen dann meistens
> in die Richtung von Zustandsmaschinen.

Falk Brunner schrieb:
> Siehe Multitasking und statemachine

Danke für die Hilfe. Okay, also muss ich wie oben schon geahnt einen 
Scheduler nutzen. Danke ;-)

von Reinhard Kern (Gast)


Lesenswert?

Emitter schrieb:
> Danke für die Hilfe. Okay, also muss ich wie oben schon geahnt einen
> Scheduler nutzen. Danke ;-)

Das ist nicht weiter schlimm, du musst dich ja nicht an Windows oder 
Linux orientieren.

Eine ganz einfache Möglichkeit ist eine main loop mit verschiedenen 
Aufgaben
in der Art

Loop:
  Call Task1
  Call Task2
  ...
  Jmp  Loop

und wenn in Task2 ein Waittimer noch nicht abgelaufen ist tut sie eben 
nichts. Der Timeinterrupt zählt einfach gesetzte Timer (z.B. einen für 
jede Task) herunter auf 0, so braucht man nicht mal einen Event, die 
Task wird halt wieder aktiv, wenn der Timer wieder auf 0 steht.

Allerdings muss man sich von dem einen linear durchlaufenden Programm 
verabschieden, das mindeste ist die häppchenweise Aufteilung in Tasks, 
die jeweils nur kurz laufen, z.B. prüfen ob ein Zeichen empfangen wurde.

Gruss Reinhard

von Peter R. (peterfido)


Lesenswert?

Emitter schrieb:
> Naja, um die globale Variable, welche im Interrupt dekrementiert wird,
> zu beschreiben, muss natürlich der Interrupt pausiert werden, da ich
> ansonsten nicht sauber reinschreiben kann. Deswegen zuerst disable
> interrupt und dann wieder enable interrupt.

Ich löse das immer so, dass ich vorher dem Timer auf 0 setze. Da bleibt 
dann genug Zeit die Variable zu setzen und der Timer läuft dann wirklich 
genau die gewünschte Zeit.

von Purzel H. (hacky)


Lesenswert?

Wenn die interruptvariable ein byte ist, ist der zugriff atomar, dh 
benoetigt keine schutzmechanismen. Ich verwende jeweils boolean.

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.