Hi, ich hab noch nicht so viel mit Timern gemacht, deshalb die Frage:
Wie macht man sowas am Besten:
ich habe 6 Bytes, die ich bitweise in einem genauen (festen) Zeitraster
(ca. 20 kHz) ohne Lücke zwischen den Bytes aus einem Portpin schieben
will. Was ist die einfachste Variante? Bisherige Überlegungen:
RS232 fällt wohl aus, weil da start- und Stopbits generiert werden, und
zwischen den Bytes dürfen keine Pausen sein.
SPI - kann man die SPI-Clock so genau einstellen? und kann man schnell
genug nachladen, so dass keine Lücken zwischen den Bytes entstehen?
Also: Timer stellen, in der ISR Timer neu laden und bitweise die 6 Byte
rausschieben. Kann man den Timer so einstellen, dass man ihn nicht in
der ISR neu laden muss? Also meinetwegen "zähle immer bis 60 und löse
dann einen Interrupt aus" ? In den Programmierbeispielen habe ich immer
gesehen, dass in der ISR (am Anfang) der Timer-wert neu gesettzt
wurde...
Also was rauskommen soll: wenn alle Bytes z.B. 55 Hex sind, sollen NUR
24 steigende und fallende Flanken in exakt gleichem Abstand
'rauskommen..
Was spricht denn gegen das neuladen des timers in der ISR. Ich mach das
immer so. Eine ISR sollte immer maximal kurz sein. Das Nachladen eines
registers ist maximal kurz und unumgaenglich fuer ein genaues timing.
Ich wuerd auch in der ISR schieben und ausgeben. Aber nicht mehr.
Naja ich dachte halt es gibt irgendeine Betriebsart, die das automatisch
macht, also das Nachladen - sonst muss man ja für das genaue Timing
rechnen / berücksichtigen, wie lange das Nachladen in der ISR dauert,
und den Nachladewert entspr. verringern, oder?
ticker schrieb:> SPI - kann man die SPI-Clock so genau einstellen? und kann man schnell> genug nachladen, so dass keine Lücken zwischen den Bytes entstehen?
Nicht zu alte AVRs können die UART als SPI schalten und dann entsteht
keine Lücke, da gepuffert.
Ich glaub der Mega8 ist dann zu alt (ich lese gerade im Datenblatt) -
man kann das Frame Format der USART nicht abschalten, und man kann auch
nicht "Low when idle" setzen.. schade :-)
Aber was die Timer angeht - es scheint einen CTC mode im Timer1 zu
geben, der automatisch nachlädt und Interrupt auslösen kann..
funktioniert das Hat jemand das schonmal gemacht ein Stück
Beispielcode?
ticker schrieb:> Naja ich dachte halt es gibt irgendeine Betriebsart, die das automatisch> macht, also das Nachladen - sonst muss man ja für das genaue Timing> rechnen / berücksichtigen, wie lange das Nachladen in der ISR dauert,> und den Nachladewert entspr. verringern, oder?
Na komm.
Wir reden hier über Laufzeitunterschiede in der ISR, die sich im
einstelligen µs Bereich (also millionstel Sekunden) oder noch weniger
abspielen. Frag dich selber: spielt das für dich eine Rolle oder nicht?
Für Video-Anwendungen spielt es eine Rolle. Aber in 99% aller anderen
Fälle tut es das nicht.
'Genau' ist dann erfüllt, wenn es 'genau genug' ist.
FAQ: Timer
Du kannst natürlich komplett jedes einzelne Bit in der ISR aus dem Port
wackeln. Dann kannst Du das Timing für jede einzelne Flanke auf den Takt
genau bestimmen. Musst halt das jeweils nächste Bit außerhalb der ISR
vorbereiten, nicht dass durch Verzweigungen in selbiger noch
Laufzeitunterschiede entstehen. Und bloß nirgends die Interrupts
blockieren. Und trotzdem alle Zugriffe sauber ordnen.
Aber siehe Karl Heinz' Antwort. Brauchst Du das? Wenn ja, hast Du
bestimmt auch eine entsprechend genaue Taktquelle, die das rechtfertigt.
Karl Heinz Buchegger schrieb:> Frag dich selber: spielt das für dich eine Rolle oder nicht?
Ich weiß nicht, wie genau es das Empfangsgerät braucht. Also wenn es
genau geht - mach ich es. Der Punkt ist ja, dass sich dieser Wert bei
jedem Interrupt einfügt, also auf alle 6 Bytes betrachtet, mit 1MHz Takt
(quarz) und 4 Takte für das Register Nachladen sind das knapp 200uS.. Ok
es hängt auch vom Prescaler ab wie genau ich es bekomme..
Malte S. schrieb:> nicht dass durch Verzweigungen in selbiger noch> Laufzeitunterschiede entstehen.
Nee, wenn ich das Nachladen am Anfang der ISR mache, ist der Rest egal,
solange ich vor dem nächsten Interrupt fertig bin.
ticker schrieb:> Karl Heinz Buchegger schrieb:>> Frag dich selber: spielt das für dich eine Rolle oder nicht?>> Ich weiß nicht, wie genau es das Empfangsgerät braucht. Also wenn es> genau geht - mach ich es. Der Punkt ist ja, dass sich dieser Wert bei> jedem Interrupt einfügt, also auf alle 6 Bytes betrachtet, mit 1MHz Takt> (quarz) und 4 Takte für das Register Nachladen sind das knapp 200uS..
* Der ISR Aufruf erfolgt auch nicht ganz taktgenau. Je nachdem
welcher Befehl gerade ausgeführt wird, wenn der Interrupt kommt
gibt es eine kleine Verzögerung, weil dieser Befehl noch fertig
abgearbeitet wird.
* Timer vorladen ist sowieso meistens unsinnig (dafür gibt es den
CTC Modus)
* 4 Takte Nachladen sind bei 1Mhz keine 200µs, sondern 4µs
* der Fehler akkumuliert sich nicht, denn der Timer zählt für sich
alleine und löst den nächsten Interrupt ausschliesslich aufgrund
seiner eigenen Zählerei aus
* ob dein Quarz genau und exakt 1000000 Schwingungen pro Sekunde macht
steht in den Sternen. Tatsächlich wäre es ein enormer Zufall, wenn
er es täte.
Du kannst natürlich auch ein 48-Bit-Schieberegister nehmen, das so
unregelmäßig die Daten auch auflaufen mögen laden und abschließend
quarzofengetaktet hinten abgreifen.
SCNR
Erzähl dochmal, wozu das überhaupt dienen soll.
Dann findet man viel einfacher eine Lösung.
Also nicht, was Du machen willst, sondern warum Du meinst, es
ausgerechnet so machen zu müssen.
Wenn das z.B. irgendeinen IC ansteuern soll, ist ein Link auf das
Datenblatt viel informativer.
Der Ehrgeiz hat mich gepackt - ich will nicht den Timer neu laden,
sondern den CTC mode auf dem mega8 in den Griff bekommen, also..
Ich habe mich mal im Datenblatt und in den oben genannten Timer-FAQ
belesen und mal ein paar Zeilen im Bascom-Simulator getestet, weil man
da so schön sieht, was passiert:
TIMSK.OCIE1A = 1 'compare-interrupt ein
OCR1AH = 0 'Vergleich mit 96
OCR1AL = 96
TCCR1A.CTC1 = 1 ' ctc-modus
'TCCR1A.WGM12 = 1 'alias, ebenfalls ctc modus
TCCR1B.CS10 = 1 'prescaler=1
Wenn ich das Programm schrittweise laufen lasse, funktioniert zunächst
alles wie geplant: Der Zähler fängt an, aufwärts bis 60(Hex) zu zählen,
und die Interrupt-Routine wird aufgerufen, bei der Rückkehr aus der ISR
wird das Interrupt-Flag zurückgesetzt,
ABER
der Zähler (TCHT1H, TCNT1L) zählt weiter und fängt nicht wieder bei 0 an
- ist das ein Verständnisproblem, hab ich was vergessen oder spinnt der
Simulator?