Forum: Mikrocontroller und Digitale Elektronik OC1A steuern im CTC Mode


von Ganymed (Gast)


Lesenswert?

Hallo zusammen

Ich habe Probleme mit dem CTC-Mode im ATmega16.

In einer Interruptroutine soll der Ausgang OC1A des Timer 1
gesetzt werden. Dann soll der Timer 1 von 0 an hochzählen
und bei Gleichheit mit dem OCR1A Register den Ausgang
OC1A wieder zurücksetzten.

Hier die entsprechenden Teile meiner Lösung, die aber nicht
funktioniert. Was muss ich anders machen?
1
//Initialisierung von Timer 1
2
 TCCR1A = (1<<COM1A1); //OC1A bei Gleichheit löschen
3
 TCCR1B = (1<<WGM12)|(1<<CS12); //CTC-Mode , Vorteiler 256
4
 SETBIT(TIMSK,OCIE1A);  //Interruptfreigabe nötig?
5
6
7
//Die Startende Interruptroutine
8
 ISR(TIMER0_OVF_vect)
9
{
10
.
11
 SETBIT(TCCR1A,FOC1A); //OC1A sollte auf 1 gehn
12
 TCNT1 = 0; //Timer zurücksetzten
13
}
14
15
ISR(TIMER1_COMPA_vect)
16
{  
17
nop; //eigentlich nichts zu tun
18
 
19
}

von Daniel R. (zerrome)


Lesenswert?

Also erstmal fehlt da ein sei()

von Ganymed (Gast)


Lesenswert?

Ja, ist klar!
Ich hab auch nur die
wirklich relevanten Teile
des Programms geschrieben.

von spess53 (Gast)


Lesenswert?

Hi

>TCCR1A = (1<<COM1A1); //OC1A bei Gleichheit löschen

TCCR1A = (1<<COM1A0); //OC1A bei Gleichheit Toggeln

Bei jedem Erreichen von OCR toggelt das Pin, und der Timer wird 
zurückgesetzt.

Den Rest kannst du dir sparen.

MfG Spess

von Daniel R. (zerrome)


Lesenswert?

CTC -> clear timer on compare match...

Zählt hoch bis compare match, fängt dann wieder bei 0 an.
Wenn dann OC1A auf toggeln gestellt ist gehts doch.

Was geht denn genau nicht bei dir?

von Ganymed (Gast)


Lesenswert?

>TCCR1A = (1<<COM1A0); //OC1A bei Gleichheit Toggeln

Er soll aber nicht Toggeln.
OC1A soll durch die ISR von T0
alle 20ms gesetzt werden und dann
je nach Wert in OCR1A nach einer
bestimmten Zeit 0,1...1,5ms
wieder aus gehen und aus bleiben.
T1 lass ich einfach weiterzählen.

von Ganymed (Gast)


Lesenswert?

>Was geht denn genau nicht bei dir?

OC1A geht gar nicht an.

von Daniel R. (zerrome)


Lesenswert?

Du hast den Port aber auch als Ausgang definiert? DDRB = (1 << DDB1); 
oder so ähnlich

von Daniel R. (zerrome)


Lesenswert?

Glaube mich daran zu erinnern, dass OCR1A nicht doppelt gepuffert ist im 
non PWP modus?!? Vielleicht verpasst du da ein compare oder so..

von Ganymed (Gast)


Lesenswert?

>Du hast den Port aber auch als Ausgang definiert?
Ja, und zwar mit diesen Befehlen:

[c]
 SETBIT(DDRD,DDD5); //OC1A Pin zum Ausgang machen
 SETBIT(PORTD,PORTD5);
[/]

von Tobi (Gast)


Lesenswert?

Wo wird OCR1A gesetzt?

von Ganymed (Gast)


Lesenswert?

Noch Mal aber richtig

>Du hast den Port aber auch als Ausgang definiert?
Ja, und zwar mit diesen Befehlen:
1
 SETBIT(DDRD,DDD5); //OC1A Pin zum Ausgang machen
2
 SETBIT(PORTD,PORTD5);

Man sieht, der Ausgang wird auch gesetzt.
Er geht auch kurz an. Aber sobald
COM1A1 gesetzt ist übernimmt der Timer 1

von Daniel R. (zerrome)


Lesenswert?

Ich kenne die SETBIT Funktion/Makro nicht aber die funktionier?
Geht der Pin denn ohne den Timer auf 5V, ich hatte schonmal nen defekten 
Pin...

Hm ok. Dann hab ich auch kein Plan mehr ^^

von Tobi (Gast)


Lesenswert?

