Forum: Mikrocontroller und Digitale Elektronik PWM & Timer ISR mit einem Counter?


von Klaus R. (klaus2)


Lesenswert?

Hallo zusammen,

ginbt es beim tiny44 eine Mgl, mit dem Timer0 einen IR auszulösen und 
gleichzeitig eine im dutycycle einstellbare PWM zu realisieren?

In welchem Mode muss man dazu den Timer0 betreiben? Einfach von 0...255 
laufen lassen, damit die ISR aufrufen und mit einem CTC Vergleich einen 
Pin setzen?

Danke, Klaus.

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


Lesenswert?

Klaus R. schrieb:
> In welchem Mode muss man dazu den Timer0 betreiben? Einfach von 0...255
> laufen lassen, damit die ISR aufrufen und mit einem CTC Vergleich einen
> Pin setzen?

Du kannst sowohl 'Phase Correct' als auch 'Fast PWM' Modi nutzen und den 
Overflow Interrupt nutzen, um das gewünschte OCR Register mit deinem 
neuen PWM Wert zu schreiben. Ein CTC ist dazu nicht nötig.
Neben der PWM Frequenz ist der Unterschied zwischen den beiden PWM Modi, 
das der TOV Interrupt bei Fast PWM bei TOP gesetzt wird und bei Phase 
Correct ist BOTTOM der Auslöser.

von Klaus2 (Gast)


Lesenswert?

Hallo Matthias,

heißt, ich könnte den timer auch ab 55 loslaufen lassen, hätte dann 200 
"incremente", iregndwo auf den wert zwischen 55...255 setze ich den 
compare. beim compare lösche ich den entspr pin, beim overflow setze ich 
ihn wieder UND incrementiere meine interne zählvariable, die mir als 
zeitbasis dient - korrekt?

Danke, Klaus.

von spess53 (Gast)


Lesenswert?

Hi

>heißt, ich könnte den timer auch ab 55 loslaufen lassen, hätte dann 200
>"incremente", iregndwo auf den wert zwischen 55...255 setze ich den
>compare. beim compare lösche ich den entspr pin, beim overflow setze ich
>ihn wieder UND incrementiere meine interne zählvariable, die mir als
>zeitbasis dient - korrekt?

Der korrekte Weg wäre Timer-Mode7 mit TCR0A als Top. Du lädst OCR0A mit 
199 und benutzt OCR0B mit 0..199 für die PWM.

MfG Spess

von Klaus2 (Gast)


Lesenswert?

Perfekt, Danke...probiere ich heute Abend sofort aus.

Klaus.

von Klaus R. (klaus2)


Lesenswert?

Hallo Spess,

mit...

ISR (TIM0_COMPA_vect) {          // Timer 0

  timebase_superslow++;
  timebase_slow++;
  timebase_fast++;
  if(delay)delay--;
  PORTA ^= (1 << LED_B);
  }

TCCR0A = (1<<WGM01) | (1<<WGM00) | (0<<COM0A1) | (0<<COM0A0) | 
(1<<COM0B1) | (1<<COM0B0);
TCCR0B |= (1<<WGM02) |(1<<CS02)|(0<<CS01)|(1<<CS00);

GIMSK |= (1<<INT0)|(0<<PCIE1)|(0<<PCIE0);
MCUCR |= (1<<SM1)|(0<<SM0)|(1<<ISC01)|(0<<ISC00);

TIMSK0 |= (1<<TOIE0) | (1<<OCIE0A) | (1<<OCIE0B);

OCR0A = timer;
OCR0B = PWM;

sei();

...macht zwar der PWM Pin OC0B exakt was er soll, die LED_B in der ISR 
toggelt jedoch nicht alle x ms, sondern geht nur für atemberaubende 
480us an (ISR wird also 2x aufgerufen, das erste Mal exakt 60us nach dem 
CompareB event) - ich gehe davon aus, dass der Compare Interrupt nur bei 
TCNT0 = OCR0A ausgelöst wird, also EINMAL pro Zähler-Zyklus?

Was hab ich übersehen? Der main-code ist komplett auskommentiert, es 
läuft nur die ISR.

Klaus.

: Bearbeitet durch User
von spess53 (Gast)


Lesenswert?

Hi

