Forum: Mikrocontroller und Digitale Elektronik Atmega 8 mit meinem Ansatz eines "Sternenhimmels" überfordert?


von Attila C. (attila)


Angehängte Dateien:

Lesenswert?

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!

von Peter II (Gast)


Lesenswert?

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.

von Peter II (Gast)


Lesenswert?

von hier könntst du viele teile übernehmen

http://www.mikrocontroller.net/articles/Soft-PWM

von commander (Gast)


Lesenswert?

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.

von Attila C. (attila)


Lesenswert?

Da jede LED unterschiedlich schnell auf und abblendet bekommt auch jede 
LED eine eigene Funktion. Vielleicht nicht sehr übersichtlich aber dafür 
einfach nachvollziehbar.

von Peter D. (peda)


Lesenswert?

Ich sehe nirgends den Timerinterrupt für die PWM.
So kann das nichts werden. Da wäre selbst eine 3GHz CPU überfordert.

Peter

von Attila C. (attila)


Lesenswert?

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.

von commander (Gast)


Lesenswert?

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.

von Attila C. (attila)


Lesenswert?

Commander: Ich habe deinen letzten Beitrag jetzt 10 mal durchgelesen und 
verstehe kein Wort. Superloop? LEDs neu gesetzt? Aktualisierungsrate der 
Frequenz?

von Christian B. (casandro)


Lesenswert?

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.

von commander (Gast)


Lesenswert?

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();
  }
}

von Attila C. (attila)


Lesenswert?

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?

von Peter (Gast)


Lesenswert?

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...

von commander (Gast)


Lesenswert?

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

von commander (Gast)


Lesenswert?

@peter: Ansätze in die Rubrik "so soll man es nicht machen" zu 
verschieben, bringt denen, die Programmieren lernen, gar nichts denke 
ich.

von Peter D. (peda)


Lesenswert?


von Attila C. (attila)


Lesenswert?

@Peter Dannegger: Den Beitrag hatte ich schon gefunden. Allerdings bin 
ich damit noch überfordert :-(

von Attila C. (attila)


Lesenswert?

@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.

von Attila C. (attila)


Lesenswert?

Nachtrag: Ich hab alle "rand()" durch einen festen Wert ersetzt. Daran 
liegt es schonmal nicht! Sehr interessant!

von Thomas E. (thomase)


Lesenswert?

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.

von Attila C. (attila)


Lesenswert?

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 ;-)

von Lukas K. (carrotindustries)


Lesenswert?

Attila Ciftci schrieb:
> Fuse steht auf EXTRCOSC_8MHZ_12MHZ_18CK_64MS
>[...] Quarz [...]
Ja, was denn nun?
AVR Fuses

von Thomas E. (thomase)


Lesenswert?

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.

von Testfall (Gast)


Lesenswert?

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.

von Attila C. (attila)


Lesenswert?

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.

von Attila C. (attila)


Lesenswert?

@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:

von Testfall (Gast)


Lesenswert?

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.

von Peter D. (peda)


Lesenswert?

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

von Attila C. (attila)


Lesenswert?

@Peter: Alles klar, Danke!

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.