Forum: Mikrocontroller und Digitale Elektronik Atmega128, Timer0 einstellen auf 32.768kHz


von Tanja H. (hoefme)


Lesenswert?

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.

von Johannes M. (johnny-m)


Lesenswert?

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).

von Tanja H. (hoefme)


Lesenswert?

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.

von Johannes M. (johnny-m)


Lesenswert?

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.

von Tanja H. (hoefme)


Lesenswert?

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.

von Udo (Gast)


Lesenswert?

Welche Frequenz hat denn dein "externer Quarz"?

von Jörg X. (Gast)


Lesenswert?

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

von Jörg X. (Gast)


Lesenswert?

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

von Tanja H. (hoefme)


Lesenswert?

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 !!!!
       }

von Jörg X. (Gast)


Lesenswert?

> 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

von Tanja H. (hoefme)


Lesenswert?

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 ????

von Andreas K. (a-k)


Lesenswert?

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.

von Jörg X. (Gast)


Angehängte Dateien:

Lesenswert?

'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

von Jörg X. (Gast)


Lesenswert?

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

von Tanja H. (hoefme)


Lesenswert?

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?

von Jörg X. (Gast)


Lesenswert?

> 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
Noch kein Account? Hier anmelden.