Forum: Mikrocontroller und Digitale Elektronik AVR Timer2 gleichzeitig für PWM und Sekundenzähler benutzen?


Announcement: there is an English version of this forum on EmbDev.net. Posts you create there will be displayed on Mikrocontroller.net and EmbDev.net.
von Marco (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Hallo,

vielleicht kann mir jemand helfen.

Folgendes ist gegeben und daran ist auch nichts zu ändern.

AVR Takt: 8MHZ, Vorteiler=1

Ich benutze Timer2 um eine PWM ~16kHz PWM zu erzeugen.

OCR2A = 255;
OCR2B = 50;



Jetzt würde ich gerne durch hinzufügen von:

TIMSK2|= (OCIE2B); einen Interrupt erzeugen um folgenden CODE aus dem 
GCC-Tutorial auszuführen und den Timer gleichzeitig zur Zeitmessung zu 
nutzen.

Wie berechne ich "millisekunden" unter den oben angegebenen 
Voraussetzungen richtig um eine relativ genaue Zeitmessung zu erziehlen?

Anders gefragt, wieviele Millisekunden sind in meinem Fall eine Sekunde, 
wenn nicht tausend?


ISR (TIMER2_COMPA_vect)
{
  millisekunden++;


  if(millisekunden == 1000)
  {
    sekunde++;
    millisekunden = 0;
    if(sekunde == 60)
    {
      minute++;
      sekunde = 0;
    }
    if(minute == 60)
    {
      stunde++;
      minute = 0;
    }
    if(stunde == 24)
    {
      stunde = 0;
    }
  }
}

von Sebastian S. (amateur)


Bewertung
0 lesenswert
nicht lesenswert
Ent- oder Weder: Ja! Aber beides nicht.
Kein Problem bei EINER konstanten Pulsweite aber alles andere würde mich 
wundern.

In den meisten Fällen liegt das Problem an anderer Stelle. Du kannst, so 
er eine ausreichend kurze Zykluszeit verwendet, einen Zähler für mehrere 
Zeiten verwenden. Ist eigentlich recht einfach, wird aber oft vergessen. 
Damit bekommst Du im Endeffekt ein paar Zeiter mehr.

von Jakob (Gast)


Bewertung
0 lesenswert
nicht lesenswert
AVR Timer 2 ist schon ganz nett, aber da ich nicht JEDEN
AVR auswendig kann, wäre vielleicht noch die Eingrenzung
Mega/Tiny und Modell-Nummer hilfreich.

Daher gehe ich jetzt nicht auf die Register und Bits ein.

Grundsätzlich:
Wenn deine PWM-Frequenz konstant ist, musst du deine
"millisekunden-Variable" bis zum Zahlenwert der sich
ergebenden PWM-Frequenz hochzählen, dann ist eine Sekunde
vergangen.
Ergibt sich aus Vorteiler und MAXCOUNT+1 eine "krumme"
Frequenz, ist deine Sekunde halt nicht sehr genau.

Ohne Quarz ist das sowieso der Fall.

In deinem Fall gehe ich mal davon aus, dass du
F_PWM = 8 MHz / 256 = 31250 Hz hast.

Erhöhst du in jedem Durchlauf eine Variable, muss sie
eben 31250 erreichen, bis eine Sekunde vergangen ist.

von Marco (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Danke euch, Sebastian und Jakob.

Zu Sebastion: Es funktioniert ja scheinbar. Nur ist die Sekunde mit 
1000Millisekunden zu schnell.

Jakob, klingt logisch. Allerdings zählt der Timer in dem Modus rauf und 
wieder runter, daher die doppelte Laufzeit bzw. 31250 / 2 = ~16kHz

von H.Joachim S. (crazyhorse)


Bewertung
0 lesenswert
nicht lesenswert
Marco schrieb:
> Nur ist die Sekunde mit
> 1000Millisekunden zu schnell.
Nö. Das ist exakt :-)
>
> Jakob, klingt logisch. Allerdings zählt der Timer in dem Modus rauf und
> wieder runter, daher die doppelte Laufzeit bzw. 31250 / 2 = ~16kHz
Hast ja deinen PWM-Mode nicht verraten, es gibt den phase-correct und 
den fast-pwm-mode.
Du wirst also phase-correct benutzen. Wenn ich mich recht errinnere, ist 
der Teiler dann 510. Das würde bedeueten 15,6xxx KHz, also keine direkte 
Sekunde möglich. Kann man aber per Software korrigieren.

von Jakob (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Na siehste: Passt doch!

1000 Millisekunden sind eine Sekunde.
Wie kommst du darauf, dass eine Variable, die 31250, oder 15625
mal pro Sekunde hochgezählt wird MILLISEKUNDEN zählt?

Sie zählt schneller hoch - ist das für dich nicht logisch???

von Marco (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Doch ist logisch. Die Variable Millisekunden hier zu verwenden ist eher 
irreführend. Werde das mal umbenennen.

von H.Joachim S. (crazyhorse)


Bewertung
0 lesenswert
nicht lesenswert
Du kannst also in 63,75µs-Schritten deine Sekunde zusammenbasteln. Der 
beste Wert wäre:
if(millisekunden == 15686)
Damit wäre deine Sekunde 999,9825ms, besser gehts nicht direkt. Je nach 
Taktquelle und Anforderung ist das i.a. mehr als gut genug.
Für die Langzeitkonstanz (Uhr) könntest du nach jeweils 51s eine 
Korrektur einfügen.

von Marco (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Wie kommst du auf 63,75µs? Wären doch 1/15265 = 64µs oder nicht bzw. 
warum nicht?

von Karl M. (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Hallo !

diese Anweisung macht nicht das von Dir gewollte und setzt das falsche 
Bit!
1
TIMSK2|= (OCIE2B);

von Marco (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Wie müsste denn die Anweisung dann richtig lauten?

von Matthias S. (Firma: matzetronics) (mschoeldgen)


Bewertung
0 lesenswert
nicht lesenswert
Marco schrieb:
> Wie müsste denn die Anweisung dann richtig lauten?

Da bin ich auch mal gespannt. Für einen Mega48/88/168/328 jedenfalls 
tuts die Anweisung

Karl M. schrieb:
> TIMSK2|= (OCIE2B);

und gibt den OC2B Compare Match als Interrupt Quelle frei.
Marco, sag endlich mal, welchen MC du benutzt.

: Bearbeitet durch User
von Marco (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Atmega328

von Karl M. (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Matthias S. schrieb:
> Da bin ich auch mal gespannt. Für einen Mega48/88/168/328 jedenfalls
> tuts die Anweisung
>
> Karl M. schrieb:
>> TIMSK2|= (OCIE2B);
>
> und gibt den OC2B Compare Match als Interrupt Quelle frei.

Na bestimmt nicht ganz so wie, man es erwartet !
Es handelt sich hierbei um die Bitnummer und nicht um die zugehörige 
Bitmaske. :-)

von Matthias S. (Firma: matzetronics) (mschoeldgen)


Bewertung
0 lesenswert
nicht lesenswert
Karl M. schrieb:
> Matthias S. schrieb:
>> Da bin ich auch mal gespannt. Für einen Mega48/88/168/328 jedenfalls
>> tuts die Anweisung
>>
>> Karl M. schrieb:
>>> TIMSK2|= (OCIE2B);
>>
>> und gibt den OC2B Compare Match als Interrupt Quelle frei.
>
> Na bestimmt nicht ganz so wie, man es erwartet !
> Es handelt sich hierbei um die Bitnummer und nicht um die zugehörige
> Bitmaske. :-)

Ach, jetzt verstehe ich. Logisch, da muss
1
TIMSK2 |= (1 << OCIE2B);
stehen. Manchmal sieht man den Wald vor lauter Bäumen nicht...

von Karl M. (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Ja genau Matthias,

Matthias S. schrieb:
> Ach, jetzt verstehe ich. Logisch, da mussTIMSK2 |= (1 << OCIE2B);
> stehen. Manchmal sieht man den Wald vor lauter Bäumen nicht...

Aber Marco hätte das doch selbst heraus finden sollen, nur durch Fehler 
lernt man und das ist auch gut so.

von Simpel (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Mit aktiviertem CLKO (Clockout Fuse) und einem Frequenzzähler dran, kann 
man auch 'krumme' Teilerverhältnisse per Osccal, Clkpr und den 
Timer-Prescalern sehr nah an die gewünschte Frequenz anpassen.

Kommt auf die Anforderung an. Immerhin hat ein Tag 86.400.000 
Millisekunden. Da läppert sich im 24/7-Betrieb schon was zusammen, auch 
wenn die Abweichung auf den ersten Blick akzeptabel erscheint.

von Matthias S. (Firma: matzetronics) (mschoeldgen)


Bewertung
0 lesenswert
nicht lesenswert
Karl M. schrieb:
> Aber Marco hätte das doch selbst heraus finden sollen, nur durch Fehler
> lernt man und das ist auch gut so.

Ich finde dieses 'Rate mal mit Rosental' dann unangebracht, wenn es 
nicht um Schule oder Prüfungsaufgaben geht, Da kann man auch einfach mal 
helfen - kost' ja nix und dafür ist so ein Forum doch da.

von H.Joachim S. (crazyhorse)


Bewertung
0 lesenswert
nicht lesenswert
Marco schrieb:
> Wie kommst du auf 63,75µs? Wären doch 1/15265 = 64µs oder nicht bzw.
> warum nicht?

8MHz/510=1568,27...kHz

von Haarlos (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Hi Marco,

ich habe bemerkt, dass ich das gleiche umsetzen wollte, wie Du.
Allerdings habe ich dazu den 16bit-Timer verwendet und so wie es 
aussieht, scheint es zu funktionieren.

Timer1 (16bit) im Modus 14 (FastPWM) betreiben. Vorteiler 1 und ICR1 als 
Zählermaximum. Im Modus 14 gibt es bei Erreichen von ICR1 enen 
Überlauf-Interrupt, sodass beide Kanäle frei für PWM sind (PWM 
funktioniert ja auch ohne Interrupt). Die PWM-Frequenz ist eben 1kHz 
fix.

Wenn Du ICR1 mit der Takt-Frequenz geteilt durch 1000 lädst, dann 
erfolgt der Überlauf-Interrupt im Millisekunden-Takt, also genau das, 
was Du wolltest.
Ich habe das mit einem externen 16MHz Quarz getestet und die Zeit über 
einige Stunden laufen lassen - keine Abweichung zur PC-Zeit erkennbar :)

Bei mir werkelt ein mega16, sollte so aber auch auf dem 328er 
funktionieren.

Vielleicht hilft Dir das ja weiter ;)

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.