Oppure

Loading
22/03/15 20:55
Roby94
Buonasera, sto apportando alcune migliorie ad un sistema di gestione illuminazioni, si tratta solo di migliorare le modalità già disponibili.
Una delle modalità è un gradiente di colori che si puo vedere come il precorrimento della circonferenza dell'HSV con S=V=1 quindi con H variabile.
Per far ciò ho questa funzione
void RGBScaleMode()//Gradiente RGB
{
	uint8_t delay = EEPROMRead(EEPROM_SCALERGB_DELAY);//Recupero il valore di delay

	while(1)
	{
		for(; GREEN != 255; GREEN++) _delay_ms(delay);//Porto il verde al massimo
		for(; RED != 0; RED--) _delay_ms(delay);//Porto il rosso al minimo
		for(; BLUE != 255; BLUE++) _delay_ms(delay);//Porto il blu al massimo
		for(; GREEN != 0; GREEN--) _delay_ms(delay);//Porto il verde al minimo
		for(; RED != 255; RED++) _delay_ms(delay);//Porto il rosso al massimo
		for(; BLUE != 0; BLUE--) _delay_ms(delay);//Porto il blu al minimo
	}	
}

e fino qui nessun problema.
Il codice visto in precedenza impone che i valori di partenza siano GREEN=BLUE=0 e RED=255, vorrei eliminare questa limitazione, potendo far partire il gradiente da un colore qualsiasi. Ho iniziato modificando cosi.
void RGBScaleMode()//Gradiente RGB
{
	uint8_t delay = EEPROMRead(EEPROM_SCALERGB_DELAY);//Recupero il valore di delay
	uint8_t *min;
	
	if(RED < GREEN && RED < BLUE) min = &RED;//Identifico quale sia la componente minore tra le 3
	else if(GREEN < RED && GREEN < BLUE) min = &GREEN;
	else min = &BLUE;	
	for(; *min != 0; *min--) _delay_ms(delay);//Lo riduco a 0 graduatamente
	
        /****/
}

Con la parte di codice aggiunta identifico quale tra le tre componenti sia la minore e la porto lentamente a 0 riportandomi sulla circonferenza facendo il minor tragitto possibile, ora però non mi viene in mente come continuare l'algoritmo per poter riprendere a percorrere la circonferenza dal nuovo colore trovato, vi viene in mente un modo? Mi aiutereste molto, io continuo a pensarci in tanto.
Grazie

PS Il topic l'avrei volentieri messo nella sezione algoritmi ma trattandosi di un algoritmo da modellarsi su un linguaggio specifico, ho pensato fosse meglio la sezione di C.
Ultima modifica effettuata da Roby94 22/03/15 20:57
aaa
22/03/15 22:27
pierotofy
Io calcolerei una mappa durante l'inizializzazione (che renderebbe il codice più veloce, oltretutto). La mappa deve essere "linearizzata" per mappare tutti i possibili valori di RGB.

Un intero ciclo impiega: 0-255 + 255-0 + 0-255 + 255-0 + 0-255 + 255 - 0 = 256 * 3 = 1536 valori.

Ogni combinazione di colori è rappresentata da 3 bytes (0-255 = 1 byte + 0-255 = 1 byte + 0-255 = 1 byte). Il tipo più vicino è quindi int (che presumo sulla tua piattaforma sia 4 bytes).

Quindi qualcosa del genere...

int colorMap[1535];


Ad inizializzazione, devi scrivere il codice che inizializzi la colorMap (o ancora meglio, puoi scrivere un programma che la calcoli staticamente e poi inizializzarla direttamente durante la compilazione).

int colorMap[1535] = {valore1, valore2, ecc.}


I valori possono essere mappati come segue:

0|R|G|B (il primo byte è zero).

Ad esempio:

void setMap(int index, uint8_t r, uint8_t g, uint8_t b){
    colorMap[index] = 0x00000000 | (r << 16) | (g << 8) | (b << 0); // << 0 non serve, ma per consistenza lo lascio.[
}

setMap(0, 255, 0, 0);
setMap(1, 254, 0, 0);
// eccetera, automatizza con un for loop simile a quello postato da te


Dopodichè, per estrarre i valori:

uint8_t r, g, b;
r = (colorMap[index] & 0x00110000) >> 16;
g = (colorMap[index] & 0x00001100) >> 8;
b = (colorMap[index] & 0x00000011) >> 0; // Lo >> 0 non serve, ma per consistenza lo lascio


Una volta che hai la mappa, puoi semplicemente incrementare index e partire da qualsiasi punto (da 0, da 300, da 600, non importa) per prendere i valori che ti servono.

Quando arrivi a 1535 riparti da 0.

:k:

Bonus: puoi salvare il 25% di spazio comprimendo gli spazi inutilizzati dallo 0 per ogni valore della mappa (invece di 0|R|G|B|0|R|G|B ... puoi fare con un pò di più complessità R|G|B|R|G|B....). L'esercizio è lasciato al lettore.
Ultima modifica effettuata da pierotofy 22/03/15 22:34
Il mio blog: piero.dev
22/03/15 22:36
Roby94
Ottima soluzione Piero, grazie, ma 6KB di array :-| è pauroso. Attualmente il codice è pensato per risiedere su ATmega328P, 32KB di flash, consiglieresti questa strada anche su un dispositivo del genere? Prendendo in considerazione che questo non è l'unica modalità presente.
aaa
22/03/15 22:37
pierotofy
Chiaramente se sei a corto di memoria questa soluzione non è adatta. Ma se hai memoria... usala!
Il mio blog: piero.dev
22/03/15 22:43
Roby94
Il problema è che non so come la memoria venga gestita, mi riferisco alla ram, l'array viene interamente caricato in memoria? se è cosi allora non è un metodo applicabile su ATmega328P se non sbaglio vi sono solo 2KB di ram.
Ultima modifica effettuata da Roby94 22/03/15 22:43
aaa
22/03/15 22:47
pierotofy
Oppure usa goto:

switch(...){
  case ... : 
    goto green;
  // ...

  default:
};

while(1)
        {      
                green:
                for(; GREEN != 255; GREEN++) _delay_ms(delay);//Porto il verde al massimo
                
                red:
                for(; RED != 0; RED--) _delay_ms(delay);//Porto il rosso al minimo
                
                blue:
                for(; BLUE != 255; BLUE++) _delay_ms(delay);//Porto il blu al massimo
                // ....
        } 


Almeno puoi partire da un determinato colore (senza la precisione esatta della mappa).
Il mio blog: piero.dev
22/03/15 22:50
pierotofy
Postato originariamente da Roby94:

Il problema è che non so come la memoria venga gestita, mi riferisco alla ram, l'array viene interamente caricato in memoria? se è cosi allora non è un metodo applicabile su ATmega328P se non sbaglio vi sono solo 2KB di ram.


Mm, si, effettivamente non funzionerà. Per accedere all'array, l'array dev'essere caricato in memoria.
Il mio blog: piero.dev
22/03/15 22:53
Roby94
Cavoli, in effetti è un metodo che garantisce una certa semplicità di utilizzo una volta generata la mappa... peccato, ti viene in mente un altro modo?
aaa