Hallo! Zum Aufbau: STK 500, ATmega 8, 8Mhz Quarz, 2 mal 74HC595, 16 LEDs. Die LEDs sollen auf und abblenden und dies mit einer jeweils zufälligen Geschwindigkeit. Mein Ansatz: Die PWM selber "bauen" und an dem jeweiligen Port der 74HC595 für je eine LED ausgeben. Das funktioniert auch bei 8 LEDs super! Es passiert genau das was passieren soll und es sieht so aus wie ich mir das vorgestellt habe. Bei 16 LEDs allerdings fängt das ganze an unangenehm zu flackern und langsam zu werden. Durch reduzieren der LEDs die angesteuert werden wird es wieder ok. Kann es sein das der Atmega am Limit operiert? Liege ich mit der Vermutung richtig das es vor allem am Einsatz des Funktion "rand()" liegt? Ist daher der Ansatz von vorn herein "Käse" da es ja am Ende auch mehr als 16 LEDs sein sollen? Vielen Dank schon mal!
also das Programm ist erstmal sehr umständlich geschrieben. Für jeden LED eine eingene funktion? Was soll das? man kann durch geschickte programmierung noch sehr viel mehr machen. Sieh das erstmal Programm als versucht, und fang noch mal von vorn an.
Hallo, unabhängig von deinem Problem: warum löst du das ganze nicht über eine Funktion, der du als Parameter die Nummer der LED übergibst? In der Funktion verwendest du dann Arrays, z.B. faktor[LED_ANZAHL] und verwendest diese faktor[LED_Nr]. LED_Nr ist hierbei dein Übergabeparameter. Das würde das Ganze vielleicht erst einmal ein bisschen übersichtlicher machen.
Da jede LED unterschiedlich schnell auf und abblendet bekommt auch jede LED eine eigene Funktion. Vielleicht nicht sehr übersichtlich aber dafür einfach nachvollziehbar.
Ich sehe nirgends den Timerinterrupt für die PWM. So kann das nichts werden. Da wäre selbst eine 3GHz CPU überfordert. Peter
Der Versuch mehr als 8 LED sinnvoll mit dem Timer anzusteuern hat nicht geklappt, was durchaus an meinem Unvermögen liegen kann. Daher ja auch der Ansatz es eben ohne Timer zu machen und die PWM selber "zu stricken" Aber ich sehe schon: Der Ansatz scheint tatsächlich nicht gut zu sein. Schade eigentlich.
Der Ansatz ist prinzipiell nicht schlecht. Peter meint, es fehlt, ein Timer, der angibt wann die LEDs erneut gesetzt werden, d.h. wann die Superloop erneut durchlaufen wird. Damit erreichst du eine von der Anzahl der LEDs unabhängige Aktualisierungsrate der Frequenz.
Commander: Ich habe deinen letzten Beitrag jetzt 10 mal durchgelesen und verstehe kein Wort. Superloop? LEDs neu gesetzt? Aktualisierungsrate der Frequenz?
Die logische Lösung wäre einfach einen Timer-Interupt im oberen kHz-Bereich. Nehmen wir mal an, Du willst die LEDs sinusförmig auf- und abblenden, dann stellst Du eine Sinus-Tabelle in das Flash. Im Pseudocode hast Du dann ungefähr das in Deiner Timer ISR: schwelle:=(schwelle+1) modulo 256; (oder ein anderer Schritt) phase1:=(phase1+frequenz1) modulo 256; (Frequenz kann eine Konstante sein) phase2:=(phase2+frequenz2) modulo 256; .... (für jede LED eine entsprechende Zeile) phasen:=(phasen+frequenzn) modulo 256; wenn sinus[phase1] dann led1 ein, sonst led1 aus wenn sinus[phase2] dann led2 ein, sonst led2 aus .... (für jede LED eine Zeile) wenn sinus[phasen] dann ledn ein, sonst ledn aus Und schon funzt das. Das Modulo 256 kannst Du weg lassen, wenn Du Variablen nutzt die 8 Bit ohne Vorzeichen sind. Das ganze sollte in Assembler sehr schnell zu implementieren sein. sinus[] ist ein konstantes Array, das sollte auch irgendwie in C gehen, welches Deine Helligkeitstabelle enthält. Du kannst natürlich die Variablen phase1, phase2,... phasen auch durch ein Array ersetzen. Somit hast Du da nur 2 kleine Schleifen. Das sollte sehr schnell durch laufen. Der Bereich mit den LEDs wird idealerweise dadurch realisiert, dass Du eine Variable für die LEDs verwendest, und da die Bits rein schiebst. Das ist aber nur eine Optimierung.
Wie oft die LEDs neu gesetzt werden, hängt im Moment von der Durchlaufzeit der Schleife ab, d.h. wenn du mehr LEDs ansprichst, braucht deine Schleife länger. Starte nach dem Setzen der LEDs einen Timer von einige ms und setze die LEDs erst neu, wenn der Timer abelaufen ist, so ist die Frequenz mit der du die LEDs setzt konstant. Mit Superloop meinte ich deine while(1)-Schleife. Der Ablauf sollte dann so aussehen: Timer_setzen(); while(1) { if(Timer_abgelaufen) { //Werte neu bestimmen Blink0(); blink1(); ... ausgabe(ausa, aus); Timer_setzen(); } }
Commander: Das werde ich mal ausprobieren. Wird dadurch das Ganze aber nicht noch langsamer? Oder verschafft dieser Trick dem Atmega mehr Zeit zum Rechnen da er keine LEDs setzen muss? Habe ich das so richtig verstanden?
Attila Ciftci schrieb: > Ist daher der Ansatz von vorn herein "Käse" Jep. Allmählich sollten wir in der Codesammlung mal eine Unterabteilung "So macht man es nicht" einrichten. Da gehört dein Programm ganz oben rein...
Das Ganze wird dadurch quasi langsamer. Aber da dein Auge ca. 15 Bilder pro Sekunde macht, sollte das kein Problem sein. Der Vorteil ist, dass die Auffrischfrequenz der LEDs damit konstant ist, da sie nur noch von der Zeit abhängt, die du per Timer einstellst. Wäre interessant, wenn du über deinen Erfolg berichten würdest. Gruß, commander
@peter: Ansätze in die Rubrik "so soll man es nicht machen" zu verschieben, bringt denen, die Programmieren lernen, gar nichts denke ich.
@Peter Dannegger: Den Beitrag hatte ich schon gefunden. Allerdings bin ich damit noch überfordert :-(
@Commander: Solltest Du noch hier mitlesen: Leider hat dein Vorschlag zu keinem brauchbaren Ergebnis geführt. Das Ganze ist tasächlich langsamer geworden. Somit das Flackern stärker. @Peter Danneger: Vielleicht magst Du mir kurz erläutern was Du mit diesem Satz meintest: "Ich sehe nirgends den Timerinterrupt für die PWM." Oder meintest Du das was Commander vorgeschlagen hat, was ja leider nicht geklappt hat? Was ist denn letzten Endes der limitierende Faktor? Ist es die Geschwindigkeit des SPI? Oder wie ich vermute: Die aufwändige Berechnung der jeweiligen "rand()" ? Wenn mir ein Profi das verraten könnte , hätte ich vielleicht die Möglichkeit mir ein neues Konzept zu überlegen. Und wenn jemand einen Tip hat wie man 24 LEDs mit einer jeweiligen zufälligen Geschwindikeit auf und abblenden kann bin ich sehr dankbar.
Nachtrag: Ich hab alle "rand()" durch einen festen Wert ersetzt. Daran liegt es schonmal nicht! Sehr interessant!
Attila Ciftci schrieb: > Zum Aufbau: STK 500, ATmega 8, 8Mhz Quarz, 2 mal 74HC595, 16 LEDs. >#define F_CPU 8000000 Hast du auch die Fuses so eingestellt? Oder läuft der Controller womöglich mit 1MHZ intern? mfg.
Thomas: Fuse steht auf EXTRCOSC_8MHZ_12MHZ_18CK_64MS Beweis: Sobald ich den Quarz entferne spinnt das Ganze nur rum. Ich habe jetzt 8 LEDs feste Werte verpasst, d.h. diese werden nicht auf und abgeblendet. Jetzt flackert auch nichts mehr. Somit liegt es nicht an SPI oder rand() Ich finde es hat was: Als Anfänger sich etwas auszudenken was einen Atmega8 an sein limit fährt. Hätte ich es mir zur Aufgabe gemacht hätte es nicht geklappt ;-)
Attila Ciftci schrieb: > Fuse steht auf EXTRCOSC_8MHZ_12MHZ_18CK_64MS >[...] Quarz [...] Ja, was denn nun? AVR Fuses
Attila Ciftci schrieb: > Fuse steht auf EXTRCOSC_8MHZ_12MHZ_18CK_64MS Da gibt es doch noch einen Clock-Divider. Was steht denn da drin? Attila Ciftci schrieb: > Als Anfänger sich etwas auszudenken was einen > Atmega8 an sein limit fährt So ein bischen LED-Geflacker mit 8, 16 oder 24 LEDs fährt den Controller nicht ans Limit. Das macht der alles hinten links in der Hosentasche. mfg.
Das Problem mit dem am Limit ist: Das Ding ist nur deshalb am Limit, weil du wie du selbst sagst noch Anfänger bist. Der Code ist schlicht Murks. T'schuldigung. Es wurde bereits auf das ganz brauchbare Beispiel hingewiesen und auch das allgemeine AVR-Tutorial ist sehr empfehlenswert. Du scheinst hier ein wenig betriebsblind geworden zu sein - keine Sorge, das kommt bei jedem mal vor. Schmeiß' deinen Code mal zur Seite und versuch das genannte Beispiel nachzuvollziehen und nachzubasteln. Das hilft dir viel mehr als an dem vermurksten Ansatz weiter zu arbeiten. Der Atmega 8 kann mehr. Deutlich mehr. Und SPI ... schau' mal ins Datenblatt des Schieberegisters. Da steht drin, wie lange die Verarbeitung dauert. Da ist noch mächtig Luft nach oben.
Ich habe jetzt mal EXTHIFXTALRES und EXTMEDFXTALRES ausprobiert. Beides ändert nichts an der Performance. Thomas: Was ist ein clock divider? Meinst Du "CKOPT" ? Damit habe ich auch rumgespielt ohne das sich was geändert hätte. Ich bin mir nicht so sicher ob mein Programm nicht doch durch ungeschicktes verballern von Resourcen den Atmega an sein Limit fährt. Der Beitrag von Peter Danneger spricht ja dafür. Auch wenn letztlich nur ein paar LEDs flackern.
@Testfall: Absolut! Meine Lösung ist die eines Anfängers die er sich beim Autofahren ausdenkt ohne viel Erfahrung mit Programier-Problemlösungstrategien zu haben. Aber letztlich ist es mir ja 100% gelungen umzusetzen was ich wollte. Hat doch auch was! :-) Du hast natürlich recht: Das Kapitel "PWM in Software" scheint die richtige Lektüre für mich zu sein:
Klar ist das der richtige Ansatz. Man muss nur den Mut haben, etwas funktionierendes weg zu packen und nochmal anzufangen. Es zeigt sich häufig: Hey, Version zwei ist ja drei mal schneller ... was ist denn anders.
Attila Ciftci schrieb: > Vielleicht magst Du mir kurz erläutern was Du mit > diesem Satz meintest: > "Ich sehe nirgends den Timerinterrupt für die PWM." 1. Eine PWM braucht zwingend einen konstanten Takt. Wenn Du sie aber in die Berechnungen reinmanscht, hast Du keinen konstanten Takt mehr, da ja diese Berechnungen keine konstante Ausführungszeit haben. 2. Eine PWM braucht eine Mindestgeschwindigkeit, damit es nicht flackert. Deine Berechnungen können aber mindestens 100-fach langsamer ablaufen. Der Timerinterrupt senkt also erheblich die CPU-Last. Wenn man Aufgaben entkoppelt und sie jeweils mit ihrer optimalen Geschwindigkeit ausführt, senkt die CPU-Last dramatisch. Außerdem verbessert das die Übersichtlichkeit. Peter
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.