Forum: Mikrocontroller und Digitale Elektronik Timerinterrupt alle 62.5Hz


von Spieker (Gast)


Lesenswert?

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

von spess53 (Gast)


Lesenswert?

Hi

Der Timer0 läuft bei 16MHz und Prescaler 1024 alle 16,384 ms über.

MfG Spess

von hw (Gast)


Lesenswert?

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.

von Spieker (Gast)


Lesenswert?

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

von m.n. (Gast)


Lesenswert?

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)

von hw (Gast)


Lesenswert?

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.

von Stefan E. (sternst)


Lesenswert?

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.

von Spieker (Gast)


Lesenswert?

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

von hw (Gast)


Lesenswert?

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.

von m.n. (Gast)


Lesenswert?

hw schrieb:
> Also geht das mit dem Timer0 nicht, man muß für 16Hz (62,5ms) einen
> 16bit-Timer benutzen.

Aber sicher geht das.

von hw (Gast)


Lesenswert?

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.

von m.n. (Gast)


Lesenswert?

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.

von Spieker (Gast)


Lesenswert?

Im Threadtitel habe ich mich selber vertan! 62.5ms sprich 16Hz.

von S.W. (Gast)


Lesenswert?

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?

von hw (Gast)


Lesenswert?

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.

von Spieker (Gast)


Lesenswert?

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.

von m.n. (Gast)


Lesenswert?

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.

von Spieker (Gast)


Lesenswert?

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

von Spieker (Gast)


Lesenswert?

m.n., das mit den Intervallen aus den Programmen habe ich nicht 
verstanden, was du damit meinst. Habe mir beide Links bereits angesehen.

von m.n. (Gast)


Lesenswert?

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.

von Spieker (Gast)


Lesenswert?

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.

von m.n. (Gast)


Lesenswert?

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!

von c-hater (Gast)


Lesenswert?

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
Noch kein Account? Hier anmelden.