Forum: Mikrocontroller und Digitale Elektronik Moodlight Sourcecode hilfe


von Mad Mike (Gast)


Lesenswert?

Guten Abend,

ich versuche mich gerade daran ein Moodlight zu basteln. Die Schaltung 
steht soweit und jetzt ist es an der Zeit den Code dafür zu schreiben. 
Was ich suche ist jetzt eine einfache Methode die Farben schön 
nacheinander durchzufaden ungefähr so

1. Alles aus
2. Rot auf max Helligkeit faden
3. Grün auf max Helligkeit faden
4. Rot auf min Helligkeit faden
5. Blau auf max Helligkeit faden
6. Grün auf min Helligkeit faden
7. Rot auf max Helligkeit faden
8. Blau auf min Helligkeit faden
weiter bei 3.

Nur alles was ich mir ausdenke ist fürchterlich kompliziert. Mit x if 
abfragen usw. Gibts es zufällig irgendwo so einen Quellcode in C der das 
schön gelöst hat? Ich habe mir mal den Fnordliche Quellcode angeschaut. 
Der ist zwar super gemacht, allerdings für meine Ansprüche schon viel zu 
kompliziert mit Time Slots und allem drum und dran. Zudem hat das 
Fnordlicht Low Active Leuchtdioden und ich kriege das zum Verrecken 
nicht invertiert.

Grüße Mike

von blödmann (Gast)


Lesenswert?

1. Setup für Timer und Ports finden.
2. SoftPWM für Deine LED's schreiben.
3. Linearisieren/Helligkeitsanpassung der PWM.
4. Zeitabhängig die "PWM-Regler" für die Jeweils gewünschte Farbe laufen 
lassen. (Sticherwort Änderungsgeschwindigkeit)

Wo liegt Dein konkretes Problem ?

von Jürgen (Gast)


Lesenswert?

Habe das schon in ASM gemacht, mit TSOP IR-Sensor zum steuern über RC5 
FB.
Kan ich dir mailen wenn es dir was bringt.

von Mad Mike (Gast)


Lesenswert?

1. Setup für Timer und Ports finden.
kein Ding


2. SoftPWM für Deine LED's schreiben.
Auch kein Problem

3. Linearisieren/Helligkeitsanpassung der PWM.
Habe ich mir noch keine Gedanken zu gemacht. Wie lineasiert man denn am 
besten?

4. Zeitabhängig die "PWM-Regler" für die Jeweils gewünschte Farbe laufen
lassen. (Sticherwort Änderungsgeschwindigkeit)
Ich denke hier liegt das Problem. Den Ablauf schön einfach runter zu 
schreiben. Wie gesagt, ich kann mir was ausdenken, mit vielen 
Verschachtelungen und if Abfragen. Allerdings denke ich bei sowas immer 
zu komplizert. Das muss auch einfacher gehen und diese Lösung suche ich.

von Jürgen (Gast)


Lesenswert?


von Jürgen (Gast)


Lesenswert?

War zu 3 gemeint.

von Mad Mike (Gast)


Lesenswert?

Ok,

also das Linearisieren habe ich jetzt verstanden, in dem Beispiel wird 
zwar die Hardware PWM des Atmel verwendet, aber es spricht ja nichts 
dagegen seine Soft PWM mit dem selben On/Off Verhältniss zu speisen.

Jetzt musst du mir bitte noch erklären, wie man das Faden elegant löst. 
Du nennst das Stichwort Änderungsgeschwindigkeit. Mal gucken, ob ich was 
dazu hier finde, wenn ich schon Linearisierung übersehen habe.

Grüße Mike

von blödmann (Gast)


Lesenswert?

OK, also Du kannst jetzt für jede Gruppe/Farbe die Helligkeit unabhängig 
von 0 bis 100% per PWM Regeln.

Du hast schon einen (Ablauf-) Plan !
(also dein wie dein Farbspiel sein soll)

Jetzt fehlt noch die Zeit die das Faden der jeweiligen Farbe dauern 
soll.

Stell Dir vor es soll die Zeit (t) dauern eine Farbe vom Anfangswert (a) 
zum Endwert (e) zu dimmen.

Dann ist doch die Änderung (d) der Helligkeit/PWM :

d=e-a

Du willst also in t eine Änderung von d.

Du hast jetzt zwei möglichkeiten die aktuelle PWM zu berechnen:

1. Du inkrementierst den aktuellen PWM-wert um d/t bis zum ende des 
Fading Vorgangs.

2. Du berechnest den jeweiligen Wert der PWM.
(x) ist die bis jetzt vergangene Zeit.

PWM=a+(x/t*d) bzw
PWM=a+((e-a)/t*x)

auf Deutsch : PWM-wert = 
Anfangswert+((endwertPWM-anfangswertPWM)*vergangene Zeit / Dauer für 
einen durchlauf)

Wofür gilt:  vergangene Zeit <= Dauer für durchlauf.


Wieder ein Teilproblem gelöst !
Du kannst jetzt eine einzelne Farbe Ein und ausfaden.

Wenn Du das jetzt nacheinander für alle weitere Farben machst,
hast Du genau das was du willst ?!

Dein Timer stellt die benötigte Zeitbasis dar...

von Mad Mike (Gast)


Lesenswert?

Hmm,

so ganz verstehe ich die Formel noch nicht oder besser die Formel im 
Zusammenhang mit der Erklärung. Aus der Zweiten der oberen Formel lese 
ich sowas

Die Beschreibung ergibt ehr

von Mad Mike (Gast)


Lesenswert?

Mist falschen Button gedrückt, ich wollte die Vorschau...

wie dem auch sei. Was mir an der Formel noch fehlt ist zum einen noch 
der Bezug auf die das Array der Lineasierung und man bräuchte ja auch 
noch eine Formel zum rausfaden. e und a sind fest gegeben, genau wie t, 
daß einzige was man ändert ist die vergangene Zeit x oder sehe ich das 
falsch?

von blödmann (Gast)


Lesenswert?

Also ich habe jetzt vorausgesetzt das Du schon einen linearisierten 
PWM-Wert benutzen kannst.
Sprich Du hast das irgendwie implementiert :

void _set_rot_brigthnes (uint brigthness);
void _set_grün_brigthnes (uint brigthness);
void _set_blau_brigthnes (uint brigthness);

Die untere Formel ist richtg.
Sorry, schau ma auf die Uhrzeit des Post...


Wegen dem aus und einfaden habe ich extra diesen a und e wert 
eingeführt.

Du willst in einem Intervall T ein fading machen.
Die Zeit vergeht in x.
Du benötigst einen "Faktor" der quasi "die Zeit aufspannt".

x/T wird immer einen wert zwischen 0 und 1 haben, das entspricht 0..100% 
der vergangenen Zeit.


In der Zeit T möchtest Du die PWM von einem Anfangswert zu einem Endwert 
laufen lassen.
Ausgangspunkt ist also a und Du willst nach e.

e-a ergibt doch die Differenz.

Wenn Du immer ein festes Stückchen der Differenz zu a addierst, und 
immer ein festes Stückchen mehr, dann wirst Du austomatisch bei e 
landen.

Rate mal was d * x/T ergibt ?

x/T läuft von 0 nach 1.

0*d = ?
0.1*d = ?
0.2*d = ?
0.3*d = ?
0.4*d = ?
0.5*d = ?
0.6*d = ?
0.7*d = ?
0.8*d = ?
0.9*d = ?
1.0*d = ?

Jetzt hattest Du aber noch einen Anfangspunkt,
denn musst Du doch einfach nur dazu addieren...


Du hast jetzt wahrscheinlich nur das einfaden betrachtet ?!?!

Jetzt stell Dir mal von a=90 e=10 !
d wird also -80.

Was denkst Du was passieren wird ?

von blödmann (Gast)


Lesenswert?

Mach mal mit dem Array langsam...

Je nach dem wie "weit" Du Abstrahieren kannst,
löse immer nur Teilprobleme.

So ein Teilproblem ist überschaubar.


Also schreib doch einfach scon mal die Funktion umd die PWMs 
anzusteuern.
Dann packst Du obigen Dreisatz in eine Funktion.
Schreib das Programm ruhig erstmal nur für eine Farbe.

Die Abwechslung bringst du dann rein, OK ?

von Mad Mike (Gast)


Lesenswert?

Ok, ich versuche das ganze mal in nen schönen Quellcode zu packen und 
stelle den dann hier rein. Momentan kämpfe ich auch noch mit dem 
Problem, daß meine UART Verbindung stellenweise hängen bleibt und ich 
danch die Schaltung reseten muss. Mal sehn ob ich da was finde. Ist 
eigentlich stumpf der Quellcode aus den Atmel Dokumenten.

Melde mich dann wieder

von blödmann (Gast)


Lesenswert?

Bedienst Du den UART aus einer ISR heraus ?

von Mad Mike (Gast)


Angehängte Dateien:

Lesenswert?

Jep tue ich. Habe mal den Code dran gehangen, noch ist er recht 
übersichtlich.

In der includierten Einstellungen.h steht nix spannendes drin, 
Funktionsdeklarationen und halt die Werte fürs UART

#define FOSC 16000000// Clock Speed
#define BAUD 57600
#define MYUBRR FOSC/16/BAUD-1

Ich mache mich jetzt mal dran die PWM Strucktur aufzubauen und das ganze 
zu linearisieren. Gab hier ja ganz gute Beispiele in den Artikeln, muss 
halt die Linearisierung nur in die Soft-PWM verpacken.

von Thomas W. (wagneth)


Lesenswert?

Hmmm...

IMHO:

Das gewackel an den Pins geht OK.
(aber warum ein PORTA = 0;, hängt da noch was anderes dran ?)

Aber das
1
USART_Transmit('k');
 würde ich so nicht machen.

Du rufst eine Funktion auf, die in einem Interrupt Zeit "verschwendet".
(Die while schleife in USART_Transmit)
Auch wenn das in dem eher fall unkritisch ist...

QuickAndDirty kannst Du ein Flag in der While Schleife von Main 
abfragen...
(volatile nicht vergessen)
Oder Du machst das ganze mit einem UART-Sende-ISR.




Geh doch nur mal zum Spaß auf 4800 oder 9600 Baud,
das sollte für Deine belange noch (dicke) reichen.
Der Fehler bei 16 MHz wird dann kleiner...

Schau mal ins Datenblatt von deinem ATMega "Examples of Baud Rate 
Setting",
dort ist auch der Prozentuale Fehler beschrieben.

Benutzt Du ein Quarz ???

Falls nicht funktionert die Übertragung bei den angebebenen Baudraten 
stabiler, ansonsten -> Quarz dranlöten.

von Mad Mike (Gast)


Lesenswert?

Mein Atmega64 hat nen 16 Mhz Quarz dran, der sollte ausreichen um später 
mal 9 bis 12 Software PWM Kanäle ausgeben zu können.

