Hallo zusammen Zwar verwende ich einen Atmega 128 und will dort beim Timer0 eine Frequenz von 32.768kHz erzeugen. Dafür habe ich folgenden code geschrieben: ASSR = 0x08; // für 32.768Khz Clock einstellen TCCR0 = 0x01; // prescaler auf 1 TCNT0 = 0x00; // 0 einstellen while(1){ // hier ausgang auf einen PIN while((ASSR&0x04)); // abfragen ob schritt erhöt wurde TIFR = 0x01; // Interrupt löschen } Problem ist das mir diese Einstellungen am PIN ein 263kHz Signal ausgibt. Kann mir da jemand helfen, finde den Fehler nicht? besten dank.
Wenn der korrekte Quarz korrekt angeschlossen ist, dann kann auch die Software nicht ohne weiteres aus 32,768 kHz 263 kHz machen... Außerdem solltest Du Dich über die Funktionsweise des Timers an sich (und speziell über das von Dir abgefragte Bit TCN0UB) informieren. Ein Overflow-Interrupt tritt erst dann auf, wenn TCNT0 überläuft (also nach jeweils 256 Zyklen).
Der Quarz wird schon richtig angeschlossen sein, denn es ist ein gekauftes Board. Was müsste ich den in meinem Programm verändern das ich auf die 32,768kHz komme. Bin jetzt sicher schon 4 stunden an diesem Problem. Dashalb sehr dankbar wenn mir jemanden weiterhelfen könnte.
Tanja Hofmann wrote: > Der Quarz wird schon richtig angeschlossen sein, denn es ist ein > gekauftes Board. Und da ist tatsächlich ein 32,768 kHz-Uhrenquarz drauf, der an den Pins TOSC1 und TOSC2 angeschlossen ist? Du schreibst auch oben irgendwo, dass Du ein Signal an einem Pin ausgeben willst, aber in Deinem Codeschnipsel ist nirgends eine Zuweisung an einen Portpin zu sehen... > Was müsste ich den in meinem Programm verändern das ich auf die > 32,768kHz komme. Bin jetzt sicher schon 4 stunden an diesem Problem. Mit einem Timer kann man grundsätzlich maximal die Hälfte des Eingangstaktes ausgeben (*), weil der Timer in der Hinsicht einen Teiler durch zwei darstellt (er wird nur von Flanken einer Richtung getaktet, eine Periode des Ausgangssignals besteht aber aus zwei Flankenwechseln). Diese Maximalfrequenz kann man z.B. im CTC-Modus des Timers erreichen, indem man ins Compare-Register eine Null schreibt und das Signal hardwaremäßig an OC0 ausgibt. Außerdem hat das Bit, das Du abfragst, wie schon oben gesagt, nichts mit dem Timertakt zu tun. Literaturempfehlung: AVR-GCC-Tutorial (*) Das heißt bei 32,768 kHz Timertakt maximal 16,384 kHz.
Mhh habe ich mich da evt einwenig unklar ausgedrückt! Was ich will ist mit dem Timer0 den externen Quarz einbinden, dass heisst die 32.768kHz dort habe. Wie setzt ich nun die Register damit das richtig funktioniert? Ich weiss das ich as AS0 auf 1 setzen. Hat da niemand ein beispiel oder ein Programm? Würde mir sehr weiterhelfen.
Aus de, Datenblatt:
1 | 1. Disable the Timer/Counter0 interrupts by clearing OCIE0 and TOIE0. |
2 | 2. Select clock source by setting AS0 as appropriate. |
3 | 3. Write new values to TCNT0, OCR0, and TCCR0. |
4 | 4. To switch to asynchronous operation: Wait for TCN0UB, OCR0UB, and TCR0UB. |
5 | 5. Clear the Timer/Counter0 interrupt flags. |
6 | 6. Enable interrupts, if needed. |
Das sieht dann wohl so aus:
1 | // Register einrichten:
|
2 | TIMSK &= ~(1<<OCIE0)|(1<<TOIE0); //Wenn noetig |
3 | ASSR = (1<<AS0); |
4 | //OCR0 = 128; // Falls noetig, z.b bei CTC, PWM
|
5 | // TCNT0=42;
|
6 | TCCR0 = (1<<CS00); // Prescaler (oder z.B. Modus) setzen |
7 | //Bevor du wieder eines der Timerregister aendern kannst:
|
8 | while(ASSR & ((1<<TCN0UB)|(1<<OCR0UB)|(1<<TCR0UB)) ) |
9 | {
|
10 | // Abwarten, bis die Busy-Bits geloescht sind
|
11 | // Das kann DAUERN!
|
12 | }
|
13 | TIFR = (1<<OCF0)|(1<<TOV0); |
14 | TIMSK |= (1<<OCIE0)|(1<<TOIE0); //Wenn noetig |
rtfm, Jörg
Da hab ich 'nen Satz Klammern vergessen, nicht:
>> TIMSK &= ~(1<<OCIE0)|(1<<TOIE0);
sondern natürlich
TIMSK &= ~((1<<OCIE0)|(1<<TOIE0));
(oder
TIMSK &= ~(1<<OCIE0)& ~(1<<TOIE0);
Gruß an Herrn Boole ;) )
hth. Jörg
Mhhh .... Kann es langsam nicht mehr haben! Der Timer macht mir so immer noch nicht die gewünschten 32.768 kHz! Habe das Programm genau so auf mein Atmega128 heruntergeladen und es funktioniert nicht so .... und der 32.768 kHz Quarz ist auch verdunden mit dem Atmega128. Ist evt im programm noch was falsch??? Bin froh um jeden tipp. //Initalisierung // Register einrichten: TIMSK &= ~((1<<OCIE0)|(1<<TOIE0)); ASSR = (1<<AS0); //OCR0 = 128; // Falls noetig, z.b bei CTC, PWM // TCNT0=42; TCCR0 = (1<<CS00); // Prescaler (oder z.B. Modus) setzen //Bevor du wieder eines der Timerregister aendern kannst: while(1){ while(ASSR & ((1<<TCN0UB)|(1<<OCR0UB)|(1<<TCR0UB)) ) { // Abwarten, bis die Busy-Bits geloescht sind // Das kann DAUERN! } TIFR = (1<<OCF0)|(1<<TOV0); TIMSK |= (1<<OCIE0)|(1<<TOIE0); //Wenn noetig toggleLED() // methode wo nur LED Togglet !!!! }
> Der Timer macht mir so immer noch nicht die gewünschten 32.768 kHz!
Woran siehst du das??
Und warum postest du meinen Code-Ausschnitt, und nicht dein
vollständiges (Test-) Programm?
(Die höchste Frequenz, die der asynchrone Timer ausgeben kann, sind
16384Hz (CTC-Mode, OCR0=0, "toggle on compare"), wurde aber oben schon
geschrieben)
hth. Jörg
So wie ich ihn das implementiert habe. Habe ja noch while schlaufen eigefürgt. Meine wenn ich ein PWM daraus mache erhalte ich ja die 32.768kHz nicht ????
Tanja Hofmann wrote: > So wie ich ihn das implementiert habe. Habe ja noch while schlaufen > eigefürgt. Meine wenn ich ein PWM daraus mache erhalte ich ja die > 32.768kHz nicht ???? Kein Timer vom AVR liefert am OC Ausgang mehr als die Hälfte seines eigenen Taktes ab. Egal in welchem Modus. Ausser vielleicht wenn du den Glitch bei OCR=0 meinst.
'Tschuldigung, hast, ja doch was am Code geändert (aber scheinbar nicht ganz verstanden, wie der Timer funktioniert) Ich meine sowas:
1 | include <stdint.h> |
2 | #include <avr/io.h> |
3 | |
4 | #define OC0_F 263 //Hertz
|
5 | #define F_TOSC 32768
|
6 | #define T0_PRE 1
|
7 | |
8 | #define OC0_VAL(_foc) (F_TOSC/(_foc * 2 * T0_PRE) -1)
|
9 | |
10 | int main(void) |
11 | {
|
12 | DDRB = (1<<PB4); // OC0 output |
13 | ASSR = (1<<AS0); |
14 | OCR0 = OC0_VAL(OC0_F); //preload for CTC |
15 | TCCR0 = (1<<WGM01)|(1<<COM00)|(1<<CS00); // Prescaler:1, CTC, toggle on compare |
16 | /* wait for timer-tick IF necessary (i.e. you want to change TCCR0/OCR0/TCNT0):
|
17 | while(ASSR & ((1<<TCN0UB)|(1<<OCR0UB)|(1<<TCR0UB)) )
|
18 | ;
|
19 | */
|
20 | //sei();
|
21 | while(1) |
22 | {
|
23 | // mainloop
|
24 | }
|
25 | return 0; |
26 | }
|
Da togglet PB4 (OC0) 'von allein', wenn ein anderer Pin togglen soll, ist die Compare ISR der beste Ort dafür (Anhang) hth. Jörg
Wenn du mit OC0 ein 32,7kHz Rechteck ausgeben willst (geht nur, wenn der Timer0 synchron getaktet wird):
1 | #define F_OC0 32768
|
2 | #define OC0_VAL (F_CPU/(F_OC0 * 2 ) -1)
|
3 | //...
|
4 | DDRB = (1<<PB4); |
5 | |
6 | OCR0 = OC0_VAL; //preload for CTC |
7 | TCCR0 = (1<<WGM01)|(1<<COM00)|(1<<CS00); // Prescaler:1, CTC, toggle on compare |
hth. Jörg ps.: ob das 32,768kHz oder 32,0 oder 33,5 kHz sind hängt dann aber vom AVR-Takt ab
Besten dank Jörg für deine Hilfeleistungen. Sozusagen kann ich einem externen 32.768kHz nicht als 32.768 kHz Puls weiterleiten. Muss sozusagen über den Systemclock gehen und diesen so richtig runterteilen? Das heisst muss folgende Einstellungen vornehmen um meinen 7,3728 Mhz auf 32.768 khz einzustellen: - TCCR0 = (1<<WGM01)|(1<<COM00)|(1<<CS00); - OCR0 = 0x70; // (7372800/((32768 *2 )-1) Habe ich das so richtig verstanden?
> Sozusagen kann ich einem externen 32.768kHz nicht als 32.768 kHz Puls weiterleiten. Exakt, das hat johnny-m aber schon in seiner zweiten Antwort geschrieben > Muss sozusagen über den Systemclock gehen und diesen so richtig runterteilen Auch richtig. Aber hier brauchst du nur meinen Code kopieren *!* Der Compiler kann die Formeln nämlich alle selbst ausrechnen und das Macro "F_CPU" ist beim AVR-GCC sowieso definiert. hth. Jörg
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.