Forum: Mikrocontroller und Digitale Elektronik Timer0, Timer1 Vorteiler


von Phil S. (kleineraffe)


Lesenswert?

Hallo Zusammen

Ich bin etwas verwirrt über den Vorteiler vom Timer0 und Timer1 bei 
einem Atmega8. Gemäss Datenblatt wird dieser ja von beiden Timern 
geteilt. Stelle ich den Vorteiler von Timer1 ein, verstellt es mir 
allerdings auch den Takt von Timer0.
Ich verwende den internen 1MHz Takt.
Vom Code ist es folgendermassen:
Timer0 init:
TCCR0 = (1 << CS02); //clkIO wird durch 256 geteilt
TIMSK |= (1 << TOIE0);  //Aktiviert Interrupt beim Überlauf

In der ISR von Timer0 lade ich den Timer vor mit:
TCNT0 = 236;
So erhalte ich in etwa alle 5ms einen Interrupt, welchen ich dazu nutze 
verschiedene regelmässige Abfragen zu machen. Soweit läuft alles 
einwandfrei.
Timer1 init: (Timer1 möchte ich als PWM verwenden)
TCCR1B |= (1 << CS10);  //Vorteiler =1 Timertakt gleich clkIO Takt
Sobald ich hier den Vorteiler einstelle, ändert mir der Timer0, dass er 
anstatt alle 5ms alle 6.7ms ausgelöst wird.

Weiss jemand von euch an was das liegen könnte? Nur weil Timer0 und 
Timer1 den Vorteiler teilen, sollte es doch möglich sein, 
unterschiedliche Teiler zu verwenden.

Besten Dank schon mal für allfällige Tips.
Gruss Phil

von Carl D. (jcw2)


Lesenswert?

Welcher Vorgang im Vorteiler sollte das Verhältnis 5 / 6,7 bewirken?
Der teilt nur in (nicht lückenlosen) ganzzahligen 2er-Potenzen.

25% Änderung des internen Takts bekommt man weder mit Temperatur noch 
mit Spannungsänderung zustande, allerdings per OSCCAL-Register.

Wie wurden die Zeiten gemessen?

: Bearbeitet durch User
von Matthias S. (Firma: matzetronics) (mschoeldgen)


Lesenswert?

Klingt mir jedenfalls so, als würdest du da einen Interrupt auslösen, 
der den Mega aus Versehen resettet - sprich, ein Interrupt ohne Service 
Routine.
Zeig doch mal das Programm.

von Stefan E. (sternst)


Lesenswert?

Oder zum zweiten Timer gehört eine ISR mit übermäßig langer Laufzeit.

von H.Joachim S. (crazyhorse)


Lesenswert?

Man stellt ja nicht wirklichen einen Teiler ein, sondern legt nur fest, 
welcher Abgriff des eh vorhandenen Teilers (der tatsächlich für alle 
Timer der gleiche ist)  als Eingangstakt benutzt wird. Eine scheinbar 
gegenseitige Beeinflussung ist ein Softwarefehler.

von Phil S. (kleineraffe)


Lesenswert?

Hier mal noch den Code.
@Stefan E.: Nein Timer1 hat keine ISR nur der über OCR1A/B verstellt 
wird.
@ H.Joachim S.: Das sehe ich genau so.
@ Matthias S.: Könntest du das etwas genauer erklären, wie es zu soetwas 
kommen kann? Ich messe am Pin PB0 nähmlich ein Rechteck, obwohl dieser 
ja konstant auf high sein sollte.

