mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik Timer Interrupt, möglichst nahe an die 32khz bringen mit 8MHz Quarz


Autor: Draco (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hiho,

ich möchte an einen Pin ein möglichst nahes 32khz Signal mit einem 
Amtega erzeugen. Der Atmega läuft mit einem 8 Mhz Quarzoszillator.

Wie fange ich am dümmsten die Rechnerrei an?!


8.000.000 Hz / 256 Int = 31.250 Hz

Das wäre ja bei einem 8Bit Int. jeder Interrupt oder sehe ich das 
falsch?!

Autor: spess53 (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hi

Nimm CTC. Vorteiler 1, OCR-Wert $7C = 32kHz.

MfG Spess

Autor: Draco (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Nachfrage:

Wenn ich nun natürlich jeden Interrupt den Pin von 0 auf 1 wechsel... 
dann habe ich ja qausi einen Takt von ~15khz. Oder zählt jeder Wechsel 
als Takt?! Also 0 zu 1 oder 1 zu 1?!

Kann ich den Intervall in welchem der Interrupt auslößt, beim 8Bit Timer 
ja 256, noch kürzen?!

Autor: spess53 (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hi

>Kann ich den Intervall in welchem der Interrupt auslößt, beim 8Bit Timer
>ja 256, noch kürzen?!

Ja. Siehe CTC-Mode.

MfG Spess

Autor: Oliver S. (zwen)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
8 bit Timer heist das Register des Timers is genau 8bit breit also zählt 
der Timer von 0 bis 256 danach gibt es einen Interrupt wenn du den Timer 
mit dem Systemtakt mitzählen lässt kommst du auf deine 31,5Khz. Es gibt 
aber auch die Möglichkeit z.B. nur jeden 8. oder 64. Systemtakt zu 
zählen. Was aber für dich interessant ist, ist das Timerregister mit 
(256-250)=6 zuladen jetzt zählt der Timer nur noch bis 250 macht genau 
32Khz. Das entsprechende Register heist  zum Beispiel beim Atmega8 TCNT0 
du musst nur noch dafür sorgen das es bei jedem Interrupt mit TCNT0=6 
geladen wird.

Autor: spess53 (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hi

>Was aber für dich interessant ist, ist das Timerregister mit
>(256-250)=6 zuladen jetzt zählt der Timer nur noch bis 250 macht genau
>32Khz.

Klar. Von hinten durch die Brust ins Auge.

MfG Spess

Autor: Nn Nn (jaytharevo)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Wenn schon denn schon, sind es 255 anstatt von 256, das wären neun bit.

Autor: spess53 (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hi

>Wenn schon denn schon, sind es 255 anstatt von 256, das wären neun bit.

Außerdem kommt noch hinzu, das eine Frequenz von 16kHz dabei 
herauskommt.

MfG Spess

Autor: Draco (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
So habe es nun so geregelt... Messen kann man es bestimmt nur mit einem 
Oszi oder?!
...
    SREG_I_bit = 1;                                    //Timer 1 Einschalten
    OCR0       = 0x7C;
    TCCR0      = 1;
    TOIE0_bit  = 1;
...

Autor: spess53 (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hi

>So habe es nun so geregelt... Messen kann man es bestimmt nur mit einem
>Oszi oder?!

Könntest du auch mal Controller und Programmiersprache bekanntgeben.

MfG Spess

Autor: Draco (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Aso... Selbstverständlich :D

µC ist ein Atmega16 auf einem EasyAVR6 mit MicroC programmiert.

Autor: spess53 (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hi

>...
>    SREG_I_bit = 1;                                    //Timer 1 Einschalten
>    OCR0       = 0x7C;
>    TCCR0      = 1;
>    TOIE0_bit  = 1;
>...

Und was soll das jetzt genau werden?

MfG Spess

Autor: Draco (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Bei MicroC ist das so:
    SREG_I_bit = 1;         //Interrupt einschalten
    OCR0       = 0x7C;      //Den CTC auf 124 stellen
    TCCR0      = 1;         //Prescaler auf 1 (2 == 4)(3 == 8) (4 == 64) etc.
    TOIE0_bit  = 1;         //TimerOverflow 0 einschalten

Im groben und ganzen wird das ein Programm welches einen MS5534C Sensor 
(Barometer) abfragt. Diesen ~32khz Takt benötigt der Sensor für seine 
Umrechnung. Der Rest wird über ein 3-Wire Serial gemacht (SCL,DIN,DOUT).

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Und wo genau schaltest du da jetzt den Timer auf CTC?
Und wozu brauchst du den Overflow Interrupt?

Autor: Draco (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hmm.. gute Frage... :D

Ich dachte nicht das man die Timer extra auf CTC schalten muß, ich 
dachte mit dem OCR Bit setze ich ausschließlich den Interrupt 
auslösenden Zähler von 255 runter auf 124?! Wie setze ich denn den CTC 
Modus?!

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Tja. Datenblatt lesen wäre von vorteil.
Da steht das alles drinn.

Hols dir von Atmel. Ohne Datenblatt kommst du nicht weit.

Autor: Draco (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Karl heinz Buchegger schrieb:
> Hols dir von Atmel. Ohne Datenblatt kommst du nicht weit.

Super, daher hatte ich es mir ja abgeleitet ;)

also... ich denke mal so ist es nun richtig oder:
    TCNT0 = 0x00; //Timer 0 mit Null initialisieren
    OCR0 = 0x7C;  //Vergleichsregister initialisieren
    TIMSK = (1<<OCIE0);    //Output Compare interrupt enable
    TCCR0 = ((1<<WGM01)  |  (1<<CS00));

Wobei ich nun noch am Rätsel bin ob ich nun auch noch COM01 setzen muß?! 
Damit der Zähler zurückgesetzt wird?! Komm da im Datenblatt nicht so 
ganz klar. :/

"Clear OC0 on compare match when up-counting. Set OC0 on compare
match when downcounting."

Autor: spess53 (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hi

>Wobei ich nun noch am Rätsel bin ob ich nun auch noch COM01 setzen muß?!

Ja.

MfG Spess

Autor: Draco (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Danke funktioniert tadellos :D

Thumps-Up

Autor: spess53 (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hi

>Danke funktioniert tadellos :D

Gut. Hauptsache du hast auch etwas dabei gelernt.

MfG Spess

Autor: Rene K. (draconix)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Jep, ich denke schon das ich was gelernt habe :D

Kleine Frage aber gleich hinterher... Wenn ich damit nahe an die 1khz 
Grenze will, werde ich wohl oder übel ein Problem bekommen oder? Ich 
Rechne mal:

8.000.000 hz / 8.000ctc = 1.000hz = 1khz

Jedoch hat der 16Bit Timer ja gerade mal 1.023 Zählintervalle... Kann 
ich im CTC Mode ebenfalls einen Prescaler nutzen? Oder bleibt mir nur 
eine möglichkeit den Counter bei 800 auslösen zu lassen, was dann ja 
10khz sind und dann in dem Counter eine Schleife bis 1000 
durchzuzählen?!

Mit einem Prescaler von 64 wäre das ja optimal:

8.000.000hz / 64ps = 125.000 / 125ctc = 1khz...

Wie würdet ihr das machen?

Autor: spess53 (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hi

>Jedoch hat der 16Bit Timer ja gerade mal 1.023 Zählintervalle

Nein. 65536.

>Kann ich im CTC Mode ebenfalls einen Prescaler nutzen?

Ja.

MfG Spess

Autor: STK500-Besitzer (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
>Jedoch hat der 16Bit Timer ja gerade mal 1.023 Zählintervalle..

16²-1 ist 65535. Sollte also kein Problem sein.
Vorteiler gibt es aber trotzdem und können auch benutzt werden.

Autor: spess53 (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hi

>16²-1 ist 65535.

Der Timer zählt von 0..65535. Und das sind 65536 unterschiedliche Werte.

MfG Spess

Autor: STK500-Besitzer (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
>Der Timer zählt von 0..65535. Und das sind 65536 unterschiedliche Werte.

Meine Rechnung stimmt aber trotzdem...

Autor: Rene K. (draconix)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Sooo also im 16Bit lassen sich ja nun die Bits doch ein wenig anderst 
setzen.. hab mich nun so durchs Datenblatt gewusselt und ich denke das 
dürfte stimmen...
TCNT1H = 0x00;                            // TCNT HighBit mit null setzen
TCNT1L = 0x00;                            // TCNT LowBit mit null setzen

OCR1AH = 0x27;                            // OCR1AH setzen mit 0x27
OCR1AL = 0x10;                            // OCR1AL setzen mit 0x10 - macht 0x2710 = 10.000 ticks

TIMSK  = (1<<OCIE1A);                     // Output Compare setzen
    
TCCR1A = ((1<<COM1A0) | (1<<COM1A1));     // Comperator setzen
TCCR1B = ((1<<CS11)   | (1<<WGM12));      // Prescaler 8 setzen, CTC einschalten

Das macht dann zwar 100Hz - aber das ist sogar noch besser für mich. Ich 
denke mal das das so stimmt.

Autor: Rene K. (draconix)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Geht nicht :/ µC hängt sich auf... hmm....

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Rene K. schrieb:
> Geht nicht :/ µC hängt sich auf... hmm....

Und jetzt bitte im ganzen Satz, äh, Programm.

Autor: Rene K. (draconix)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Aso.... ja klar :D Hier die Timer Initialisierung:
    //----- Timer 0
    TCNT0 = 0x00;
    OCR0 = 0x73;                                   //Sprungmarke auf 124 für 32.000hz bei 8Mhz    0x7B
    TIMSK = (1<<OCIE0);
    TCCR0 = ((1<<WGM01) | (1<<COM01) |  (1<<CS00));

    //----- Timer 1
    TCNT1H = 0x00;                                 // TCNT HighBit mit null setzen
    TCNT1L = 0x00;                                 // TCNT LowBit mit null setzen

    OCR1AH = 0x10;                                 // OCR1AH setzen mit 0x27
    OCR1AL = 0x27;                                 // OCR1AL setzen mit 0x10 - macht 0x2710 = 10.000

    TIMSK  = (1<<OCIE1A);             // Output Compare setzen

    TCCR1A = ((1<<COM1A0) | (1<<COM1A1));          //Comperator setzen
    TCCR1B = ((1<<CS11) | (1<<WGM12));             //Prescaler 8 setzen, CTC einschalten
    SREG_I_bit = 1;

Und hier die Timer an sich:
 void KhzClockGenerator() org 0x0026 {  //IVT_ADDR_TIMER0_COMP
    MCL = ~MCL;
}

 void Sekunde() org 0x000C {    //IVT_ADDR_TIMER1_COMPA
     timer_counter++;

     if(timer_counter == 100)
     {
         Sekunde++;

         if (sekunde >= 60) {
            minute++;
            sekunde = 0;
         }

         if (minute >= 60) {
            stunde++;
            minute = 0;
         }
         
         timer_counter = 0;
     }
 }

Es wird dann KEINER der beiden Timer gestartet. :/ Kommentier ich jedoch 
die Initialisierung des Timer 1 aus, geht der andere ganz normal.

Autor: spess53 (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hi

>   TIMSK = (1<<OCIE0);
>   TIMSK  = (1<<OCIE1A);

Was denkst du denn, was da rauskommt?

MfG Spess

Autor: Rene K. (draconix)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
TIMSK = 0b00010010 - gehe ich doch mal stark davon aus?! So wie ich das 
Datenblatt verstehe wird in TIMSK für alle drei Timer die Interruptmask 
gesetzt.:

[OCIE2][TOIE2][TICIE1][*OCIE1A*][OCIE1B][TOIE1][*OCIE0*][TOIE0]

Autor: spess53 (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hi

Wenn du schreibst:

    A=1
    A=2

Welchen Wert hat A zum Schluss?

MfG Spess

Autor: Rene K. (draconix)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Achso.. ja ist mir nun auch eingeleuchtet :D

Nun laufen zwar die Timer, ich schätze mal alle beide - jedoch spinnt 
nun mein LCD völlig verrückt... Da kommt nur noch Mist auf PORTD rauß. 
Kann auch nicht schauen wie es Programmiert ist, da in MicroC die LCD 
Bibliothek nicht einsehbar ist. :/

Solange nur einer von den beiden Timern läuft geht alles wunderbar, bei 
beiden macht er Mist.

Werde mir es nun aber so umschreiben das ich von Timer0 einfach 320
 Schritte zurückzähle - dann komme ich auch auf meine 100 Herz.

Autor: Rene K. (draconix)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Jetzt habe ich einen Lichtblick gehabt. Sehe ich das richtig das der 
Atmega Pins zur Verfügung stellt welche (Atmega16: OC0 = Pin A3.. 
etc...) beim Interrupt den Takt ausgeben?!

Kann ich dies umgehen?! Das ist auch der Grund warum mein LCD spinnt, 
der liegt auf PortD, dort wo auch OC2 und OC1A/B liegt.

Autor: spess53 (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hi

>Kann ich dies umgehen?!

Dann erkläre mal, wozu diese Zeile:

>   TCCR1A = ((1<<COM1A0) | (1<<COM1A1));          //Comperator setzen

da ist.

Mfg Spess

Autor: Rene K. (draconix)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
spess53 schrieb:
> Hi
>
>>Kann ich dies umgehen?!
>
> Dann erkläre mal, wozu diese Zeile:
>
>>   TCCR1A = ((1<<COM1A0) | (1<<COM1A1));          //Comperator setzen
>
> da ist.
>
> Mfg Spess

Ach Spess wenn ich dich nicht hätte :D

Stimmt, sehr schön das man dies auf die Pins legen kann, hätte ich das 
vorher gewusst, hätte ich meinen 32khz Clock ja direkt auf den OC0 Pin 
legen können. Nun habe ich mir eh einen externen Rechteckgenerator mit 
32,57khz gebaut, so das ich dies aus meinem Programm nehmen kann.

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.