Forum: Mikrocontroller und Digitale Elektronik PWM Dimmen mit MSP430


von Tom (Gast)


Lesenswert?

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:
1
#include <string.h>
2
#include <msp430x14x.h>
3
#include "defines.h"
4
5
6
7
/**********************************************************************************/
8
/* Globale Variablen */
9
unsigned int FLAG = 0;      //Flag aus TimerA jede Sekunde
10
unsigned int arg =  0;      //Laufvariable der Statemachine
11
12
unsigned int timerA_Counter_1 =0;
13
unsigned int timerA_Counter_2 =0;
14
unsigned int PWM_state_p1= 1;    
15
unsigned int upTimeCnt_1;
16
unsigned int downTimeCnt_1;
17
unsigned int up_Time_1;
18
unsigned int down_Time_1;
19
20
unsigned int PWM_state_p2= 1;    
21
unsigned int upTimeCnt_2;
22
unsigned int downTimeCnt_2;
23
unsigned int up_Time_2;
24
unsigned int down_Time_2;
25
26
27
unsigned int index_dir_1 = 0;    //Richtung der Helligkeits  0 = heller werdend, 1 = dunkler werdend
28
unsigned int index_dir_2 = 0;    //Richtung der Helligkeits  0 = heller werdend, 1 = dunkler werdend
29
30
unsigned int PeriodIndex_1 = 0;
31
unsigned int PeriodIndex_2 = 0;
32
unsigned int PeriodLenght_1;        //Laufgeschwindigkeit PWM Kanal 1.2 der Helligkeitsänderung!
33
unsigned int PeriodLenght_2;
34
35
36
#define PWM_PERIOD_STEPS 64
37
38
unsigned int PWMPeriod[PWM_PERIOD_STEPS] = {0, 1, 1, 2, 2, 2, 2, 2, 3, 3, 3, 4 , 4, 4, 
39
5, 5, 5, 6, 6 ,6, 7, 8, 9, 10, 11, 12, 13, 15, 17, 18, 19, 21, 24, 26, 30, 34, 38, 42, 
40
47, 53, 58, 64, 76, 87, 99, 111, 123, 136, 147, 156, 164, 173, 189, 200, 215, 230, 
41
250, 280, 320, 370, 400, 430, 470, 511};
42
43
/********************************************************************************************/
44
void init_Timer_A(void)
45
{
46
  CCTL0 = CCIE;                         // CCR0 interrupt enabled
47
    CCR0 = 100;             
48
    TACTL = TASSEL_2 + MC_1;              // SMCLK, upmode to CCR0
49
    
50
}
51
/*********************************************************************************************/
52
53
//------------------------------------------------------------------------------
54
void Set_DCO (void)                         // Set DCO to selected frequency
55
//------------------------------------------------------------------------------
56
{
57
58
#define DELTA 125              // target DCO = DELTA*(32768) = 4096000
59
  unsigned int Compare, Oldcapture = 0;
60
  
61
  CCTL2 = CM_1 + CCIS_1 + CAP;              // CAP, ACLK
62
  TACTL = TASSEL_2 + MC_2 + TACLR;          // SMCLK, cont-mode, clear
63
64
  while (1)
65
  {
66
    while (!(CCIFG & CCTL2));               // Wait until capture occured
67
    CCTL2 &= ~CCIFG;                        // Capture occured, clear flag
68
    Compare = CCR2;                         // Get current captured SMCLK
69
    Compare = Compare - Oldcapture;         // SMCLK difference
70
    Oldcapture = CCR2;                      // Save current captured SMCLK
71
72
    if (DELTA == Compare) break;            // If equal, leave "while(1)"
73
    else if (DELTA < Compare)               // DCO is too fast, slow it down
74
    {
75
      DCOCTL--;
76
      if (DCOCTL == 0xFF)
77
      {
78
        if (!(BCSCTL1 == (XT2OFF)))
79
        BCSCTL1--;                          // Did DCO roll under?, Sel lower RSEL
80
      }
81
    }
82
    else
83
    {
84
      DCOCTL++;
85
      if (DCOCTL == 0x00)
86
        {
87
          if (!(BCSCTL1 == (XT2OFF + 0x07)))
88
          BCSCTL1++;                        // Did DCO roll over? Sel higher RSEL
89
        }
90
    }
91
  }
92
  CCTL2 = 0;                                // Stop CCR2
93
  TACTL = 0;                                // Stop Timer_A
94
}
95
96
/*****************************************************************/
97
void change_PWM_Parameters_1(void)
98
{
99
  up_Time_1 = PWMPeriod[PeriodIndex_1];
100
    //down_Time = PWMPeriod[PeriodIndex].LowTime;
101
  //PeriodLenght = PWMPeriod[PeriodIndex].PeriodLenght_1;  
102
  
103
104
  if ( index_dir_1 == 0 )
105
  {
106
    if ( PeriodIndex_1 < PWM_PERIOD_STEPS - 1 )
107
    {
108
      PeriodIndex_1++;
109
    }
110
    else
111
    {
112
      index_dir_1 = 1;
113
    }
114
  }
115
  else
116
  {
117
    if ( PeriodIndex_1 > 0 )
118
    {
119
      PeriodIndex_1--;
120
    }
121
    else
122
    {
123
      index_dir_1 = 0;
124
    }
125
  }
126
    
127
}
128
129
/*****************************************************************/
130
131
void change_PWM_Parameters_2(void)
132
{
133
  up_Time_2 = PWMPeriod[PeriodIndex_2];
134
    //down_Time = PWMPeriod[PeriodIndex].LowTime;
135
  //PeriodLenght = PWMPeriod[PeriodIndex].PeriodLenght_1;  
136
  
137
    
138
  if ( index_dir_2 == 0 )
139
  {
140
    if ( PeriodIndex_2 < PWM_PERIOD_STEPS - 1 )
141
    {
142
      PeriodIndex_2++;
143
    }
144
    else
145
    {
146
      index_dir_2 = 1;
147
    }
148
  }
149
  else
150
  {
151
    if ( PeriodIndex_2 > 0 )
152
    {
153
      PeriodIndex_2--;
154
    }
155
    else
156
    {
157
      index_dir_2 = 0;
158
    }
159
  }
160
    
161
}
162
163
/*****************************************************************/
164
165
166
/*********************************************************************************/
167
void PWM_Output_1(void)
168
{
169
    down_Time_1 = 512 - up_Time_1;
170
    
171
        if(PWM_state_p1)
172
        {
173
          upTimeCnt_1++;
174
          if(upTimeCnt_1 > up_Time_1)
175
          {
176
            P1OUT &=~BIT3;  
177
            PWM_state_p1 = 0;
178
            upTimeCnt_1 = 0;
179
          }
180
        }
181
        else
182
        {
183
          downTimeCnt_1++;
184
          if(downTimeCnt_1 >down_Time_1)
185
          {
186
            P1OUT |=BIT3;
187
            PWM_state_p1 = 1;
188
            downTimeCnt_1 = 0;
189
          }
190
        }    
191
  
192
}
193
194
/*****************************************************************/
195
196
/*********************************************************************************/
197
void PWM_Output_2(void)
198
{
199
    down_Time_2 = 512 - up_Time_2;
200
    
201
        if(PWM_state_p2)
202
        {
203
          upTimeCnt_2++;
204
          if(upTimeCnt_2 > up_Time_2)
205
          {
206
            P1OUT&=~ BIT2;  
207
            PWM_state_p2 = 0;
208
            upTimeCnt_2 = 0;
209
          }
210
        }
211
        else
212
        {
213
          downTimeCnt_2++;
214
          if(downTimeCnt_2 >down_Time_2)
215
          {
216
            P1OUT |= BIT2;
217
            PWM_state_p2 = 1;
218
            downTimeCnt_2 = 0;
219
          }
220
        }    
221
  
222
}
223
224
/*****************************************************************/
225
226
/*****************************************************************/
227
228
void Process(void)
229
{
230
  if(FLAG)      //Timer A Flag alle 2,5ns bei DCO = 4MHz
231
  {
232
    timerA_Counter_1++;
233
    timerA_Counter_2++;
234
    
235
    P6OUT ^= BIT0;
236
    
237
    PWM_Output_1();
238
    
239
    PWM_Output_2();
240
    
241
    
242
    
243
    if(timerA_Counter_1 > PeriodLenght_1)
244
    {
245
      change_PWM_Parameters_1();
246
      timerA_Counter_1 = 0;
247
    }  
248
    
249
    if(timerA_Counter_2 > PeriodLenght_2)
250
    {
251
      change_PWM_Parameters_2();
252
      timerA_Counter_2 = 0;
253
    }  
254
    
255
    
256
    
257
    FLAG=0;  
258
  }
259
  
260
}
261
/*****************************************************************/
262
263
/*****************************************************************/
264
void main(void)
265
{
266
  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
      case 0:
292
      
293
      
294
      
295
      break;
296
      
297
      
298
      
299
      case 1:
300
      
301
      
302
      
303
      break;
304
      
305
      case 2:
306
      
307
      
308
      break;
309
      
310
      case 3:
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
__interrupt void Timer_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

von Jörg S. (joerg-s)


Lesenswert?

Vielleicht könntest du noch ein paar Worte zu deinem Ccde bzw. dessen 
Funktionsweise sagen, dann muss man nicht alles selbst zusammenreimen.

von Gast (Gast)


Lesenswert?

>  if(FLAG)      //Timer A Flag alle 2,5ns bei DCO = 4MHz

Was bedeutet diese Zeile?

von Tom (Gast)


Lesenswert?

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!

von Christian R. (supachris)


Lesenswert?

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.

von Tom (Gast)


Lesenswert?

Der Wert im CCR0 Register des Timer ist auf 100 gesetzt, was dem Faktor 
aus deiner Rechnung entspricht!


Gruß tom

von Jörg S. (joerg-s)


Lesenswert?

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?

von Tom (Gast)


Lesenswert?

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

von Christian R. (supachris)


Lesenswert?

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?

von Jörg S. (joerg-s)


Lesenswert?

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

von Jörg S. (joerg-s)


Lesenswert?

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.

von Johnny (Gast)


Lesenswert?

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.

von Tom (Gast)


Lesenswert?

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

von Christian R. (supachris)


Lesenswert?

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.

von Jörg S. (joerg-s)


Lesenswert?

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]--;
  }
}

