Hallo,
kann mir einer kurz sagen, wie ich diesen Timer soweit anpassen kann,
dass dieser mit einer Frequenz von 16Hz bzw. 62.5ms einen Interupts
auslöst?
TCCR0A = (1<<WGM01);
TCCR0B |= (1<<CS02 | 1<<CS00); // Prescaler 1024
OCR0A = 1000;
TIMSK0 |= (1<<OCIE0A);
sei();
ISR (TIMER0_COMPA_vect) {
// code
}
Verwendet wird ein Atmega328P + 16MHz Quarz
Spieker schrieb:> TCCR0A = (1<<WGM01);> TCCR0B |= (1<<CS02 | 1<<CS00); // Prescaler 1024> OCR0A = 1000;> TIMSK0 |= (1<<OCIE0A);> sei();
Der CTC-Modus ist ja schon mal richtig.
Aber OCR0A=1000; funktioniert nicht. OCR0A ist nur ein 8bit-Register.
@spess53 warum alle 16.x ms?
QuarzFreq(16MHz) / Prescaler(1024) ergibt bei mir 15.625ms.
Mit OCR0A habe ich bereits im Atmel Studio gemerkt, gibt mir die Warnung
raus, welche soweit auch verständlich ist
Warning 1 large integer implicitly truncated to unsigned type [-
Woverflow]
Es gibt viele Möglichkeiten.
Direkt für den ATmega328 kann ich Dir diese anbieten:
http://www.mino-elektronik.de/Generator/takte_impulse.htm#bsp3
Dort ist die ISR(TIMER1_COMPB_vect) verwendbar, wenn Du außer der
Initialisierung den ganzen Rest ignorierst. In der ISR wird die
Periodendauer (un)sinnigerweise als 'frequenz' bezeichnet. Das kommt
davon, wenn man sich neue Programme nur noch aus alten zusammenkopiert
:-)
Weitere Programme zeigen, dass diese Periodendauer durchaus auch mit
einem 8-Bit Timer (ATtiny25) erzeugt werden kann:
http://www.mino-elektronik.de/Generator/takte_impulse.htm#bsp5
Da ist dann auch die Periode als solche ersichtlich.
Siehe: ISR(TIMER1_COMPA_vect)
Spieker schrieb:> @spess53 warum alle 16.x ms?>> QuarzFreq(16MHz) / Prescaler(1024) ergibt bei mir 15.625ms.>> Mit OCR0A habe ich bereits im Atmel Studio gemerkt, gibt mir die Warnung> raus, welche soweit auch verständlich ist> Warning 1 large integer implicitly truncated to unsigned type [-> Woverflow]
Setz mal OCR0A auf 124.
Im Datenblatt steht die Formel:
fOCnx = fCLK_io / 2 N (1+OCRnx)
umgestellt nach OCRnx ergibt sich
OCRnx = (fCLK_io / 2 N fOCnx) - 1
Mit N = 1024, fCLK_io=16MHz und fOCnx=62,5Hz ergibt sich ein Wert von
124 für OCRnx.
hw schrieb:> Setz mal OCR0A auf 124.>> Im Datenblatt steht die Formel:> fOCnx = fCLK_io / 2 N (1+OCRnx)> umgestellt nach OCRnx ergibt sich> OCRnx = (fCLK_io / 2 N fOCnx) - 1>> Mit N = 1024, fCLK_io=16MHz und fOCnx=62,5Hz ergibt sich ein Wert von> 124 für OCRnx.
Das ist gleich in zweifacher weise falsch.
1) Das fOCnx in der Formel ist die Frequenz an einem Pin, der bei jedem
Compare-Ereignis getoggelt wird. Für seinen Zweck fällt der Faktor 2
weg, und das Ergebnis wäre 249.
2) Er will keine 62,5Hz, sondern 16Hz.
16Hz ist nicht zwingend vorgeschrieben, jedoch soll diese 2^n betragen.
Bevorzug 16, darf aber auch 32 oder 64 betragen, höher sollte diese aber
nicht gehen, da ich den ISR möglichst selten auslösen möchte
Stefan Ernst schrieb:> Das ist gleich in zweifacher weise falsch.>> 1) Das fOCnx in der Formel ist die Frequenz an einem Pin, der bei jedem> Compare-Ereignis getoggelt wird. Für seinen Zweck fällt der Faktor 2> weg, und das Ergebnis wäre 249.>> 2) Er will keine 62,5Hz, sondern 16Hz.
Okay, du hast recht. Faktor 2 nicht beachtet. Sorry.
Zu Punkt 2: Ich hab den Wert aus dem Thread-Titel. Im Text steht dann
was anderes :-)
Also geht das mit dem Timer0 nicht, man muß für 16Hz (62,5ms) einen
16bit-Timer benutzen.
m.n. schrieb:> hw schrieb:>> Also geht das mit dem Timer0 nicht, man muß für 16Hz (62,5ms) einen>> 16bit-Timer benutzen.>> Aber sicher geht das.
Wenn du weißt wie, dann ist dieser Satz von dir überhaupt nicht
hilfreich.
"Ich weiß was, aber ich sag es nicht!"
Mit einem Zähler in der ISR, dann ja. Aber mit dem T0 alleine im
CTC-Modus reicht doch der Prescaler von 1024 nicht. Da käme für OCR0A
975 raus, aber mit 8Bit nicht machbar.
hw schrieb:> Wenn du weißt wie, dann ist dieser Satz von dir überhaupt nicht> hilfreich.> "Ich weiß was, aber ich sag es nicht!"
Wie es geht, habe ich doch weiter oben beschrieben. Ein bißchen
Mitdenken erwarte ich schon.
hw schrieb:> Da käme für OCR0A> 975 raus, aber mit 8Bit nicht machbar.
Das Intervall zelegt man in 2 x 256, 232 und 231 Schritte.
hw schrieb:> Also geht das mit dem Timer0 nicht, man muß für 16Hz (62,5ms) einen> 16bit-Timer benutzen.
62.5ms aus mehreren Teilintervallen zusammenzusetzen, ist dir wohl nicht
geheuer?
m.n. schrieb:> hw schrieb:>> Wenn du weißt wie, dann ist dieser Satz von dir überhaupt nicht>> hilfreich.>> "Ich weiß was, aber ich sag es nicht!">> Wie es geht, habe ich doch weiter oben beschrieben. Ein bißchen> Mitdenken erwarte ich schon.>> hw schrieb:>> Da käme für OCR0A>> 975 raus, aber mit 8Bit nicht machbar.>> Das Intervall zelegt man in 2 x 256, 232 und 231 Schritte.
Ich bin davon ausgegangen, daß der Spieker eine Auslösung des Interrupts
aller 62,5ms haben will, wie er es schrieb. Und deswegen schrieb ich
auch, daß das mit dem CTC-Modus nicht machbar ist. Mit deiner Methode
werden ja mehrere Interrupt-Auslösungen gebraucht, um auf das Intervall
zu kommen. Ist kein Problem, klar. Ist ja auch in Ordnung so. Aber ich
habe mich an die Vorgabe des TO gehalten, und der wollte die ISR des TO
aller 62,5ms auslösen.
Es geht darum, dass ich alle 1/16 Sekunde einen Wert hochzähle
1
ISR (TIMER0_COMPA_vect)
2
{
3
cycle++;
4
if(ms >= 16) cylce = 0;
5
}
Jede Sekunde soll somit in einem Wert von 0 - 15 unterteilt sein. Timer1
mit 16Bit ist keine Alternative.
Sicherlich könnte man den Interupt nun noch um ein paar weitere
Rechenoperationen erweitern, so dass diese häufiger aufgerufen wird und
nur bedingt weiterzählt. Jedoch muss ich relativ nah an dieser Frequenz
bleiben.
Derzeit läuft alles noch wie folgt
TCCR0A = (1<<WGM01);
TCCR0B |= (1<<CS01 | 1<<CS00);
OCR0A = 249;
TIMSK0 |= (1<<OCIE0A);
Die ISR wird dann jede ms einmal ausgeführt. Die Interupt Routine wird
damit aber viel zu häufig aufgeführt, was ich wenn möglich vermeiden
möchte. Das Problem ist, dass ich mich relativ stark an den Timings von
den WS2812B (lightwight lib) halten muss. Wird die ISR zu häufig
aufgerufen, habe ich auf Dauer eine zu hohe Abweichung der ms. 1000 ms
in Echtzeit entsprechen dann fast zwischen 1050 und 1300ms, was zu viel
ist. Eine RTC läuft ebenfalls mit, die einmal täglich die Zeit des
Atmega wieder anpasst.
Spieker schrieb:> Wird die ISR zu häufig> aufgerufen, habe ich auf Dauer eine zu hohe Abweichung der ms.
Dann machst Du etwas verkehrt.
Die Programme, auf die ich Dich oben verwiesen habe, lösen die
gewünschten 62500µs Periodendauer auf den Timertakt genau auf. Nimmst Du
als Vorteiler von Timer0 1/64, so ist die zeitliche Auflösung 4µs. Damit
werden die 62,500ms exakt erreicht.
Die Intervalle betragen 60 x 256, 1 x 133, 1 x 132 und werden in der ISR
automatisch berechnet und verwendet.
[quote]
Autor: Tim (cpldcpu)
Datum: 26.07.2014 07:35
Hain schrieb:
> kann es sein, dass die Methode meinen Timer0 beeinflusst?
Den Timer nicht, aber die Interrupts werden natürlich gesperrt. Versuche
doch einmal, die Interrupt-Frequenz zu verringern. Der Fehler wird immer
dann auftauschen, wenn während des WS2812 calls zwei interrupts
aufgerufen werden.[/quote]
Beitrag "Lightweight WS2811/WS2812 Library"
Habe das Problem wie bei dem anderen User auch beschrieben.
Spieker schrieb:> m.n., das mit den Intervallen aus den Programmen habe ich nicht> verstanden, was du damit meinst.
Bleiben wir beim obigen Beispiel mit 1/64 Vorteiler und 62500µs für die
gewünschten 16Hz.
Um die 62500µs mit den 4µs Auflösung des Timers zu erhalten, muß der
Timer bis 15625 zählen. Wegen seiner 8-bittigen Auflösung kann er nur
bis 256 zählen und muß nach Erreichen der 256 erneut zählen; das habe
ich mit Intervall bezeichnet. Nach 60 Intervallen hat er es bis 60*256 =
15360 geschafft, und es bleibt ein Rest von 265. Um ein genaues Timing
zu erhalten, wird der Wert von 265 auf zwei weitere Intervalle 133 und
132 aufgeteilt. Danach ist der Zählerstand 15625 erreicht.
In den obigen Programmen ist es ein wenig anders programmiert. Dort wird
der Startwert in 'nachlade_temp' (hier 15625) pro ISR-Aufruf (Intervall)
um 255 vermindert und das OCR1A-Register (8-Bit Register T1 beim
ATtiny25) entsprechend nachgeladen. Wenn 'nachlade_temp' bei 0
angekommen ist, sind die 62500µs abgelaufen und der Zyklus wird neu
gestartet.
An dieser Stelle erhälst Du Dein 16Hz Signal.
Für Deine Anwendung reicht es, für 'periode' und 'nachlade_temp'
uint16_t Variablen zu benutzen; die Berechnungen werden ein wenig
schneller.
Falls man ein Signal nur jede Sekunde benötigt, könnte man den Vorteiler
anstatt 1/64 mit 1/1024 wählen. Dann würden 62 Interrupts/s vom Timer
ausgeführt werden, und das Timing bliebe weiterhin exakt.
Etwas vereinfacht könnte man auch 62 Intervalle mit 252 implementieren,
was die ISR verschlanken würde. Allerdings käme man dann auf einen
Zählwert von 15624, was einen kleinen Fehler ergäbe.
Hallo mn,
das hört sich nun doch etwas anders an. Werde es mit Hilfe der Seiten
mal versuchen und dann entsprechend mal hier reinstellen, ob es so
richtig gemeint ist.
Spieker schrieb:> Sicherlich könnte man den Interupt nun noch um ein paar weitere> Rechenoperationen erweitern, so dass diese häufiger aufgerufen wird und> nur bedingt weiterzählt. Jedoch muss ich relativ nah an dieser Frequenz> bleiben.
Typische Anwendung für DDS/Bresenham-Algorithmus.
Immer nach dem Motto: Verteile bekannte Timing-Fehler wenigstens
möglichst gleichmäßig.