>Was hab ich übersehen? Der main-code ist komplett auskommentiert, es
>läuft nur die ISR.
           ^^^

Und wo sind die restlichen beiden ISR?

MfG Spess

von Klaus R. (klaus2)


Lesenswert?

...restlichen beiden?

OCR0B setzt direkt den Pin, da läsuft die PWM ja auch. Aus OCR0A wollte 
ich nur eine ISR abzweigen, um die internen Zählvariablen zu 
inkrementen...die gibt es also nicht. INT0 dient nur zum Zählen von 
Flanken, das funktionierte auch einwandfeei (bis ich den T0 statt mit 
Signal Overflow auf Timer & PWM umgebaut habe)...

ISR (INT0_vect) {   // Einsprung (nach Ende sleep_mode) durch INT0

off_count++;

}

EDIT: Falls du die PWM ISR meinst, die gibt es (noch) nicht, die PWM 
läuft derzeit mit Fix-werten.

: Bearbeitet durch User
von Norbi (Gast)


Lesenswert?

Klaus R. schrieb:
> TIMSK0 |= (1<<TOIE0) | (1<<OCIE0A) | (1<<OCIE0B);
>
> OCR0A = timer;
> OCR0B = PWM;
>
> sei();

Compare 0B Interrupt ist aber auch enabled. Wenn da keine ISR existiert, 
gibts einen Reset? oder sonst was. Entweder ISR deklarieren oder den 
OCIE0B nicht enablen.

von Klaus R. (klaus2)


Lesenswert?

...einen Reset? Hoppa. Das wäre ggf eine Erklärung.

Laut Datenblatt nahm ich an, dass das I-Bit gesetzt wird, aber dann auch 
wieder gelöscht wird. Und fertig. Ich kann für COMP_B ja mal eine 
Dummy-ISR anlegen.

Klaus.

von spess53 (Gast)


Lesenswert?

Hi

>Laut Datenblatt nahm ich an, dass das I-Bit gesetzt wird, aber dann auch
>wieder gelöscht wird. Und fertig.

Die Stelle aus der du das heraus gelesen haben willst möchte ich mal 
sehen. Das I-Bit wird durch einen ausgeführten Interrupt oder durch 
Schreiben einer Eins ins I-Bit gelöscht.

>Ich kann für COMP_B ja mal eine Dummy-ISR anlegen.

Dann fehlt immer noch die Overflow-ISR. Einfacher wäre es die 
Interruptfreigaben zu löschen.

MfG Spess

von Karl H. (kbuchegg)


Lesenswert?

Klaus R. schrieb:
> ...einen Reset? Hoppa. Das wäre ggf eine Erklärung.
>
> Laut Datenblatt nahm ich an

Zuständig ist hier nicht das Prozessor Datenblatt sondern die Compiler 
Doku (ich nehm mal an wir reden vom GCC).

Alle freigegebenen Interrupts, für die keine ISR existiert, werden zu 
einer Standard-ISR geroutet, welche - tata - einen Programm Neustart in 
die Wege leitet.

Man gibt niemals einen Interrupt frei, für den man keine ISR hat!
Oder man jubelt der Runtime eine Default-ISR unter, die nichts tut.
Tut man keines von beiden, dann kriegt man eben Programm-Neustarts 
sobald die Interrupt Situation auftritt.

: Bearbeitet durch User
von Klaus R. (klaus2)


Lesenswert?

...verrückt, diese Compiler :) Ist aber sehr plausibel.

Danke, ich werde berichten!

EDIT: Wie gil ist das denn bitte - das wars! Diese &%$§*# ISR Routine 
hat mich echt vor ein Rästel gestellt - wieder was gelernt.

D-A-N-K-E Karl-Heinz!

: Bearbeitet durch User
von Klaus R. (klaus2)


Lesenswert?

...ja, ich schon wieder :)

Ich habe von Karl-Heinz schon einen Beitrag dazu gefunden

Beitrag "OCR1A lässt sich nur 1x ändern"

aber auch ich habe noch das Problem, dass OCR0B nur den initialen Wert 
von OCR0B_Load einmal übernimmt und sich von

