Forum: Projekte & Code 8-Bit Software PWM für mehr als 8 Kanäle


von Paul H. (powl)


Lesenswert?

Da man eine funktionierende PWM immer gebrauchen kann um mal ein 
schnelles LED-Projekt aufzuziehen habe ich mir mal den Soft-PWM Artikel 
angeschaut. Allerdings war ich zu "faul" den Code durchzupflücken und 
hab mir eine eigene PWM geschrieben. Das widerspricht sich zwar nun aber 
meine Priorität lag beim Lerneffekt durch das Selbstschreiben.

Das ganze ist sicherlich noch optimierungsfähig aber es funktioniert auf 
meinem ATmega8 bei 8Mhz Systemtakt mit 122Hz PWM-Frequenz.

Es können theoretisch soviele Kanäle wie freie Portpins mit einbezogen 
werden. Wenn man noch einen weiteren Port einbeziehen will muss man an 
den entsprechenden Stellen den Code selbst dazuprogrammieren, ist 
allerdings hauptsächlich eine Sache von Copy&Paste.

Die CPU-Last ist nicht besonders hoch. Verwendet werden können alle 
Controller die einen Timer besitzten, der zwei Compare-Register besitzt 
und im CTC-Modus laufen kann.

Das Demoprogramm lässt eine Sinuswelle auf 10 LEDs laufen die an PB0-PB7 
und PC0-PC1 gegen Masse angeschlossen sind.

lg PoWl

von Paul H. (powl)


Angehängte Dateien:

Lesenswert?

Blöde Sache mit dem Anhang hier.. dann eben als Zip beide in einem.

Hier ist das ganze auch nochmal als Version für einen einzigen Port mit 
maximal 8 Kanälen.

von Paul H. (powl)


Angehängte Dateien:

Lesenswert?

Hier nochmal mit 3 Ports und 22 Kanälen. Baut das mal auf, ist wirklich 
schön anzusehen :-)

Über Feedback (konstruktive Kritik) freue ich mich natürlich!

lg PoWl

von Paul H. (powl)


Angehängte Dateien:

Lesenswert?

Noch mehr Anhang

von Bernhard M. (boregard)


Lesenswert?

Was ist denn ".3gp" jetzt schon wieder für ein Format?
Unter Linux sagt file dazu:
1
file sinedemo22.3gp
2
sinedemo22.3gp: ISO Media, MPEG v4 system, 3GPP
und Xine konnte es (allerdings ohne Ton) abspielen, aber mich würde doch 
mal interessieren, wo das herkommt ;-)

von Paul H. (powl)


Lesenswert?

Das kommt von meinem Handy, die meisten Handys speichern ihre Videos in 
3gp. Das hat irgendwas mit MPEG4 zu tun, glaub ich zumindest. Der 
Qualität und der Dateigröße nach zu Urteile kann die Komprimierung aber 
nicht wirklich so hypergut sein.

Ton ist im Video eh keiner drin ausser den Geräuschen die ich beim 
Filmen mache ;-)

lg PoWl

von Björn V. (froghut)


Lesenswert?

Hi,

wollt mich nur mal bedanken, dein Code funktioniert wunderbar, genau das 
was ich gesucht hatte!

Grüße

Björn

von Paul H. (powl)


Angehängte Dateien:

Lesenswert?

Bitte bitte, wollte schon immer mal was coden, das es wert ist, in die
Codesammlung gestellt zu werden :-)

Leider hat sich da noch ein Denkfehler eingeschlichen. Da sind ein paar 
unnötige Codezeilen drin, ausserdem noch ein weiterer Fehler, den ich 
noch nicht ganz ergründet hab.

Hier nochmal die drei korrigierten Versionen.

Wenn man bei der 3-Port die Delay-Zeit in der while-schleife auf 10ms 
setzt dann stockt das ganze ziemlich seltsam. Mit 9ms und 8ms 
funktioniert es dann komischerweise wieder, unterhalb 8ms stockt es 
wieder. Es ist zwar möglich, dass durch die PWM-Frequenz von 122,5Hz hin 
und wieder mal ein Schritt übersprungen wird aber stocken sollte da 
eigentlich nichts.

Interessanterweise hilft es, wenn man der COMPB-ISR etwas Arbeit abnimmt 
indem man die Masken schon in der pwm_update-Funktion negiert. Ich komme 
allerdings nicht drauf was die Ausführzeit der ISR mit der 
Updatefrequenz zu tun hat.

lg PoWl

von Hansi C. (honsey)


Angehängte Dateien:

Lesenswert?

Paul,

erstmal vielen Dank für den Code. Funktioniert wunderbar. Ich habe ihn 
umgeschrieben für einen ATMEGA1280 und würde gerne 56 LEDs antreiben. 
Leider funktioniert das nicht so wie ich mir das wünsche. Sie blinken 
nur nach einem sehr komischen Rhytmus – alle gleichzeitig.

Was mache ich falsch?

