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


von Andreas H. (andy61)


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!

von Johann L. (gjlayde) Benutzerseite


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.

von Andreas H. (andy61)


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

von Andreas H. (andy61)


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

von futzi (Gast)


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

von C30 (Gast)


Lesenswert?

Versuch mal so:
1
#define PWM_PERIOD_MAX  1023  // 10Bit Auflösung

von C30 (Gast)


Lesenswert?

Ist das so gewollt:
1
Blue=PWM_PERIOD_MAX4;
max4?

von Andreas H. (andy61)


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!

von Johann L. (gjlayde) Benutzerseite


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.

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.