ISR (TIM0_COMPB_vect) {          // Timer0 - PWM Reload

  void WriteOCR0B(){

  OCR0B = OCR0B_Load;

  }

nicht sonderlich beeindrucken lässt...?!

Klaus.

von spess53 (Gast)


Lesenswert?

Hi

>ISR (TIM0_COMPB_vect) {          // Timer0 - PWM Reload

>  void WriteOCR0B(){

>  OCR0B = OCR0B_Load;

>  }

Kannst du mir, als notorischen Assemblerprogrammierer, mal erläutern, 
was du damit bezweckst.  Sieht irgendwie schräg aus.

MfG Spess

von J. T. (chaoskind)


Lesenswert?

Wird denn dein OCR0B_Load irgendwo im Programm geändert? Ansonsten wäre 
es kein Wunder, das dir immer nur dein Startwert ins Register geladen 
wird.

von Klaus R. (klaus2)


Lesenswert?

Hi Spess,

es gibt eine "Lichtfunktion", in der aus einem lookup eine PWM Kennlinie 
in der main in OCROB_Load geschrieben wird. Wenn die ISR aufgerufen 
wird, soll das der nächste Compare Wert sein und das Licht langsam über 
die Kennlinie hochdimmen.

Das void... kann ich mir schenken, klar. Aber guck dir mal den Link an, 
oben :) Laut DB wird das Register beim compare nachgeladen...also, so 
wie ich das verstehe.

Klaus.

: Bearbeitet durch User
von Stefan E. (sternst)


Lesenswert?

Klaus R. schrieb:
> Das void... kann ich mir schenken, klar.

Auch ohne das void ist das immer noch Unsinn.

Wenn du OCR0B ändern willst, dann tue das auch, statt eine Funktion in 
einer anderen Funktion zu definieren, die das tun könnte, wenn man sie 
denn auch aufrufen würde.

von Klaus R. (klaus2)


Lesenswert?

...ich meine ja die gane funktion, nicht nur das void...

Aber, auch so geht es nicht

ISR (TIM0_COMPB_vect) {          // Timer0 - PWM Reload

  OCR0B = OCR0B_Load;


Ratlosigkeit :/

Klaus.

von spess53 (Gast)


Lesenswert?

Hi

Wie ist 'OCR0B_Load' definiert?

MfG Spess

von Klaus R. (klaus2)


Lesenswert?

...volatile unsigned int?

Und wir in der main mit den "lesbaren" PWM Werten aus dem Array 
berechnet:

OCR0B_Load = ((100-LED_W_PWM)*2-1);

...und nein, auch mit Werten <100 funktioniert es nicht (die gefährliche 
-1 fällt mir grad auf)

Klaus.

: Bearbeitet durch User
von Bastler (Gast)


Lesenswert?

Beim den PWM-Modes der AVR-Timer werden übrigens OCRnx nur zu 
definierten, für den Ablauf ungefährlichen Zeitpunkten von sichtbaren 
Register in die wirklich benutzten Schattenregister übernommen. Ein 
setzen zu einem bestimmten Zeitpunkt (per ISR) ist also garnicht 
notwendig. Einfach jederzeit reinschreiben, die HW synchronisiert das 
dann zur laufenden PWM.

von Klaus R. (klaus2)


Lesenswert?

Weiß ich, alles schon gelesen - aber selbst wenn ich in der main stumpf

OCR0B_Load = ((100-LED_W_PWM)*2);

schreibe, scheint das nur beim "Start" zu gehen, dann übernimmt er nix 
mehr.

Aber ich teste es nochmal genauer...kann also eigentlich nicht sein?

Klaus.



EDIT:

Nix...nur Dunkelheit - änder ich die Werte per Hand, macht die PWM, was 
sie soll:

  LED_W_PWM = LED_W_PWM + 1;

    OCR0B_Load = ((100-LED_W_PWM)*2);

vs.

OCRB_Load = 5; (aber da weiß ich nicht, ob das halt nur einmal 
ausgeführt wird, wenn der Interrupt initialisiert wird)

EDIT2: ...nope, er nimmt den Wert nur genau einmal direkt nach dem Init 
der Register. Dann (in der while(1) Essig...man man.

EDIT3: OK, Fixwerte, also "einfache Zahlen" werden übernommen - aber 
keine Variableninhalte. Müssen die VAR speziell initialisiert sein o.ä.? 
Ist volatile unsigned int niO?

Klaus.

: Bearbeitet durch User
von Karl H. (kbuchegg)


Lesenswert?

Klaus R. schrieb:

> EDIT3: OK, Fixwerte, also "einfache Zahlen" werden übernommen - aber
> keine Variableninhalte.
> Müssen die VAR speziell initialisiert sein o.ä.?
> Ist volatile unsigned int niO?

Doch ist es.

Zeig dein komplettes Programm. Oder eine vollständige abgespeckte 
Version.

: Bearbeitet durch User
von Klaus R. (klaus2)


Lesenswert?

...so, ich weiß jetzt auch nicht wieso, aber nun gehts.

Murphy & ich gehen jetzt schlafen, GN8.

von Karl H. (kbuchegg)


Lesenswert?

> EDIT3: OK, Fixwerte, also "einfache Zahlen" werden übernommen - aber
> keine Variableninhalte.

Quatsch

Die Syntax ist
1
    Ziel = Ausdruck;
wie der der Teil 'Ausdruck' zusammengesetzt ist, spielt keine Rolle. 
'Ausdruck' kommt mit einem Zahlenwert hoch, egal wie kompliziert der 
Ausdruck aufgebaut ist. Und dieses Ergebnis wird an das Ziel zugewiesen.

Dein job ist es, dafür zu sorgen, dass der Wert, der aus 'Ausdruck' 
resultiert auch der Wert ist, den du haben willst. Aber wie 'Ausdruck' 
aufgebaut ist, ob Konstante oder arithmetischer Ausdruck, ob mit oder 
ohne Variablen, ob durch Funktionsaufrufe zusammengesetzt oder nicht, 
spielt keine Rolle. Resultierender Wert ist resultierender Wert. Wir 
sind doch hier nicht bei BASCOM.

von Marc V. (Firma: Vescomp) (logarithmus)


Lesenswert?

Karl Heinz schrieb:
> Wir sind doch hier nicht bei BASCOM.

 BASCOM hin, C her, Assembler dort, am Compiler liegt es nicht.

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


Lesenswert?

Klaus R. schrieb:
> ...volatile unsigned int?

Dir ist aber schon klar, das der Timer 0 beim Tiny 44 ein 8-bit Modell 
ist und damit auch die OCR Register nur 8 bit breit sind? Ein
1
volatile unsigned char 
2
// oder
3
volatile uint8_t
sieht da m. E. richtiger aus.

von Horsti (Gast)


Lesenswert?

Karl Heinz schrieb:
> spielt keine Rolle. Resultierender Wert ist resultierender Wert. Wir
> sind doch hier nicht bei BASCOM.

Man möge sich nur vorstellen, Bascom hätte die gleichen Möglichkeiten 
wie C.

von Klaus R. (klaus2)


Lesenswert?

Was ist denn BASCOM? :)

Letzte Frage: Wieso bleibt bei OCR0A = 0 ein Puls von 130us überig? Den 
sieht man :( [Naja, man kann sich wunderschön die DIE-Struktur der LED 
und den fleckigen Phosphor und die Bonddrähte ansehen] - wenn ich OCR0A 
= 100 setze, geht er jedoch auf volle 100%?

Klaus.

von Klaus R. (klaus2)


Lesenswert?

Aha! ...dachte ich es mir, amn sieht es im Diagramm des DB.

FAQ

Wieso geht die LED nie ganz aus?
    Es ist normal, dass die LED selbst bei OCR1A = 0 immer noch ganz 
schwach leuchtet. Die Hardware-PWM funktioniert so, dass bei einem 
Timerwert von 0 auf jeden Fall der Ausgang eingeschaltet wird. Danach 
kommt der Compare Match bei 0 und schaltet gleich wieder aus. Daher ist 
der Ausgang für einen PWM-Takt eingeschaltet. Um das zu ändern, muss man 
entweder invertierte PWM nutzen, dann ist allerdings der Ausgang nie zu 
100% High, sondern hat immer einen Takt Low beim maximalem PWM-Wert. 
Oder man schaltet bei 0 einfach die PWM-Funktion ab und und setzt den 
Ausgang normal auf Low. [1].

Klaus.

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.