Hallo liebes Forum. Ich habe derzeit ein Problem mit einem ATTiny 2313. Ich habe an den ATTiny extern an XTAL1 und XTAL2 einen Chrystal Oszillator 4,096 MHz gehängt. Die Fusebits für den Chip habe ich so gesetzt : CKSEL0 = 1 CKSEL1 = 0 CKSEL2 = 1 CKSEL3 = 1 SUT0 = 1 SUT1 = 1 CKOUT = 1 CKDIV = 1 Meine Initialisierung für den Timer0 sieht folgendermaßen aus: TIMSK |= (1<<TOIE0);// Timer/Counter0 Overflow Interrupt Enable TCCR0B |= (1<<CS02)|(1<<CS00);// Prescaler 1024 sei(); // Global Interrupt Enable wenn der Timer0 überläuft soll jeweils dies ausgeführt werden: ISR (TIMER0_OVF_vect) { if (counter == 40) //entspricht 100HZ { if (counter2 == 100) //entspricht 1HZ { counter2 = 0; if(Zustand == 0) { PORTB &= ~(1<<Hour); Zustand = 1; } else { PORTB |= (1<<Hour); Zustand = 0; } } else counter2++; } else counter++; } jedoch entspricht die IF Abfrage von Counter2 nicht annähernd 1HZ. Ist dort irgendetwas Falsch ? oder an meiner Berechnung für 1 HZ: 4096000HZ / 1024 = 4000 erste If Schleife: 4000/40 = 100 zweite IF Schleife: 100/100 = 1 Ich sehe nirgends einen Fehler. Wäre nett, falls einer den Fehler findet. MFG
du hast den overflow übersehen!? timer-takt ist clck/1024. timer 0 ist 10 bit? dann macht er mit dieser frequenz 1024 schritte -> overflow alle 3.9s
Koko Lores wrote: > du hast den overflow übersehen!? > > timer-takt ist clck/1024. timer 0 ist 10 bit? dann macht er mit dieser > frequenz 1024 schritte -> overflow alle 3.9s Ich kann zwar verstehen, dass Du auch mal helfen möchtest, aber Du solltest da doch vorher mal einen Blick ins Datenblatt des Tiny2313 werfen. Timer0 und 10 Bit passt irgendwie nicht so recht zusammen... ------- > Ich habe an den ATTiny extern an XTAL1 und XTAL2 einen Chrystal > Oszillator 4,096 MHz gehängt. Diese Info halte ich für falsch, denn ein Quarzoszillator (Chrystal-oscillator) braucht nur einen XTAL-Anschluss. Er wird Fusebit-mäßig als external clock angesehen. Wenn Du beide XTAL-Pins benutzt, dann hast Du vermutlich einen einfachen Quarz, der vom im Tiny2313 integrierten Oszillator zum Schwingen gebracht wird. Aus dem Rest halte ich mich mangels C-Wissen 'raus, ich programmiere AVRs nur in ASM. ...
Ich habe den Quarz wie in Figure12 auf Seite 26 des Datenblattes des ATTiny2313 angehängt.
Bis auf die falsche Annahme über die Beschaffenheit des Timers hat Koko Recht:
Allerdings hat der Timer 8 Bit und dementsprechend bekommst Du bei einem Prescaler von 1024 und f_CPU=4,096 MHz eine Overflow-Frequenz von etwas mehr als 15 Hz (MAX ist beim 8-Bit-Timer 255). Ein Overflow tritt also alle 64 ms auf. Das ist, um genaue Sekunden zu zählen, ein ziemlich ungünstiger Wert. Stelle besser den Prescaler auf 8. Dann bekommst Du alle 500 µs einen Overflow (also mit einer Frequenz von 2 kHz). Da lässt es sich wesentlich leichter zählen. Noch besser gehts i.d.R. mit dem CTC-Modus... > Ich habe den Quarz wie in Figure12 auf Seite 26 des Datenblattes des > ATTiny2313 angehängt. Hannes' Beitrag bezog sich darauf, dass Du einen QuarzOSZILLATOR erwähnt hast. Und das ist was völlig anderes...
> erste If Schleife: ...
Es gibt keine "if-Schleifen"! Eine "if"-Anweisung stellt eine
Entscheidung oder Verzweigung dar, aber keine Schleife...
> ... auch mal helfen ... Das war kein Schuss ins Blaue.. ;-) Den Fehler sieht man in dieser Annahme: >4096000HZ / 1024 = 4000 >erste If Schleife: _4000_/40 = 100
sehe ich das Falsch: 4,096 MHz mit einem Prescaler von 8 sind doch 512kHz oder ?
@ Koko Lores (Gast): "counter" scheint eine globale Variable zu sein, deren Typ allerdings nicht angegeben ist, wenn das mindestens ein "int" ist sollte dieser Teil funktionieren. Man sieht aber, dass es besser ist die Formel in den Code zu schreiben statt der "magic numbers".
@Gast: Ich glaube, Dir fehlt ein wenig Grundverständnis zum Thema Timer. Der Timer besteht im Prinzip aus einem 8-Bit-Register und ein wenig Hardware rundrum. Wenn der Timer eine Taktflanke bekommt, dann wird der (Binär-)Wert des Registers (TCNT0 ist das beim AVR) um eins erhöht. Das geschieht nun bei jeder entsprechenden Taktflanke. Irgendwann erreicht der Wert im Register "11111111" oder in Dezimalschreibweise 255. Das ist der höchste mit 8 Bit darstellbare Wert. Wenn jetzt noch eine Taktflanke kommt, dann wird der Wert noch mal um eins erhöht. Da 256 aber in 8 Bit nicht mehr darstellbar ist, "springt" das Zählregister TCNT0 auf "0", d.h. der Timer fängt wieder von vorne an zu zählen. Das passiert bei jedem 256. Takt (beim 8-Bit-Timer). Dieses Umspringen vom Maximalwert auf 0 nennt man Overflow. Tritt ein Overflow auf, dann wird das dazugehörige Interrupt-Flag gesetzt und (wenn doe Interrupt-Bearbeitung freigegeben ist) der dazugehörige Interrupt Handler ausgeführt. Der Takt, mit dem der Timer zählt, wird über einen Vorteiler (den Prescaler) aus dem Systemtakt erzeugt. Wenn als Taktquelle für den Timer der Prescaler-Ausgang "f_CPU/1024" ausgewählt ist, dann heißt das, dass bei jeder 1024. Taktflanke des Prozessortaktes (der bei Dir 4096000 Hz beträgt) das Timerregister TCNT0 um eins erhöht wird. Das bedeutet, der Timer selbst wird mit 4096000/1024 Hz = 4000 Hz getaktet. Ein Overflow tritt nun bei jedem 256. Timertakt auf, also mit einer "Frequenz" von 4000 Hz/256 = 15,625 Hz. Das macht einen Overflow alle 64 ms. Jetzt klar?
counter und counter2 sind vom Typ uint8_t die in der Library inttypes.h deffiniert sind. wieso kommt johnny m. denn mit einem Prescaler von 8 auf 500µS ? wenn ich also einen Prescaler von 1024 wählen würde, müsste ich dann den 16 Bit Timer nehmen ?
sehe ich das jetzt so richtig : Der Vorteiler teilt mir meine FCPU = 4,096 MHz auf 512 kHz. Mit dieser Taktrate wird dann das Register des Timer inkrementiert. Sobald das Register denn Wert 255 erreicht hat, wird beim nächsten Takt das Register wieder auf 0 gesetzt und ein Interrupt ausgelöst ? und daher komme ich dann auch auf die 2kHz :)
@Koko Lores: Sry, Hast recht! jetzt seh ich auch, dass da das eigentliche Zählen fehlt (noch mal durch TOP +1 teilen) @Gast genau! (und 4000 passen nicht in ein "uint8_t"...)
> (und 4000 passen nicht in ein "uint8_t"...)
Das war wiederum nicht das Problem..
Dann hat Gast ja jetzt bald sein Sekunden-Blinken - Du kannst übrigens
auch mit einer exklusiv-Oder Verknüpfung den Ausgangspin direkt
Umschalten. Guck mal in der Artikelsammlung (links 'alle artikel') nach
bitmanipulation.
ich bins mal wieder :( habe das Programm soweit jetzt geändert :
1 | /* Library´s */
|
2 | #include <avr/io.h> |
3 | #include <avr/interrupt.h> |
4 | #include <inttypes.h> |
5 | |
6 | /* Unterprogramme */
|
7 | void PORT_INIT (void); |
8 | void TIMER_INIT (void); |
9 | |
10 | /* Define´s */
|
11 | #define Hour PB2
|
12 | #define Min PB1
|
13 | #define Sec PB0
|
14 | |
15 | /* Variabeln */
|
16 | uint8_t counter = 0; // counter |
17 | uint8_t counter2 = 0; |
18 | uint8_t sec_count = 30; |
19 | uint8_t min_count = 30; |
20 | uint8_t hour_count = 30; |
21 | uint8_t Zustand = 0; |
22 | |
23 | int main (void) { |
24 | // Hauptprogramm
|
25 | PORT_INIT(); |
26 | TIMER_INIT(); |
27 | while(1); |
28 | return 1; |
29 | }
|
30 | |
31 | void PORT_INIT (void) { |
32 | DDRB = (1<<Sec)|(1<<Min)|(1<<Hour); |
33 | DDRD = 0x3F; |
34 | PORTD = 0x3F; |
35 | PORTB = 0xFF; |
36 | }
|
37 | |
38 | void TIMER_INIT (void) { |
39 | TIMSK |= (1<<TOIE0); // Timer/Counter0 Overflow Interrupt Enable |
40 | TCCR0B |= (1<<CS01); // Prescaler 8 |
41 | sei(); // Global Interrupt Enable |
42 | }
|
43 | |
44 | ISR (TIMER0_OVF_vect) { |
45 | if (counter == 20) // entspricht 100 Hz |
46 | {
|
47 | if (counter2 == 100) |
48 | {
|
49 | counter2 = 0; |
50 | if(Zustand == 0) |
51 | {
|
52 | PORTB &= ~(1<<Hour); |
53 | Zustand = 1; |
54 | }
|
55 | else
|
56 | {
|
57 | PORTB |= (1<<Hour); |
58 | Zustand = 0; |
59 | }
|
60 | }
|
61 | else counter2++; |
62 | }
|
63 | else counter++; |
64 | }
|
jedoch wird kein Sekunden Takt erzeugt, ist im Programm ein Fehler oder bei den (im ersten Beitrag) Einstellung der Fusebits ?
Ich denke, Du müsstest, wenn counter 20 ist, diese Variable auch wieder auf Null setzen, wie Du es ja auch mit counter2 machst.
autsch *Kopf => Wand ;)* danke Johnny (mal wieder :) ). nochma eine kleine Frage zur Logik, um einen genauen Sekunden Takt zu erzeugen, müsste ich doch eigentlich bei den beiden IF-Anweisungen die Werte die ich abfrage um 1 verringern. Also bei if(counter==19) und if(counter2==99) um einen genauen Sekunde Takt zu erzeugen ? Da (so wie ich es denke) der Interrupt 20 mal aufgerufen werden muss um den Counter auf 20 hochzuzählen. Beim 21.ten Aufruf würde dann erst der nächste Zähler hochgezählt wird. Stimmt meine Logik?
In Deinem Beispiel müsstest Du tatsächlich genaugenommen die Werte um 1 reduzieren, da Du erst nach der Abfrage die Zähler inkrementierst und die Abfrage des inkrementierten Zählers erst im nächsten Zyklus geschieht. Ich persönlich bevorzuge die Pre-Increment-Methode, bei der der betreffende Zähler erst inkrementiert und dann abgefragt wird.
1 | ISR (TIMER0_OVF_vect) |
2 | {
|
3 | if (++counter == 20) // entspricht 100 Hz |
4 | {
|
5 | counter = 0; |
6 | if (++counter2 == 100) |
7 | {
|
8 | counter2 = 0; |
9 | //Code
|
10 | }
|
11 | }
|
12 | }
|
So ginge es mit 20 und 100 und erspart die else-Anweisungen... Wenn Du es so lässt wie oben, dann musst Du 19 und 99 nehmen, damit es genau stimmt.
Danke Johnny :) Die Schreibweise in einer If-Anweisung war mir bisher nicht bekannt. Aber ma lernt nie aus (wobei ich noch ne "Menge" zu lernen habe).
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.