Soft PWM habe ich jetzt auch mehr oder weniger am laufen. Ich habe das 
Beispiel aus dem Soft-PWM Artikel hier benutzt. Das erste war auch kein 
Problem einzubinden. Momentan versuche ich mich an dem dritten Beispiel, 
soll ja CPU Zeit sparen. Das klappt aber noch nicht wirklich, sobald 
mehr als 2 Kanäle gesetzt werden flackert es. Mal gucken ob ich den 
Fehler finden und dann muss ich mir gedanken machen, wie man da noch die 
Linearisierung rein bekommt.

von Mad Mike (Gast)


Lesenswert?

Ok,

der intelligente Lösungsansatz für PWM funktioniert wirklich nicht. 
Fehler kann ich so keinen Finden, auch nicht, dass jetzt noch Atmega64 
spezifisch angepasst werden müsste. Dennoch gibt es Kombinationen von 
Helligkeitsstufen die zu einem wilden geflacker führen. Keine Ahnung 
warum. Ich habe schon alles an Quellcode rausgeworfen und original den 
Code aus dem Artikel hier benutzt, nur eben die Frequenz angepasst, 
selber Effekt.

Bin ich denn etwa der erste der hier versucht eine linearisierte 
Soft-PWM für Atmegas zu schreiben?

von Thomas W. (wagneth)


Lesenswert?

Bist Du nicht...


Machs Dir nicht unnötig schwer...

Bastell Dir doch eine Timer ISR nach dem Motto :

1
volatile uint16   pwm_counter, // Gibt den Zähler für die PWM ab
2
                               // läuft bei 65535 nach 0 über
3
                               // das entspricht einer 16 Bit PWM
4
                  pwm_r, pwm_b, pwm_g; // in den Variablen werden die Grenzwerte
5
                                       // und somit das PWM-Verhältnis gespeichert
6
 
7
8
9
ISR Timer_vect ()
10
{
11
12
   if (pwm_counter > pwm_r) Pin_r = 0; //Wenn Counter > PWM_Grenzwert dann Pin aus
13
   else Pin_r=1;  // ansonsten Pin an
14
15
   if (pwm_counter > pwm_g) Pin_g = 0;
16
   else Pin_r=1;
17
18
   if (pwm_counter > pwm_b) Pin_b = 0;
19
   else Pin_r=1;
20
21
   pwm_counter++;
22
23
}

So verbrauchst Du fast immer die gleiche Rechenzeit.
Blöd ist, die Spannungsquelle wird mit spitzen belastet...

Jetzt macht das ding schonmal die "echte+reine" PWM.

Wenn du die pwm_r,g,b Variablen änderst, legst du dort nur den 
entsprechenden Wert aus der Tabelle rein.
1
void set pwm_r (unit16_t pwm)
2
{
3
 pwm_r = LogLookUpTab [pwm]; // Das ist jetzt Sau schwer ;)
4
}

Zum testen kannst Du zum einen die "reine" PWM also direkt in pwm_r 
schreiben bzw nach einem festen intervall prm_r++;

...und Dann mit der LookUp-Tabelle.

Ach, alles nur Pseudo-code...

von Mad Mike (Gast)


Lesenswert?

Ok,

so geht es auch. Allerdings gefällt mir die Version mit geringer 
Rechenzeit natürlich besser, besonders wenn man später mal 12 Kanäle 
nutzen will und nebenbei noch Daten durch die gegend schieben will. Und 
das mit der linearisierung macht mir auch immer noch etwas 
Kopfzerbrechen. Lang leben fertige Bibiotheken.

von Thomas W. (wagneth)


Lesenswert?

Nee, hab doch mal ein bisschen Ehrgeiz !

Wenn Du das selbst zusammengebastelt hast, ist das erfolgserlebnis viel 
grösser.

Habe auch noch was nachgetragen.

von Mad Mike (Gast)


Lesenswert?

Jut jut,

also du meinst eine Look-Up Table wie dieser hier zu verwenden
1
uint16_t pwmtable_16[256] PROGMEM = {0, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2,
2
                                     2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3,
3
                                     4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 6, 6, 6,
4
                                     6, 7, 7, 7, 8, 8, 8, 9, 9, 10, 10, 10, 11,
5
                                     11, 12, 12, 13, 13, 14, 15, 15, 16, 17, 17,
6
                                     18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28,
7
                                     29, 31, 32, 33, 35, 36, 38, 40, 41, 43, 45,
8
                                     47, 49, 52, 54, 56, 59, 61, 64, 67, 70, 73,
9
                                     76, 79, 83, 87, 91, 95, 99, 103, 108, 112,
10
                                     117, 123, 128, 134, 140, 146, 152, 159, 166,
11
                                     173, 181, 189, 197, 206, 215, 225, 235, 245,
12
                                     256, 267, 279, 292, 304, 318, 332, 347, 362,
13
                                     378, 395, 412, 431, 450, 470, 490, 512, 535,
14
                                     558, 583, 609, 636, 664, 693, 724, 756, 790,
15
                                     825, 861, 899, 939, 981, 1024, 1069, 1117,
16
                                     1166, 1218, 1272, 1328, 1387, 1448, 1512,
17
                                     1579, 1649, 1722, 1798, 1878, 1961, 2048,
18
                                     2139, 2233, 2332, 2435, 2543, 2656, 2773,
19
                                     2896, 3025, 3158, 3298, 3444, 3597, 3756,
20
                                     3922, 4096, 4277, 4467, 4664, 4871, 5087,
21
                                     5312, 5547, 5793, 6049, 6317, 6596, 6889,
22
                                     7194, 7512, 7845, 8192, 8555, 8933, 9329,
23
                                     9742, 10173, 10624, 11094, 11585, 12098,
24
                                     12634, 13193, 13777, 14387, 15024, 15689,
25
                                     16384, 17109, 17867, 18658, 19484, 20346,
26
                                     21247, 22188, 23170, 24196, 25267, 26386,
27
                                     27554, 28774, 30048, 31378, 32768, 34218,
28
                                     35733, 37315, 38967, 40693, 42494, 44376,
29
                                     46340, 48392, 50534, 52772, 55108, 57548,
30
                                     60096, 62757, 65535};

Dann habe ich eine 16 Bit Soft-PWM mit 256 Schritten. Kann also 3x256 
Helligkeitsstufen einstellen. Wobei die PWM eigentlich mit jeweils 
anderen Obergrenzen läuft. Hier maximal 65353.

von Thomas W. (wagneth)


Lesenswert?

Jepp, so hätte ich mir das gedacht.

...und Funktioniert es jetzt ??? :)

von Thomas W. (wagneth)


Lesenswert?

Habe mir jetzt den Artikel auch mal angeschaut... ;)
Zum ende hin hat da jemand gut nachgedacht...

Aber, versuche doch erstmal mit dem was Du kannst zu einem akzeptablen 
Ergebnis zu kommen.

PS: Vergiss erstmal 16Bit PWM ;) 10 Bit ist realistischer...

von Mad Mike (Gast)


Lesenswert?

Wenn du gerade einen Atmega64 da hast, kannst du ja mal das letzte der 
unteren Beispiele ausprobieren. Wie gesagt, bei mir geht es nicht. Bei 
machen Kombinationen für die einzelnen PWM Kanäle kommt nur noch 
geblitze raus. Ansonsten bin ich momentan nicht zum Proggen gekommen, 
vielleicht Morgen wieder.

von Mad Mike (Gast)


Lesenswert?

Ah by the way. Angenommen ich will eine 16Bit Software PWM mit 150 Hz 
Frequenz programmieren, dann gilt:

1. T=1/150Hz = 6,66 ms Periodendauer
2. 16 Bit = 65535 Stufen
3. t = 6,66ms / 65535 = 101,73 ns

Somit müsste ich also für eine 16 Bit PWM den Timer Interrupt 102 ns 
ausfühen lassen. Sollte mit nem 16 MHz Quarz wohl klappen.

Aber die Timer des Atmel laufen ja anders. Da stellt man ja nicht ein, 
nach wievielen Sekunden der Interrupt erfolgen soll, sondern der Timer 
zählt bis 16 Bit rauf und löst dann aus.

Ah verwirrt. Wie macht man das denn jetzt? Die Auflösung der PWM sollte 
doch die Anzahl der Zwischenstufen sein. Also bei 16 Bit 65535 Stufen 
innerhalb einer Periode. Dann zähle ich diese Stufen rauf und toggle 
meinen Pin beim erreichen der gewünschten Stufe. Beim erreichen von 16 
Bit wird wieder alles zurückgesetzt und das Spiel kann von neuen 
Beginnen. Nur wenn der Interrupt ja schon bis 16 Bit zählt währe das 
doch doppelt gemoppelt. Der Interrupt kommt nur alle 65535 mal und 
ebenso zähle ich 65535 Interrupts. Ist doch viel zu viel Rechenaufwand.

von Thomas W. (wagneth)


Lesenswert?

Tja, eben nicht...

Wenn Du deinen Timer aufsetzt generiert der immer nur zu einem 
bestimmten Zeitpunkt einen Interrupt,
dieser interrupt endet in deiner ISR.

Bei der Hardware PWM wird TCNTx verglichen und dementsprechend ein pin 
getoggeld. (OCx)
Das kostet keine Rechenzeit, es gibt aber nur eine begrenzte Menge an 
OCx Pins...

Der Atmega 644 hat z.b. 6 PWM-Channels.
Der Atmega 32 hat 4 PWM-Channels.
Teilweise hängen die dann auch zusammen auf einem TCNT-Zähler.

Bei Deiner Soft-PWM Kannst Du nicht das TCNTx benutzen,
denn Du bekommst von dem Gezähle nichts mit.

Wenn Du schnellere Interrupts haben willst,
musst Du den Timer nur anders einstellen.

Die ATMegas habe im übrigen verschiede Timer die man in verschieden Modi 
fahren kann. (Normal, CTC, 8/16 Bit, ISR bei überlauf oder vergleich mit 
compare Register, TCNT ist vorladbar...)
-- Siehe Artikel oder Datenblatt (ich habe mir angewöhnt nur noch die 
Datenblätter zu lesen).

Da nicht bei jedem Timer-Tick ein Interrupt ausgelöst wird,
kannst Du das TCNTx nicht benutzen.

Deshalb musst Du deinen eigenen Zähler benutzen.
Dein Timer stellt dir nur die Zeitbasis zur Verfügung.

Denk mal darüber nach :

1. Wie lange ein Taktzyklus ist
2. Wieviele Befehle in dieser Zeit ausgeführt werden können
3. Wieviel Zeit zwischen den einzelnen Interrupts vergehen darf

Im Soft-PWM Artikel stand was von rund 100 Takten,
dein Hauptprogramm braucht auch noch etwas Rechenzeit.

Da werden 16MHz recht wenig.
(schätze so 1-3Hz PWM)

Deswegen meinte ich was von 10 Bit PWM wäre realistischer.

von Mad Mike (Gast)


