Hallo,
ich möchte trotz unzähliger Beiträge dazu, die bereits hier verfasst
wurden, dieses Thema nochmals anbringen.
Grund ist die mir "noch" fehlende Performance bei Ansteuerung mehrerer
LEDs.
Ich verwende den MSP430F149 mit dem CCE von TI. Ziel soll es sein, bis
zu maximal 10 LED Gruppen unabhängig voneinander in ihrem
Helligkeitsverlauf dynamisch zu steuern. Dadurch sollen verschiedene
Lichteffekte erreicht werden. Gleichzeitig soll auch ein Dauerbetrieb
jeder Gruppe möglich sein. Die Auswahl soll über Taster erfolgen und
eine Rückmeldung über ein angeschlossenes Display. Display und Taster
sind soweit kein Problem. Die eigentliche Funktionalität auch nicht, nur
aktuell habe ich jetzt 2 Gruppen im Code implementiert und grenze jetzt
schon an der Sichtbarkeitsgrenze der PWM Wiederholfrequenz. Der µC läuft
aktuell mit 4MHz aus dem DCO: siehe code:
PeriodLenght_1=2000;//Änderungsgeschwindigkeit des Dimmens
267
PeriodLenght_2=2000;
268
269
270
WDTCTL=WDTPW+WDTHOLD;// Stop WDT
271
272
Set_DCO();
273
274
init_PORTS();
275
init_Timer_A();
276
277
278
_EINT();//Enable Interrupt global
279
280
281
282
283
while(1)
284
{
285
286
Process();
287
288
289
switch(arg++)
290
{
291
case0:
292
293
294
295
break;
296
297
298
299
case1:
300
301
302
303
break;
304
305
case2:
306
307
308
break;
309
310
case3:
311
312
313
314
break;
315
316
default:
317
318
arg=0;
319
320
break;
321
322
323
}
324
325
}
326
327
}
328
329
330
// Timer A0 interrupt service routine
331
#pragma vector=TIMERA0_VECTOR
332
__interruptvoidTimer_A(void)
333
{
334
FLAG=1;
335
336
}
die leeren Switch Anweisungen sind geleert, dort kommen die
Funktionalitäten fürs Display etc. rein. Soll eine State machine werden.
Nun bin ich nicht der große Programmierer und suche deshalb Hilfe hier,
wie man diesen Code optimieren kann, um die erforderliche
Geschwindigkeit in der Abarbeitung zu erreichen. jetzt liege ich bei ca.
50Hz PWM Frequenz, was grad so reicht für die 2 LED Gruppen. Gelesen
habe ich hier
[[Beitrag "Software-PWM zu heftig für µC?"]]
den Hinweis von Karl Heinz Buchegger. Dazu würde ich gerne etwas mehr
wissen, also nicht wie es im Detail programmiert wird, sondern ob es den
von mir erwünschten Zeitgewinn bringt um Vergleich zu meinem Entwurf und
wo die Grenze liegt bzw. welche Auflösung der Schritte notwendig ist für
eine weiche Helligkeitsänderung auch bei Änderungszeiten von bis zu 5sek
(Hell -> dunkel) ungefähr.
Ich danke vorab und bin für jeden Tip dankbar!
Gruß Tom
Ich
Hallo,
danke erstmal für die Wortmeldungen,
@ gast:
dort wird das Flag, das in der ISR gesetzt wird überprüft. Dieses wird
alle 2,5ns bei 4MHz vollzogen. nur dann werden die PWM funktionen
aufgerufen. Das sorgt für die PWM Taktung!
Mehr zum Code:
Process() wird in jedem Durchlauf aufgerufen und wenn die ISR "Flag
setzt" werden darin die Funktionen gestartet.
TimerCounter_1 und TimerCounter_2 sind Zähler, die die
Helligkeitsänderungsgeschwindigkeit steuern. Immer wenn dieser
abgelaufen ist, werden neue Werte aus dem Array
PWMPeriod[PWM_PERIOD_STEPS] geladen und mit Change_PWM Parameter()
gesetzt.
Dazwischen werden immer die PWM_Output funktionen, für jede Gruppe LEDs
eine Funktion, aufgerufen, die mit Hilfe des Wertes aus dem Array die
PWM generieren. Die Zahl aus dem array ist die HIGH Zeit und die LOW
Zeit wird mit Hilfe der Gesamtzahl(512) minus der Highzeit betimmt.
Somit erzeuge ich eine PWM in Abhängigkeit des Wertes in dem Array.
Diese Werte werden mit der Geschwindigkeit, die der TimerCounter angibt
durchlaufen und somit ergibt sich eine Helligkeitsverlauf von dunkel zu
hell. In Change-Paramter() wird bei Erreichen des letzten Wertes des
Array wieder rückwärts gezählt und somit der Verlauf von Hell zu dunkel
generiert..Das läuft dann in einer schleife!
Ich hoffe das war ein wenig verständlicher!
Gruß Tom
P6OUT ist dort nur eine Testausgabe!
Tom schrieb:
> Hallo,>> danke erstmal für die Wortmeldungen,>> @ gast:>> dort wird das Flag, das in der ISR gesetzt wird überprüft. Dieses wird> alle 2,5ns bei 4MHz vollzogen. nur dann werden die PWM funktionen> aufgerufen. Das sorgt für die PWM Taktung!
??? 2,5ns und 4MHz? Das passt nicht. 2,5ns wären 400MHz, so schnell ist
kein MSP430. Oder meinst du µs? Das wären 10 Takte...immer noch
sportlich, Einsprung und Aussprung aus der ISR dauern da länger.
Wie Christian schon gesagt hat, du hast 4Mhz. D.h. im Controller ist
NICHTS schneller als 250ns. Wenn der Timer mit 4MHz läuft und CCR0 auf
100 steht, sind das dann also 25µs.
Noch mal zum Code:
Du hast also nur 2 PWM Ausgänge? P1.2 und P1.3?
Du willst ganz normal von 0 bis 100% regeln, aber die Änderung soll
nicht schlagartig, sondern mit einer maximalgeschwindigkeit erfolgen?
Wenn es nur 2 PWM Ausgänge sind, warum generierst du nicht die PWM in
Hardware?
Ok, mein Fehler! richtig mit 25µs!!
Zur Zeit sind nur 2 PWM Ausgänge realisiert ja, aber es sollen bis zu 10
sein dann! Also nicht mehr mit Hardware machbar.
ja die Änderung soll veränderbar sein. Keine statische Änderung, sondern
von Dauerlicht (PWM 100%) bis zum sehr schnellen Fading, was dann einem
Blinken nahe kommt! Alle dazwischen liegenden Zustände solllen per
externer Manipulation(Poti, Taster, Rs232 etc.) möglich sein!
[[Beitrag "Wieso 8 PWM Kanäle beim ATmega 64"]]
hier ist ja ein Ansatz, nur weiß ich nicht, ob der mir weiter hilft
dabei, das Timing zu verbessern.
Gruß Tom
Du hast doch Timer A mit 3 PWM und Timer B mit nochmal 7 PWM. Dann
kannst du das in Hardware machen. Außerdem hast du dann noch den Basic
Timer und den WatchDog Timer für sonstige Aufgaben. Wieso also in
Software?
>ja die Änderung soll veränderbar sein. Keine statische Änderung, sondern>von Dauerlicht (PWM 100%) bis zum sehr schnellen Fading, was dann einem>Blinken nahe kommt!
Blinken wäre ein verlangsamen der PWM Frequenz. Ist das jetzt noch
zusätzlich, oder hattest du das mit der Änderungsgeschwindigkeit
gemeint?
Ich fasse noch mal zusammen:
10 PWM Kanäle die in alle in Tastverhältnis und Frequenz unabhängig
steuerbar sein sollen, richtig?
Christian R. schrieb:
> Du hast doch Timer A mit 3 PWM und Timer B mit nochmal 7 PWM. Dann> kannst du das in Hardware machen. Außerdem hast du dann noch den Basic> Timer und den WatchDog Timer für sonstige Aufgaben. Wieso also in> Software?
Die CCR0 Register fallen ja weg, und wenn er die Frequenz der PWM
unabhängig voneinander steuern will, geht's mit der Hardware PWM sowieso
nicht.
Du kannst die Aufgabe auch gut in Software lösen, wenn natürlich auch
etwas aufwändiger als mit der Peripherie. Das macht Dich dann auch
flexibler.
Dein Ansatz scheint mir aber ein wenig kompliziert. Schau mal im Manual
vom MSP nacht, wie das mit den Timern und PWM genau funktioniert. Ich
würde dann was ähnliches in der Software nachbauen. Das ganze sollte
auch kompakt und effizient sein, denn es sollte in einem Timer IRQ
ausgeführt werden, damit nichts flackert (gleichbleibendes Timing).
Du brauchst dann also einen Grundzähler, ähnlich dem CCR0 und pro PWM
Kanal einen Compare-Wert. Diese kannst Du ja in einem Array speichern,
so wird das ganze skalierbar. Damit gedimmt werden kann, vielleicht zwei
Arrays, eines mit dem aktuellen PWM wert und eines mit dem Zielwert.
@ jörgS.
"Blinken wäre ein verlangsamen der PWM Frequenz. Ist das jetzt noch
zusätzlich, oder hattest du das mit der Änderungsgeschwindigkeit
gemeint?
Ich fasse noch mal zusammen:
10 PWM Kanäle die in alle in Tastverhältnis und Frequenz unabhängig
steuerbar sein sollen, richtig?"
Ja damit war die Änderungsgeschwindigkeit gemeint. Die PWM Frequenz soll
fest sein!
Also nicht die frequenz änderbar, nur die Änderungsgeschwindigkeit von
hell zu dunkel. Ansonsten ja: 10 Kanäle unabhängig voneinander als PWM!
@Johnny:
Ja so in etwa dieses Prinzip zeigt ja auch der Link aus meinem
vorherigen Post! Nur denke ich, dass meine aktuelle Funktion : PWM
Output() dafür zulang ist. ich werde diesen Ansatz mal weiter verfolgen,
wobei mir eine Idee für die effiziente Änderung der Helligkeitsänderung
außerhalb der ISR irgendwie fehlt. Wahrscheinlich auch über einen
Zähler, dessen Wert den Zeitpunkt des Überschreibens der Compare Werte
dann bestimmt.
Wäre das ne Möglichkeit?
Gruß und danke erstmal für die Hilfen bis hier!
Jörg S. schrieb:
> Christian R. schrieb:>> Du hast doch Timer A mit 3 PWM und Timer B mit nochmal 7 PWM. Dann>> kannst du das in Hardware machen. Außerdem hast du dann noch den Basic>> Timer und den WatchDog Timer für sonstige Aufgaben. Wieso also in>> Software?> Die CCR0 Register fallen ja weg, und wenn er die Frequenz der PWM> unabhängig voneinander steuern will, geht's mit der Hardware PWM sowieso> nicht.
Achso. Hab ich wohl überlesen.
Wenn die Frequenz für alle gleich ist, würde ich es so machen:
- Timer A als Counter für PWM
- Timer B als Counter für Änderungsgeschwindigkeit
- Ein Array für PWM Sollvorgabe vom Menü
- Ein Array für PWM Sollvorgabe die tatsächlich ausgegeben wird
Timer A ISR:
{
PWM_OUT_ALL_LOW; // Alle Outputs Low
}
Main-Schleife:
{
if (TAR > PWM_Soll[0]) PWM_OUT_0_HIGH; // Portpin auf high
if (TAR > PWM_Soll[1]) PWM_OUT_1_HIGH;
if (TAR > PWM_Soll[2]) PWM_OUT_2_HIGH;
if (TAR > PWM_Soll[3]) PWM_OUT_3_HIGH;
...
}
Timer B oder Watchdog ISR:
// Für Änderungsgeschwindigkeit
{
int i;
for (i = 0; i < 10; i++)
{
// PWM_Soll_In vom Menü auf wirklichen Ausgang kopieren
// Auch "+= 2" o.ä. möglich (schnellere Änderung)
if (PWM_Soll_In[i] < PWM_Soll[i]) PWM_Soll[i]++;
if (PWM_Soll_In[i] > PWM_Soll[i]) PWM_Soll[i]--;
}
}
Hallo, danke erstmal.
timer A und Main soweit klar.
Nur das mit dem Array vom Menü ist mir noch nicht ganz klar.
mein Array für PWM_Soll würde die Werte des Tastverhältnisses das
aktuell eingestellt werden soll für jeden Ausgang enthalten also
ungefähr so: PWM_Soll = [PORT1,PORT2,PORT3,PORT4,..] = PWM_Soll =
[23,105,45,189,...]
Dann wird TimerB oder Watchdog ausgelöst! In welchem Verhältnis zum
TimerA wäre das sinnvoll?
Dabei wird ein Sollwert dann verglichen mit dem aktuellen Wert aus
PWM_Soll? Dieser Teil ist mir noch unklar!
Wo taucht die Wertetabelle auf für die Auflösung der PWM, also die der
dem menschlichen Auge entsprechende Werte enthält, die über den
Helligkeitsverlauf dann eingestellt werden müssen?
Danke für die Hilfe!!
Tom
>Dann wird TimerB oder Watchdog ausgelöst! In welchem Verhältnis zum>TimerA wäre das sinnvoll?
Je nachdem wie schnell oder langsam du dir das vorstellst.
>Dabei wird ein Sollwert dann verglichen mit dem aktuellen Wert aus>PWM_Soll? Dieser Teil ist mir noch unklar!
Da geht es um die Änderungsgeschwindigkeit.
Beispiel:
Aktuelle PWM ist 0% (PWM_Soll = 0, PWM_Soll_In = 0), jetzt wird per Menü
der Wert auf 100% gesetzt (PWM_Soll_In = 100). Timer B kommt und es wird
festgestellt das der PWM_Soll_In (100) > PWM_Soll (0) ist. Daraufhin
wird PWM_Soll erhöht (MSP gibt 1% aus), nächster Timer B kommt PWM_Soll
wird erhöht (MSP gibt 2% aus) usw. bis der MSP tatsächlich auch 100%
ausgibt.
Um so eine "Verzögerung" ging es dir doch, oder?
>Wo taucht die Wertetabelle auf für die Auflösung der PWM, also die der>dem menschlichen Auge entsprechende Werte enthält, die über den>Helligkeitsverlauf dann eingestellt werden müssen?
Die Werte sollte man direkt als Timer A Werte umrechnen und in die
Arrays (PWM_Soll, PWM_Soll_In) eintragen.
Vorab:
Wie kann ich hier text kommentieren, also das in grün??
Ich werde das mal durchdenken und testen. habe die Hardware nicht hier
und jetzt auch keine Zeit mehr. ich melde mich dann wieder!
Befürchte, dass da alle die gleiche Laufvariable für die
Änderungsgeschwindigkeit haben, alle den gleichen Helligkeitsverlauf bei
gleicher geschwindigkeit haben werden!
Ich will da aber vorerst testen!
Danke bis hierher! Vor allem für die Geduld!
Gruß Tom
>Wie kann ich hier text kommentieren, also das in grün??
Als Gast muss du das '>' Zeichen manuell einfügen, dann wird's grün :)
>Befürchte, dass da alle die gleiche Laufvariable für die>Änderungsgeschwindigkeit haben, alle den gleichen Helligkeitsverlauf bei>gleicher geschwindigkeit haben werden!
Man kann anstatt "PWM_Soll[i]++" auch "PWM_Soll[i] += 2" schreiben oder
halt "PWM_Soll[i] += Addition_Array[i]". Dabei muss man halt nur darauf
achten das man keinen Überlauf baut (0 - 1 = 0xFFFF).
Hallo,
also danke erstmal für den Tip mit dem Kommentieren
>Als Gast muss du das '>' Zeichen manuell einfügen, dann wird's grün :)
Klappt! Werd mich hier auch mal anmelden!
Also programmiert habe ich es noch nicht, weil keine Zeit, aber ich habe
es nochmal durchdacht im Zug.
Ich würde gern nur ansatzweise den Inhalt der arrays wissen. Weil ich
habe jetzt in einem array die Werte für den Helligkeitsverlauf
hier
8Bit-sollte reichen erstmal.
Die müssen ja dann beim Update als Sollwert dann im Takt des TimerB
übernommen werden. Aber dieser Ablauf mit deinen beiden Arrays PWM_Soll
und PWM_Soll_in erschliesst sich mir nicht!
habe Geduld mit mir ;-)
Gruß
Hallo, hier mal ein schneller Entwurf der prinzipiellen Struktur.
Die PWM wird im TimerA Interrupt erledigt.
Alle PWM Kanäle sind als Array angelegt!
Im TimerB oder anders wird dann das Ändern der Werte gemacht, um den
Helligkeitsverlauf generieren zu können.
Aber die Übergabe der Werte aus der PWM table zeitlich passend zu jedem
Kanal ist mir noch nicht klar!
Danke schonmal!
Wenn man die Werte aus der Lookup-Table will, würde ich das so machen
das PWM_Soll_In[] dann nicht den realen Wert erhält, sondern nur den
Index der Lookup-Table:
1
ISR_TimerB(...)
2
{
3
4
if(TimerA_FLAG)
5
{
6
for(inti=0;i<10;i++)
7
{
8
if(pwmtable_8B[PWM_Soll_In[i]]<PWM_Soll[i])
9
PWM_Soll[i]=pwmtable_8B[PWM_Soll_In[i]-1];
10
if(pwmtable_8B[PWM_Soll_In[i]]>PWM_Soll[i])
11
PWM_Soll[i]=pwmtable_8B[PWM_Soll_In[i]+1];
12
}
13
14
TimerA_FLAG=0;
15
}
16
}
Was willst du mit PWM_Counter machen? Dafür würde ich auf jeden fall
direkt das TAR Register nehmen.
Wozu soll TimerA_FLAG gut sein?
Ok, wenn ich den TAR verwende, müsste CCR0 = 255 in meinem Fall sein?
Richtig? Muss zugeben mit dem habe ich noch nie gearbeitet!
TimerA_Flag soll mir sagen, ob ein Zyklus der PWM Generierung
abgeschlossen ist, so dass nicht mein TimerB vorher einspringt und dies
unterbricht. Es wäre also ein fester Ablauf und das Werte ändern
zeitlich klar getrennt von dem PWM Erzeugen! Liege ich da falsch oder
wie kann man es noch relalisieren?
1
for(inti=0;i<10;i++)
2
{
3
if(pwmtable_8B[PWM_Soll_In[i]]<PWM_Soll[i])
4
PWM_Soll[i]=pwmtable_8B[PWM_Soll_In[i]-1];
5
if(pwmtable_8B[PWM_Soll_In[i]]>PWM_Soll[i])
6
PWM_Soll[i]=pwmtable_8B[PWM_Soll_In[i]+1];
7
}
soweit ist das klar, nur sehe ich immer noch nicht, welche Werte in der
PWM_Soll_In[i]..Tabelle stehen!! Wo, bzw.wann bekommt sie ihre Werte?
tut mir leid wenn das hier ins fundamentale Prog Wissen geht, aber ich
will es ja auch verstehen können!
Gruß
Tom schrieb:
> Ok, wenn ich den TAR verwende, müsste CCR0 = 255 in meinem Fall sein?
Ja
> TimerA_Flag soll mir sagen, ob ein Zyklus der PWM Generierung> abgeschlossen ist, so dass nicht mein TimerB vorher einspringt und dies> unterbricht.
Das GIE Bit ist automatisch gelöscht wenn in ein Interrupt gesprungen
wird. Ein Interrupt wird also (wenn du es nicht so willst) NIEMALS
unterbrochen. Höchstens von einem NMI (Reset, Oszillatorfehler,..).
> soweit ist das klar, nur sehe ich immer noch nicht, welche Werte in der> PWM_Soll_In[i]..Tabelle stehen!! Wo, bzw.wann bekommt sie ihre Werte?
Die Kommen vom Menü oder RS232,..
// 0% setzen:
PWM_Soll_In[i] = pwmtable_8B[0];
// 100% setzen:
PWM_Soll_In[i] = pwmtable_8B[31];
Wie ich sehe sind da in der Lookup-Table einige Werte doppelt, das gibt
dann etwas Probleme mit dem jetzigem Aufbau.
PWM_Soll könnte man aber in ein 10x2 Array umbauen. Der erste Wert währe
dann der Lookup Index und der 2. der Realwert.
zu dem TAR Register nochmal,
diese ist doch immer 255 in dem Fall wenn ich in die ISR springe und
somit ist das nicht geeignet für meine Vergleiche mit dem Sollwert. In
deinem ersten Beispiel war diese funktionalität in der Main, da würde es
so funktionieren, aber nicht wenn ich alles das in der ISR mache!
deshalb hatte ich den PWM_Counter genutzt.
>Das GIE Bit ist automatisch gelöscht wenn in ein Interrupt gesprungen
wird. Ein Interrupt wird also (wenn du es nicht so willst) NIEMALS
unterbrochen. Höchstens von einem NMI (Reset, Oszillatorfehler,..).
Ok, danke, das wusste ich nicht!
Das mit dem Verändern der Werte nach bestimmten Zeitabständen im Timer B
muss ich erst durchdenken! Danke für den Ansatz!
Was mich dabei noch interessiert ist die Realisierung des Versatzes der
Helligkeit der einzelnen stufen beim Durchlaufen..also erst grün hell->
dunkel danach dann rot hell-> dunkel usw. mit sich leicht
überschneidenen Anfangs- und Endwerten, so dass ein Ineinander faden
möglich ist!
Gruß Tom
>zu dem TAR Register nochmal,>diese ist doch immer 255 in dem Fall wenn ich in die ISR springe und>somit ist das nicht geeignet für meine Vergleiche mit dem Sollwert.
Das glaube ich auch :) Der Ansatz das in einer ISR zu machen ist
natürlich grundsätzlich gut, da dann das Menü nicht dazwischen funken
kann, aber im prinzip müsstest du ja bei jedem Takt eine ISR aufrufen.
Von daher macht das ganze in der Main mehr sinn, aber das Menü/Display
könnte die Sache stören. Muss man denke ich mal ausprobieren. Wie ist
das Display angebunden (Hardware Schnittstelle vom MSP?)?
Grundsätzlich bin ich etwas sekptisch ob das mit 4MHz ordentlich
funktioniert. Ein F2xx MSP mit 16MHz wäre wohl die bessere Wahl gewesen.
>Was mich dabei noch interessiert ist die Realisierung des Versatzes der>Helligkeit der einzelnen stufen beim Durchlaufen..also erst grün hell->>dunkel danach dann rot hell-> dunkel usw. mit sich leicht>überschneidenen Anfangs- und Endwerten, so dass ein Ineinander faden>möglich ist!
Du willst was genau machen?
Hallo,
ich teste grad ob es ohne main geht, also die HElligkeitsveränderung im
TimerB.
>Du willst was genau machen?
Ich will Lichteffekte erzeugen, bei denen die einzelnen Farben(meine
Kanäle) nacheinander auf- und abdimmen, möglichst sogar mit leichtem
überschneiden...das muss aber nicht sein! also Farbwechsel seriell
sozusagen!
Hallo,
also die Helligkeitssteuerung in den TimerB auszulagern funktioniert bis
hierher sehr gut. Zur Zeit sind 3 Kanäle beschalten und die Performance
leidet nicht (noch nicht). Die PWM Generierung läuft im Timer A! bis
hierher also keine Problem.hier mal das Stück Code aus dem TimerB dazu:
1
// Timer B0 interrupt service routine
2
#pragma vector=TIMERB0_VECTOR
3
__interruptvoidTimer_B(void)
4
{
5
6
// TimerB_Counter++;
7
8
if(a<PWM_PERIOD_STEPS-1)
9
{
10
PWM_SOLL[ti]=pwmtable_8B[a++];
11
12
else
13
{
14
ti++;
15
a=0;
16
}
17
18
if(a>255)a=0;
19
20
if(ti==3)ti=0;
21
}
Ich breche zur Zeit aber auch ab nach dem 3. Kanal. siehe if(ti == 3)
Veränderung der Fading Zeit über TBCCR0 möglich!
Nun möchte ich noch weitere Szenarien einstellen können, also nicht nur
den sequentiellen Durchlauf aller angeschlossenen Farben, sondern auch
einzeln bestimmte asuwählen können und da die GEschwindigkeit und
Helligkeit ändern. Ich will das Ändern der Geschwindigkeit mit einem
Poti und dem ADC machen. Den Rest mit Taster. Eine Variante wie ich
diese Funktionalität in meine Statemachine bekomme würde mir helfen.
Gruß Tom