Forum: Mikrocontroller und Digitale Elektronik Zyklische Interrupts - Verständnissproblem


von Coco J. (Firma: Student) (dathcoco)


Lesenswert?

Schönen guten Abend.

Ich möchte einen Interrupt realisieren der mit 80khz auftritt.
Dafür nutze ich den 8-Bit Counter TCNT0. (bei einem at_tiny2313)

Ich habe ursprünglich errechnet, dass ich bei 16MHz Tackt und einem 
Prescaler von 1 einen Registerwert von 100 brauche um auf meine 80MHz zu 
kommen. Aber in der Realität scheint es dass ich dort den Wert 77 
eingeben muss (habe ich mit meinem Multimeter, ein gutes von PeakTech, 
gemessen), und 40kHz gemessen (das sollte richtig sein, da es ja eine 
Periodendauer misst).

also ich nutze folgenden Code:
1
int main(void)
2
{
3
  DDRB |=  0xFF;
4
  PORTB = 0x00;
5
  //USI_init();
6
  interrupt_init();
7
  
8
  sei();
9
    while(1)
10
    {
11
    asm("nop");
12
    }
13
}
14
15
void interrupt_init(void)
16
{
17
  TCCR0B = _bv(CS00);  //prescaler 1
18
  TIMSK = _bv(TOIE0); // interrupt enable für Timer-Overflow
19
}
20
21
ISR(TIMER0_OVF_vect)
22
{
23
  TCNT0 = 77; // 100 zählerstände zählen => 80kHz, 77 in der realität
24
  PORTB ^= _bv(PB0);
25
}


Um das ganze herauszufinden habe ich mir die zugehörige lls Datei 
angesehn, und folgenden ASM Code gefunden:
1
  5e:  1f 92         push          ;2
2
  60:  0f 92         push  r0        ;2
3
  62:  0f b6         in  r0, 0x3f  ; 63  ;1
4
  64:  0f 92         push  r0        ;2
5
  66:  11 24         eor  r1, r1        ;1
6
  68:  8f 93         push  r24        ;2
7
  6a:  9f 93         push  r25        ;2
8
  TCNT0 = 77; // 100 zählerstände zählen => 80kHz
9
  6c:  8d e4         ldi  r24, 0x4D  ; 77  ;2
10
  6e:  82 bf         out  0x32, r24  ; 50
11
  PORTB ^= _bv(PB0);
12
  70:  98 b3         in  r25, 0x18  ; 24
13
  72:  81 e0         ldi  r24, 0x01  ; 1
14
  74:  89 27         eor  r24, r25
15
  76:  88 bb         out  0x18, r24  ; 24
16
  78:  9f 91         pop  r25
17
  7a:  8f 91         pop  r24
18
  7c:  0f 90         pop  r0
19
  7e:  0f be         out  0x3f, r0  ; 63
20
  80:  0f 90         pop  r0
21
  82:  1f 90         pop  r1
22
  84:  18 95         reti

die zahlen hinten bis zu der ; 77 stehen für die Tackte die der Befehl 
braucht.

Zusammengerechnet brauche ich 14 Tackte bis die 77 im Register ist und 
hochgezählt wird.

100-77 sind für mich aber 23, also wo sind die fehlenden 9 Tackte?

lg Coco

von Rolf Magnus (Gast)


Lesenswert?

Die braucht der Prozessor, um überhaupt erstmal zur ISR zu springen, 
wenn der Interrupt auftritt. Da kann aber variieren.
Generell sollte man für sowas den CTC-Modus benutzen und kein manuelles 
Neuladen des Zählers, denn das ist nie so richtig genau, und Fehler 
addieren sich auf.

von Coco J. (Firma: Student) (dathcoco)


Lesenswert?

ok, dachte, dass der Einsprung in die ISR die "push"-Befehle dauert, und 
nicht selber  noch etwas verbraucht.

Dann werd ich mir wohl Morgen mal ein Beispiel mit dem CTC-Modus 
schreiben.
Danke für die schnelle Antwort.

von Stefan E. (sternst)


Lesenswert?

Das sind gleich 2 Sachen im Argen:

1) Bei 16 MHz Systemtakt und einer Interrupt-Häufigkeit von 80 kHz sind 
200 Takte nötig und nicht 100.

2) Der Zähler zählt aufwärts. Wenn du ihn also mit 77 vorlädst, sind es 
256-77 = 179 Zähler-Takte bis zum nächsten Überlauf. Das plus die 14 
Takte, die du noch gefunden hast, plus die, die du vergessen hast, sind 
dann auch zusammen 200 und der Grund, warum 77 das gewünschte Ergebnis 
liefert.

von bitte löschen (Gast)


Lesenswert?

Im Handbuch heißt es dazu:
"The interrupt execution response for all the enabled Atmel®AVR® 
interrupts is four clock cycles minimum. After four clock cycles, the 
Program Vector address for the actual interrupt handling routine is 
executed. During this 4-clock cycle period, the Program Counter is 
pushed onto the Stack. The Vector is normally a jump to the interrupt 
routine, and this jump takes three clock cycles. If an interrupt 
occurs during execution of a multi-cycle instruction, this instruction 
is completed before the interrupt is served."

4+3 = 9, also exakt das, was Du gesucht hast, wobei noch die Abarbeitung 
des gerade in der Hauptschleife befindlichen Befehls dazu kommen müsste.
Dein µC verbringt in der Hauptschleife einen Takt mit einem NOP und 2 
Takte mit einem RJMP. Entsprechend verteilt ist die Wahrscheinlichkeit, 
dass der µC gerade im ersten Takt des Sprungbefehls ist, also nicht 
unmittelbar nach dem Takt unterbrechen kann, 1/3. In 1/3 der Fälle wird 
also eine Periode Deiner Frequenz um einen Takt länger.
CTC halte ich hier auch für angebrachter.

von Stefan E. (sternst)


Lesenswert?

Philipp K. schrieb:
> 4+3 = 9

Rechne besser nochmal nach. ;-)


Aber wie bereits gesagt: 179 + 14 + 7 = 200

von Wolfgang (Gast)


Lesenswert?

coco jack schrieb:
> Aber in der Realität scheint es dass ich dort den Wert 77
> eingeben muss (habe ich mit meinem Multimeter, ein gutes von PeakTech,
> gemessen), und 40kHz gemessen (das sollte richtig sein, da es ja eine
> Periodendauer misst).

Warum guckst du dir nicht erstmal die simulierte Realität an, indem du 
in AVR Studio das ganze im Debugger laufen läßt und z.B. im 
Einzelschritt bzw. mit Hilfe von Breakpoints in der ISR anhand der 
Stop-Watch genau die Laufzeit bis zum nächsten Interrupt und die Zeiten 
für den Einspung verfolgen kannst. Diskrepanzen wie 80 vs. 40 kHz siehst 
du sofort ohne das Schätzeisen herauszukramen.

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.