Lesenswert?

Das bringt mich alles nicht weiter. Sind zwar alles nette Tips, wenn man 
aber keine so richtige Idee hat wie das alles Funktioniert bringen die 
auch nix.

Aber gut, rechnen wir mit 10 Bit, damit kann man immer noch ganz gut auf 
256 Stufen linearisieren.

Also, ich will beispielsweise eine Frequenz von 150Hz haben, dann ist 
die Periodendauer. Das sind 6,66ms. Diese sollen nun mit 10 Bit 
Auflösung angesprochen werden. Sind 1024 Stufen, die zusammen 6,66 ms 
ergeben müssen. Also dauert eine Stufe ungefähr 6,5µs. Somit muss mein 
Timer alle 6,5ns einen Interrupt auslösen.

So welche Rolle spielt es jetzt, ob ich einen 8 oder 16 Bit Timer nehme?
Wie stelle ich den Timer am besten ein?
Gehe ich richtig in der Annahme, daß bei einem 16MHz Quarz ein Tick im 
Timer 62,5ns dauert. Dann müsste der Timer überlauf ja nach 100 Ticks 
geschehen?

Grüße ein inzwischen schon recht verzweifelter Mike

von Thomas W. (wagneth)


Lesenswert?

Hallo Mike,

alles wird gut so lange Du wild bist...

Ich habe nur versucht Dir den Zusammenhang zu vermitteln.
(Bin wohl kein guter Lehrer, könnte daran liegen das ich keiner bin ;))

t=1/f

Controllerfrequenz  ist 16 MHz ein Takt sollte 62.5ns dauern, richtig !

Was für einen Timer Du bei der Soft-PWM benutzt ist grundsätzlich egal,
Du musst nur auf deine gesuchte Zeitbasis kommen.

Wenn Du eine PWM-Frequenz von 150 Hz (t=6,666) haben möchtest,
musst Du während diesem t bis 1024 (2^10) gezählt haben.

Dein Timer muss also alle 6,666ms/1024=6,51µs einen Interrupt auslösen,
das geschieht also mit ca 153,6kHz -- das ist schon ordentlich.

Wie kommst Du jetzt auf diese 6,5ns ?

Du musst Dir jetzt einen Timer aussuchen,
je nach dem was verfügbar ist, ob Du die 8 oder 16 lieber magst oder 
vielleicht nach Deiner Sockengrösse.
Alles egal Hauptsache Du kommst mit dem Timer auf die 153,6kHz.

Jetzt wirst Du in das Datenblatt von deinem µC schauen müssen und einen 
Timer konfigurieren...

Alles klar ?


Wenn nicht schick mir deine Festnetznummer... ;)

von Mad Mike (Gast)


Angehängte Dateien:

Lesenswert?

Ok, verschrieben

die Zeit ist 6,51us. Ich habe mir jetzt mal die Software PWM Nr 2 aus 
dem Artikel hier eingebaut. Die läuft soweit, nur kriege ich die nicht 
auf 10 Bit erweitert. Wird ja eigentlich alles von alleine berechnet. 
Tipt man aber mehr als 256 ein gibt es einen Integer Overflow. Ok 8 Bit 
sind ja 256 aber selbst das Ändern der Variablen auf 16 Bit hilft da 
nicht. Lässt man die Berechnung für den Timer Reload Wert weg und tippt 
direkt die 156 ein gibts den Fehler nicht. Komisches Ding.

Was auch nicht klappt ist das Linearisieren. Ich habe mal den Code 
drangehangen, vielleicht fällt einem ja was ein. Das Problem ist 
folgendes. Ich habe ja ein Array definiert und weise meiner PWM dann in 
einer Schleife alle Werte zu. Wobei ich eigentlich am Maximum aufhöhre. 
Somit müsste bereits nach wenigen momenten die volle Helligkeit erreicht 
sein, alles was ich aber kriege ist nen leichtes geflimmer und weniger 
Leuchtkraft.

Grüße Mike

von Thomas W. (wagneth)


Lesenswert?

1
while(1)
2
{
3
  for(i=0;i<31;i++)
4
  {
5
  pwm_setting[0]=pwmtable[i];
6
  }
7
}

Wie lange dauert ein durchlauf der Schleife ?
Wie schnell änderst Du den Helligkeitswert ?
Wie schnell ist das komplette Array durchgelaufen ?

Was kannst Du den µC machen lassen ?

von Thomas W. (wagneth)


Lesenswert?

Forumssuche bei mir 3. Eintrag : 
Beitrag "Frage zu Soft-PWM"

von Mad Mike (Gast)


Lesenswert?

Super Thomas,

vielen Dank, daß du dir die Mühe machst und für mich die Forensuche 
kreisen lässt. Ich denke den Fehler mit der Schleife habe ich selber 
gefunden. Die Schleife wird ja permanent ausgeführt, läuft bis 32 hoch, 
bricht ab. Nun ginge es ansich weiter im Programm. Hier schlägt die 
while Schleife zu, startet die for Schleife wider neu. I wird auf Null 
gesetzt und das Spiel geht von vorne los.

Sehe ich das richtig, daß der Prescaler bei ner Software PWM nicht 
wirklich was bringt? Er teilt ja einfach nur den Systemtakt runter, 
somit werden weniger Interrups in der selben Zeit durch den Timer 
ausgelöst und man verliert an Auflösung in der PWM.

Ansonsten währe es jetzt vielleicht mal ganz interessant zum Problem mit 
dem Fading zu kommen und wie man die ganz oben genannte Reihenfolge 
möglichst elegant programmieren kann.

Grüße Mike

von Thomas W. (wagneth)


Lesenswert?

Hmmmm....

Auch wenn ich ein kleiner Misanthrop bin,
gehöre ich doch irgendwie zu den guten ;)


Hast Du denn mal ein delay (ob mit der delay.h oder über deinen 
Interrupt) in die Schleife eingebaut ???

Quasi um zu schauen ob dein Fremdcode mit deinem Frendcode (TM) 
Funktioniert ?

Wenn das ganze Funktioniert kannst Du gerne mal zwei dieser Schleifen 
hintereinander in die while Schleife packen.
(Die zweite für eine andere Farbe..)

Wie Du sicherlich weisst,
kann dein Controller mit einer Schleife auch wieder schön nach unten 
zählen.

Denke für deine Anwendung brauchst Du keine grossartige Ablaufsteuerung. 
;)

Hast Du mal im Datenblatt zu deinem Controller nachgeschaut wie die 
Timer Funktionieren ?

Wie geschrieben.
Der Interrupt den dein Timer auslöst dient nur als Zeitbasis für deine 
PWM.

Der Prescaler des Timers hat durchaus einen Sinn !

Denn wenn der Zähler der im Timer hochläuft nicht mehr ausreicht um den 
Quarz-Takt runterzuteilen,
dann nutzt man den Prescaler um diesen Takt vor zu teilen.
(Prescaler == Vorteiler)

Rechenbeispiel 16MHz / 16Bit Timer = 244Hz

Du kannst mit dem 16Bit Timer und dem Prescaler=1 keinen Takt kleiner 
als 244Hz erzeugen.
Bei einem 8Bit Timer kommst Du nicht unter 62,745 KHz...



>Ansonsten währe es jetzt vielleicht mal ganz interessant zum Problem mit
>dem Fading zu kommen und wie man die ganz oben genannte Reihenfolge
>möglichst elegant programmieren kann.


 Die Antwort ist : "42"

Was willst Du wissen ?

von Mad Mike (Gast)


Lesenswert?

Nun im ersten Posting hatte ich ne beispielhafte Reihenfolge für den 
Farbwechsel gepostet. Da ich beim Proggen immer zu kompliziert denke 
würde ich halt gerne ne einfache Lösung finden. Ich hätte ja mit x 
if-Abfragen die ganzen Zustände ausprogrammiert. Quasi eine 
Ablaufsteuerung

if rot = 0 und blau = max dann fade rot rein
ist rot = max und blau = max, dann fade blau raus

usw.

Ich wette da gibt es auch eine unkomplizeret Lösung zu.

von Thomas W. (wagneth)


Lesenswert?

Ähhh ?
1
while(1)
2
{
3
  for(i=0;i<31;i++)
4
  {
5
   pwm_setting[0]=pwmtable[i];
6
   Dein_delay(deine_verzögerung);
7
  }
8
9
  for(i=0;i<31;i++)
10
  {
11
   pwm_setting[1]=pwmtable[i];
12
   Dein_delay(deine_verzögerung);
13
  }
14
15
  for(i=0;i<31;i++)
16
  {
17
   pwm_setting[2]=pwmtable[i];
18
   Dein_delay(deine_verzögerung);
19
  }
20
21
  for(i=31;i>0;i--)
22
  {
23
   pwm_setting[0]=pwmtable[i];
24
   Dein_delay(deine_verzögerung);
25
  }
26
27
  for(i=31;i>0;i--)
28
  {
29
   pwm_setting[1]=pwmtable[i];
30
   Dein_delay(deine_verzögerung);
31
  }
32
33
  for(i=31;i>0;i--)
34
  {
35
   pwm_setting[2]=pwmtable[i];
36
   Dein_delay(deine_verzögerung);
37
  }
38
}

Was wird obiges wohl bewirken ???
Bzw, jetzt dürftest Du doch wohl alles zusammenhaben, damit es Cool 
aussieht ?!?!

von Karl H. (kbuchegg)


Lesenswert?

Wenn ich mich einmischen darf.
Mad Mike ist auf der Suche nach einer Art Tabellensteuerung mit der er 
die Farbwechsel 'progammieren' kann.

Ist machbar. Vor allem, weil er ja mit dem Timer eh schon einen 
Basistakt hat. Aber mein Vorschlag wäre: Brings erst mal so zum laufen 
und dann such nach alternativen Methoden, wie du die Farbwechsel 
codieren kannst.

So, klink mich wieder aus. Thomas ist ja eh drann.

von Mad Mike (Gast)


Lesenswert?

Ich sage ja ich mache es mir immer viel zu kompliziert g

Vom Quellcode her sieht es jetzt eigentlich gut aus. PWM ist da, 
Linearisierung ist da und auch das Fading ist schön einfach 
programmiert. Jetzt muss ich nur noch rauskriegen, warum es nicht 
richtig klappt :P

Alles was ich kriege ich nen hübsches geflacker und irgendwann bleibt 
mein Programm dann bei einer Farbe stehen. Zumindest scheint es kein 
Geschwindigkeitsproblem zu sein, denn der Fehler ist auch bei 50 und 
sogar bei nur 20 Herz PWM Frequenz präsent. Ist die Frage, ob mein 
Atmega64 zum 32er kompatibel ist. Beide haben als Timer1 einen 16 Bit 
Timer und dieser wird ja in der Soft-PWM verwendet. Ansonsten kann ich 
in den Datenblättern so keinen Unterschied feststellen. Der Atmega103 
Kompatibilitätsmodus ist auch deaktiviert. Als Quelle habe ich für 
meinen 16 MHz Quarz ext.Chrystal/Resonator High-Freq 16K CK + 64ms 
eingestellt. Damit sollte man ja definitiv auf der sicheren Seite sein 
und der Quarz sauber einschwingen.

Hmmpf moren nochmal auf meine Hardware gucken, an irgendwas muss es ja 
liegen.

von Thomas W. (wagneth)


Lesenswert?

...wollte gerade schreiben das ich nicht weiss was im moment überhaupt 
funktioniert.
Poste doch bitte nochmal schnell Deinen Source.
Wäre doch gelacht...

von Mad Mike (Gast)


Angehängte Dateien:

Lesenswert?

Jo,

hier der Quellcode. Ist schon komisch, wenn ich manuell die Werte für 
die PWM zuweise klappt es ohne flackern. Setzte ich aber alle von Hand 
auf den Höchstwert, also im Fall meiner Lookup-Table 255 bleibt die LED 
dunkel. Scheint also fast nen Problem mit dem Maximalwert der PWM zu 
sein. Das könnte das Geflacker erklären. Kannst ja mal drüber gucken, 
vielleicht fällt dir noch spontan was ein.

Grüße Mike

von Thomas W. (wagneth)


Lesenswert?

@kbuchegg

Wie bereits geschrieben,
hatte noch keine Erfolgsmeldung.

...und für einen fest vorgegebenen Ablauf gleich mit Kanonen auf Spatzen 
zu schiessen, ich weiss nicht.
Wenn das sein Wunsch ist, gehts halt weiter. ;)

Aber jetzt muss erstmal das Fading funktionieren !

PS: Das war doch keine Einmischung und wenn dann ist sie sehr 
willkommen.

von Mad Mike (Gast)


Lesenswert?

PS alles über 219 für die On-Time knipst die Lampe aus

von Thomas W. (wagneth)


Lesenswert?

Hmmm...

- Der Prolog mit den 8MHz stimmt nicht mehr, oder ?
- In main() fehlt eine Klammer (die vom While)

Du sagst wenn Du ohne pwmtable, also die reale PWM, langsam hochfährst,
geht das ganze ohne geflackere ?

von Thomas W. (wagneth)


Lesenswert?

Übernimm mal :
1
#include <avr/pgmspace.h>

...und hole die Werte aus dem FLASH mit :
1
   pgm_read_word(&pwmtable[i])


Ich denke dann Funktioniert das Programm !


Denke da liegt der Hase...
1
uint16_t pwmtable[32]  PROGMEM = {0, 1, 2, 2, 2, 3, 3, 4, 5, 6, 7, 8, 10, 11,
2
                                    13, 16, 19, 23, 27, 32, 38, 45, 54, 64, 76,
3
                                    91, 108, 128, 152, 181, 215, 254};

Das Array der LookUp Tabelle wird durch das Schlüsselwort PROGMEM im 
Flash deines Controllers angelegt,
die Funktion pgm_read_word aus progmem.h liefert den Wert der 
entsprechenden Speicherzelle zurück.

Hier könnte man sofort ein wenig Optimieren.
Die LookUp Tabelle beinhaltet keinen Wert grösser 255.
Dafür kann man auch den Datentyp uint8_t nehmen (verbraucht nur noch die 
hälfte des Speichers :)).

Die Funktion zum Auslesen heisst dann : pgm_read_byte

Wenns klappt, gehen wir an deine Ablaufsteuerung.

von Mad Mike (Gast)


Lesenswert?

Jein,

wenn ich die Werte von Hand setzt und sie unter 200 für die On-Time 
bleiben geht es recht zuverlässig. Allerdings auch nicht immer und 
gelegentlich scheint das Programm abzustürzen. Ich werde morgen mal 
deinen Tip für das Einlesen einbauen. Dann kann ich vorher nochmal die 
Hardware kontrollieren.

Was die Klammer angeht, fehlte die wohl nur im Moment des speicherns 
dieser Version. Sonst hätte der Compiler meckern müssen. Im Quelltext wo 
ich den Inhalt der While-Schleife auskommentiert habe und die Werte von 
Hand setzt ist sie jedenfalls drin.

von Mad Mike (Gast)


Angehängte Dateien:

Lesenswert?

Mist,

lässt einen doch keine Ruhe sowas. Ich habe jetzt deine korrektur 
eingebaut. Damit geht das ganze schon wesentlich besser. Richtig klappen 
tut es aber immer noch nicht. Früher oder später gerät das System aus 
den Fugen. Am Anfang fadet es noch recht hübsch, dann stellt es nach 
lust und laune Farben ein. Geht mal auf volle Helligkeit, blinkt und 
blitzt, fängt sich irgendwann vielleicht auch wieder. Wirklich komisch 
das ganze.
Wie gesagt morgen mal Hardware checken.

Anbei sonst der Quellcode wie ich den aktuell compiliert habe.

von Thomas W. (wagneth)


Lesenswert?

Das mit dem Wert von unter 200 meinst in der pwm_settings,
oder über die LookUp-Tabelle ?

Vielleicht kannst Du den Wert einmal Statisch, ohne hoch oder 
runterzählen, ausserhalb der while-Schleife setzen...

Damit würden wir den Fehler auf die Interrupt-Routine eingrenzen.

von Thomas W. (wagneth)


Lesenswert?

Wobei das hier komisch ist (siehe Kommentar):
1
ISR(TIMER1_COMPA_vect) {
2
    static uint8_t pwm_cnt=0;
3
    uint8_t tmp=0;
4
 
5
    OCR1A += (uint8_t)T_PWM; // Was macht der Cast an dieser stelle ? Ist doch 16Bittig
6
        
7
    if (pwm_setting[0] > pwm_cnt) tmp |= (1<<0);
8
    if (pwm_setting[1] > pwm_cnt) tmp |= (1<<1);
9
    if (pwm_setting[2] > pwm_cnt) tmp |= (1<<2);
10
    if (pwm_setting[3] > pwm_cnt) tmp |= (1<<3);
11
    PWM_PORT = tmp;                         // PWMs aktualisieren
12
    if (pwm_cnt==(uint8_t)(PWM_STEPS-1))
13
        pwm_cnt=0;
14
    else
15
        pwm_cnt++;
16
}


Das l_value (Register OCR1A) ist zwar 16 Bitig,
aber das r_value wird durch den Type-Cast ((unit8_t)) auf 8 Bit 
reduziert.

Solch ein Type-Cast wird zur Typumwandlung benutzt,
um zb float nach int zu bekommen.

Hier macht er genau das,
aber die errechneten 625 für T_PWM passen nicht in den Datentyp uint8_t 
(0..255).
Dein Compiler schneidet jetzt 8 Bit ab -> der Wert stimmt also nicht.

Glaube ich.


PS: Du hast doch nur "3 Farben",LED-ketten oder so an dem Controller !? 
Dann kannst Du die Abfrage pwm_setting[3] rauswerfen.

von MWS (Gast)


Lesenswert?

Also nix für ungut wenn ich mich hier einmische :-)

Mein Ding ist eher Bascom & Assembler.

Aber hier denke ich es ist gar keine gute Idee, eine Typumwandlung mit 
(uint8_t)T_PWM zu machen, wenn der T_PWM Wert laut Rechnung einen Wert 
von 625 enthält. Das gibt Murks.

Warum eigentlich nicht den CTC Mode & Prescaler nehmen ? Dann muss man 
OCR1A nicht immer nachladen.

von Thomas W. (wagneth)


Lesenswert?

Das ist doch ein aus einem Artikel geklauter Sourcecode.
Warscheinlich hatte der Schreiber von Anfang an vor die Variante 3 zu 
Programmieren.
Da ist es doch sinnvoll, oder ?

Soft-PWM

Aber Pssst... soll keiner Wissen.

von MWS (Gast)


Lesenswert?

Hm, ja...
Aber auch im Originalartikel wird immer der OCR1A mit T_PWM aufaddiert. 
Wobei das selbst da keinen Sinn macht, die Anweisung ist unnötig wenn 
der richtige CTC verwendet wird. Diese Addition kostet 102400 Zyklen/s, 
0,64% der Rechenleistung und hat für den gegebenen Zweck keinerlei 
Nutzen.

von Thomas W. (wagneth)


Lesenswert?

Hmmm... naja was soll ich sagen...

Der Schreiber von dem Artikel macht es bei allen 3 Varianten.
Warum weiss ich auch nicht...

Wer hat das denn geschrieben, dann fragen wir einfach mal nach ?
(sehe dort weder einen Namen noch ein erklärendes Kommentar)

@MWS :

Man merkt gleich das Du Assembler Programmierst ;)

Was passiert eigentlich wenn OCR1A überläuft ?
Mir kam es Suspect vor, habe es auch ehrlich nicht kapiert aber es 
scheinte zu funktionieren.

Für mich mache ich nur das was ich auch verstehe.
Bin da ein Eigenbrödler... ;)

von MWS (Gast)


Lesenswert?

Du meinst, was passiert wenn nach einer Addition mehr als 65535 
rauskommt ? Das Gleiche wie beim Überlauf eines unsigned int, Bits über 
15 werden einfach abgeschnitten, im Register steht dann der Rest des 
Überlaufs.

Prinzipiell funktioniert die Routine schon (außer der zuaddierte Wert 
wird so klein, daß der Zähler bereits weiter als der neue Wert in OCR1A 
ist).

Das Ganze ist aber wie gesagt programmiertechnisch zweckfrei, bzw. 
schädlich solange geeignetere Modi zur Verfügung stehen.

von Thomas W. (wagneth)


Lesenswert?

Vielleicht habe ich es deshalb nicht verstanden... ;)

Ich denke aber mal das es für die 3. Soft-PWM Variante doch gut 
passt.
Da muss während der Timer läuft modifiziert werden.

Stelle mir das im Normal oder CTC - Modus eher Problematisch vor.

von MWS (Gast)


Lesenswert?

Ja genau, beim dritten Beispiel ist es notwendig. Aber das zweite 
Beispiel argumentiert mit Laufzeitersparnis durch geschicktere Anordnung 
des Codes. Da fällt natürlich auf, wenn dort ein unnötiger Befehl 
drinsteht, der die Ausführungszeit verlängert statt verkürzt.

von Thomas W. (wagneth)


Lesenswert?

>Autor: Thomas W. (wagneth)
>Datum: 21.01.2009 22:30

>Das ist doch ein aus einem Artikel geklauter Sourcecode.
>Warscheinlich hatte der Schreiber von Anfang an vor die Variante 3 zu
>Programmieren.
>Da ist es doch sinnvoll, oder ?

>Soft-PWM

>Aber Pssst... soll keiner Wissen.

^--- Das hatte ich in meinem Post weiter oben gemeint...

Du hast natürlich recht, aber Mad Mike hat sich für Copy&Paste 
entschieden.
Was soll ich tun, ausser seinen Code zu "DeBugen". :)

Ich bin da eher für selber schreiben.
Nur so bekommt man ein Gefühl für die Sprache.
Auch Fehler helfen einem beim lernen.

Aber das ganze soll erstmal funktionieren.

Jetzt bin ich OffTopic...
Wenn Mad Mike das alles lesen muss wird er wirklich noch mad ;)

Gute Nacht !

von MWS (Gast)


Lesenswert?

Da hast Du recht, es ist ungemein hilfreich, wenn man weis, was man 
macht :-)

Gute Nacht.

@Mad Mike
Also ich würd' den CTC-Modus nehmen, bei:
...
    TCCR1B = 1;             // Timer läuft mit vollem Systemtakt
    TIMSK |= (1<<OCIE1A);   // Interrupt freischalten

-->    OCR1A = (uint16_t)T_PWM; // Obere Grenze des Timers einstellen

...

Dafür     OCR1A += (uint8_t)T_PWM aus der ISR löschen

Dann in die main:
...
-->    TCCR1B = 1 | CTC1;  // Timer läuft mit vollem Systemtakt &
                        // wird bei Erreichen von OCR1A zurückgesetzt

    TIMSK |= (1<<OCIE1A);   // Interrupt freischalten
....

Dann noch in die for/next Schleifen 31 statt 10 reinschreiben, denn die 
pwmtable hat 32 Werte, und so wird's nie richtig hell.

Viel Spass bei der Erleuchtung ;-)

von Thomas W. (wagneth)


Lesenswert?

@MWS
Naja, ich denke das Programm würde auch ohne CTC laufen.
Den Fehler mit dem Cast hatte ich eine Minute vor Dir gepostet,
der Zugriff auf den Flash sollte jetzt auch Funktionieren.

Aber:
Jetzt kann er schon wieder mit Copy&Paste Arbeiten.

Ich glaube nicht das er daraus viel lernt.
Less Dir den Thread mal von vorne durch...
(er weiss immer noch nicht was der CTC-Modus ist)
Sorry.

@ Mad Mike: Warte auf Deine Erfolgsmeldung... :)

von MWS (Gast)


Lesenswert?

Yup. Kannst recht haben.

Hab' oft den Eindruck hier daß lernen nicht sooo gefragt ist, eher die 
fertige Lösung zum Problem ohne viel Aufwand. Man könnte ein Sticky 
machen mit der Nachricht: RTFM

Natürlich funktioniert auch das Orginalbeispiel mit Aufaddieren des 
OCR1A, und mit der Korrektur des falschen Typecast sollte das Ding jetzt 
auch laufen.

Sollte von mir nur eine Anregung sein, sich über die Funktion des Timers 
und des CTC-Modus Gedanken zu machen, außerdem ist schon noch etwas 
Kreativität gefragt, meine Zeilen an passender Stelle einzufügen :-)

von Thomas W. (wagneth)


Lesenswert?

Neee, war doch auch nicht böse gemeint.

Will doch nur das er sich selbst mit der Lösung seines Problems 
beschäftigt.
Dann geht das nächste Projekt schon ganz alleine von der Hand. :)

IMHO:
Es liegt nicht nur an dem Fragesteller,
auch der Gefragte trägt zum Verlauf bzw der "Selbstständigkeit" (oder 
wie man das auch immer nennen will) des TEs bei.

Ich erwarte nur das der Fragende mit seiner Problematik sich aktiv 
auseinandersetzt und Fragen formuliert.

Oft finde ich beim ausformulieren einer Frage bzw. der Möglichkeiten
schon eine/mehrer Lösung des Problems.


Also wenn ich antworte will ich auch helfen. :)

von Mad Mike (Gast)


Lesenswert?

Sehr gut, weiter so g
Ich verkrümele mich gleich mal hinter mein Oszi und checke die Hardware. 
Denn ansich sollte man ja erwarten können, daß hier quasi als 
Musterlösung präsentierter Quellcode auch funktioniert. Das es bei allen 
3 irgendwie flackert ist schon komisch. Deshalb checke ich nochmal meine 
Hardware, daß kann ich wenigstens im vergleich zum programmieren. Danach 
gehe ich mal die ganzen Tips hier durch und melde mich dann wieder. Aber 
zur allgemeinen Beruhigung, daß mit dem OCR1A aufaddieren war mir auch 
aufgefallen und ich fragte mich nach dem Sinn. Da kommt dann aber wieder 
der Punkt mit dem Mustercode. Das steht da, also muss es funktionieren 
g

von Thomas W. (wagneth)


Lesenswert?

Hmmm...

Denke Deine Hardware ist OK.
Wenn Du mit :
1
 PORTA=255;

Deine LEDs zum leuchten bekommst dürfte alles OK sein.

Denke dieses "verschlucken"-Problem kommt von dem Type-Cast in der ISR.
Der muss vom Typ
1
(uint16_t)
 sein...

Wenn Du noch die funktion
1
pgm_read_word ()
 benutzt sollte dein Programm Funktionieren !

Melde Dich ;)

von Mad Mike (Gast)


Angehängte Dateien:

Lesenswert?

So,

es wird immer besser. Jetzt fadet er schon ein paar mal sauber rauf und 
runter bevor das wilde Geflacker wieder anfängt. Ich habe den Quellcode 
mal nach MSW Vorschlag abgeändert. Wobei seine Zeile

TCCR1B = 1 | CTC1;

nicht laufen wollte, CTC1 sei unbekannt. Ich habe das Register dann mit 
einer 9 geladen, sollte das selbe Ergebniss sein. Was das Geflacker 
angeht, so habe ich auch schon einen Verdacht. Das könnte wirklich an 
der Hardware liegen. Wenn ich den Port ändere und weg von meiner 
High-Power LED mit Treiber IC gehe kann ich immer schön die PWM messen. 
Gleich mal ein paar normale LEDs an den Port klemmen und gucken was 
passiert. Wobei nen Hardwarefehler im LED Chip währe komisch, den wenn 
der nebenbei auf voller Power läuft klappt die Schaltung auch. Sehr 
misteriös. Also ihr kümmert euch im die Software und ich nehme mir die 
Hardware zur brust g

Anbei die letzte Software Version. Melde mich wieder wenn ich die 
Hardware zerlegt habe.

von MWS (Gast)


Lesenswert?

@Mad Mike,

ja CTC1 heist auch WGM12 und ist Bit3 des TCCR1B, somit ist 9 richtig.

Sehe keinen Fehler mehr, einfach mal verschiedene Haltepunkte in die 
for/next Schleifen reinsetzen um zu sehen, ob die while Schleife 
wenigstens einmal komplett durchläuft, oder wo's sonst klemmt.

Ansonsten HP LED mit weniger Saft betreiben, sehen ob's an 
Spannungseinbrüchen liegt. Was ist das für ein LED Treiber ? 
Schaltregler ?

von Mad Mike (Gast)


Lesenswert?

Moinsen,

es scheint wirklich an der Hardware zu liegen. Ich habe das ganze jetzt 
mal auf einen Atmega8 geproggt und der macht PWM Kanäle ohne Probleme. 
Nur ganz aus gehen die LEDs nicht. Das liegt aber wohl an der 
for-Schleife.

for(i=31;i>0;i--)

geht ja nie wirklich auf Null, da Null zum Abbruch der Schleife führt 
und nicht mehr geladen wird, schreibe ich jedoch

for(i=31;i>=0;i--)

fängt die LED beim erreichen von 0 wieder an zu flackern und es geht 
nicht weiter. Dabei ist die 0 in der Look Up Table ja sauber definiert. 
Verstehe ich gerade nicht so ganz. Kann der Wert für i vielleicht nicht 
negativ werden, so dass die Abbruchbedingung nie erfüllt würde?

Was die High-Power LED angeht, so werde ich mal versuchen die 
Spannungsversorgung zu puffern. Ich denke diese 350mA Sprünge pro Kanal 
können nicht schnell genug geliefert werden

von Thomas W. (wagneth)


Lesenswert?

Software sollte OK sein (habs natürlich nicht auf der Hardware 
getestet).
Jedenfalls sehe ich keine Fehler mehr.

Wenn Du nur 3 Farben/Ausgänge verwendest kannst Du

Was ist das für ein Treiber den Du verwendest ?


By the way: Du kannst das Array pwm_settings eins kleiner 
Dimensionieren, und auch die if-Abfrage in der ISR rausnehmen.

Ändere doch auch mal den Prolog mit den 8MHz ;)

In Main.c :
1
    // Timer 1 OCRA1, als variablem Timer nutzen
2
   OCR1A += (uint16_t)T_PWM;
3
    TCCR1B = 9;            // Timer l�uft mit vollem Systemtakt und CTC1
4
    TIMSK |= (1<<OCIE1A);   // Interrupt freischalten

Was machst Du denn da mit dem OCR1A ?
Wieso Addierst Du, mach doch nur eine Zuweisung,
das wirkt unsauber.



Weiss jetzt grad nicht ob OCR1A mit 0 Vorinitialisiert wird oder schon 
einen Wert != 0 enthalten kann.
Dabei kannst Du gleich in das (1<<WGM12) ersetzen.



Mach doch mal einen Schaltplan von dem was Du aufgebaut hast.
(Multiple-Bugs g)

von Mad Mike (Gast)


Lesenswert?

Äh ja das += gehört da gar nicht hin, blödes copy und paste.

Schaltplan gibt es zu der Schaltung natürlich schon längst, auch ne 
geätzte Platine ist vorhanden, sonst ist Löten von Fine Pitch immer ne 
qual. Das Treiber IC ist ein AS3691

http://www.austriamicrosystems.com/eng/Products/Lighting-Management/LED-Drivers/AS3691

Quasi ein 4 Fach Linearregler mit max. 400mA pro Kanal. Ist ansich ein 
ganz einfacher Baustein, sollte aber Reflow gelötet werden, da 
Kühlfläche auf der Unterseite. Ich schmeiß den gleich mal unter die 
Röntenkamera bei uns im Labor und gucke ob die Reflow Lötung geklappt 
hat. Toll wenn man das gesammte Labor seiner HW Abteilung zur Verfügung 
hat, gelle g

von Thomas W. (wagneth)


Lesenswert?

Ich erblasse vor neid...

...und ja die Schleife wird nie null.

Der Plan sollte doch für uns werden...

Bin wirklich blass. ;)

von Mad Mike (Gast)


Lesenswert?

Ja, wenn du mal was geroutet und geätzt haben musst, melde dich g
Kleine Wiedergutmachung für die Nerven, die du in meinen Quellcode 
gesteckt hast

von Mad Mike (Gast)


Lesenswert?

Ich sitze bei EADS in der Hardwareentwickelung,

habe mit Software also eigentlich so rein gar nichts am Hut. Mache das 
ganze jetzt zum privaten Vergnügen.

