HSV > RGB: Problem mit weichen Farbübergängen

OP #1692908
Lesenswert?

Hallo Leute

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

Hier der Source:
1
#include "p24fj64ga002.h"     // CPU: PIC24FJ64GA002
2

3
#define PWM_PERIOD_MAX  1024  // 10Bit Auflösung
4

5
/****************************************************************************/
6
/* * * * * * * * * * * * * *      FUNKTIONEN      * * * * * * * * * * * * * */
7
/****************************************************************************/
8
//----------------------------------------------------------------------------
9
// Funktionsnamen : init_system()
10
//
11
// Beschreibung   : CPU Register init
12
// Arguments      : ---
13
// Return         : ---
14
//----------------------------------------------------------------------------
15
void init_system(void)
16
{
17
    
18
// PWM Output Capture Setup -----------------------------------------------------
19

20
  OC1CON = 0x0000;     // Turn off Output Compare 1 Module        
21
  OC1R = 0;        // init at 0% PWM
22
  OC1RS = 0;         // init at 0% PWM
23
  OC1CON = 0x000E;    // activate the PWM Module
24
  
25
  OC2CON = 0x0000;     // Turn off Output Compare 1 Module        
26
  OC2R = 0;        // init at 0% PWM
27
  OC2RS = 0;         // init at 0% PWM
28
  OC2CON = 0x000E;    // activate the PWM Module
29
  
30
  OC3CON = 0x0000;     // Turn off Output Compare 1 Module        
31
  OC3R = 0;        // init at 0% PWM
32
  OC3RS = 0X;       // init at 0% PWM
33
  OC3CON = 0x000E;    // activate the PWM Module
34
  
35
  OC4CON = 0x0000;     // Turn off Output Compare 1 Module        
36
  OC4R = 0;        // init at 0% PWM
37
  OC4RS = 0;         // init at 0% PWM
38
  OC4CON = 0x000E;    // activate the PWM Module
39
    
40
// Timer3 Setup --------------------------------------------------------------
41
// Timer für RGB PWM Signale
42

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

51
//----------------------------------------------------------------------------
52
// Funktionsnamen : hsv_to_rgb
53
//
54
// Beschreibung   : HSV nach RGB konvertieren 
55
// Arguments      : ---
56
// Return         : ---
57
//----------------------------------------------------------------------------
58
void hsv_to_rgb (float hue,float saturation,float value)  
59
{
60
  float H,S,V;
61
  float r,g,b;  
62
  unsigned short i;
63
  float f,p,q,t;  
64
  
65
    H=hue;        // Bereich 0-360°
66
    S= saturation/100;  // 100% = 1
67
    V= value/100;    // 100% = 1
68
    
69
   if(S == 0) 
70
   {
71
     //r,g,b = V;
72
    Red=PWM_PERIOD_MAX, Green=PWM_PERIOD_MAX, Blue=PWM_PERIOD_MAX4; // Weiss
73
  }
74
  else
75
  {
76
    H /= 60;        // sector 0 to 5
77
    i = floor(H);
78
    f = H - i;      
79
    p = V * (1 - S);
80
    q = V * (1 - S * f);
81
    t = V * (1 - S * (1 - f));
82
  
83
     switch(i)
84
        {
85
        case 0:
86
          r = V; g = t; b = p; 
87
        break;
88
        
89
        case 1:
90
          r = q; g = V; b = p; 
91
        break;
92
          
93
        case 2:
94
          r = p; g = V; b = t; 
95
        break;
96
            
97
        case 3:
98
          r = p; g = q; b = V; 
99
        break;      
100
            
101
        case 4:
102
          r = t; g = p; b = V; 
103
        break;
104
                    
105
        default:                
106
          r = V; g = p; b = q; 
107
        break;        // case 5:          
108
      }
109
    
110
    // In RGB Integer konvertieren 
111
    
112
    Red=r*PWM_PERIOD_MAX;
113
    Green=g*PWM_PERIOD_MAX;
114
    Blue=b*PWM_PERIOD_MAX;  
115
    
116
  }  
117
  
118
  // OCxRS Register wird in Timer3 IRQ in OCxR Register kopiert
119
  OC1RS = Red;   // PWM Werte invertieren und ausgeben
120
  OC2RS = Green;   // PWM Werte invertieren und ausgeben
121
  OC3RS = Blue;   // PWM Werte invertieren und ausgeben
122
  
123
  if(W_LED_ENABLED)  OC4RS = 0;     // Weisse LED einschalten
124
  if(W_LED_DISABLED) OC4RS = PWM_PERIOD;  // Weisse LED ausschalten    
125
}
126

127

128
/****************************************************************************/
129
/* * * * * * * * * * * * *       HAUPTPROGRAMM        * * * * * * * * * * * */
130
/****************************************************************************/
131
int main(void)
132
{
133
  volatile unsigned short H,S,V;  
134

135
  init_system();
136

137
    H=0;
138
    S=100;
139
    V=100;
140
    
141
    W_LED_OFF;  // Weisse LED ausschalten
142
  
143
  while(1) // endless
144
  {  
145
    
146
    if(H < 360) H++;   // 0-360° Farbwechsel jede Millisekunde
147
      else H=0;   
148
      
149
    hsv_to_rgb(H,S,V);  // HSV Werte in RGB konvertieren und ausgeben
150
      
151
    __delay_ms(100);  // 100ms warten
152
  
153
  }
154
}    
155

156
// 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!
Gast #1693003
Lesenswert?

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

da hat jedes PWM-Modul sein eigenes PRx-Register
OP #1693059
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!

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren