mikrocontroller.net

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


Autor: Tanja Hofmann (hoefme)
Datum:

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

Autor: Johannes M. (johnny-m)
Datum:

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

Autor: Tanja Hofmann (hoefme)
Datum:

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

Autor: Johannes M. (johnny-m)
Datum:

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

Autor: Tanja Hofmann (hoefme)
Datum:

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

Autor: Udo (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Welche Frequenz hat denn dein "externer Quarz"?

Autor: Jörg X. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Aus de, Datenblatt:
1. Disable the Timer/Counter0 interrupts by clearing OCIE0 and TOIE0.
2. Select clock source by setting AS0 as appropriate.
3. Write new values to TCNT0, OCR0, and TCCR0.
4. To switch to asynchronous operation: Wait for TCN0UB, OCR0UB, and TCR0UB.
5. Clear the Timer/Counter0 interrupt flags.
6. Enable interrupts, if needed.
Das sieht dann wohl so aus:
  // Register einrichten:
  TIMSK &= ~(1<<OCIE0)|(1<<TOIE0); //Wenn noetig
  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(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

rtfm, Jörg

Autor: Jörg X. (Gast)
Datum:

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

Autor: Tanja Hofmann (hoefme)
Datum:

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

Autor: Jörg X. (Gast)
Datum:

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

Autor: Tanja Hofmann (hoefme)
Datum:

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

Autor: Andreas K. (a-k)
Datum:

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

Autor: Jörg X. (Gast)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
'Tschuldigung, hast, ja doch was am Code geändert (aber scheinbar nicht 
ganz verstanden, wie der Timer funktioniert)
Ich meine sowas:
include <stdint.h>
#include <avr/io.h>

#define OC0_F 263 //Hertz
#define F_TOSC 32768
#define T0_PRE 1

#define OC0_VAL(_foc) (F_TOSC/(_foc * 2 * T0_PRE) -1)

int main(void)
{
  DDRB = (1<<PB4); // OC0 output
  ASSR = (1<<AS0);
  OCR0 = OC0_VAL(OC0_F); //preload for CTC
  TCCR0 = (1<<WGM01)|(1<<COM00)|(1<<CS00); // Prescaler:1, CTC, toggle on compare
/*  wait for timer-tick IF necessary (i.e. you want to change TCCR0/OCR0/TCNT0):
  while(ASSR & ((1<<TCN0UB)|(1<<OCR0UB)|(1<<TCR0UB)) )
    ;
*/
  //sei();
  while(1)
  {
  //  mainloop
  }
  return 0;
}
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

Autor: Jörg X. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Wenn du mit OC0 ein 32,7kHz Rechteck ausgeben willst (geht nur, wenn der 
Timer0 synchron getaktet wird):
#define F_OC0 32768
#define OC0_VAL (F_CPU/(F_OC0 * 2 ) -1)
//...
  DDRB = (1<<PB4);
  
  OCR0 = OC0_VAL; //preload for CTC
  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

Autor: Tanja Hofmann (hoefme)
Datum:

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

Autor: Jörg X. (Gast)
Datum:

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

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]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [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.