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


von Draco (Gast)


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

von spess53 (Gast)


Lesenswert?

Hi

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

MfG Spess

von Draco (Gast)


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

von spess53 (Gast)


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

von Oliver S. (zwen)


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.

von spess53 (Gast)


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

von Nn N. (jaytharevo)


Lesenswert?

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

von spess53 (Gast)


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

von Draco (Gast)


Lesenswert?

So habe es nun so geregelt... Messen kann man es bestimmt nur mit einem 
Oszi oder?!
1
...
2
    SREG_I_bit = 1;                                    //Timer 1 Einschalten
3
    OCR0       = 0x7C;
4
    TCCR0      = 1;
5
    TOIE0_bit  = 1;
6
...

von spess53 (Gast)


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

von Draco (Gast)


Lesenswert?

Aso... Selbstverständlich :D

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

von spess53 (Gast)


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

von Draco (Gast)


Lesenswert?

Bei MicroC ist das so:
1
    SREG_I_bit = 1;         //Interrupt einschalten
2
    OCR0       = 0x7C;      //Den CTC auf 124 stellen
3
    TCCR0      = 1;         //Prescaler auf 1 (2 == 4)(3 == 8) (4 == 64) etc.
4
    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).

von Karl H. (kbuchegg)


Lesenswert?

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

von Draco (Gast)


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

von Karl H. (kbuchegg)


Lesenswert?

Tja. Datenblatt lesen wäre von vorteil.
Da steht das alles drinn.

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

von Draco (Gast)


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:
1
    TCNT0 = 0x00; //Timer 0 mit Null initialisieren
2
    OCR0 = 0x7C;  //Vergleichsregister initialisieren
3
    TIMSK = (1<<OCIE0);    //Output Compare interrupt enable
4
    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."

von spess53 (Gast)


Lesenswert?

Hi

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

Ja.

MfG Spess

von Draco (Gast)


Lesenswert?

Danke funktioniert tadellos :D

Thumps-Up

von spess53 (Gast)


Lesenswert?

Hi

>Danke funktioniert tadellos :D

Gut. Hauptsache du hast auch etwas dabei gelernt.

MfG Spess

von Rene K. (draconix)


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?

von spess53 (Gast)


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

von STK500-Besitzer (Gast)


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.

von spess53 (Gast)


Lesenswert?

Hi

>16²-1 ist 65535.

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

MfG Spess

von STK500-Besitzer (Gast)


Lesenswert?

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

Meine Rechnung stimmt aber trotzdem...

von Rene K. (draconix)


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...
1
TCNT1H = 0x00;                            // TCNT HighBit mit null setzen
2
TCNT1L = 0x00;                            // TCNT LowBit mit null setzen
3
4
OCR1AH = 0x27;                            // OCR1AH setzen mit 0x27
5
OCR1AL = 0x10;                            // OCR1AL setzen mit 0x10 - macht 0x2710 = 10.000 ticks
6
7
TIMSK  = (1<<OCIE1A);                     // Output Compare setzen
8
    
9
TCCR1A = ((1<<COM1A0) | (1<<COM1A1));     // Comperator setzen
10
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.

von Rene K. (draconix)


Lesenswert?

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

von Karl H. (kbuchegg)


Lesenswert?

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

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

von Rene K. (draconix)


Lesenswert?

Aso.... ja klar :D Hier die Timer Initialisierung:
1
    //----- Timer 0
2
    TCNT0 = 0x00;
3
    OCR0 = 0x73;                                   //Sprungmarke auf 124 für 32.000hz bei 8Mhz    0x7B
4
    TIMSK = (1<<OCIE0);
5
    TCCR0 = ((1<<WGM01) | (1<<COM01) |  (1<<CS00));
6
7
    //----- Timer 1
8
    TCNT1H = 0x00;                                 // TCNT HighBit mit null setzen
9
    TCNT1L = 0x00;                                 // TCNT LowBit mit null setzen
10
11
    OCR1AH = 0x10;                                 // OCR1AH setzen mit 0x27
12
    OCR1AL = 0x27;                                 // OCR1AL setzen mit 0x10 - macht 0x2710 = 10.000
13
14
    TIMSK  = (1<<OCIE1A);             // Output Compare setzen
15
16
    TCCR1A = ((1<<COM1A0) | (1<<COM1A1));          //Comperator setzen
17
    TCCR1B = ((1<<CS11) | (1<<WGM12));             //Prescaler 8 setzen, CTC einschalten
18
    SREG_I_bit = 1;

Und hier die Timer an sich:
1
 void KhzClockGenerator() org 0x0026 {  //IVT_ADDR_TIMER0_COMP
2
    MCL = ~MCL;
3
}
4
5
 void Sekunde() org 0x000C {    //IVT_ADDR_TIMER1_COMPA
6
     timer_counter++;
7
8
     if(timer_counter == 100)
9
     {
10
         Sekunde++;
11
12
         if (sekunde >= 60) {
13
            minute++;
14
            sekunde = 0;
15
         }
16
17
         if (minute >= 60) {
18
            stunde++;
19
            minute = 0;
20
         }
21
         
22
         timer_counter = 0;
23
     }
24
 }

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

von spess53 (Gast)


Lesenswert?

Hi

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

Was denkst du denn, was da rauskommt?

MfG Spess

von Rene K. (draconix)


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]

von spess53 (Gast)


Lesenswert?

Hi

Wenn du schreibst:

    A=1
    A=2

Welchen Wert hat A zum Schluss?

MfG Spess

von Rene K. (draconix)


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.

von Rene K. (draconix)


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.

von spess53 (Gast)


Lesenswert?

Hi

>Kann ich dies umgehen?!

Dann erkläre mal, wozu diese Zeile:

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

da ist.

Mfg Spess

von Rene K. (draconix)


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.

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.