PWM & Timer ISR mit einem Counter?

OP #3786514
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.
(Firma: matzetronics) #3786674
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.
Gast #3786930
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.
Gast #3786953
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
OP #3787425
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.
OP #3787509
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.
Gast #3787603
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
#3787621
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.
OP #3787812
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.
Gast #3787829
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
OP #3787853
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.
Gast #3787943
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.
OP #3787950
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.
#3787991
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.
OP #3789077
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.
OP #3789339
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.

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren