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
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.
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
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 ;-)
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
Hi, wollt mich nur mal bedanken, dein Code funktioniert wunderbar, genau das was ich gesucht hatte! Grüße Björn
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
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
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.
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!
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.