Guten Tag,
an meinem ATMega16 haben ich einen Ausgang, den ich über einen
Variableninhalt steuern möchte.
Wenn der Variableninhalt z.B. 0xFF ist, so soll der Ausgang dauerhaft an
sein. Bei einem 0x00 dauerhaft aus und bei einem 0x80 dementsprechend
ca. 50% an.
Ich habe keine Idee wie ich die ISR gestalten müsste, damit ich dieses
Resultat erhalte.
Hat da jemand eine Lösung für?
klingt nach einer Hausaufgabe.
Deine ISR wird regelmäßig aufgerufen (Frequenz darfst du dir
ausrechnen).
In der ISR zählst du eine Veriable hoch.
Entspricht sie deinem Grenzwert, schaltest du den Ausgang um.
Irgendwann hat die Variable den oberen Grenzwert (Überlauf...) erreicht,
dann schaltest du den Ausgang wieder.
Vorher noch die Abfrage, ob der Sollwert einem deiner beiden Grenzwerte
entspricht, und entsprechend den Ausgang schalten.
Georg M. schrieb:> Tim schrieb:>> Ich habe noch alle Timer frei.>> Und warum soll das dann Pseudo-PWM sein?
Naja, "Pseudo-PWM" ist es ja sowieso nicht, auch eine in Software
realisierte PWM-Lösung ist natürlich einfach nur PWM und nix anderes.
Software PWM kann durchaus sinnvoll sein. Immer dann, wenn man viele
PWM-Kanäle braucht. Und natürlich insbesondere dann, wenn man mehr
PWM-Kanäle braucht, als die verfügbaren Timer anzubieten haben.
Oder aber auch, wenn man eine höhere Auflsung braucht, als die
verfügbaren Timer anzubieten haben.
STK500-Besitzer schrieb:> klingt nach einer Hausaufgabe.
find ich auch, daher gibts weitere Tipps auch nur auf Nachfrage wenn ein
Grundkozept steht.
Zwei Fragen hätte ich aber noch. Welche Sprache solls denn werden, und
soll es eine Fast PWM (nur hochzählen) oder eine Phase Correct PWM (hoch
und runterzählen) werden?
c-hater schrieb:> Software PWM kann durchaus sinnvoll sein.
auf nem Mega16 mit allen Timern unbenutzt und nur 8 bit eher nicht
wirklich, klingt zu sehr nach Hausaufgabe. Oder Anfänger mit
halbfertigem Ansatz, dann bitte das wirkliche Problem schildern (was
soll die PWM tun, wer ändert wann den Wert usw.) und nicht den gewählten
Lösungsweg. Dann gibt es sehr viel Aussagekräftigere Hilfe.
K. S. schrieb:> auf nem Mega16 mit allen Timern unbenutzt und nur 8 bit eher nicht> wirklich
Naja, der Kracher ist der Mega16 mit maximal 4 PWM-Kälen in Hardware
(davon nur zwei in 16Bit-Auflösung) ja nun auch nicht wirklich. Da
könnte durchaus mal der Wunsch nach einer Software-PWM aufpoppen...
> klingt zu sehr nach Hausaufgabe.
Wäre durchaus möglich. Aber ich habe ihm ja auch keinen Code geliefert,
er muss sie also immer noch alleine erledigen ;o)
Hausaufgabe? Okay. Wie putzig :)
Ich habe mir tatsächlich auch schon etwas überlegt, aber das macht
meiner Meinung nach eher weniger Sinn, weshalb ich auf das posten
verzichtet hatte.
1
volatile uint8_t percent = 40 * 255 / 100; // => 40% an, 60% aus
2
ISR(TIMER0_OVF_vect)
3
{
4
static uint8_t cnt = 0;
5
6
if(cnt >= percent) PORTA &= ~(1 << PA7);
7
else PORTA |= (1 << PA7);
8
9
cnt++;
10
}
Mir gefällt an dieser Lösung aber nicht, dass im jedem Aufruf auch die
Bedingung überprüft wird. Gibt es dafür eine elegantere Lösung?
Tim schrieb:> Mir gefällt an dieser Lösung aber nicht, dass im jedem Aufruf auch die> Bedingung überprüft wird. Gibt es dafür eine elegantere Lösung?
Die Bedingung zu überprüfen würde mich weniger stören, als jedes mal den
Port zu updaten.
Ausserdem musst du noch einen Spezialfall (entweder Dauer-low oder
Dauer-high) behandeln.
Vorschlag:
1
volatile uint8_t pwm_duty = 102; // 40% an, 60% aus
Tim schrieb:> Mir gefällt an dieser Lösung aber nicht, dass im jedem Aufruf auch die> Bedingung überprüft wird. Gibt es dafür eine elegantere Lösung?
Etliche. Praktisch alle davon wurden bereits hier oder in "Projekte und
Code" gezeigt. Das Grundprinzip bleibt allerdings immer das Gleiche. Die
verschiedenen Implementierungen unterscheiden sich nur darin, an welcher
Stelle die Bedingung geprüft wird und wie deutlich das für einen
Programmier-Laien noch erkennbar ist, dass da irgendwo was geprüft wird.
Die Prüfung an sich ist aber völlig unverzichtbar. Das liegt in der
Natur des Problems...
Tim schrieb:> Mir gefällt an dieser Lösung aber nicht, dass im jedem Aufruf auch die> Bedingung überprüft wird. Gibt es dafür eine elegantere Lösung?
naja, für nur einen 1 Kanal PWM nur bedingt:
- du nimmst einen Timer mit Overflow sowie Compare Match Interrupt, in
einem setzt du den Ausgang, im anderen löscht du den Ausgang wieder. ist
dann aber eine Hardware PWM mit Umwegen. Vorteil ist es funktioniert
auch mit mehreren PWM Kanälen, Beispiel weiter unten hier:
https://www.mikrocontroller.net/articles/Soft-PWM
- du lässt es so wie es ist, der Overhead um die ISR funktion auzurufen
ist wahrscheinlich eh länger als die ISR selber.
- Du speicherst bei Änderung der PWM 256 Werte in einem Array, und
schiebst die dann in der ISR nur raus, ist aber Aufwendiger und
ineffizienter als Testen. Weiterhin musst du die Aktualisierung dieses
Arrays synchronisieren, sonst bekommst du Glitches (und wenn du alle
interrupts währenddessen einfach anhältst kannst du auch Glitches
bekommen)
c-hater schrieb:> Die Prüfung an sich ist aber völlig unverzichtbar. Das liegt in der> Natur des Problems...
da kommst du nicht drum rum
bei 1kHz PWM und 8bit brauchst du einen entsprechend oft aufgerufenen
Interrupt, da bleibt echt kaum Zeit übrig. Rechne mal selber nach,
vergiss nicht die Zyklen für JMP/RETI und Register sichern, das wird
schon eng. Guck mal in die Listing Files vom GCC (wenn du den
Verwendest), dann siehst du wie lang die ISR wirklich ist. Daher würde
ich zu dem Ansatz mit Timer raten.