Prinzip des Timer-Interrupts
Problem: Ein Z-Eye läuft mit 1 MHz Systemtakt und soll LED0 mit 2 Hz blinken lassen.
Ein Timer ist ein Zähler der mit einer bestimmten (möglichst genauen) Frequenz betrieben wird und dadurch eine Zeitspanne erzeugen kann. Bsp:
Zeitspanne: 250 ms
Frequenz: 1 MHz
Taktzahl = Zeitspanne * Frequenz
Nach 250000 Takten sind 250 ms Zeit vergangen.
Taktzahl = Zeitspanne / Periodendauer
Bsp: 250000 = 250ms/1µs = 250 * (E-3/E-6) = 250 E3
Präsentation mit Timer-Overflow-Interrupt
(Mit den Pfeiltasten steuern)
8 Bit Timer0 Overflow-Interrup
Die Interrupt Service Routine (ISR) soll zu bestimmten Zeiten aufgerufen werden, hier alle 250ms. Ein Overflow-Interrupt wird beim Überlauf des Zählers vom höchsten Wert -hier 0xFF nach 0x00 ausgelöst.
Interruptzeit = (Werteanzahl-Vorsteller)*Vorteiler/Systemtakt
Zahnradmodell: Der Systemtakt wird wie bei einem Getriebe "heruntertransformiert". Hier ein zweistufiges Getriebe mit den Zahnrädern Vorteiler und Vorsteller.
Ziel ist es, eine möglichst genaue Teilung zu erhalten, wobei die Stufen nur begrenzte Einstellmöglichkeiten bieten.
Der Werteanzahl ist der grösste Wert des Zählers, bei 8Bit sind dies 256.
Durch Vorstellen des Zählers können kleinere Zähl-Werte bis zum Overflow-Interrupt erreicht werden.
Sei Systemtakt clkI/O hier 1Mhz
Taktzahl: (Systemtakte bis ISR-Aufruf): Taktzahl = clkI/O *Sollzeit = 1Mhz*250ms = 250.000
Vorteiler : Taktzahl/Werteanzahl = 250.000/256 = 976,6 gewählt wird der nächst höhere Wert aus {1,8,64,256,1024} also 1024
Vorsteller : Werteanzahl - Taktzahl/Vorteiler = 256 - 250.000/1024 = 11,9 gewählt 12
Probe der Genauigkeit : (Werteanzahl-Vorsteller)*Vorteiler/clkI/O =( 256-12)*1024/1MHz = 249,9 ms
Hier ist nur der Vorteilerwert 1024 möglich, kleinere Werte würden mehr Zählimpulse erfordern als mit 8Bit zählbar wären. Bei einer Vorstellung des Zählers mit dem Wert 12 wird nach 256-12=244 Takten der Overflow-Interrupt ausgelöst.
Initialisierung
TCCR0B |= 5; // TimerCounterControllRegister0B 1: /1; 2: /8; 3: /64; 4: /256; 5: /1024
TIMSK |= 1<<TOIE0; // TimerOverflowInterruptEnable0
Quellcode für Version mit 8Bit Timer0 Overflow-Interrupt
Quellcode [blinker_overflowinterrupt.c ] #include <avr/io.h>
int main( ) { // Hauptprogramm
PORTB = 0xe0 ;
DDRB = 0xff ;
TCCR0B = 5 ; // Systemtakt durch 1024
TIMSK |= 1 << TOIE0; // TimerOverflowInterruptEnable0
sei( ) ; // globale Interruptfreigabe
while ( 1 ) ; // Endlosschleife
}
ISR( TIMER0_OVF_vect) { // Interrupt Service Routine
TCNT0 = 12 ; // wieder vorstellen
PORTB ^= 1 ; // Ausgang PB0 invertieren
}
Grössere Untersetzungen realisieren
Die LED soll bei 1MHz Systemtakt nun mit 1Hz blinken, somit muss alle 500ms ihr Zustand invertiert werden.
8Bit Timer0 Overflow-Interupt und Zähler in ISR
Zahnradmodell: Das Transformationsverhältnis ist dabei 500.000 : 1.
Mit den Zahnrädern Vorteiler und Vorsteller lassen sich maximal
1024*256 = 262.144 : 1 erreichen.
Mittels eines weiteren Zahnrads in der ISR, einem Zähler der beim Aufruf inkrementiert wird und bei Erreichen eines bestimmten Wertes erst die Aktion auslöst, lassen sich erheblich längere Zeiten realisierten.
Das Zahnrad in der ISR wird folgend als ISR-Teilfaktor bezeichnet.
Taktzahl : (Systemtakte bis ISR-Aufruf): Taktzahl = clkI/O *Sollzeit = 1Mhz*500ms = 500.000
Vorteiler : Taktzahl/Werteanzahl = 500.000/256 = 1953! Der Wert für den Vorteiler ist zu gross! Gewählt wird nun der höchste Wert aus {1,8,64,256,1024} also 1024. In der ISR muss nun weiter gezählt werden:
ISRTeilfaktor : Taktzahl/Werteanzahl/Vorteiler = 500.000/256/1024 = 1,9 Aufrunden: 2 Beim 2. Mal erst Aktion.
Vorsteller berechnen: Werteanzahl - Taktzahl/Vorteiler/ISRTeilfaktor = 256 - 500.000/1024/2 = 11,9 gewählt 12
Probe der Genauigkeit : (Werteanzahl-Vorsteller)*Vorteiler/clkI/O i*ISRTeilfaktor =( 256-12)*1024/1MHz*2 = 499,7 ms
In der ISR wird zusätzlich hoch gezählt, dazu dient eine lokale statische (persistente, also nicht nach dem Ende der ISR wieder gelöschte) Variable teiler , die beim ersten Aufruf der ISR mit 0 initialisiert wird: teiler merkt sich den Wert bis zum nächsten Mal.
Quellcode [blinker-1s_over8bit.c ] #include <avr/io.h>
int main( ) { // Hauptprogramm
PORTB = 0xe0 ; // LED aus
DDRB = 0xff ; // PB als Ausgang
TCCR0B = 5 ; // Systemtakt durch 1024
TIMSK |= 1 << TOIE0; // TimerOverflowInterruptEnable0
sei( ) ; // globale Interruptfreigabe
while ( 1 ) ; // Endlosschleife
}
ISR( TIMER0_OVF_vect) { // Interrupt Service Routine
static unsigned char teiler= 0 ; // persistente lokale Variable mit 0 initialisiert
TCNT0 = 12 ; // wieder vorstellen
if ( teiler< 1 ) { // bis (Teilfaktor-2) hoch zaehlen, hier bei 0
teiler++;
}
else { // bei Teilfaktor-1 Aktion ausfuehren, hier bei 1
teiler= 0 ;
PINB = 1 ; // Ausgang PB0 invertieren (PORTB ^= 1)
}
}
16Bit Timer1Overflow-Interrupt
Neben dem 8Bit Timer0 gibt es noch einen 16Bit Timer1, dessen Maximalwert ist 65536 und ermöglicht dadurch längere und genauere Zeiten.
Taktzahl : (Systemtakte bis ISR-Aufruf): Taktzahl = clkI/O *Sollzeit = 1Mhz*500ms = 500.000
Vorteiler : Taktzahl/Werteanzahl = 500.000/65536 = 7,6 gewählt wird der nächst höhere Wert aus {1,8,64,256,1024} also 8
Vorsteller berechnen: Werteanzahl - Taktzahl/Vorteiler = 65536 - 500.000/8 = 3036
Probe der Genauigkeit : (Werteanzahl-Vorsteller)*Vorteiler/clkI/O =(65536-3036)*8/1MHz = 500 ms
Quellcode [blinker-1s_over16bit.c ] #include <avr/io.h>
int main( ) { // Hauptprogramm
PORTB = 0xe0 ;
DDRB = 0xff ;
TCCR1B = 2 ; // Systemtakt durch 8
TIMSK |= 1 << TOIE1; // TimerOverflowInterruptEnable0
sei( ) ; // globale Interruptfreigabe
while ( 1 ) ; // Endlosschleife
}
ISR( TIMER1_OVF_vect) { // Interrupt Service Routine
TCNT1 = 3036 ; // wieder vorstellen
PORTB ^= 1 ; // Ausgang PB0 invertieren
}
8 Bit Timer / Counter0 Clear Timer on Compare Match (CTC) Mode (Auto Reload)
Im CTC Modus wird der Wert des TCNT0 mit dem Register OCR0A verglichen. Bei Gleichheit wird der Zähler wieder auf 0 gesetzt und es kann dabei ein OC1A Interrupt ausgelöst werden.
Systemtakt clkI/O hier 1Mhz
Interruptzeit = (1+OCR0A)*Vorteiler/Systemtakt
Taktzahl: (Systemtakte bis ISR-Aufruf): Taktzahl = clkI/O *Sollzeit = 1Mhz*250ms = 250.000
Vorteiler : Taktzahl/Werteanzahl = 250.000/256 = 976,6 gewählt wird der nächst höhere Wert aus {1,8,64,256,1024} also 1024
OCR0A : Taktzahl/Vorteiler-1 = 250.000/1024 -1 = 243,1 gewählt 243
Probe der Genauigkeit : (1+OCR0A)*Vorteiler/clkI/O =( 1+243)*1024/1MHz = 249,9 ms
Initalisierung
TCCR0A |= 1<<WGM01; // Timer im CTC-Mode
TCCR0B |= 5; // Vorteiler 1: /1; 2: /8; 3: /64; 4: /256; 5: /1024
TIMSK |= 1<<OCIE0A; // Timer/Counter0 Output Compare Match A Interrupt Enable
OCR0A = 243; // Wert bei dem der Timer wieder auf 0 gesetzt wird
Quellcode [blinker_ctc.c ] #include <avr/io.h>
int main( ) { // Hauptprogramm
PORTB = 0xe0 ;
DDRB = 0xff ;
TCCR0A |= 1 << WGM01; // Timer im CTC-Mode
TCCR0B |= 5 ; // Vorteiler 1: /1; 2: /8; 3: /64; 4: /256; 5: /1024
TIMSK |= 1 << OCIE0A; // Timer/Counter0 Output Compare Match A Interrupt Enable
OCR0A = 243 ; // Wert bei dem der Timer wieder auf 0 gesetzt wird
sei( ) ; // globale Interruptfreigabe
while ( 1 ) ; // Endlosschleife
}
ISR( TIMER0_COMPA_vect) { // Interrupt Service Routine
PORTB ^= 1 ; // Ausgang PB0 invertieren (PINB = 1)
}
16Bit Timer1 Clear Timer on Compare Match (CTC) Mode (Auto Reload)
Taktzahl : (Systemtakte bis ISR-Aufruf): Taktzahl = clkI/O *Sollzeit = 1Mhz*500ms = 500.000
Vorteiler : Taktzahl/Werteanzahl = 500.000/65536 = 7,6 gewählt wird der nächst höhere Wert aus {1,8,64,256,1024} also 8
OCR1A : Taktzahl/Vorteiler-1 = 500.000/8-1= 62499
Probe der Genauigkeit : (1+OCR1A)*Vorteiler/clkI/O =(1+62499)*8/1MHz = 500 ms
Initalisierung
TCCR1B |= 1<<WGM12; // Timer im CTC-Mode
TCCR1B |= 2; // Vorteiler 1: /1; 2: /8; 3: /64; 4: /256; 5: /1024
TIMSK |= 1<<OCIE1A; // Timer/Counter0 Output Compare Match A Interrupt Enable
OCR1A = 62499; // Wert bei dem der Timer wieder auf 0 gesetzt wird
Quellcode [blinker-1s_ctc16bit.c ] #include <avr/io.h>
int main( ) { // Hauptprogramm
PORTB = 0xe0 ;
DDRB = 0xff ;
TCCR1B |= 1 << WGM12; // Timer im CTC-Mode mit OCR1A als Top
TCCR1B |= 2 ; // Systemtakt durch 8
TIMSK |= 1 << OCIE1A; // Timer/Counter1 Output Compare Match A Interrupt Enable
OCR1A = 62499 ; // Vergleichswert Timer wieder auf 0
sei( ) ; // globale Interruptfreigabe
while ( 1 ) ; // Endlosschleife
}
ISR( TIMER1_COMPA_vect) { // Interrupt Service Routine
PORTB ^= 1 ; // Ausgang PB0 invertieren (PINB = 1)
}
Übungsaufgaben
Blinken 1Hz an PB0 mit 4 MHz Systemtakt, 8Bit-Timer0, Overflow-Interrupt
Lösung anzeigen..
Quellcode [blink-over_4-1_8bit.c ]/* 4 MHz Systemtakt, 8Bit-Timer 0, Overflow-Interrupt, Blinken mit 1 Hz (0,5s an; 0,5s aus) an PB0
Taktzahl: Systemtakt*Sollzeit = 4Mhz*500ms = 2.000.000
Vorteiler: Taktzahl/Werteanzahl = 2.000.000/256 = 7813! => 1024
ISRTeilfaktor: Taktzahl/Werteanzahl/Vorteiler = 2.000.000/256/1024 = 7,6 Aufrunden: 8
Vorsteller: Werteanzahl - Taktzahl/Vorteiler/ISRTeilfaktor = 256 - 2.000.000/1024/8 = 11,9 => 12
Probe: (Werteanzahl-Vorsteller)*Vorteiler/Systemtakt*ISRTeilfaktor =(256-12)*1024/4MHz*8 = 499,7 ms
*/
#include <avr/io.h>
int main( ) { // Hauptprogramm
PORTB = 0xe0 ;
DDRB = 0xff ;
TCCR0B = 5 ; // Systemtakt durch 1024
TIMSK |= 1 << TOIE0; // TimerOverflowInterruptEnable0
sei( ) ; // globale Interruptfreigabe
while ( 1 ) ; // Endlosschleife
}
ISR( TIMER0_OVF_vect) { // Interrupt Service Routine
static unsigned char teiler= 0 ;
TCNT0 = 12 ; // wieder vorstellen
teiler++;
if ( teiler>= 8 ) { // Teilfaktor in ISR
teiler= 0 ;
PORTB ^= 1 ; // Ausgang PB0 invertieren (PINB = 1)
}
} Blinken 1Hz an PB0 mit 8 MHz Systemtakt, 16Bit-Timer1, Overflow-Interrupt
Lösung anzeigen..
Quellcode [blink-over_8-1_16bit.c ]/* 8 MHz Systemtakt, 16Bit-Timer 1, Overflow-Interrupt, Blinken mit 1 Hz an PB0
Taktzahl: Systemtakt*Sollzeit = 8Mhz*500ms = 4.000.000
Vorteiler: Taktzahl/Werteanzahl = 4.000.000/65536 = 61 aus {1,8,64,256,1024} => 64
Vorsteller: Werteanzahl - Taktzahl/Vorteiler = 65536 - 4.000.000/64 = 3036
Probe: (Werteanzahl-Vorsteller)*Vorteiler/Systemtakt =(65536-3036)*64/8MHz = 500 ms
*/
#include <avr/io.h>
int main( ) { // Hauptprogramm
PORTB = 0xe0 ;
DDRB = 0xff ;
TCCR1B = 3 ; // Systemtakt durch 64
TIMSK |= 1 << TOIE1; // TimerOverflowInterruptEnable1
sei( ) ; // globale Interruptfreigabe
while ( 1 ) ; // Endlosschleife
}
ISR( TIMER1_OVF_vect) { // Interrupt Service Routine
TCNT1 = 3036 ; // wieder vorstellen
PORTB ^= 1 ; // Ausgang PB0 invertieren (PINB = 1)
} Interrupt alle 30ms, 1 MHz Systemtakt, 8Bit-Timer0, Overflow-Interrupt
Lösung anzeigen..
Quellcode [30ms-1mhz-8bit-overflow.c ]/* Interrupt alle 30ms, 1 MHz Systemtakt, 8Bit-Timer 0, Overflow-Interrupt, Wechsel an PB0
Taktzahl: Systemtakt*Sollzeit = 1Mhz*30ms = 30.000
Vorteiler: Taktzahl/Werteanzahl = 30.000/256 = 117 aus {1,8,64,256,1024} => 256
Vorsteller: Werteanzahl - Taktzahl/Vorteiler = 256 - 30.000/256 => 139
Probe: (Werteanzahl-Vorsteller)*Vorteiler/Systemtakt =(256-139)*256/1MHz = 29,95 ms
*/
#include <avr/io.h>
int main( ) { // Hauptprogramm
PORTB = 0xe0 ;
DDRB = 0xff ;
TCCR0B = 4 ; // Vorteiler 1: /1; 2: /8; 3: /64; 4: /256; 5: /1024
TIMSK |= 1 << TOIE0; // TimerOverflowInterruptEnable0
sei( ) ; // globale Interruptfreigabe
while ( 1 ) ; // Endlosschleife
}
ISR( TIMER0_OVF_vect) { // Interrupt Service Routine
TCNT0 = 139 ; // wieder vorstellen
PORTB ^= 1 ; // Ausgang PB0 invertieren (PINB = 1)
} Interrupt alle 250µs, 1 MHz Systemtakt, 8Bit-Timer0, Overflow-Interrupt
Lösung anzeigen..
Quellcode [250us-1mhz-8bit-overflow.c ]/* Interrupt alle 250us, 1 MHz Systemtakt, 8Bit-Timer 0, Overflow-Interrupt, Wechsel an PB0
Taktzahl: Systemtakt*Sollzeit = 1Mhz*250us = 250
Vorteiler: Taktzahl/Werteanzahl = 250/256 = 0,98 aus {1,8,64,256,1024} => 1
Vorsteller: Werteanzahl - Taktzahl/Vorteiler = 256 - 250/1 => 6
Probe: (Werteanzahl-Vorsteller)*Vorteiler/Systemtakt =(256-6)*1/1MHz = 250us
*/
#include <avr/io.h>
int main( ) { // Hauptprogramm
PORTB = 0xff ;
DDRB = 0xff ;
TCCR0B = 1 ; // Vorteiler 1: /1; 2: /8; 3: /64; 4: /256; 5: /1024
TIMSK |= 1 << TOIE0; // TimerOverflowInterruptEnable0
sei( ) ; // globale Interruptfreigabe
while ( 1 ) ; // Endlosschleife
}
ISR( TIMER0_OVF_vect) { // Interrupt Service Routine
TCNT0 = 6 ; // wieder vorstellen
PORTB ^= 1 ; // Ausgang PB0 invertieren (PINB = 1)
}
// gemessen 268us woher stammt die Abweichung? Interrupt alle 50ms, 4 MHz Systemtakt, 8Bit-Timer0, Overflow-Interrupt
Lösung anzeigen..
Quellcode [50ms-4mhz-8bit-overflow.c ]/* Interrupt alle 50ms, 4 MHz Systemtakt, 8Bit-Timer 0, Overflow-Interrupt, Wechsel an PB0
Taktzahl: Systemtakt*Sollzeit = 4Mhz*50ms = 200.000
Vorteiler: Taktzahl/Werteanzahl = 200.000/256 = 781 aus {1,8,64,256,1024} => 1024
Vorsteller: Werteanzahl - Taktzahl/Vorteiler = 256 - 200.000/1024 => 61
Probe: (Werteanzahl-Vorsteller)*Vorteiler/Systemtakt =(256-61)*1024/4MHz = 49,9ms
*/
#include <avr/io.h>
int main( ) { // Hauptprogramm
PORTB = 0xe0 ;
DDRB = 0xff ;
TCCR0B = 5 ; // Vorteiler 1: /1; 2: /8; 3: /64; 4: /256; 5: /1024
TIMSK |= 1 << TOIE0; // TimerOverflowInterruptEnable0
sei( ) ; // globale Interruptfreigabe
while ( 1 ) ; // Endlosschleife
}
ISR( TIMER0_OVF_vect) { // Interrupt Service Routine
TCNT0 = 61 ; // wieder vorstellen
PORTB ^= 1 ; // Ausgang PB0 invertieren (PINB = 1)
} Interrupt alle 100ms, 4 MHz Systemtakt, 8Bit-Timer0, Overflow-Interrupt
Lösung anzeigen..
Quellcode [100ms-4mhz-8bit-overflow.c ]/* Interrupt alle 100ms, 4 MHz Systemtakt, 8Bit-Timer 0, Overflow-Interrupt, Wechsel an PB0
Taktzahl: Systemtakt*Sollzeit = 4Mhz*100ms = 400.000
Vorteiler: Taktzahl/Werteanzahl = 400.000/256 = 1562! aus {1,8,64,256,1024} => 1024
ISRTeilfaktor: Taktzahl/Werteanzahl/Vorteiler = 400.000/256/1024 = 1,5 Aufrunden: 2
Vorsteller: Werteanzahl - Taktzahl/Vorteiler/ISRTeilfaktor = 256 - 400.000/1024/2 = 60,7 => 61
Probe: (Werteanzahl-Vorsteller)*Vorteiler/Systemtakt*ISRTeilfaktor =(256-61)*1024/4MHz*2 = 99,8 ms
*/
#include <avr/io.h>
int main( ) { // Hauptprogramm
PORTB = 0xff ;
DDRB = 0xff ;
TCCR0B = 5 ; // Vorteiler 1: /1; 2: /8; 3: /64; 4: /256; 5: /1024
TIMSK |= 1 << TOIE0; // TimerOverflowInterruptEnable0
sei( ) ; // globale Interruptfreigabe
while ( 1 ) ; // Endlosschleife
}
ISR( TIMER0_OVF_vect) { // Interrupt Service Routine
static unsigned char teiler= 0 ;
TCNT0 = 61 ; // wieder vorstellen
teiler++;
if ( teiler>= 2 ) { // Teilfaktor in ISR
teiler= 0 ;
PORTB ^= 1 ; // Ausgang PB0 invertieren (PINB = 1)
}
}
Interrupt alle 30ms, 1 MHz Systemtakt, 8Bit-Timer0, CTC-Interrupt
Lösung anzeigen..
Quellcode [30ms-1mhz-8bit-ctc.c ]/* Interrupt alle 30ms, 1 MHz Systemtakt, 8Bit-Timer 0, CTC-Interrupt, Wechsel an PB0
Taktzahl: Systemtakt*Sollzeit = 1Mhz*30ms = 30.000
Vorteiler: Taktzahl/Werteanzahl = 30.000/256 = 117 aus {1,8,64,256,1024} => 256
OCR0A: Taktzahl/Vorteiler -1 = 30.000/256 -1 = 116,1 gewaehlt 116
Probe: (1+OCR0A)*Vorteiler/Systemtakt =(1+116)*256/1MHz = 29,95 ms
*/
#include <avr/io.h>
int main( ) { // Hauptprogramm
PORTB = 0xe0 ;
DDRB = 0xff ;
TCCR0A |= 1 << WGM01; // Timer im CTC-Mode
TCCR0B |= 4 ; // Vorteiler 1: /1; 2: /8; 3: /64; 4: /256; 5: /1024
TIMSK |= 1 << OCIE0A; // Timer/Counter0 Output Compare Match A Interrupt Enable
OCR0A = 116 ; // Wert bei dem der Timer wieder auf 0 gesetzt wird
sei( ) ; // globale Interruptfreigabe
while ( 1 ) ; // Endlosschleife
}
ISR( TIMER0_COMPA_vect) { // Interrupt Service Routine
PORTB ^= 1 ; // Ausgang PB0 invertieren (PINB = 1)
} Interrupt alle 1000ms, 1 MHz Systemtakt, 16Bit-Timer1, CTC-Interrupt
Lösung anzeigen..
Quellcode [1000ms-1mhz-16bit-ctc.c ]/* Interrupt alle 1000ms, 1 MHz Systemtakt, 16Bit-Timer 1, CTC-Interrupt, Wechsel an PB0
Taktzahl: Systemtakt*Sollzeit = 1Mhz*1000ms = 1.000.000
Vorteiler: Taktzahl/Werteanzahl = 1.000.000/65536 = 15,2 aus {1,8,64,256,1024} => 64
OCR0A: Taktzahl/Vorteiler-1 = 1.000.000/64 -1 = 15624 gewaehlt 15624
Probe: (1+OCR0A)*Vorteiler/Systemtakt =(1+15624)*64/1MHz = 1000ms = 1s
*/
#include <avr/io.h>
int main( ) { // Hauptprogramm
PORTB = 0xff ;
DDRB = 0xff ;
TCCR1B |= 1 << WGM12; // Timer im CTC-Mode
TCCR1B |= 3 ; // Vorteiler 1:/1; 2:/8; 3:/64; 4:/256; 5:/1024
TIMSK |= 1 << OCIE1A; // Timer/Counter1 Output Compare Match A Interrupt Enable
OCR1A = 15624 ; // Wert bei dem der Timer wieder auf 0 gesetzt wird
sei( ) ; // globale Interruptfreigabe
while ( 1 ) ; // Endlosschleife
}
ISR( TIMER1_COMPA_vect) { // Interrupt Service Routine
PORTB ^= 1 ; // Ausgang PB0 invertieren (PINB = 1)
}
Interrupt alle 250µs, 1 MHz Systemtakt, 8Bit-Timer0, CTC-Interrupt
Lösung anzeigen..
Quellcode [250us-1mhz-8bit-ctc.c ]/* Interrupt alle 250us, 1 MHz Systemtakt, 8Bit-Timer 0, CTC-Interrupt, Wechsel an PB0
Taktzahl: Systemtakt*Sollzeit = 1Mhz*250us = 250
Vorteiler: Taktzahl/Werteanzahl = 250/256 = 0,98 aus {1,8,64,256,1024} => 1
OCR0A: Taktzahl/Vorteiler-1 = 250/1 -1 = 249 gewaehlt 249
Probe: (1+OCR0A)*Vorteiler/Systemtakt =(1+249)*1/1MHz = 250us
*/
#include <avr/io.h>
int main( ) { // Hauptprogramm
PORTB = 0xe0 ;
DDRB = 0xff ;
TCCR0A |= 1 << WGM01; // Timer im CTC-Mode
TCCR0B |= 1 ; // Vorteiler 1: /1; 2: /8; 3: /64; 4: /256; 5: /1024
TIMSK |= 1 << OCIE0A; // Timer/Counter0 Output Compare Match A Interrupt Enable
OCR0A = 249 ; // Wert bei dem der Timer wieder auf 0 gesetzt wird
sei( ) ; // globale Interruptfreigabe
while ( 1 ) ; // Endlosschleife
}
ISR( TIMER0_COMPA_vect) { // Interrupt Service Routine
PORTB ^= 1 ; // Ausgang PB0 invertieren (PINB = 1)
}
// gemessen 250us Yeah!