mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik HSV > RGB: Problem mit weichen Farbübergängen


Autor: Andreas Häusler (andy61)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo Leute

Bin am verzweifeln. Kriege einfach keine saubere Farbmischung mit der 
HSV > RGB Funktion hin. (Herzlichen Dank an Fly!)

Hier der Source:

#include "p24fj64ga002.h"     // CPU: PIC24FJ64GA002

#define PWM_PERIOD_MAX  1024  // 10Bit Auflösung

/****************************************************************************/
/* * * * * * * * * * * * * *      FUNKTIONEN      * * * * * * * * * * * * * */
/****************************************************************************/
//----------------------------------------------------------------------------
// Funktionsnamen : init_system()
//
// Beschreibung   : CPU Register init
// Arguments      : ---
// Return         : ---
//----------------------------------------------------------------------------
void init_system(void)
{
    
// PWM Output Capture Setup -----------------------------------------------------

  OC1CON = 0x0000;     // Turn off Output Compare 1 Module        
  OC1R = 0;        // init at 0% PWM
  OC1RS = 0;         // init at 0% PWM
  OC1CON = 0x000E;    // activate the PWM Module
  
  OC2CON = 0x0000;     // Turn off Output Compare 1 Module        
  OC2R = 0;        // init at 0% PWM
  OC2RS = 0;         // init at 0% PWM
  OC2CON = 0x000E;    // activate the PWM Module
  
  OC3CON = 0x0000;     // Turn off Output Compare 1 Module        
  OC3R = 0;        // init at 0% PWM
  OC3RS = 0X;       // init at 0% PWM
  OC3CON = 0x000E;    // activate the PWM Module
  
  OC4CON = 0x0000;     // Turn off Output Compare 1 Module        
  OC4R = 0;        // init at 0% PWM
  OC4RS = 0;         // init at 0% PWM
  OC4CON = 0x000E;    // activate the PWM Module
    
// Timer3 Setup --------------------------------------------------------------
// Timer für RGB PWM Signale

  T3CON = 0x0000;     // Stops the Timer3 and reset control reg.
  PR3 = PWM_PERIOD-1;    // PWM Periode 1kHz > PR3= (PWM_Periode/TCY)-1 = (0,001s/62,5ns)-1  
  _T3IP = 0x01;
  _T3IF = 0;        // Interrupt Flag löschen
  _T3IE = 1;        // Timer 3 Interrupt freigeben  
  T3CON = 0x8010;      // (1,95kHz) Timer 3 freigeben, prescaler 1:8 internal clock   
}

//----------------------------------------------------------------------------
// Funktionsnamen : hsv_to_rgb
//
// Beschreibung   : HSV nach RGB konvertieren 
// Arguments      : ---
// Return         : ---
//----------------------------------------------------------------------------
void hsv_to_rgb (float hue,float saturation,float value)  
{
  float H,S,V;
  float r,g,b;  
  unsigned short i;
  float f,p,q,t;  
  
    H=hue;        // Bereich 0-360°
    S= saturation/100;  // 100% = 1
    V= value/100;    // 100% = 1
    
   if(S == 0) 
   {
     //r,g,b = V;
    Red=PWM_PERIOD_MAX, Green=PWM_PERIOD_MAX, Blue=PWM_PERIOD_MAX4; // Weiss
  }
  else
  {
    H /= 60;        // sector 0 to 5
    i = floor(H);
    f = H - i;      
    p = V * (1 - S);
    q = V * (1 - S * f);
    t = V * (1 - S * (1 - f));
  
     switch(i)
        {
        case 0:
          r = V; g = t; b = p; 
        break;
        
        case 1:
          r = q; g = V; b = p; 
        break;
          
        case 2:
          r = p; g = V; b = t; 
        break;
            
        case 3:
          r = p; g = q; b = V; 
        break;      
            
        case 4:
          r = t; g = p; b = V; 
        break;
                    
        default:                
          r = V; g = p; b = q; 
        break;        // case 5:          
      }
    
    // In RGB Integer konvertieren 
    
    Red=r*PWM_PERIOD_MAX;
    Green=g*PWM_PERIOD_MAX;
    Blue=b*PWM_PERIOD_MAX;  
    
  }  
  
  // OCxRS Register wird in Timer3 IRQ in OCxR Register kopiert
  OC1RS = Red;   // PWM Werte invertieren und ausgeben
  OC2RS = Green;   // PWM Werte invertieren und ausgeben
  OC3RS = Blue;   // PWM Werte invertieren und ausgeben
  
  if(W_LED_ENABLED)  OC4RS = 0;     // Weisse LED einschalten
  if(W_LED_DISABLED) OC4RS = PWM_PERIOD;  // Weisse LED ausschalten    
}