Also der Chip ansich sieht gut verlötet aus. Jeder Kanal für sich 
funktioniert auch wunderbar, erst wenn man 2 zusammen benutzt gerät das 
System aus den Fugen. Vielleicht ist der Chip intern zerstört, mal sehn 
ob ich einen neuen Auflöte, die sind schwer wieder runter zu kriegen. 
Mal an einen anderen Port ausprobieren, was der mit normalen LEDs macht. 
Dann hätte ich den Fehler definitiv auf die Hardware begrenzt.

Grüße Mike

von Thomas W. (wagneth)


Lesenswert?

Das mit der Software ist kein Problem...


Du hast sicherlich schon die Spannungen an den wichtigen Punkten 
Oszilloskopiert ?

Vielleicht sind die Pulse etwas viel für Deine Spannungsquelle ?

Welchen Chip meinst Du, µC oder Treiber ?
(wahrscheinlich beide)


"Typische Sachen" wären nicht alle der 3xGND/2xVCC/1xAVCC Pins 
verbunden.

Laut Datenblatt ATMega64 ist AVCC allerdings nur die Spannungsversorgung 
für PortF, sollte aber trotzdem verbunden werden. (Datasheet Seite 7)

Ist die Spannung am Reset-Pin stabil bei 5V ?

Was für einen Programmer benutzt Du ?

von Mad Mike (Gast)


Lesenswert?

Also ich habe es jetzt auf einen Hardwarefehler runterbrechen können. 
Mit Low Current LEDs an einem anderen Port tut das ganze einwandfrei. 
Tja, da muss ich wohl noch mal ne runde Datenblätter lesen.

Die Versorgungsspannung jedenfalls ist stabil. Es ist ehr der Treiber IC 
der Probleme macht. Na ja, wird schon werden. Die Software PWM mit 
Linearisierung tut jedenfalls. Jetzt könnte man noch überlegen, wie man 
schöne verläufe hinbekommt.

Mike

von Mad Mike (Gast)


Lesenswert?

Ok,

es wird echt zu spät. Wenn ich die Farben nicht fade sondern fest 
einstelle, macht die PWM keine Probleme. Ist es vielleicht doch kein 
Hardware fehler, aber warum geht die Software dann Problemlos auf einem 
anderen Port oder uC? Das spricht für Hardwarefehler, dass bei fester 
Farbe die Lampe geht spricht für Software.

Man ey, so was einfaches und ich finde den Fehler nicht, zum kotzen. Na 
ja morgen mal gucken. Jetzt wird erstmal ne Runde mit dem Laser gespielt 
^^

von Thomas W. (wagneth)


Lesenswert?

...schade um die schöne Platine !
Nur interessehalber, wie hast Du gelötet ?

Neee, Laser-Reflow ?!



Also wenn es direkt mit einem anderen Port funktioniert sollte es die 
Hardware sein.
Entweder der Port des µC oder Dein Treiber.

Wenn es mit einem Kanal geht, würde ich eher auf Spikes oder 
schwächelnde Versorgung zu wenig Blockkondensatoren oder sowas tippen.


OK, Mike liebt also die Abwechslung...

Zuerst müssen wir planen wie das ganze aussehen soll.

Soll immer nur eine Farbe gefadet werden ?
Also reicht es abwechselnd Farben ein und auszublenden ?


Überlegen wir mal was wir alles brauchen...

Jemand der Regie führt -- Eine Tabelle in der Zeiten und Helligkeiten 
abgelegt werden.

Eine Zeitbasis -- Wir wollen etwas in Abhängigkeit der Zeit verändern.

Was muss jetzt alles in einen Datensatz rein ?

1. Welche Farbe
2. Dauer,
3. Anfangswert,
4. Endwert, des Fadings
5. Pausenzeit

Solch einen Datensatz kann man in einem Struct kombinieren.
Nun kann man ein Array von diesem Struct erzeugen.

In dieser Struktur kann man nun auf einfache weise den gesamten Ablauf 
speichern (Für Fading nacheinander).

von MWS (Gast)


Lesenswert?

Mad Mike,

die Seite über den Led Treiber gibt nicht genug Info über die Specs, 
bist Du sicher, daß Du diesen Treiber im Rahmen seiner Specs betreibst ?
Probier doch mal folgendes, ist nicht viel Arbeit im Falle es nicht 
geht:

