Forum: Compiler & IDEs Verständnisfrage zu Interrupt Routine


von Firebird (Gast)


Lesenswert?

Hallo zusammen

Unten ist eine Interrupt Routine die ich nicht ganz verstehe.

Timer1 zählt aufwärts wärend tdelay reduziert wird wenn die Bedingung 
timer1==0 erfüllt ist.

Wie ist void delay() zu verstehen und wie ist die Auswirkung auf int 
main(void)? Was ich verstanden habe ist kommentiert.

Danke und Gruss
Firebird
1
volatile uint8_t tdelay = 0;
2
volatile uint8_t timer1 = 0;
1
ISR(TIMER1_OVF_vect)
2
{
3
if (++timer1==0)      // zuerst erhöhen, dann bewerten
4
  {
5
    if (tdelay)       // gemäss void delay() ist der Anfangswert 10
6
      tdelay--;       // um 1 reduzieren
7
                      // nur wenn timer1 == 0
8
  }
9
}
1
void delay(uint8_t time)
2
{
3
  tdelay = time;      // tdelay = time (Anfangswert 10)    
4
  while (tdelay);     // ???
5
}
1
int main(void)
2
{
3
  sei();
4
  
5
  while (1)
6
  {
7
    delay(10);
8
    // mach etwas ...
9
  }
10
}

von Karl H. (kbuchegg)


Lesenswert?

Firebird schrieb:

> Timer1 zählt aufwärts wärend tdelay reduziert wird wenn die Bedingung
> timer1==0 erfüllt ist.

Ja.
Aber der springende Punkt ist, dass timer1 eine uint8_t Variable ist. 
D.h. wenn die hochgezählt wird, dann zählt sie:

  0, 1, 2, 3, 4, ... 127, 128, 129, .... 253, 254, 255, 0, 1, 2, 3

mit anderen Worten. Das ist ein zusätzlicher Softwareteiler, der den 
Code in seinem abhängigen if-Block

   if( ++timer1 == 0 )
   {

       diesen Block

   }

nur bei jedem 256ten ISR Aufruf ausführt.

> Wie ist void delay() zu verstehen

eine Verzögerung.
die Variable tdelay wird auf einen Wert gesetzt und dann nach und nach 
von den ISR Aufrufen wieder auf 0 heruntergezählt. Ist die Variable 
wieder 0 geworden, so wird die while Schleife verlassen.

Also eine Stoppuhr, die einfach nur rückwärts gezählt wird, so wie die 
Uhren die die Friseusen beim Haarefärben benutzen.

von Falk B. (falk)


Lesenswert?

@  Firebird (Gast)

>Unten ist eine Interrupt Routine die ich nicht ganz verstehe.

Ich auch nicht. Der Gesamtzusammenhang ist sinnlos, deine CPU vertrödelt 
nur Zeit.

>Timer1 zählt aufwärts wärend tdelay reduziert wird wenn die Bedingung
>timer1==0 erfüllt ist.

Nö, genau anders herum.

>Wie ist void delay() zu verstehen

Das ist der Funktionname. Die Funktion liefert keinen Rückgabewert 
(void).

>und wie ist die Auswirkung auf int
>main(void)?

Gar keine.

> Was ich verstanden habe ist kommentiert.

Hmmm.

>volatile uint8_t tdelay = 0;
>volatile uint8_t timer1 = 0;

Siehe Interrupt.

>ISR(TIMER1_OVF_vect)
>{
>if (++timer1==0)      // zuerst erhöhen, dann bewerten

Impliziter Überlauf. Die Bedingung ist nach jeweils 256 Durhläufen 
einmal wahr.

>  {
>    if (tdelay)       // gemäss void delay() ist der Anfangswert 10
>      tdelay--;       // um 1 reduzieren
>                      // nur wenn timer1 == 0

Nöö, wenn tdelay ungleich Null, dann reduzieren

>void delay(uint8_t time)
>{
>  tdelay = time;      // tdelay = time (Anfangswert 10)
>  while (tdelay);     // ???

Solange warten, wie tdelay ungleich Null ist.

>int main(void)
>{
>  sei();

Interrupts freigeben. Naja, da fehtl mindestens die Initialisierung des 
Timers.

>  while (1)

Endlosschleife.

>  {
>    delay(10);

10 Einheiten warten, währenddessen geht nichts anderes.

Alles in allem eins sinnlose, resourcenfressende Kopie von _delay_ms(), 
die es im AVRGCC schon gibt. Wenn man ohne Blockade warten will, muss 
man Multitasking betreiben. Ist eigentlich nicht allzuschwer.

MFG
Falk

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Falk Brunner schrieb:
> Alles in allem eins sinnlose, resourcenfressende Kopie von _delay_ms(),
> die es im AVRGCC schon gibt. Wenn man ohne Blockade warten will, muss
> man Multitasking betreiben. Ist eigentlich nicht allzuschwer.

Sinnlos würd ich nicht sagen, vielleicht unglücklich angewandt.

Mit Code wie
1
void main_loop (void)
2
{
3
    while (1)
4
    {
5
        if (!tdelay)
6
        {
7
            // Timer abgelaufen, wieder aufziehen
8
            tdelay = 10;
9
            blink();
10
        }
11
12
        /* Mach andere wichtige Dinge */
13
14
    } // while (1)
15
}

kann man eine einfache Blink-Funktionalität umsetzen, die nicht die 
Hauptschleife blockiert.

Das ganze ist übersichtlich und bei weitem nicht so schwer zu verstehen, 
korrekt zu implementieren oder anzuwenden wie echtes Multitasking.

Mit einer weiteren Variablen ist es zB ganz easy, einen Blinker alle 10 
Durchläufe zu blinken und einen anderen quasiparallel alle 11 
Durchläufe.

Solche Countdown-Zähler find ich eine sinnvolle Ergänzung in der 
Wergzeugkiste zwischen den blockierenden Delay-Schleifen, die nur für 
kürzeste Wartezeiten (zB externe Hardware) sinnvoll sind, und 
Multitasking, das vielmals Overkill ist und sich bei sehr zeitkritischen 
Sachen sogar als obsolet darstellt.

von Firebird (Gast)


Lesenswert?

Dann ist es sinnvoller die Interrupt Routine von Timer1 unabhängig 
laufen zu lassen unter Berücksichtigung von Fcpu, Prescaler und 
eventuell dem Preload Wert TCNT1.

In der Hauptfunktion dann bestimmen was geschehen soll wenn ein 
bestimmter Zeitpunkt erreicht ist, oder Zeitbereich.

Danke und Gruss
Firebird

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.