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
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
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.
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.
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 | }
|
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.
Ich vermisse sei() Oder ist das hier nicht nötig, und wenn, warum nicht?
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.
Das meine ich doch auch! Ok, je nach Einstellung darf der AVR mit seinen PWM Beinchen wackeln. Aber mehr auch nicht.
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
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.