...
    if (pwm_cnt==(uint8_t)(PWM_STEPS-1))
       {
        pwm_cnt=0;
-->       sync_now = TRUE
    else
        pwm_cnt++;
...


...
uint8_t i=0;
-->  static int8_t sync_now = FALSE
while(1)
{
  for(i=0;i<32;i++)
  {
-->  while(! sync_now); // Auf Sync warten (1/100 sec)
       pwm_setting[0]=pgm_read_byte(&pwmtable[i]);
         sync_now = FALSE;
           //  _delay_ms raus !
  }
usw...
...

Nagel mich nicht auf die Syntax fest, kann's nicht testen. 
Möglicherweise gibt's in C ein Boolean, dann nimm den anstatt des int 
für den sync_now.

Klar was das macht ? Jedesmal wenn ein PWM Zyklus zu Ende ist wird das 
sync_now gesetzt, die while Schleife vor der for(i=0... wartet bis das 
geschehen ist und schreibt dann erst einen neuen Wert in die 
pwm_setting, damit findet kein Wechsel während des PWM Zyklus statt, ist 
also nun synchron dazu. Möglicherweise zickt Dein Treiber bei 
unregelmässiger PWM. Allerdings wärst Du mit dieser Methode auf maximal 
die F_PWM festgelegt, mit dem Du die Werte hochzählst. Gegenüber Deiner 
_delay_ms(10) Version würde sich aber nix ändern, denn 1/100 Hz = 10ms.

von MWS (Gast)


Lesenswert?

Nochmal nachgedacht, bin nicht mehr sicher, ob mein Ansatz Sinn macht, 
aber probier's immerhin aus.

Noch etwas, hab' ich gerade nachgelesen: In ISR & main verwendete 
Variablen in C müssen volatile deklariert werden.

Also static int8_t sync_now = FALSE nicht in die ISR, sondern als 
volatile int8_t sync_now unter globale Variablen.

von Thomas W. (wagneth)


Lesenswert?

Hmmm...

Denke der Knackpunkt ist nicht der Zugriff auf den Flash,
es kann ja nur an der Zuweisung liegen !

Aber ein Byte überträgt der AVR doch in einem Rutsch, oder ?
(8Bit als 8 Bitter ?!!?)

@MWS : Wie sähe das denn in Assembler aus ? (die Zuweisung)

Ob der neue PWM-Wert ein oder zwei PWM Perioden später aktualisiert wird 
dürfte nur bei sehr niedrigen Werten bis garnicht auffallen...

Denke das ist es nicht.


Zumal das Programm an einem anderen Port mit anderer Beschaltung 
Funktioniert.

Ich Tippe auf Hardware/Versorgung.

(http://de.wikipedia.org/wiki/Ockhams_Rasiermesser)

Ein nicht ganz frischer Wagneth.

PS: Das Datenblatt ist wirklich nicht so "auskünftig"...

von Mad Mike (Gast)


Lesenswert?

Also ich gehe eigentlich auch von einem Hardwareproblem aus, nur ist es 
irgend so ein kleiner fieser Fehler, der sich nicht finden lässt. Aber 
das kriege ich noch raus, ich kann nen Flugzeug fliegen lasse aber keine 
Lampe zum leuchten bringen, währe doch gelacht.

Die Lötstellen sahen sowohl unter dem Mikroskop, als auch unter der 
Röntgenkamera gut aus. Das interne Chip Bonding weißt auch keine Fehler 
auf. Thermalkamera zeigt keine ungewöhnliche Wärmeverteilung. Analyse 
der Spannungsversorgung zeigte Schwankungen beim Schalten der Frequenzen 
im Bereich von max 0,2V. Stromanalyse und analyse auf Oberwellen in der 
Spannungsversorgung bin ich noch nicht zu gekommen, aber die LED mit nem 
Elko zu puffern schien das ganze ehr noch schlimmer zu machen. Als 
nächstes werde ich mal den Belastungsgrad des Treibers ändern. Da er ja 
mit einem Kanal und 350mA wunderbar läuft, könnte er mit 3x30mA 
vielleicht auch tun, wenn ja ist es definitiv ein Problem in der 
Spannungsversorgung.
Was ich auch noch testen könnte, wie sich der Treiber IC verhält, wenn 
ich ihn mit nem Frequenzgenerator ansteuer. Da haben wir ein paar schöne 
programmierbare hier, mit denen kann man auch PWMs durchfaden g

Aber das muss bis nach der Arbeit warten, jetzt muss ich erstmal wieder 
meinen Chef glücklich machen.

PS hier ein Link zum vollständigen Datenblatt des AS3691
http://www.datasheetarchive.com/pdf-download/Datasheet-025/DSA00435991.html

von MWS (Gast)


Lesenswert?

Welche Zuweisung ? pgm_read_byte(&pwmtable[i]) ? Die schaut aber gut 
aus, genauso wie's sein soll. Und klar werden da nicht Bits einzeln 
übertragen, der neue Wert steht entweder bereits in der pwm_setting wenn 
die ISR zuschlägt, oder eben auch nicht, dann wird der alte Wert 
verwendet.

Wie in Assembler ? Da gibt's nur Befehle für Zugriffe entweder auf den 
normalen Speicherbereich oder auf die IO Register. Sowas wie Progmem 
gibt's da nicht, das ist speziell eine C Anweisung.

Wenn ein schneller Wechsel der PWM Werte stattfindet und der mit etwa, 
aber eben nicht genau mit der F_PWM, kann's schon ungewohnte Effekte 
geben. Um das auszuschließen mein Vorschlag zur Synchronisierung.

Würd' auch um den Fehler einzukreisen Zug um Zug solche Programmteile 
wie die Anpassung rausnehmen und einfach schreiben
for(i=255;i>0;i--), pwm_setting[2]= i, usw.

@Mad Mike, Datenblatt für den Treiber hab' ich gefunden, ist die 
Versorgung des MC bei Deiner Schaltung von der Versorgung des Treibers / 
der LED entkoppelt ?

von Thomas W. (wagneth)


Lesenswert?

Ich wollte auf den Grund raus, warum das Sync da rein sollte ?!

Ich meinte das funktion pgm_read keine Probleme damit hat,
höchstens die anschliessende Zuweisung.

Ein Byte wird entweder vor dem nächsten Interrupt Zugewiesen,
oder danach. Das sollte nicht schaden.

Probelem gäbe es ja zb nur wenn er 16Bit übertragen würde...
Dann könnte es vielleicht sein das nur Low oder High - Byte Übertragen 
würden.

Das würde zum Fehlerfall führen, ev. sein Flackern.

Ich dachte da könntest Du uns mit deinen Assembler-Kenntnissen 
aufklären...


Aber er überträgt immer nur ein Byte. Da dauert die Zuweisung doch 
bestimmt nur einen Takt, oder ?
Das war die Frage !

Drücke ich meine Gedanken unverständlich aus ?


PS: Ich schrieb Byte, und bezog mich auf den Grund warum da ein Sync 
rein muss/sollte. Habe Dich so interpretiert als ob es bei der Zuweisung 
zu Problemen kommt. Aber bei einen einzelnen Byte kann der Interrupt 
doch nicht sazwischen kommen !? Sorry.

von Mad Mike (Gast)


Lesenswert?

@MSC
Die Chips sind mit den üblichen Maßnahmen, wie Blockkondensatoren, 
sauberer VCC und Masseführung usw. ausreichend von einander entkoppelt. 
Die Spannungsversorgung für den AS3691 ist auch nicht so spannend. 
Besser ist die Frage nach der Vorsorgung der LED. Die hängt zwar am 
selben Netzteil, wird aber bis zur LED über eine eigene Leitung direkt 
versorgt. Wie gesagt, daß VCC Signal schwankt max. um 0,2V und das kommt 
einfach durch die sprunghafte Belastung der Stromquelle. 
Pufferkondensator könnte abhilfe schaffen, tut er aber nicht so ganz. 
Ich denke inzwische, daß der AS3691 vielleicht nicht sauber auf die 
Groundplane gelötet ist und somit nen Strom über 350mA nicht abführen 
kann. Ich werde später mal den AS mit Frequenzgeneratoren ansteuern, 
dann herscht Klarheit über den µC als Fehlerquelle.

@Thomas
Ich habe inzwischen den Grund gefunden, warum die for-Schleife nicht 
tut, wenn man sie auf >=0 setzt. Schleifen werden erst immer 
inkrementiert/dekrementiert, bevor die neue Bedingung getestet wird. Bei 
mir ist die Zählervariable aber als unsigned integer definiert und das 
kann nicht negativ werden. Ist die Schleife also bei 0 angekommen ist 
die Prüfbedigung gültig, i müsste nun auf -1 gesetzt werden, damit bei 
der nächsten Prüfung die Schleife abbricht. -1 Ist für uint halt aber 
nicht zulässig.

von MWS (Gast)


Lesenswert?

Nö, hab' Dich schon verstanden, während des Interrupts kommt sicher nix 
dazwischen, außer man macht das absichtlich so. Bei einer 16 Bit 
Zuweisung würde man den Interrupt disablen und nachher wieder enablen.

Das ist auch nicht mein Punkt. Aber ein Zyklus dauert 256 Schritte , die 
werden 100mal in der Sekunde durchlaufen, jetzt nimm mal an der PWM Wert 
wird in der {main} 300mal pro Sekunde geändert, dann würde Änderungen 
innerhalb dieser 256 Schritte vollzogen. Wie denkst Du würde das PWM 
Signal am Port aussehen ?

Das würde natürlich davon beeinflusst. Jetzt sagt mir mein Verständnis 
vom Programmablauf, daß das im Ergebnis nichts machen dürfte, aber lass 
doch nur Spikes auf dem Port entstehen und der Treiber fängt dann an zu 
zicken. Das ist meine Gedanke dahinter.

Ist Dir übrigens aufgefallen, daß diese PWM eine Schwachstelle hat ? Der 
Port kann zwar komplett auf Low gehen, aber nie auf High, er wird selbst 
beim PWM Wert 255 Spikes von 39us nach Low haben. Die Bedingung 
pwm_setting[x] > pwm_cnt kann nämlich für pwm_cnt 255 nie zutreffen, der 
Port geht da immer auf Low, was er eigentlich nicht dürfte. Und daraus, 
zusammen mit dem asynchronen Zuweisen der PWM Werte könnten besagte 
Probleme im Treiber entstehen, während eine normale LED das wegsteckt.

Zu synchronisieren ist möglicherweise auch nur ein Schuss ins Blaue, 
aber wie gesagt, ist wenig Arbeit diese Sync reinzuschreiben. Ich geh so 
vor, wenn ich nicht weiterweis, daß ich solche Tests anstelle und dann 
schau was passiert.

von MWS (Gast)


Lesenswert?

Mad Mike,

ich glaube man wäre auf der sicheren Seite wenn man dem Atmel eine 
eigenen Spannunsregler mit Glättung verpassen würde. Aber das muss nicht 
der Grund sein. Probier mal testweise, was ich zur Software geschrieben 
habe.

von Mad Mike (Gast)


Lesenswert?

So,

fehler gefunden würde ich mal sagen. Der Chip war nicht sauber mit 
seiner Massefläche auf GND verbunden. Das hat dann wohl dazu geführt, 
daß er bei hohen Strömen, also meheren Farben nicht mitgespielt hat. Das 
ganze Teil nochmal in den Reflow Oven gepackt und ordentlich warm 
gemacht, kurz mit ner Pinzette runtergedrückt und abkühlen lassen. Jetzt 
läuft die Lampe. Die Farbwechsel sind stellenweise noch etwas "hart". 
Ich werde mal die Snychronisation einbauen, vielleicht bringt das was 
verbesserung.

von MWS (Gast)


Lesenswert?

Prima, gratuliere, freut mich das es geht.

Ob eine Synchronisation den Farbwechsel verbessert, würd' ich 
bezweifeln. Aber probier's aus und sag' uns das Ergebnis.

Denke es könnte mehr Sinn machen, die Funktionen für den Farbwechsel zu 
ändern (statt for/next Schleifen)

Grüsse

Magic White Smoke

von Mad Mike (Gast)


Lesenswert?

Jup,

danke danke. Also die Snychronisation hat soweit nix gebracht. 
Interessanter währe jetzt vielleich dein Einwand daß die PWM nie völlig 
Hight ist. Könnte man doch recht einfach lösen, indem man die PWM nur 
mit 254 Schritten macht, oder?

@Thomas

struct fade
{
uint8_t farbe;
uint8_t anfang;
uint8_t ende;
uint8_t dauer;
uint8_t pause
};


struct fade this[x];

das sollte deinem Vorschlag entsprechen. Ist die Frage, legt man sich 
auf eine maximale Anzahl Farbwechsel fest oder macht man es dynamisch 
mit malloc. Dann müsste man sich auch noch um die Speicherverwaltung 
kümmern, sauber einketten, ausketten, löschen und vielleicht auch noch 
wo der µC es speichert. Denn die Zellen im Eeprom darf man ja nicht so 
oft beschreiben.

von MWS (Gast)


Lesenswert?

Ja das geht, ist zwar wie ich denke nur ein Schönheitsfehler und hat 
nichts mit dem gleich- oder ungleichmässigen Faden zu tun.

if (pwm_cnt==(uint8_t)(PWM_STEPS-2))
...

Viel mehr zu tun hat damit, daß Du eine PWM mit 256 Schritten durch die 
Anpassung über die pwm_table auf 32 Schritte reduzierst. Da siehst Du 
halt dann die Stufen. Entweder eine größere pwm_table verwenden, oder 
mal eine Formel stricken, welche die table nachahmt, kostet halt 
Rechenzeit. Aber noch hast Du. Schätze mal, bei 8 MHz bleiben für das 
Gefade noch 60-70% Prozessorzeit übrig.

von Thomas W. (wagneth)


Lesenswert?

Klasse mit dem Fehler. :)

--
 Der PWM-Fehler

 Der Fehler Beträgt ca 0.392 % bei 8 Bit.
 Bei 10Bit ca 0,098 %

 Naja der Vergleich in der ISR sieht so aus :


 Setting > Counter = ?
 255 > 0   = 1
 255 > 1   = 1
 255 > 2   = 1
 ...
 255 > 253 = 1
 255 > 254 = 1
 255 > 255 = 0

 256 > 255 = 1   // Spinnerei aus meinem Hirn.

 Da hilft auch die Schrittweite nicht wirklich weiter.

 Als evil-fix könntest Du am Anfang ein Setting++; machen.
 Das Tastet die Schrittweite nicht an, Du verschwendest nicht mehr 
Rechenpower mit einer weiteren Abfrage innerhalb der ISR und bei 0 
ändert sich nichts.
 Kostet allerdings Speicher für dickere Variablen.
 ...und Du musst die PWM-Werte über eine Funktion ändern,
    oder das ganze zusammenlegen.

 Aber, Du hast deine 0% und 100 %. Wobei die 0% da schon wichtiger sind 
;)
 Wenn es Funktioniert wie ich es mir denke.

 Untestet :
1
void Set_PWM (uint8_t ch,pwm_set;)
2
{
3
 if (pwm_set > 0) pwm_settings [ch] = ++pwm_set;
4
 else pwm_settings [ch] = 0;
5
 return;
6
}

--

Wenn das Fading sauber werden soll musst Du mit dem PWM_steps hochgehen,
momentan benutzt Du eine 8Bit-PWM.

Versuche doch mal die 10Bit Variante.
Leider musst Du alle beteiligten Variablen und die LookUp-Tabelle 
ändern.

Laut Artikel machen die 2 Bit nicht viel aus, aber man kann es mal 
Probieren.

Die 16Bit Variante dürfte mit der Rechenzeit nicht mehr hinkommen.
(2 Takte für die ISR ist def. zu kurz)


Vielleicht kannst Du mit den Werten der LookUp ein bisschen vermitteln.
Das könnte das ganze ein wenig "verschmieren".

---

An PortA kann man auch keine Hardware-PWM betreiben :(
Das wären PortE+B, dann hättest Du mit der Hardw.PWM Rechenzeit ohne 
ende.

---

Für Farbe hätte ich vielleicht ein enum genommen.
Aber eigentlich egal...
1
typedef struct    {
2
        enum      {
3
              rot  = 0, 
4
              blau = 1, 
5
              gruen= 2
6
            } farbe;
7
        uint16_t  dauer,
8
            pause;
9
        uint8_t    startPWM,
10
            stopPWM;
11
12
      } _FADEREC;
13
_FADEREC FaderAr[10];

Wenn Du ansonsten keine Anforderungen hast auf zum Nächsten Punkt.
Willst Du im laufenden Betrieb per UART, Taster o.ä. den Ablauf 
verändern ?

Bei einem festen Muster würde ich das ganz im Flash unterbringen.
(genauso wie die LookUp-Tabelle)

Wenn das ganze per UART o.ä. nachgeladen werden soll bleibt Dir nur noch 
EPROM oder RAM.
Im EPROM würde die Fad-Daten auch nach einem Reset noch liegen.
(immerhin würde das für ca 256 Fadings reichen)

100.000 Schreibzyklen sind schon ein wenig. Da musst Du viel mit 
spielen.

Auswerten würde ich das Array mit einem Zähler und einem switch-case 
gerippe.

Edit : PWM_Table ist von den Stufen eigentlich schon am Limit.(die 
vielen doppelten Werte...)

von Mad Mike (Gast)


Lesenswert?

Hardware PWM fällt aus, da das Teil eigentlich für 12 Kanäle gedacht 
war. Das ist quasi der Prototyp und später mache ich ne neue Platine wo 
dann alles fertig drauf kommt. Man muss ja erstmal gucken, ob man mit 
dem Treiber zurecht kommt.

Ansonsten hast die Platine einen FTDI drauf der die Lampe dann per UART 
steuern können sollte. Andere Dinge, die möglich währen. DMX, Touchpad, 
IR Fernbedienung, Sound2Light. Was es halt so an netten Spielerreien 
gibt. Aber in erster Linie währe Fading mit PC Anschluss schon mal toll.

Ich gehe jetzt mal hin und schraube die PWM auf 10Bit rauf und mache die 
Look Up Table größer.

von Thomas W. (wagneth)


Angehängte Dateien:

Lesenswert?

Morgen Mike,

hab im Anhang mal eine bisschen rumgespielt.


Vielleicht reicht Dir so ein einfaches Konstrukt.
(Du musst daran aber noch richtig Arbeiten)

Wenn Du gerne mal mit dem PC ein neues Schema einspielen willst, würde 
ich es erstmal im RAM des Controllers ablegen.
(zumal der 2x so gross wie das EPROM ist)

Mit einem "Befehl" per UART könnte man das ganze in das EPROM 
übertragen.


Überlege Dir doch mal wie lange die Pausen bzw Überblendzeiten sein 
sollen !?

Den demnach würde ich einen Timer auslegen so das daß uint8_t für die 
Maximale Dauer ausreicht...


---

Solch ein switch-case mit einem kleinen Ringpuffer eignet sich auch für 
das auswerten von deinem UART-Datenstrom.

Nach dem Motto :

Befehl "a" heisst neuen Datensatz emfpangen,
in Zeile 3 überschreiben,
Befehl "rot",
Dauer 100,
StartPWM = 0,
EndPWM = 9999 ...

oder

Befehl "r" heisst vielleicht Daten von EPROM nach RAM   übertragen.
Befehl "e" heisst vielleicht Daten von RAM   nach EPROM übertragen.
Befehl "p" heisst vielleicht Play.
...

Jetzt bist Du gefordert... :)


Grüße
  Thomas

PS: Erinnerst Du dich noch an die Formel vom Anfang ?

von Mad Mike (Gast)


Lesenswert?

Man Thomas,

ich glaube wenn das Teil richtig läuft, musst du mir mal dein Adresse 
geben. Dann kriegst von mir auch so ne Platine, wenn du schon den halben 
Quellcode dafür schreibst.

Was den Timer angeht, so würde ich mal sagen 10 Sekunden sind da mehr 
als ausreichend. Fading im 10 Sekunden takt ist ja schon sehr gemütlich. 
Somit währe laut der Rechnung in deinem Quelltext die Interrupt dauer 
auf ungefähr 40ms festzulegen. Sollte mit einem Prescaler wohl machbar 
sein. Bedeutet aber auch, daß das schnellste Fading 40ms dauert. So, ein 
Tick dauert 62,5ns. Ich will mit nem 8 Bit Timer auf 40ms kommen, kann 
also nur bis 256 zählen. 40ms/256 = 156,25µs / 62,5ns = 2500. Ok passt 
nicht, bei nem 16 Bit Counter würde ein Prescaler von 10 reichen, könnte 
man also mit 8 machen.

von Thomas W. (wagneth)


Lesenswert?

Siehst Du einen Unterschied bei der 10Bit PWM ?


Hmmm...

40ms entsprechen 25Hz.

Mit Timer0 kommen wir laut :
t= (Prescaler*TimerTicks)/Fclk
t=16,32ms

Zählbar mit 8Bit bedeutet ca 4,16s
Zählbar mit 16Bit bedeutet ca 1069s ^= 17 Minuten
Irgendwie ist das blöd.
Ausserdem würden wir Rechenzeit für die zusätzliche ISR "verschwenden"
(rein und raus aus der ISR -- weiss aber nicht wieviel das ausmacht)
---

Neuer Ansatz:

Die vorhandene ISR Arbeitet mit 25,6 KHz.
Aber die PWM Arbeitet doch mit 100Hz das entspricht 10ms...

Wenn wir mit 255 zählen kommen wir auf 2,55s
Wenn wir mit 65535 zählen kommen wir auf 655,35s

Angenommen die PWM würde nur mit 60Hz laufen...

Da kommen wir mit einem von Zähler 255   auf 4,25s
Da kommen wir mit einem von Zähler 65535 auf 1092s


Schlüssel wäre also diese Stelle :
1
...
2
    if (pwm_setting[0] > pwm_cnt) tmp |= (1<<0);
3
    if (pwm_setting[1] > pwm_cnt) tmp |= (1<<1);
4
    if (pwm_setting[2] > pwm_cnt) tmp |= (1<<2);
5
    if (pwm_setting[3] > pwm_cnt) tmp |= (1<<3);
6
    PWM_PORT = tmp;                         // PWMs aktualisieren
7
    if (pwm_cnt==(uint8_t)(PWM_STEPS-1))
8
        pwm_cnt=0;                          //Hier kann man die 100Hz abgreifen 
9
    else
10
        pwm_cnt++;
11
}

Es dürfte also geschickter sein mit einer 16Bit-Variable zu Timern...
1
volatile unit16_t mood_timer; // Zähler ist Global
2
3
...
4
    PWM_PORT = tmp;                         // PWMs aktualisieren
5
    if (pwm_cnt==(uint8_t)(PWM_STEPS-1))
6
    {
7
        pwm_cnt=0; 
8
        mood_timer++;
9
    }
10
    else
11
        pwm_cnt++;
12
}


