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.
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.
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.
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
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
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
...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
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.
...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.
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
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
...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
...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.
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
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.
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
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.
...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.
...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
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.
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
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
...so, ich weiß jetzt auch nicht wieso, aber nun gehts. Murphy & ich gehen jetzt schlafen, GN8.
> 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.
Karl Heinz schrieb: > Wir sind doch hier nicht bei BASCOM. BASCOM hin, C her, Assembler dort, am Compiler liegt es nicht.
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.
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.
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.
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.