Ausserdem: IM CTC Modus zählt der Timer bis zu OCR1A und setzt sich 
selber zurück. Wenn der OC1A pin aktiv ist, kann man den Pin nicht mehr 
über PORT-Zugriffe steuern, d.h. der Pin wird vom Timer gesteuert. Wenn 
Du ihn einmal setzten willst, wird der Pin gesetzt und bleibt dann high, 
egal was du sonst noch machst. Ausser du initaialisiert den Timer samt 
Pin neu.

von Tobi (Gast)


Lesenswert?

TCCR1A = (1<<COM1A1); //OC1A bei Gleichheit löschen


Diese Zeile macht dir das

von Ganymed (Gast)


Lesenswert?

Erst mal Danke für die Tipps.
Hier noch mein ganzes Testprogramm.
In Abhängigkeit von einer Taste
sollte OC1A im Rhythmus von 2Sek
eine halbe oder eine Sek an sein.
1
#include <avr/io.h>
2
#include <avr/interrupt.h>
3
#define F_CPU 8000000UL //Taktfequenz in Hz. Wichtig für alle 
4
                        //zeitabhängigen Funktionen und ISRs
5
#include <util/delay.h>
6
7
#define nop asm volatile ("nop")  //nop für ganz kurze Pausen
8
9
//Makros für die Bitverarbeitung
10
#define SETBIT(adr, bit) (adr |=  (1<<bit))
11
#define CLEARBIT(adr, bit) (adr &= ~(1<<bit))
12
#define TOOGELBIT(adr, bit) (adr ^=  (1<<bit))
13
#define CHECKBIT(adr, bit) (adr  &  (1<<bit))
14
15
16
//Anschlussklemmen der beiden LED und der Glühlampe
17
#define led_r PORTC5    //LED rechts
18
#define led_l PORTD7    //LED links und Glühlampe
19
#define port_r PORTC
20
#define port_l PORTD
21
22
23
int main(void)
24
{
25
 SETBIT(DDRC,led_r);   //LED Pins zu Ausgängen machen
26
 SETBIT(DDRD,led_l);
27
 CLEARBIT(port_r,led_r);//LED ausschalten
28
 CLEARBIT(port_l,led_l);
29
30
 SETBIT(DDRD,DDD5); //OC1A Pin zum Ausgang machen
31
 SETBIT(PORTD,PORTD5);//bleibt eine halbe Sek an
32
33
 _delay_ms(500);      //0,5s Pause
34
35
 //Timer 0 einrichten.
36
 //ISR wird jede ms aufgerufen
37
 TCCR0 = 1; //Prescaler auf 0
38
 SETBIT(TIMSK, TOIE0);
39
 TCNT0 = 0;
40
41
 //Timer 1 vorbereiten CTC-Mode mit OCR1A Register. Bei
42
 //Gleichheit von Zähler und OCR1A wird der Pin OC1A gelöscht
43
44
 TCCR1A = (1<<COM1A1);
45
 TCCR1B = (1<<WGM12)|(1<<CS12);
46
 SETBIT(TIMSK,OCIE1A);
47
48
 sei();
49
50
 while(1)
51
 { 
52
53
//Eine Taste wird abgefragt und OCR1A belegt.
54
//eigentlich müsste OCR1 eine ein halbe
55
//oder eine Sekund an sein.
56
  if(CHECKBIT(PIND,PIND2)) OCR1A = 15625;
57
  else OCR1A = 31250;
58
 }
59
} //Ende main
60
61
62
//##### T0 Überlauf ISR  ##################
63
ISR(TIMER0_OVF_vect)
64
{
65
 static unsigned int n = 62500;
66
 
67
 if(n--) return; 
68
69
 n = 62500; 
70
 
71
 SETBIT(TCCR1A,FOC1A);
72
 TCNT1 = 0;
73
74
 TOOGELBIT(port_r,led_r);  //OC1A Pin umschaltenschalten
75
                           //2 Sek. an, 2 Sek. aus
76
                           //Die LED blinkt richtig
77
}
78
79
//##### T1 Compare Match ISR  ##################
80
ISR(TIMER1_COMPA_vect)
81
{  
82
nop;
83
}

von Daniel R. (zerrome)


Lesenswert?

Äh,
1
ISR(TIMER0_OVF_vect)
2
{
3
 static unsigned int n = 62500;
4
 
5
 if(n--) return; 
6
7
 n = 62500;
irre ich mich oder wird da jetzt bei jedem Aufruf der ISR n immer neu 
mit 62500 initialisiert, dann einen runter gezählt und auf 0 geprüft, 
nur um dann wieder auf 62500 gesetzt zu werden?

/Edit

nein ich irre mich :)

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.