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