Hier wie gewünscht noch den Code
1
ISR(TIMER0_OVF_vect)
2
{
3
  /*Achtung ! Durch verzögerter Aufruf dieser ISR kann das Vorladen des Timers zu Jetter führen.
4
   *  Ist nicht geeignet für Anwendungen bei der ein exaktes Mittel von 5ms erreicht werden soll. 
5
   *  Theoretischer Wert = 184 da: 3686400 /256 / 200 = 72 => 256-72 = 184
6
   *                                Quarz / Vorteiler / gewünschte Frequenz = Muss noch alle 72 Takte ausgelöst werden.
7
   *  -> Messtechnisch wurde 184 überprüft, was genau 200Hz ergibt -> 5ms Interrupt (gilt nur solange keine anderen ISR, der Aufruf dieser ISR verzögern)
8
   */
9
  TCNT0 = 256- (F_CPU / 256 / 200); // Counter vorlader
10
  PORTB ^=(1<<PB3);
11
}
12
13
14
15
16
int main(void)
17
{  
18
//Pin PB0 wird eingeschaltet um einen Reset zu sehen
19
DDRB |= ((1<<PB0) | (1<<PB3));
20
PORTB |= (1<<PB0);
21
22
//Timer0
23
  TCCR0 = (1<<CS02);
24
  TIMSK |= (1 << TOIE0);
25
26
  _delay_ms(500); //Damit man auf KO den Takt von Timer0 sieht
27
28
//PWM Outputs
29
  DDRB |= (1<<PB1);
30
  DDRB |= (1<<PB2);
31
  PORTB &= ~((1 << PB1) | (1 << PB2)); //Beide Outputs auf low stellen
32
//Timer1 
33
  TIMSK |= ((1 << OCIE1A) |(1 << OCIE1B)); //Interrupts Enable von Compare A und B
34
  TCCR1A |= ((1 << COM1A1) |(1 << COM1A0) | (1 << COM1B1)| (1 << COM1B0)); //Output wird gesetzt beim Hochzählen, gelöscht beim Herunterzählen
35
  TCCR1A &= ~((1 << FOC1A) | (1 << FOC1B)); // Aus Kompatibilitätsgründen auf 0 gesetzt.
36
  TCCR1B |= (1 << WGM13); //WGM13 = 1, WGM12= 0, WGM11= 0, WGM10= 0 entspricht dem Modus 8 Phasen und Freuquenz korrekter PWM
37
  SFIOR &= ~(1<<PSR10);
38
  TCCR1B |= (1 << CS10); // CS12, CS11 und CS10 bestimmen den Vorteiler für Takt von Timer1 -> 0 = Timer gestoppt, 1 = kein Vorteiler
39
//Nachdem TCCR1B mit CS10 gesetzt wurde stimmt Timer0 nicht mehr
40
41
  OCR1A = 0x8000; // CompareWert für Kanal A
42
  OCR1B = 0x8000; // CompareWert für Kanal B
43
  ICR1 = 0xFFFF; // Legt den TOP Wert des Zählers fest (16bit)
44
45
  while(1) { }
46
  return 0;
47
48
}

von Jim M. (turboj)


Lesenswert?

Der Compare Interrupt Vector heisst nicht TIMER0_OVF_vect, damit 
resettet Dein Programm regelmäßig.

Das erklärt auch das Rechteck auf PB0.


Schau Dir mal in der Doku an wie die ganzen Timer interrupts heissen und 
wann sie aktiv werden.

von Einer K. (Gast)


Lesenswert?

Ich vermisse sei()
Oder ist das hier nicht nötig, und wenn, warum nicht?

von Matthias S. (Firma: matzetronics) (mschoeldgen)


Lesenswert?

Arduino Fanboy D. schrieb:
> Oder ist das hier nicht nötig, und wenn, warum nicht?

Gute Frage. Das Programm hat zwar mindestens zwei IRQs, die ins Leere 
zeigen
1
TIMSK |= ((1 << OCIE1A) |(1 << OCIE1B)); //Interrupts Enable von Compare A und B
aber eigentlich sollte ohne sei() gar nichts passieren.

von Einer K. (Gast)


Lesenswert?

Das meine ich doch auch!
Ok, je nach Einstellung darf der AVR mit seinen PWM Beinchen wackeln.
Aber mehr auch nicht.

von Phil S. (kleineraffe)


Lesenswert?

Mmm, ja da habt ihr natürlich recht. Das sei()ist vorhanden, habs nur in 
eine inlinefunktion im header und diesen beim kopieren nicht 
mitgenommen, damit alles im main ist. sei() wird also schon aufgerufen

Gruss Phil

von Einer K. (Gast)


Lesenswert?

Ach so...
Du zeigst Fantasiecode...

Naja, dann gebe ich hier auf.

von Phil S. (kleineraffe)


Lesenswert?

Problem gelöst:
- Das sei() brauchts natürlich, damit überhaupt eine ISR läuft, das war 
mir jedoch klar.
- Das Problem war (wie Matthias S. schon sehr früh vermutete), dass die 
ISR für den Timer1 nicht vorhanden waren.
1
TIMSK |= ((1 << OCIE1A) |(1 << OCIE1B)); //Interrupts Enable von Compare A und B

Ich dachte, dass man diese aktivieren muss, damit sich die Outputs bei 
einem Match umschalten. Dem ist nicht so, wie ich nun herausgefunden 
habe.

Danke euch viel mals für den Tip und die Unterstützung.
Gruss Phil

Beitrag #5580229 wurde vom Autor gelöscht.
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.