Guten Tag,
ich versuche eine Software-PWM zu implementieren:
1
TIMSK|=((1<<OCIE0)|(1<<TOIE0));
2
OCR0=10;
3
TCCR0=(1<<CS00);
4
sei();
5
// ...
6
7
// in einer Endlosschleife dann:
8
if(pwm_duty!=i2cdata[1]){
9
pwm_duty=i2cdata[1];
10
cli();
11
OCR0=pwm_duty;
12
sei();
13
}
14
15
// ..
16
17
ISR(TIMER0_COMP_vect){
18
PORTA&=~(1<<PA7);
19
}
20
21
ISR(TIMER0_OVF_vect){
22
PORTA|=(1<<PA7);
23
}
Irgendwie aber ändert sich, unabhängig davon ob OCR0 nun 0x00 oder 0xFF
ist, die Helligkeit der angeschlossenen LED kaum.
Sieht jemand einen Fehler im Code?
spess53 schrieb:> Du hast weder den PWM-Mode noch die COM-Bits (beides in TCCR0A)> eingestellt.
Ihm will ja auch kein PWM Modus.
Und die COM Bits sind hier flüssiger als Wasser.
Denn es soll in der ISR mit einem anderen(?) Pin gewackelt werden.
(warum auch immer)
thomas schrieb:> Sieht jemand einen Fehler im Code?
Und du hast den Code bis zur Untestbarkeit verstümmelt.
Auch der µC ist (warum auch immer) geheim.
Stimmt. Das war natürlich dumm von mir. Ich habe einen ATMega16.
Im Anhang befindet sich lauffähiger Code, der sich schon nicht so
verhält wie erwartet.
In der Zeile:
OCR0 = 0xFF;
Egal ob dort 0x00 oder 0xFF steht, die Helligkeit ändert sich kaum.
Versuchs mal mit:
OCR0 = 0x01;
Statt
OCR0 = 0x00;
Und du wirst sehen!
Übrigens:
Bei einem Teiler von 1, gehen ca 12% der Takte für die ISR drauf.
Diese 12% fehlen dir dann an beiden Enden des Einstellbereiches.
thomas schrieb:> Sowohl bei 0xFE wie auch bei 0x01 sieht das Signal jeweils gleich aus.
Das kann ich nicht bestätigen.
Teste allerdings mit einem Mega328P
S. Landolt schrieb:> Also bei mir läuft das auf einem ATmega16
Das glaube ich nicht. Ganz sicher jedenfalls nicht über den gesamten
Wertebereich. Es ist zwar im Detail noch etwas komplizierter, als von
"Arduino Fanboy D." dargestellt, aber seine Grundaussage ist absolut
zutreffend: die Laufzeit der ISRs schränkt den mit dieser naiven
PWM-Methode tatsächlich abbildbaren Wertebereich ein, bei Prescaler 1
sogar in einem recht dramatischen Umfang.
Ich würde mal darauf tippen, dass du deine Testmethode nicht richtig
durchdacht hast...
Das vom TO gezeigte Oszillogramm ist jedenfalls absolut realistisch,
hier spielt eben noch ein Detail mit, was der Fanboy nicht bedacht hat:
1*100/256 = 0,4% und: 0,4% << 12%. Er wollte wohl primär die
Singularität bei gleichzeitiger Auslösung der beiden Interrupts
darstellen, die es obendrein auch noch gibt...
c-hater schrieb:> Das glaube ich nicht.
Ist der Timer des Mega16 denn so vom Timer des Mega328P verschieden?
Klar, etwas andere Register und ihre Bezeichnungen...
Aber die Grundfunktion?
c-hater schrieb:> Das vom TO gezeigte Oszillogramm ist jedenfalls absolut realistisch,
Ja?
Denn ich sehe bei mir dort einen großen Unterschied zwischen 0x01 und
0xFE
Arduino Fanboy D. schrieb:> Ist der Timer des Mega16 denn so vom Timer des Mega328P verschieden?> Klar, etwas andere Register und ihre Bezeichnungen...> Aber die Grundfunktion?
Naja, man könnte sagen, der Timer0 des M16 ist eine stark vereinfachte
Variante dessen, was du vom M328 kennst. Kann nicht alle Modi, hat nur
einen PWM-Kanal. Aber die Grundfunktionaltät ist dieselbe.
Wie übrigens bei den meisten AVR8-Timern. Solange nicht Asynchronität
zur MCU in's Spiel kommt ist das alles ziemlich die gleiche Soße, mit
nur geringen Variationen.
c-hater schrieb:> Aber die Grundfunktionaltät ist dieselbe.
Also ist der Test auf einem Mega328P aussagekräftig.
c-hater schrieb:> 1*100/256 = 0,4% und: 0,4% << 12%. Er wollte wohl primär die> Singularität bei gleichzeitiger Auslösung der beiden Interrupts> darstellen, die es obendrein auch noch gibt...
Was das heißen soll, ist mir ein Rätsel.
Mit Pin wird in der ISR gewackelt.
Also geht die ISR Laufzeit voll ein
c-hater schrieb:> Naja, man könnte sagen, der Timer0 des M16 ist eine stark vereinfachte> Variante dessen, was du vom M328 kennst. Kann nicht alle Modi, hat nur> einen PWM-Kanal. Aber die Grundfunktionaltät ist dieselbe.
Ergänzung: Das Problem der Singularität hängt vom Timer-Modus ab. Mal
liegt sie bei 0, mal bei 1. Das könnte der entscheidende Unterschied
sein.
Besser wäre also, die Testpunkte auf 2 und 0xFE zu legen. Dann sollte
sich in jedem Fall ein invertiertes Oszillogramm für die beiden
Testpunkte ergeben, allerdings in beiden Fällen mit viel zu langem Puls.
Das ist dann die Laufzeit der ISRs.
> die Testpunkte auf 2 und 0xFE
Wenn der compare match auf 2 erfolgt ist die Overflow ISR noch lange
nicht fertig.
Erst bei OCR0 Werten von über 0x20 zeigt sich eine Verlängerung des High
Pulses.
Vergleichbares gilt für hohe Werte, nur dass dann eben die Overflow ISR
verzögert wird.
Der konkrete Wert ist sicherlich auch von der
Optimierungsstufe/Kompilerversion abhängig.
Arduino Fanboy D. schrieb:> Erst bei OCR0 Werten von über 0x20 zeigt sich eine Verlängerung des High> Pulses.> Vergleichbares gilt für hohe Werte, nur dass dann eben die Overflow ISR> verzögert wird.
So isses.
> Der konkrete Wert ist sicherlich auch von der> Optimierungsstufe/Kompilerversion abhängig.
Nicht, wenn man in Assembler programmiert. Dann kann man ganz genau
vorhersagen, wie sich die Scheisse verhalten wird und ist nicht auf
Raterunden angewiesen.
Wenn man das tut, fallen einem allerdings auch diverse Tricks ein, das
Verhalten zu verbessern. Der allerbeste davon lautet allerdings: man
benutzt dieses naive PWM-Schema erst garnicht...
Es gibt ja schließlich reichlich bessere Lösungen für Soft-PWM. Sogar
etliche in C...
In diesen Forum findet man massig funktionierende
Codebeispiele.
Warum sind viele nicht in der Lage diese als Grundlage für ihre eigenen
Ideen zu nutzen.
Alleine schon der Lerneffekt ist nicht zu verachten.
Daneben sollte man nicht im Nebel herum stochern, sondern das Dateblatt
vollständig lesen.
Koofschüttel...
Manchmal frage ich mich, muss das wirklich sein?
Es gibt genug günstige Prozessoren, die haben eine Hardware PWM-Einheit.
Da werden ein halbes Dutzend Register gesetzt, und der Rest geht
automatisch.
Alternativ gibt es bei Reichelt I2C Dacs für 76 Cent. Da brauche ich
mich auch nicht um die Glättung zu kümmern.
Warum muss immer die billigste CPU genommen werden, und dann verkrampft
eine SW von Anfängern entworfen werden?
Nur einen Euro mehr, und man hätte keine Probleme.
c-hater schrieb:> man benutzt dieses naive PWM-Schema erst garnicht...
Da hat man schon so eine schöne Hardware PWM, und dann wird sie so
sträflich ignoriert.
Das auch mir schon ein wenig weh.
c-hater schrieb:> Nicht, wenn man in Assembler programmiert.
Ja, man kann das Problem mit Assembler etwas optimieren.
So wie man aus jedem Problem das Maximum raus holen kann.
Aber schöner wirds dadurch auch nicht.
PittyJ schrieb:> Manchmal frage ich mich, muss das wirklich sein?> Es gibt genug günstige Prozessoren, die haben eine Hardware PWM-Einheit.
Natürlich muß das nicht sein, haben die AVR8 ja auch. Und nicht nur
eine, sondern mehrere, manche sogar ganz schön viele.
Bloß wollte der TO die halt aus unerfindlichen Gründen nicht benutzen...
thomas schrieb:> cli();> OCR0 = pwm_duty;> sei();
Zugriffe auf 8bit Register sind immer atomar. Die Kommandos cli() und
sei() bewirken hier nichts hilfreiches.
Das wird allerdings nicht die Ursache deines Problems sein.