Alsooo ich bin zur Zeit dabei mir die AVR Programmierung in C bei zu
bringen und bin bei dem Thema Timer/Counter am verzweifeln.
Das Ziel:
Wie so oft Standartmäßig, auch in vielen Tutorials zu sehen, eine LED im
Sekundentakt toggeln zu lassen an einem ATmega328P-PU unter verwendung
des Timer0 im CTC-Mode.
Herangehensweise:
-Schritt1: Hardwaretest:
Atmega328 in Minimalbeschaltung auf Breadboard aufgebaut, LED an PIN PD0
mit passendem Vorwiderstand angehängt. Minimalbeschaltung, d.h.
Verwendung des internen RC bei 8MHz ohne vorteiler.Erstmal mit delay die
LED zum Blinken gebracht um den Breadboardaufbau auf seine Richtigkeit
überprüfen - passt.
-Schritt2: Vorüberlegung Timer0 einstellungen:
Wenn ich das Richtig verstanden habe, würde, ohne Prescale, der Timer
bei einem Takt von 8MHz 8 Millionen mal pro Sekunde erhöht werden.
Deshalb entschloss ich mich für einen Prescale von 64 -> Damit würde er
nur noch 125000 mal die Sekunde oder 125 mal die Millisekunde erhöht
werden. D.h. nach 1 ms wäre er bei 124 (von Null an gezählt). Wenn ich
also in das Register in OCR0A einen Wert 124 als Match übergebe, habe
ich jede Millisekunde einen Interrupt? Diese Interrupts kann ich zählen,
nach 1000 gezählten Interrupts habe ich meine sekunde Voll und kann die
LED Toggeln und den Zähler zurücksetzten.
-Schritt 3: Register einstellungen (gesamter Code folgt am Ende):
Zu erst im Register TCCR0A WGM01 setzten um dem Controller mitzuteilen,
dass ich gerne Timer0 im CTC Mode-hätte und den CTC-Match auf 124
setzten.
1 | TCCR0A |= (1 << WGM01);
|
2 | OCR0A = 0x7C;
|
Dann im Timer/Counter Interrupt Mask Register den compare match A
interrupt erlauben und alle Interrupts aktivieren.
1 | TIMSK0 |= (1 << OCIE0A);
|
2 | sei();
|
Den Prescale einstelen auf 64:
1 | TCCR0B |= (1 << CS01) | (1 << CS00);
|
Abschließend in der ISR das LED toggeln nach 1000 gezählten Interrupts
einfügen
1 | ISR(TIMER0_COMPA_vect)
|
2 | {
|
3 | InterruptCounter++;
|
4 | if (InterruptCounter >= 1000) //8MHz mit 64 Prescale, Interrupt Wert 124 -> ca. alle 1ms ein Interrupt.
|
5 | {
|
6 | InterruptCounter=0;
|
7 | PORTD ^= (1<<PD0);
|
8 | }
|
9 | }
|
-Gesamter Code:
1 | #include <avr/io.h>
|
2 | #include <avr/interrupt.h>
|
3 |
|
4 | volatile uint8_t InterruptCounter = 0;
|
5 |
|
6 | int main(void)
|
7 | {
|
8 | DDRD |= (1<<PD0); //LED an PD0
|
9 | PORTD |= (1<<PD0); //Port auf HIGH initialisieren.
|
10 |
|
11 | TCCR0A |= (1 << WGM01);//Timer im CTC Mode.
|
12 | OCR0A = 0x7C; //CTC Match bei 124.
|
13 |
|
14 | TIMSK0 |= (1 << OCIE0A); //ISR auf COMPA vect setzten.
|
15 | sei(); //Interrupts aktivieren.
|
16 |
|
17 | TCCR0B |= (1 << CS01) | (1 << CS00); //Prescale mit 64.
|
18 |
|
19 |
|
20 | while (1)
|
21 | {
|
22 | //NetflixAndChill
|
23 | }
|
24 | }
|
25 | ISR(TIMER0_COMPA_vect)
|
26 | {
|
27 | InterruptCounter++;
|
28 | if (InterruptCounter >= 1000) //8MHz mit 64 Prescale, Interrupt Wert 124 -> ca. alle 1ms ein Interrupt.
|
29 | {
|
30 | InterruptCounter=0;
|
31 | PORTD ^= (1<<PD0);
|
32 | }
|
33 | }
|
->Beobachtung: LED blinkt nicht, sonder leuchtet const. Warum?