www.mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik PWM Dimmen mit MSP430


Autor: Tom (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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:

#include <string.h>
#include <msp430x14x.h>
#include "defines.h"



/**********************************************************************************/
/* Globale Variablen */
unsigned int FLAG = 0;      //Flag aus TimerA jede Sekunde
unsigned int arg =  0;      //Laufvariable der Statemachine

unsigned int timerA_Counter_1 =0;
unsigned int timerA_Counter_2 =0;
unsigned int PWM_state_p1= 1;    
unsigned int upTimeCnt_1;
unsigned int downTimeCnt_1;
unsigned int up_Time_1;
unsigned int down_Time_1;

unsigned int PWM_state_p2= 1;    
unsigned int upTimeCnt_2;
unsigned int downTimeCnt_2;
unsigned int up_Time_2;
unsigned int down_Time_2;


unsigned int index_dir_1 = 0;    //Richtung der Helligkeits  0 = heller werdend, 1 = dunkler werdend
unsigned int index_dir_2 = 0;    //Richtung der Helligkeits  0 = heller werdend, 1 = dunkler werdend

unsigned int PeriodIndex_1 = 0;
unsigned int PeriodIndex_2 = 0;
unsigned int PeriodLenght_1;        //Laufgeschwindigkeit PWM Kanal 1.2 der Helligkeitsänderung!
unsigned int PeriodLenght_2;


#define PWM_PERIOD_STEPS 64

unsigned int PWMPeriod[PWM_PERIOD_STEPS] = {0, 1, 1, 2, 2, 2, 2, 2, 3, 3, 3, 4 , 4, 4, 
5, 5, 5, 6, 6 ,6, 7, 8, 9, 10, 11, 12, 13, 15, 17, 18, 19, 21, 24, 26, 30, 34, 38, 42, 
47, 53, 58, 64, 76, 87, 99, 111, 123, 136, 147, 156, 164, 173, 189, 200, 215, 230, 
250, 280, 320, 370, 400, 430, 470, 511};

/********************************************************************************************/
void init_Timer_A(void)
{
  CCTL0 = CCIE;                         // CCR0 interrupt enabled
    CCR0 = 100;             
    TACTL = TASSEL_2 + MC_1;              // SMCLK, upmode to CCR0
    
}
/*********************************************************************************************/

//------------------------------------------------------------------------------
void Set_DCO (void)                         // Set DCO to selected frequency
//------------------------------------------------------------------------------
{

#define DELTA 125              // target DCO = DELTA*(32768) = 4096000
  unsigned int Compare, Oldcapture = 0;
  
  CCTL2 = CM_1 + CCIS_1 + CAP;              // CAP, ACLK
  TACTL = TASSEL_2 + MC_2 + TACLR;          // SMCLK, cont-mode, clear

  while (1)
  {
    while (!(CCIFG & CCTL2));               // Wait until capture occured
    CCTL2 &= ~CCIFG;                        // Capture occured, clear flag
    Compare = CCR2;                         // Get current captured SMCLK
    Compare = Compare - Oldcapture;         // SMCLK difference
    Oldcapture = CCR2;                      // Save current captured SMCLK

    if (DELTA == Compare) break;            // If equal, leave "while(1)"
    else if (DELTA < Compare)               // DCO is too fast, slow it down
    {
      DCOCTL--;
      if (DCOCTL == 0xFF)
      {
        if (!(BCSCTL1 == (XT2OFF)))
        BCSCTL1--;                          // Did DCO roll under?, Sel lower RSEL
      }
    }
    else
    {
      DCOCTL++;
      if (DCOCTL == 0x00)
        {
          if (!(BCSCTL1 == (XT2OFF + 0x07)))
          BCSCTL1++;                        // Did DCO roll over? Sel higher RSEL
        }
    }
  }
  CCTL2 = 0;                                // Stop CCR2
  TACTL = 0;                                // Stop Timer_A
}

/*****************************************************************/
void change_PWM_Parameters_1(void)
{
  up_Time_1 = PWMPeriod[PeriodIndex_1];
    //down_Time = PWMPeriod[PeriodIndex].LowTime;
  //PeriodLenght = PWMPeriod[PeriodIndex].PeriodLenght_1;  
  

  if ( index_dir_1 == 0 )
  {
    if ( PeriodIndex_1 < PWM_PERIOD_STEPS - 1 )
    {
      PeriodIndex_1++;
    }
    else
    {
      index_dir_1 = 1;
    }
  }
  else
  {
    if ( PeriodIndex_1 > 0 )
    {
      PeriodIndex_1--;
    }
    else
    {
      index_dir_1 = 0;
    }
  }
    
}

/*****************************************************************/

void change_PWM_Parameters_2(void)
{
  up_Time_2 = PWMPeriod[PeriodIndex_2];
    //down_Time = PWMPeriod[PeriodIndex].LowTime;
  //PeriodLenght = PWMPeriod[PeriodIndex].PeriodLenght_1;  
  
    
  if ( index_dir_2 == 0 )
  {
    if ( PeriodIndex_2 < PWM_PERIOD_STEPS - 1 )
    {
      PeriodIndex_2++;
    }
    else
    {
      index_dir_2 = 1;
    }
  }
  else
  {
    if ( PeriodIndex_2 > 0 )
    {
      PeriodIndex_2--;
    }
    else
    {
      index_dir_2 = 0;
    }
  }
    
}

/*****************************************************************/


/*********************************************************************************/
void PWM_Output_1(void)
{
    down_Time_1 = 512 - up_Time_1;
    
        if(PWM_state_p1)
        {
          upTimeCnt_1++;
          if(upTimeCnt_1 > up_Time_1)
          {
            P1OUT &=~BIT3;  
            PWM_state_p1 = 0;
            upTimeCnt_1 = 0;
          }
        }
        else
        {
          downTimeCnt_1++;
          if(downTimeCnt_1 >down_Time_1)
          {
            P1OUT |=BIT3;
            PWM_state_p1 = 1;
            downTimeCnt_1 = 0;
          }
        }    
  
}

/*****************************************************************/

/*********************************************************************************/
void PWM_Output_2(void)
{
    down_Time_2 = 512 - up_Time_2;
    
        if(PWM_state_p2)
        {
          upTimeCnt_2++;
          if(upTimeCnt_2 > up_Time_2)
          {
            P1OUT&=~ BIT2;  
            PWM_state_p2 = 0;
            upTimeCnt_2 = 0;
          }
        }
        else
        {
          downTimeCnt_2++;
          if(downTimeCnt_2 >down_Time_2)
          {
            P1OUT |= BIT2;
            PWM_state_p2 = 1;
            downTimeCnt_2 = 0;
          }
        }    
  
}

/*****************************************************************/

/*****************************************************************/

void Process(void)
{
  if(FLAG)      //Timer A Flag alle 2,5ns bei DCO = 4MHz
  {
    timerA_Counter_1++;
    timerA_Counter_2++;
    
    P6OUT ^= BIT0;
    
    PWM_Output_1();
    
    PWM_Output_2();
    
    
    
    if(timerA_Counter_1 > PeriodLenght_1)
    {
      change_PWM_Parameters_1();
      timerA_Counter_1 = 0;
    }  
    
    if(timerA_Counter_2 > PeriodLenght_2)
    {
      change_PWM_Parameters_2();
      timerA_Counter_2 = 0;
    }  
    
    
    
    FLAG=0;  
  }
  
}
/*****************************************************************/

/*****************************************************************/
void main(void)
{
  PeriodLenght_1 = 2000;                //Änderungsgeschwindigkeit des Dimmens
  PeriodLenght_2 = 2000;
  
  
  WDTCTL = WDTPW + WDTHOLD;                 // Stop WDT

  Set_DCO();
  
  init_PORTS();
  init_Timer_A();
  
  
  _EINT();      //Enable Interrupt global
  


  
  while(1)
  {
  
    Process();  

  
    switch(arg++)
    {
      case 0:
      
      
      
      break;
      
      
      
      case 1:
      
      
      
      break;
      
      case 2:
      
      
      break;
      
      case 3:
      
      
      
      break;
      
      default:
      
      arg=0;
      
      break;
      
      
    }
  
  }

}


// Timer A0 interrupt service routine
#pragma vector=TIMERA0_VECTOR
__interrupt void Timer_A (void)
{
  FLAG=1;
  
}


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

Autor: Jörg S. (joerg-s)
Datum:

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

Autor: Gast (Gast)
Datum:

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

Was bedeutet diese Zeile?

Autor: Tom (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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!

Autor: Christian R. (supachris)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Tom (Gast)
Datum:

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


Gruß tom

Autor: Jörg S. (joerg-s)
Datum:

Bewertung
0 lesenswert
nicht 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?

Autor: Tom (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Christian R. (supachris)
Datum:

Bewertung
0 lesenswert
nicht 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?

Autor: Jörg S. (joerg-s)
Datum:

Bewertung
0 lesenswert
nicht 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?

Autor: Jörg S. (joerg-s)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Johnny (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Tom (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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!

Autor: Christian R. (supachris)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Jörg S. (joerg-s)
Datum:

Bewertung
0 lesenswert
nicht 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]--;
  }
}

Autor: Tom (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Jörg S. (joerg-s)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Tom (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Jörg S. (joerg-s)
Datum:

Bewertung
0 lesenswert
nicht 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).

Autor: Tom (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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

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ß

Autor: Tom (Gast)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht 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!

Autor: Jörg S. (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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:

ISR_TimerB(...)
{
    
    if(TimerA_FLAG)
    {
        for(int i=0;i<10;i++)
        {
           if (pwmtable_8B[PWM_Soll_In[i]] < PWM_Soll[i])
             PWM_Soll[i] = pwmtable_8B[PWM_Soll_In[i] - 1];
           if (pwmtable_8B[PWM_Soll_In[i]] > PWM_Soll[i])
             PWM_Soll[i] = pwmtable_8B[PWM_Soll_In[i] + 1];
        } 
        
        TimerA_FLAG = 0;
    }  
}

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?

Autor: Tom (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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?

for(int i=0;i<10;i++)
        {
           if (pwmtable_8B[PWM_Soll_In[i]] < PWM_Soll[i])
             PWM_Soll[i] = pwmtable_8B[PWM_Soll_In[i] - 1];
           if (pwmtable_8B[PWM_Soll_In[i]] > PWM_Soll[i])
             PWM_Soll[i] = pwmtable_8B[PWM_Soll_In[i] + 1];
        } 

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ß

Autor: Jörg S. (joerg-s)
Datum:

Bewertung
0 lesenswert
nicht 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.
for(int i=0;i<10;i++)
{
  if (PWM_Soll_In[i] < PWM_Soll[i][0])
  {
    PWM_Soll[i][1] = pwmtable_8B[PWM_Soll_In[i] - 1];  // Wert runter
    PWM_Soll[i][0]--;                                  // Index runter
  }
  if (PWM_Soll_In[i] > PWM_Soll[i][0])
  {
    PWM_Soll[i][1] = pwmtable_8B[PWM_Soll_In[i] + 1];  // Wert hoch
    PWM_Soll[i][0]++;                                  // Index hoch
  }
} 

Autor: Tom (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Jörg S. (joerg-s)
Datum:

Bewertung
0 lesenswert
nicht 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?

Autor: Tom (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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!

Autor: Tom (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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:

// Timer B0 interrupt service routine
#pragma vector=TIMERB0_VECTOR
__interrupt void Timer_B (void)            
{ 
  
//  TimerB_Counter++;
  
          if(a<PWM_PERIOD_STEPS - 1 )
           {
               PWM_SOLL[ti] = pwmtable_8B[a++];
              
           else
           {
               ti++;
               a=0;
           }
          
         if(a > 255) a=0;  
           
        if(ti==3) ti=0;   
}

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

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.