/****************************************************************************/
/* * * * * * * * * * * * *       HAUPTPROGRAMM        * * * * * * * * * * * */
/****************************************************************************/
int main(void)
{
  volatile unsigned short H,S,V;  

  init_system();

    H=0;
    S=100;
    V=100;
    
    W_LED_OFF;  // Weisse LED ausschalten
  
  while(1) // endless
  {  
    
    if(H < 360) H++;   // 0-360° Farbwechsel jede Millisekunde
      else H=0;   
      
    hsv_to_rgb(H,S,V);  // HSV Werte in RGB konvertieren und ausgeben
      
    __delay_ms(100);  // 100ms warten
  
  }
}    

// END ----------------------


Bin jetzt schon seit Tagen am ausprobieren.

Das Ziel sollte ein möglichst langsames Durchlaufen (Dauer ca. 36 Sek.) 
aller Farben von 0-360° sein. Dabei sollten die Farbübergänge sehr weich 
ineinander fliessen.
Ich habe nun das Problem, dass beim Übergang von H= 360 auf 0 die Farbe 
kurz sprunghaft ändert.
Ein weiteres Problem befindet sich im blauen Bereich (zwischen H=190 bis 
250) während ein paar Sekunden ein Flimmern zu sehen ist.

Vielleicht kann mir auch noch jemand sagen, wie ich einen möglichst 
einfachen "Weissabgleich" der 3 Grundfarben durchführen kann.
Evt. stehen ja die obenganannten Probleme im Zusammenhang mit einem 
schlechten Abgleich der RGB- LED's zueinander.

Bin für jede Hilfe sehr dankbar!

Autor: Johann L. (gjlayde) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
H darf nicht 360 sein. Der Fall wird im switch nicht behandelt (i=6).

Gibt es nach der float-Rechnung Rundungsfehler, so daß PWM-Werte nicht 
mehr in [0..1024] sind --> Werte Saturieren.

Autor: Andreas Häusler (andy61)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hi Johann

Danke für Deine Antwort.
Hast natürlich Recht, werde den H-Bereich auf 0-359 begrenzen.

Was meinst Du mit "Werte Saturieren"?

Autor: Andreas Häusler (andy61)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Muss mich korrigieren.
Der Wert 360 ist über den "default Zweig" der Switch Answeisung 
abgedeckt und ergibt:

Rote LED = 1024
Grüne Led = 0
Blaue LED = 1024

Autor: futzi (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
ich denke du kommst vom PIC18 daher, beim pic24 rennt das mit der PWM 
etwas anders:
OC4CON = 0;          // It is a good practice to clear off the control bits initially
OC4CONbits.OCTSEL = 1;    // This selects the peripheral clock as the clock input to the OC module
OC4RS = 0x0000;       // Determines the Period
PR4 = 0x0FFF;

da hat jedes PWM-Modul sein eigenes PRx-Register

Autor: C30 (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Versuch mal so:
#define PWM_PERIOD_MAX  1023  // 10Bit Auflösung

Autor: C30 (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ist das so gewollt:
Blue=PWM_PERIOD_MAX4; 
max4?

Autor: Andreas Häusler (andy61)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@futzi:
Meiner Meinung nach gibt es 1 PRx Register für jeden Timer, (Timer 2 & 
Timer 3) welche für die PWM Ausgabe verwendet werden können.

Das OCxRS Register kann jederzeit mit einem neuen Duty Wert geladen 
werden.
Bei jedem Timer IRQ (abhängig vom PRx- Register) wird der Inhalt des 
OCxRS Registers in das OCxR Register kopiert, also quasi gebuffert.

Hoffe, ich habe das ganze richtig verstanden...

@C30: PWM_PERIOD_MAX4 ist natürlich "nur" ein Schreibfehler, sorry...
Werde ich morgen mal testen, hab ich glaub aber auch schon probiert :-(

Danke Leute!

Autor: Johann L. (gjlayde) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Andreas Häusler schrieb:

> Der Wert 360 ist über den "default Zweig" der Switch Answeisung
> abgedeckt ...

Ich hatte mich unklar ausgedrückt. Der Wert wird zwar im default 
behandelt, allerdings wie 5 mod 6, er ist allerdings zu behandeln wie 0 
= 6 mod 6. Evtl. macht's kein Unterschied, aber mal nachschauen.

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.