von Tom (Gast)


Lesenswert?

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

von Jörg S. (joerg-s)


Lesenswert?

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

von Tom (Gast)


Lesenswert?

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

von Jörg S. (joerg-s)


Lesenswert?

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

von Tom (Gast)


Lesenswert?

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
1
unsigned char pwmtable_8B[32] = {0, 1, 2, 2, 2, 3, 3, 4, 5, 6, 7, 8, 10, 11,13, 16, 19, 23, 27, 32, 38, 45, 54, 64, 76,91, 108, 128, 152, 181, 215, 255};

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ß

von Tom (Gast)


Angehängte Dateien:

Lesenswert?

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!

von Jörg S. (Gast)


Lesenswert?

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(int i=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?

von Tom (Gast)


Lesenswert?

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(int i=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ß

von Jörg S. (joerg-s)


Lesenswert?

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.
1
for(int i=0;i<10;i++)
2
{
3
  if (PWM_Soll_In[i] < PWM_Soll[i][0])
4
  {
5
    PWM_Soll[i][1] = pwmtable_8B[PWM_Soll_In[i] - 1];  // Wert runter
6
    PWM_Soll[i][0]--;                                  // Index runter
7
  }
8
  if (PWM_Soll_In[i] > PWM_Soll[i][0])
9
  {
10
    PWM_Soll[i][1] = pwmtable_8B[PWM_Soll_In[i] + 1];  // Wert hoch
11
    PWM_Soll[i][0]++;                                  // Index hoch
12
  }
13
}

von Tom (Gast)


Lesenswert?

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

von Jörg S. (joerg-s)


Lesenswert?

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

von Tom (Gast)


Lesenswert?

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!

von Tom (Gast)


Lesenswert?

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
__interrupt void Timer_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

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.