Verständnisfrage zu Interrupt Routine

Gast #2195721
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
}
#2195737
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.
#2195741
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
Persönliche Seite #2195810
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.
Gast #2195858
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

Antwort schreiben

Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt. Bitte hier nur auf die ursprüngliche Frage antworten, für neue Fragen einen neuen Beitrag erstellen.

Formatierung
  • [c]C-Code[/c]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] – Link zu einem Artikel
  • Verweis auf einen anderen Beitrag: Rechtsklick auf dessen Beitrags-ID (#8078628), „Adresse kopieren“, in den Text einfügen

Mehr zur Formatierung

Längeren Sourcecode als Anhang, nicht in den Text. JPG nur für Fotos und Scans; Zeichnungen und Screenshots als PNG oder GIF. Siehe Bildformate.

Schon registriert? Anmelden

Wird nicht angezeigt. Wir schicken dir einen Link; sobald du damit bestätigst, erscheint dein Beitrag.

Mit dem Abschicken legst du einen kostenlosen Account an und erkennst die Nutzungsbedingungen und die Datenschutzerklärung an.