Vielen Dank,
Hans

von Paul H. (powl)


Lesenswert?

Puh, du benutzt da wirklich verdammt viele Ports. Ich schätze mal, dass 
die ISR einfach total überfordert ist und dadurch andere Ereignisse 
blockiert. Hast du mal versucht den Code zu simulieren? Wenn ein 
PWM-Zyklus durchlaufen wird, müssen an dessen Ende die Zeiger getauscht 
werden. Im ungünstigsten Fall muss das nach einem Timer-Takt erledigt 
sein, da dann wieder der neue PWM-Zyklus anfängt. Du könntest den 
Prescaler des Timers jetzt versuchsweise mal ganz hoch setzen um zu 
gucken ob es dann wenigstens normal läuft. Außerdem steht da irgendwo 
noch
1
  /*
2
  // Der ISR etwas Arbeit abnehmen
3
  for(uint8_t i=1; i<(CHANNELS + 1); i++)
4
  {
5
    ptr_PORTA_main[i] = ~ptr_PORTA_main[i];
6
    ptr_PORTB_main[i] = ~ptr_PORTB_main[i];
7
    ptr_PORTC_main[i] = ~ptr_PORTC_main[i];
8
  ptr_PORTD_main[i] = ~ptr_PORTD_main[i];
9
  ptr_PORTE_main[i] = ~ptr_PORTE_main[i];
10
  ptr_PORTF_main[i] = ~ptr_PORTF_main[i];
11
  ptr_PORTG_main[i] = ~ptr_PORTG_main[i];
12
  ptr_PORTH_main[i] = ~ptr_PORTH_main[i];
13
  ptr_PORTK_main[i] = ~ptr_PORTK_main[i];
14
  ptr_PORTL_main[i] = ~ptr_PORTL_main[i];
15
  }
16
  */

Da machst du die Kommentarzeichen mal weg und hier
1
ISR(TIMER1_COMPB_vect)
2
{
3
  pwm_cycle++;
4
5
  PORTA &= ~ptr_PORTA_isr[pwm_cycle];
6
  PORTB &= ~ptr_PORTB_isr[pwm_cycle];
7
  PORTC &= ~ptr_PORTC_isr[pwm_cycle];
8
  PORTD &= ~ptr_PORTD_isr[pwm_cycle];
9
  PORTE &= ~ptr_PORTE_isr[pwm_cycle];
10
  PORTF &= ~ptr_PORTF_isr[pwm_cycle];
11
  PORTG &= ~ptr_PORTG_isr[pwm_cycle];
12
  PORTH &= ~ptr_PORTH_isr[pwm_cycle];
13
  PORTK &= ~ptr_PORTK_isr[pwm_cycle];
14
  PORTL &= ~ptr_PORTL_isr[pwm_cycle];

ersetzt du jedes PORTX &= ~ptr_PORTX_isr[pwm_cycle]; durch PORTX = 
ptr_PORTX_isr[pwm_cycle];

Soweit ich mich daran erinnern kann, was ich da damals gemacht hab, 
müsste das zu ner Verbesserung verhelfen.

von Hansi C. (honsey)


Lesenswert?

Hey Powl,

leider hat das alles nicht so geklappt, aber eigentlich sollte das ja 
möglich sein, oder? Alleine die doppelte Rechenleistung (16Mhz) sollte 
doch die doppelten Bänke aushalten, oder?

Notfalls hat der ATMEGA1280 auch noch 3 weitere 16Bit Timer an Board. 
Ich kann mir leider keinen Reim machen, wie man das Programm verändern 
müsste, um mehrer Interrupts zu nutzen… (Bringt das eigentlich was?)

Merci & Tsschüss!

von Paul H. (powl)


Lesenswert?

Nein, da du nur einen Prozessor hast. Ob du die Aufgaben in drei ISRs 
oder in eine packst dürfte egal sein.

Ich kann dir da jetzt leider nicht helfen, das war schon eine ganze 
Weile her seitdem ich mich das letzte mal damit beschäftigt hatte und 
auch da habe ich nicht ergründen können warum da teilweise so seltsame 
Phänomene auftreten.

Versuch doch mal schrittweise jeweils einen Port hinzuzufügen und guck, 
ab wann es nicht mehr funktioniert. Und simulier das mal im AVR 
simulator oder sowas, wenn das geht (ging bei mir damals leider nicht, 
das AVR studio war einfach zu buggy). Eventuell kollidieren da halt noch 
irgendwelche Interrupts miteinander. Anders kann ich mir das nun auch 
nicht erklären. Vielleicht dauert auch die Update-routine immens lange 
bei den vielen Ports.

Eventuell lässt sich das alles auch noch optimieren. Die Update-Funktion 
könnte vielleicht auch ein Double-Buffering vertragen. Während durch die 
ISR die Zeiger getauscht werden kann nicht geupdated werden bzw. während 
geupdated wird können keine Zeiger getauscht werden.

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.