Eine andere Lösung wäre noch verrückter:
1
uint8_t mood_timer;
2
3
ISR(TIMER1_COMPA_vect) {
4
    static uint8_t pwm_cnt=0;
5
    static uint8_t mood_prescaler=0; // ein Prescaler !
6
7
    uint8_t tmp=0;
8
9
    if (pwm_setting[0] > pwm_cnt) tmp |= (1<<0);
10
    if (pwm_setting[1] > pwm_cnt) tmp |= (1<<1);
11
    if (pwm_setting[2] > pwm_cnt) tmp |= (1<<2);
12
    if (pwm_setting[3] > pwm_cnt) tmp |= (1<<3);
13
14
    PWM_PORT = tmp;                         // PWMs aktualisieren
15
16
    if (pwm_cnt==(uint8_t)(PWM_STEPS-1))
17
    {
18
        pwm_cnt=0;
19
        mood_prescaler++;
20
21
        if (mood_prescaler>=3) //wir zählen von 0..3 = 4 * 10ms
22
        {
23
           mood_prescaler=0;  // Unser "prescaler" faktor 4 wird hier zurückgesetzt 
24
           mood_timer++;      //...und unser Timer "aufgeladen" somit haben wir ca 4*10ms pro step.             
25
        }
26
27
    } else pwm_cnt++;
28
}

Denke das wäre eine passable Lösung :)
Bei der in der Tabelle 16-8 Bit "gespart" blieben.

Wenn Du jetzt das Timing ändern willst, hängt aber alles andere mit 
dran.

PS: Bräuchte Deine EMail Adresse...

von Mad Mike (Gast)


Lesenswert?

Hmm,

ich krige die PWM nicht vernünftig auf 10 Bit umgebaut. Habe zwar die 
passenden Variablen auf 16Bit erhöht, aber bei den höheren Stufen der 
PWM (also die mit mehr On-Zeit) fängt es an zu flackern. Mal gucken, ob 
ich rauskriege für welche PMW Werte da anfangen problematisch zu werden.

von Mad Mike (Gast)


Lesenswert?

Ach, ich glaube ich weiß schon. Muss ja jetzt dann auch Word lesen und 
nicht nur Byte, wenn ich auf mein Linearisierungs Array zugreifen will.

von Thomas W. (wagneth)


Lesenswert?

Solche Erkenntnisse können einem den ganzen Tag versauen,
man macht den Fehler dann aber auch in 100Jahren nicht mehr. ;)

von Mad Mike (Gast)


Angehängte Dateien:

Lesenswert?

Jap,

nur zu dumm, dass es nichts gebracht hat. Bei 10 Bit läuft die PWM nicht 
sauber durch und einen wirklichen Fehler kann ich nicht erkennen. Am 
Anfang dimmt sie noch schön rein und bei größerer On-Time tickt sie dann 
aus.

von Mad Mike (Gast)


Lesenswert?

Ok, vergess es. Ich habe den Fehler gefunden. Man sollte auch sicher 
sein, daß man wirklich alle benötigten Werte auf 16 Bit umgestellt hat. 
Jetzt habe ich eine wirklich schöne 10 Bit PWM.

Ok, also zurück zum Thema. Ausprogrammieren der Farbverläufe.
Thomas hast mail

von MWS (Gast)


Angehängte Dateien:

Lesenswert?

Mad Mike,

wenn Du dann einmal Deine ganzen Farbverläufe hast und feststellst daß 
Dir die Rechenleistung ausgeht, (Du verwendest momentan ca. 50% davon) 
dann kannst Du den Lösungsansatz verwenden den ich hier programmiert 
habe. Allerdings in Basic, sollte aber verständlich sein.

Dir wird aufgefallen sein, daß zwischen den 64 Werten für die Anpassung 
auf die Kennlinie des Auges und den 1024 Schritten Deiner PWM eine 
ziemliche Verschwendung von Rechenleistung liegt.

Mein Programm macht das Gleiche wie Deines, hat auch eine Dynamik von 
10bit und 64 Schritte, verwendet allerdings bereits 8 Kanäle und braucht 
geschätzt 1/20 der Rechenleistung Deiner einfachen Lösung, ohne daß es 
recht kompliziert ist.

Der Assemblerteil ist so effizient wie möglich, sollte Dein C-Compiler 
da mehr Code für die ISR erzeugen, so wäre die Einsparung noch etwas 
größer.

von Mad Mike (Gast)


Lesenswert?

Ich bin scho umgestiegen auf die intelligente Software-PWM Lösung. Die 
dürfte selbst bei den 10 Bit auf denen sie momentan läuft nur gute 2% 
Rechenzeit brauchen

von MWS (Gast)


Lesenswert?

Na dann viel Spass beim Proggen der Farbverläufe, halt' uns über Dein 
Ergebnis auf dem Laufenden.

Gruss

Ludwig

aka MWS

von MWS (Gast)


Lesenswert?

Seh' gerade noch, daß ich durch copy/paste Fehler in meinem Quelltext 
habe, Du hast das sicher schon korrigiert:

ORI       R21,&b00001000 ab Label NoPAB3 muss natürlich auch die 
restlichen Ports ansprechen, also

ORI       R21,&b00010000
...
ORI       R21,&b00100000
...
usw.

Hatte die PWM ursprünglich auf 4 Kanäle geschrieben und für Dich auf 8 
Kanäle erweitert - und schon ist der Bug drin :-)

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.