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
Hi Der Timer0 läuft bei 16MHz und Prescaler 1024 alle 16,384 ms über. MfG Spess
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.
hw schrieb: > Also geht das mit dem Timer0 nicht, man muß für 16Hz (62,5ms) einen > 16bit-Timer benutzen. Aber sicher geht das.
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.
m.n., das mit den Intervallen aus den Programmen habe ich nicht verstanden, was du damit meinst. Habe mir beide Links bereits angesehen.
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.
Es müßte dann etwa so aussehen: #define PERIODE 15625 ISR(TIMER0_COMPA_vect) { static uint16_t nachlade_temp = PERIODE; uint16_t temp = 0xff; if(nachlade_temp <= temp) temp = nachlade_temp; else if(nachlade_temp < 0x1ff) temp = nachlade_temp/2; nachlade_temp -= temp; // laengere Intervalle stueckweise // abarbeiten OCR0A += temp; if(nachlade_temp == 0) { nachlade_temp = PERIODE; // Intervall abgelaufen, nachladen cycle++; cycle &= 0x0f; // cycle von 0 - 15 } } Die Initialisierung muß noch ergänzt werden. Viel Erfolg!
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.
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.