Forum: Mikrocontroller und Digitale Elektronik Timer0, Timer1 Vorteiler


Announcement: there is an English version of this forum on EmbDev.net. Posts you create there will be displayed on Mikrocontroller.net and EmbDev.net.
von Phil S. (kleineraffe)


Bewertung
0 lesenswert
nicht 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)


Bewertung
0 lesenswert
nicht 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)


Bewertung
2 lesenswert
nicht 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)


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

von H.Joachim S. (crazyhorse)


Bewertung
1 lesenswert
nicht 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)


Bewertung
0 lesenswert
nicht 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)


Bewertung
0 lesenswert
nicht 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 Arduino Fanboy D. (ufuf)


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

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


Bewertung
0 lesenswert
nicht 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 Arduino Fanboy D. (ufuf)


Bewertung
0 lesenswert
nicht 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)


Bewertung
0 lesenswert
nicht 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 Arduino Fanboy D. (ufuf)


Bewertung
1 lesenswert
nicht lesenswert
Ach so...
Du zeigst Fantasiecode...

Naja, dann gebe ich hier auf.

von Phil S. (kleineraffe)


Bewertung
-1 lesenswert
nicht 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.

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.