Ir a página principal
Ir al índice del tema
Ir a página anterior de este tema



PROGRAMANDO LA PLACA DE DESARROLLO Mini-STM32 - VIII

DESCUBRIENDO LA GAMA CROMÁTICA


Mientras sigo en vilo por quien será el misterioso personaje del Audi que está indagando sobre mi persona, y temiéndome que sea del CNI, o de la CIA, o del Mossad, o peor aún, de la SGAE, he decidido retomar un tema que cerré en falso en una entrega anterior. Se trata de los colores, que en el software de esta placa están pobremente representados por 10 únicas posibilidades, y que si descontamos el blanco, el negro y un tono de gris, nos reduce a 7 la "gama cromática" disponible para nuestros programas.


  
   Retomando el asunto de los colores en la Mini-STM32


En la página VI de este tutorial hablé un poco sobre el formato de colores de la Mini-STM32. El display y su controlador pueden en teoría mostrar 262.144 colores, lo cual representa una información de 6+6+6=18 bits para cada punto de color, o lo que es equivalente, 64 niveles de color distintos para cada uno de sus componentes primarios, el rojo, el verde y el azul.

Y sin embargo, justo bucear un poco en las librerías gráficas descubro que en la práctica estos 64 niveles se mantienen únicamente para el verde, pero se reducen a 32 para el rojo y el azul. De esta forma, la palabra binaria que define un punto de color determinado tiene 5 bits para el rojo, 6 para el verde y 5 para el azul, totalizando 16 bits en una configuración de 65.536 colores.

Mi idea en la página VI era al menos poder utilizar otros colores intermedios a los 10 iniciales que vienen definidos por su nombre (
White, Black, Grey, Blue, Blue2, Red, Magenta, Green, Cyan, Yellow) y que si bien serán suficientes para la gran mayoría de los usos de la placa, resultan un abanico realmente pobre en caso de tratar con gráficos o imágenes. En esta misma página incluí entonces una sencilla fórmula para hallar el valor de un nuevo color a partir de los correspondientes valores RGB de Windows, que podemos obtener de cualquier programa de retoque de imágenes, como por ejemplo el Photoshop, pero tal fórmula era aproximada y debo confesar que no daba muy buenos resultados en colores muy claros o muy oscuros.

Por otra parte, he descubierto en las librerías una función denominada RGB565CONVERT(rojo, verde, azul) que efectúa dicha transformación mediante desplazamientos binarios, lo que elimina el error causado por los cálculos decimales, y a partir de los valores "Windows" R, G y B nos da el valor en decimal o hexadecimal que necesitamos para crear un nuevo color. Un ejemplo de uso de esta instrucción sería el siguiente:

   LCD_RectangleFill ( 0, 0, 40, 40, Red) 

...nos dibujaría un rectángulo rojo de 40x40 pixels en la esquina superior-izquierda

   LCD_RectangleFill ( 0, 0, 40, 40, RBG565CONVERT (255, 0, 0) )

...haría lo mismo que la anterior, con la salvedad que cambiando los valores (rojo, verde, azul) encerrados en el paréntesis podríamos conseguir cualquier otro color de la escala. Por ejemplo, el naranja, que no está definido originalmente por una palabra, sería:

  
LCD_RectangleFill ( 0, 0, 40, 40, RBG565CONVERT (255, 127, 0) )

...y un gris intermedio entre blanco y negro sería:


  
LCD_RectangleFill ( 0, 0, 40, 40, RBG565CONVERT (127, 127, 127) )

Y sin embargo, hay un problema. Éste consiste en que el cromatismo de la pantalla LCD de la placa difiere bastante del que podamos tener en la de nuestro ordenador y esto puede provocar que en realidad no obtengamos una réplica del color deseado, lo cual no sería demasiado importante para representar imágenes fotográficas en que los colores absolutos pierden importancia respecto a su relación, pero sí puede serlo en caso de diseño de interfaces para nuestros programas.

Para este caso caso he decidido explorar el tema un poco más a fondo, y he realizado un par de programas experimentales que ayudarán a despejar dudas y a obtener con exactitud en la pantalla de la Mini-STM32 cuantos colores deseemos entre la gama de los 65 mil.

A igual que en otros casos anteriores, para poder compilarlos será necesario bajar el proyecto denominado 08-GLC-Touch-Color.rar así como disponer en el ordenador del Keil uVisión 4.1 y el Flash Loader Demo.

___________________________________
  
  
Respecto a los proyectos de Keil uVisión, las versiones de sus librerías y los archivos auxiliares


Respecto a los proyectos de Keil que he utilizado a lo largo de estas páginas, hasta ahora los he adaptado de forma un tanto arbitraria, pero mi idea es que sean "ascendentemente compatibles", es decir, que los últimos puedan servir para compilar los primeros programas de este tutorial, pero no al revés, ya que en las librerías he ido añadiendo funciones propias que no estarán disponibles en las primeras versiones. Por este motivo procuraré ir actualizando las más antiguas para estandarizar un poco su contenido y no llegar al punto de tener que utilizar cien proyectos distintos a lo largo del tutorial.

Otros cambios son que los programas de ejemplo que figuran en cada página, estarán también ahora contenidos en el proyecto pero guardados en forma de texto en la carpeta Doc, y por tanto podrán ser copiados hacia el "main" desde el propio proyecto, sin necesidad de hacer un copiar-pegar desde la página web. De igual forma, también incluyo en la carpeta del proyecto los archivos ejecutables de formato .hex que ya están compilados y verificados, y por tanto pueden cargarse directamente a la placa utilizando el Flash Loader Demo.

En este caso concreto, al bajar el archivo 08-GLCD-Touch-color.rar y descomprimirlo, dentro de la carpeta del proyecto del mismo nombre vemos directamente los dos archivos ejecutables Program-08-01.hex y Program-09-02.hex que corresponden a los dos programas que describo a continuación. Los archivos de texto del mismo nombre con el código C compilable están guardados en la subcarpeta USER.

___________________________________


   Programa generador de gama cromática continua para la Mini-STM32

Al primer programa lo llamo "Generador de gama cromática continua para la Mini-STM32" y el código aparece en el recuadro de texto que viene a continuación. Dicho código tiene muchas partes comunes a otros que hemos visto antes, en concreto toda la parte de inicialización de la placa y de la pantalla, aunque para limitar al máximo la extensión del "main" propiamente dicho, he creado algunas funciones que junto al resto explicaré más abajo. Así que mejor lo cargamos mediante cualquiera de las opciones reseñadas y directamente observamos que hace.


Programa generador de gama cromática continua para la Mini-STM32

//programa generador de gama cromática continua para Mini-STM32
//by Anilandro (http://sites.google.com/site/anilandro/), noviembre de 2011

#include "stm32f10x.h"
    // inclusión de librerías necesarias
 
#include "TouchPanel.h"
#include "systick.h"
#include "GLCD.h"
#include <stdio.h>

                                                      //declaración de funciones particulares

void PrintVals(void);              
// imprime valores numéricos RGB y de nivel de gris

void PrintBars(void);
              // imprime barras de ajuste de valores cromáticos

void PrintRect(void);
              // imprime cuadro sólido de color elegido

void PrintPRect(uint8_t);
      // imprime cuadro de paleta continua de color

void LimitsRGB(void);
             // establece límites de valores RGB

void Reset(void);
                     // resetea variables y redibuja objetos gráficos generales


int16_t r,g,b,k,ar,ag,oper,aoper,aux;   // declaración de variables comunes
int f,h;
char cadena[10];

int main(void)
                                               // inicio del main

    {

    uint16_t x, y, p;
                                        // declaración de variables particulares del main



    SystemInit();
                                            // iniciación de los elementos

    LCD_Initializtion();
                                  // iniciación del LCD

    LCD_BackLight_Init();                            // encendido de retroiluminación del LCD
    delay_init();
    LCD_BackLight(255);
                              // establece brillo de luz

    LCD_FormatSet(0);
                                 //establece formato de pantalla en horizontal

    TP_Init();
                                                    //inicia TouchPanel

    TouchPanel_Calibrate();
                         //calibración del TouchPanel

    LCD_Clear(White);
                                   // iniciación del LCD


    Reset();
                                                      //iniciación de elementos gráficos del programa


//============================================================================

    while(1)                                                      //comienza bucle principal del programa
        {
        p=LCD_TouchRead(&display);         //lee la posición del puntero sobre la pantalla
        x=display.x;                                          //extrae coordenada x
        y=display.y;                                          //extrae coordenada y

        if(p==1)
                                                 //detecta pulsación sobre barras de color y escala de grises

            {
            aux=3+((x-11)*2);
            if((x>8)&&(x<138)&&(y>152)&&(y<167)){r=aux,oper=1;}   //detecta cambio valor barra roja
            if((x>8)&&(x<138)&&(y>169)&&(y<184)){g=aux,oper=2;}   //detecta cambio valor barra verde
            if((x>8)&&(x<138)&&(y>186)&&(y<201)){b=aux,oper=3;}   //detecta cambio valor barra azul
            if((x>8)&&(x<138)&&(y>203)&&(y<218)){k=aux,oper=4;}   //detecta cambio valor barra gris
            LimitsRGB();

            if(oper>0)
     //efectúa el redibujado de barras y de la paleta cromática continua

                {
                if(oper<4){aoper=oper;}
                if(oper==4){r=k,g=k,b=k;}      // cambio nivel de gris
                PrintBars();
                PrintVals();
                PrintRect();
                PrintPRect(aoper);
                oper=0;
                }

            if((x>9)&&(x<142)&&(y>11)&&(y<142))      //detecta coordenadas x-y en la paleta cromática continua
            {
            ar=r;
            ag=g;
            if(aoper==1){g=((x-13)*2),b=((y-13)*2);}
            if(aoper==2){r=((x-13)*2),b=((y-13)*2);}
            if(aoper==3){r=((x-13)*2),g=((y-13)*2);}
            LimitsRGB();
            PrintVals();
            PrintRect();
            PrintBars();
            }

            if((x>198)&&(x<278)&&(y>199)&&(y<215))      //detecta pulsación de RESET y establece valores iniciales
            {
            Reset();
            for(f=0;f<1000000;f++);
            }

        }
    }      //final de "while"
}          //final de "main"

//============================================================================
//=========================   Funciones privadas  =====================================

//============================================================================


void PrintVals(void)
                                           //función imprime variables

    {
    int tot;

    sprintf(cadena,"R %d",r);
    GUI_Text(152,151,"     ",Red,White);
    GUI_Text(152,151,cadena,Red,White
);   //imprime valor rojo
    sprintf(cadena,"G %d",g);
    GUI_Text(152,167,"     ",Red,White);
    GUI_Text(152,167,cadena,Red,White);
   //imrime valor verde

    sprintf(cadena,"B %d",b);
    GUI_Text(152,183,"     ",Red,White);
    GUI_Text(152,183,cadena,Red,White);
   //imprime valor azul

    sprintf(cadena,"Y %d",k);
    GUI_Text(152,199,"     ",Red,White);
    GUI_Text(152,199,cadena,Red,White);
   //imprime valor gris


    sprintf(cadena,"RGB %02X%02X%02X",r,g,b);
    GUI_Text(198,151,"          ",White,Blue);
    GUI_Text(198,151,cadena,White,Blue);
   //imprime valor RGB en hexadecimal de 24 bits (888)


    tot=((31*r/255)*2048)+((63*g/255)*32)+((31*b/255)*1);
    sprintf(cadena,"RGB %X",tot);
    GUI_Text(198,167,"          ",White,Blue);
    GUI_Text(198,167,cadena,White,Blue);
    //imprime valor en hexadecimal de 16 bits (565)

    }

//============================================================================

void PrintBars(void)               //función imprime barras de color y grises
    {
    for(f=0;f<128;f++)           // dibuja barra cromática roja
        {
        if(f<(r/2)){LCD_DrawLine(f+11, 152, f+11, 167, RGB565CONVERT(f*2,0,0));}
        if(f>(r/2)){LCD_DrawLine(f+11, 152, f+11, 167, White);}
        }
    for(f=0;f<128;f++)            // dibuja barra cromática verde
        {
        if(f<(g/2)){LCD_DrawLine(f+11, 169, f+11, 184, RGB565CONVERT(0,f*2,0));}
        if(f>(g/2)){LCD_DrawLine(f+11, 169, f+11, 184, White);}
        }
    for(f=0;f<128;f++)            // dibuja barra cromática azul
        {
        if(f<(b/2)){LCD_DrawLine(f+11, 186, f+11, 201, RGB565CONVERT(0,0,f*2));}
        if(f>(b/2)){LCD_DrawLine(f+11, 186, f+11, 201, White);}
        }
        k=(r+g+b)/3;                   // calcula escala grises
        for(f=0;f<128;f++)        // dibuja escala de grises
        {
        if(f<(k/2)){LCD_DrawLine(f+11, 203, f+11, 218, RGB565CONVERT(f*2,f*2,f*2));}
        if(f==(k/2)-1){LCD_DrawLine(f+11, 203, f+11, 218, RGB565CONVERT(0,0,0));}
        if(f>(k/2)){LCD_DrawLine(f+11, 203, f+11, 218, White);}
        }

    }

//============================================================================

void PrintRect(void)
     //función imprime cuadrado sólido de color elegido

    {
    LCD_RectangleFill(150,10,128,127,RGB565CONVERT(r,g,b));
    }

//============================================================================

void PrintPRect(uint8_t color)
     //función imprime paleta continua de color

    {
    for(f=0;f<128;f++)
        {
        for(h=0;h<128;h++)
            {
            if (color==1){LCD_SetPoint(f+10,h+10,RGB565CONVERT(r,f*2,h*2));}
            if (color==2){LCD_SetPoint(f+10,h+10,RGB565CONVERT(f*2,g,h*2));}
            if (color==3){LCD_SetPoint(f+10,h+10,RGB565CONVERT(f*2,h*2,b));}
            }
        }
    }

//============================================================================

void LimitsRGB(void)
     //establece límites de valores RGB

    {
    if(r>255){r=255;}
    if(g>255){g=255;}
    if(b>255){b=255;}
    if(k>255){k=255;}
    if(r<0){r=0;}
    if(g<0){g=0;}
    if(b<0){b=0;}
    if(k<0){k=0;}
    }

//============================================================================

void Reset(void)
     //función de reteseo de variables y redibujar objetos gráficos generales

    {
    LCD_Rectangle(8,8,131,131,2,Black);           // dibuja recuadro negro superior izquierda
    LCD_Rectangle(148,8,131,131,2,Black);      // dibuja recuadro negro superior derecha
    LCD_Rectangle(8,148,132,72,2,Black);        // dibuja recuadro negro inferior izquierda
    LCD_Rectangle(148,148,134,72,2,Black);   // dibuja recuadro negro inferior derecha

    GUI_Text(208,151,"RGB",White,Blue);
    GUI_Text(198,200," RESET ",White,Red);

    r=255,g=255,b=255,k=255,oper=0,aoper=1;

    PrintBars();
    PrintVals();
    PrintRect();
    PrintPRect(1);
    }


Al arrancar el programa primeramente nos parecerá la pantalla azul oscuro de calibrado del Touch Panel, con las tres cruces sucesivas que deberemos marcar con el punzón de plástico, y seguidamente ya veremos la imagen que viene a continuación, donde distinguimos cuatro partes diferenciadas.

Generador de gama cromática continua para la Mini-STM32


1) El cuadro de la esquina inferior-izquierda contiene cuatro barras de desplazamiento, las tres RGB, correspondientes a los colores básicos Rojo, Verde y Azul, y la de escala de grises. Estas barras son desplazables con el punzón y establecen el valor desde 0 a 255 del color correspondiente, o de la luminosidad total en grises del punto en cuestión. En teoría, estos controles bastan para crear cualquier color de los 65.536 posibles. Dicho color aparecerá en forma sólida en el cuadrado de la esquina superior-derecha.
En caso de pulsar la escala de grises observamos como el resto de barras adoptan el mismo valor, los cual crea precisamente dicha escala de grises, sin que le punto tenga ningún matiz cromático que destaque sobre los demás.

2) Mientras hemos creado colores por el procedimiento anterior habremos observado como también cambia el cuadro de la parte superior-izquierda, que a diferencia del derecho muestra una especie de degradado de color. Pues bien, este cuadro representa los colores situados "alrededor" del que hemos estado creando, el cual ocupa más o menos el centro geométrico del cuadrado, y nos ayudará a elegir matices y variaciones que sin verlas difícilmente se nos ocurrirían. Los colores de este cuadro son también "elegibles", es decir, que si pulsamos con el punzón sobre cualquier punto, el color de dicho punto aparecerá en forma sólida en el cuadro de la derecha, a la vez que las barras inferiores cambiarán de acuerdo a la nueva proporción de colores básicos.

3) Todo esto es muy bonito, pero de poco nos serviría si no sabemos como reproducir los colores que creemos mediante estos procedimientos. Para ello necesitamos saber numéricamente los porcentajes de Rojo, Verde y Azul que contiene cada color. Dichos valores nos lo suministra el programa en el recuadro de la esquina inferior-derecha, en diversos formatos:

A)
En forma R,G y B, más la luminosidad Y, con valores para cada uno que van de 0 a 255 (compatibles con escalas de Windows).

B) Los mismos valores combinados en forma de número hexadecimal de 6 caracteres (equivalentes a 8-8-8 bits, también compatibles con Windows), siendo los dos primeros el valor del rojo, el segundo y el tercero el valor del verde, y los dos últimos el valor del azul.
C) Los mismos valores combinados en forma de número hexadecimal de 4 caracteres (5-6-5 bits) que es el valor que deberemos utilizar para reproducir este color en el formato particular de la Mini-STM32.
 
___________________________________

 
   Descripción secuencial del programa "Generador de gama cromática continua"

A partir de ahora ya no describiré los programas en toda su extensión, ya que se supone que hemos ido adquiriendo una pequeña experiencia en C y podemos entender la acción de la mayoría de las órdenes individuales. La idea es que este tutorial pueda ser más rápido y directo, aunque a veces es difícil acertar en el punto justo de concrección sin saltarnos cosas importantes.

Entremos en materia. Por una parte podemos repasar el contenido del bucle principal del programa, y de la otra las seis funciones privadas de este programa. La secuencia, que podemos seguir sobre el código anterior, es la siguiente:


1) Comienza el bucle "while( )" principal del programa
2) Comprueba si hay pulsación sobre la pantalla y en este caso establece valores de coordenadas x, y, con p=1 si la pulsación es fiable
3) Calcula valor de horizontal de "x" para establecer nuevo valor de barra de color
4) Detecta si hay pulsación sobre rectángulo de barra roja
5) Detecta si hay pulsación sobre rectángulo de barra verde
6) Detecta si hay pulsación sobre rectángulo de barra azul
7) Detecta si hay pulsación sobre rectángulo de barra gris

8) De acuerdo a lo abtenido anteriormente, redibuja gráficos de barras de color con PrintBars( )
9) Redibuja los valores númericos de color con PrintVals( )
10) Redibuja color sólido en cuadro de arriba-derecha con PrintRect( )
11) Redibuja paleta de color degradado en cuadro de arriba-izquierda con PrintPRect( )

12) Comprueba si hay pulsación sobre cuadro de paleta de color degradado y en consecuencia:
13) Comprueba que los valores R, G, B estén dentro de los límites con LimitsRGB( )
14) Actualiza valores númericos del color con PrintVals( )
15) Redibuja color sólido en cuadro de arriba-derecha con PrintRect( )
16) Redibuja gráficos de barras al valor anterior con PrintBars( )

17) Comprueba si hay pulsación en rectángulo RESET y recupera todos los gráficos, valores y colores iniciales con Reset( )

18) Cierra el bucle "while(1)" y vuelve al principio

En esta ocasión, la parte del "main" es bastante corta, ya que la mayoría del trabajo lo realizan las seis funciones privadas que he definido:


    Las funciones privadas de este programa

19) La void PrintVals(void), imprime los valores númericos de los colores R, G y B y de la luminosidad Y. Imprime además los valores combinados RGB en hexadecimal, en dos formatos, el de 24 bits (8+8+8), y el especial de esta placa de 16 bits (5+6+5)

20) La void PrintBars(void), dibuja las barras de color R, G, B e Y de una longitud entre su origen y el punto donde el marcador toca la pantalla (naturalmente siempre dentro del rectángulo permitido. La forma de dibujo es en color degradado hasta el tope de la barra y en blanco, y por tanto invisible, hasta el tope. Los valores de las variables de color se actualizan al cambiar las barras, así como el cuadro el color degradado.

21)
La void PrintRect(void), dibuja el cuadrado de color sólido de la parte superior-derecha. El color es el seleccionado con el marcador a través de las barras o bien en el cuadro de color degradado.

22) La void PrintPRect(uint8_t color), dibuja el cuadrado con una paleta de color degradado de la parte superior-izquierda. Esta paleta se crea con nivel fijo del color cuya barra se haya pulsado en último lugar, y una gradación de 0 a 255 de los otros dos colores. Al marcar sobre un punto de esta paleta seleccionamos el color sólido correspondiente en el cuadro de la derecha y, a la vez, las barras de color reaccionan adoptando la mezcla de colores primarios que lo forman. Las variables numéricas de color también cambian de acuerdo a cada cambio absoluto de cualquier color.

23) La void LimitsRGB(void), establece el límite cromático controlando que los valores de color, así como los de luminosidad, no sean inferiores a 0 ni superiores a 255

24) La void Reset(void), redibuja gráficos y pone variables en sus valores iniciales.
 
___________________________________


   Programa generador de gama cromática por colores definidos para la Mini-STM32

El segundo programa es algo distinto, ya que cambia la gama continua por 12 colores definidos, y a partir de cada uno de ellos crea 9 grados de saturación, correspondiendo la central al color definido original. Aparte de eso genera una escala de grises de 9 pasos, correspondiendo el primero al blanco y el último al negro.

Programa generador de gama cromática por colores definidos para la Mini-STM32

//programa generador de gama cromática por colores definidos para Mini-STM32
//by Anilandro (http://sites.google.com/site/anilandro/), noviembre de 2011

#include "stm32f10x.h"    
// inclusión de las librerías necesarias

#include "TouchPanel.h"
#include "systick.h"
#include "GLCD.h"
#include <stdio.h>
                                                   // declaración de funciones particulares
                                                   
void PrintMatrix(void);
        // imprime matriz de cuadros para ser rellenados de color

void PrintColors(void);
        // rellena cuadros de colores definidos

void ShowVals(void);
           // muestra valores numéricos de colores


int f;
                                          // declaración de variables públicas

uint16_t x,y,p,color;

int main(void)
                        // inicio del "main"

     {
    SystemInit();
                     // inicialización de elementos de la placa

    LCD_Initializtion();
    LCD_BackLight_Init();
    delay_init();
    LCD_BackLight(255);      
// establece brillo de luz

    LCD_FormatSet(0);
          // establece formato de pantalla en horizontal

    TP_Init();                           
// inicia TouchPanel

    TouchPanel_Calibrate();
// calibración del TouchPanel

    LCD_Clear(White);

    PrintMatrix();
                     // imprime matriz de cuadros vacíos

    PrintColors();                    
// imprime escala de colores en cuadros

    ShowVals();                        // muestra valores numéricos de colores


    while(1)
                               // comienza bucle principal del programa

        {
        p=LCD_TouchRead(&display);
       // lee la posición del puntero sobre la pantalla

        x=display.x;
                                       // extrae coordenada x

        y=display.y;
                                       // extrae coordenada y


        if(p==1)
            {
            ShowVals();
     // muestra valores del color elegido

            }
        while(p==1)
        // retiene el ciclo si no se deja de pulsar la pantalla

            {
            p=LCD_TouchRead(&display);    // lee estado de puntero sobre la pantalla
            }
        }
    }

//========================================================================
//=========================   Funciones privadas definidas  ===========================

//========================================================================


void ShowVals(void)     //muestra valores de color elegido

    {
    uint16_t cr,cg,cb,aux;
    char cadena[30];

    for(f=0;f<100;f++)
        {
        color=(uint16_t)LCD_GetPoint(1,1);    
// lee valor de color de punto x-y en pantalla

        }
    color=(uint16_t)LCD_GetPoint(x,y);       
  // lee valor de color de punto x-y en pantalla


    cr=((color>>11)*255)/31;
                   // extrae valor del rojo
    aux=color<<5;
                                               // extrae valor del verde

    cg=((aux>>10)*255)/63;
    aux=color<<11;
                                             // extrae valor de azul

    cb=((aux>>11)*255)/31;

    sprintf(cadena,"C565 %04X ",color);       // imprime valor RGB565 en hexadecimal de 16 bits

    GUI_Text(2,2,"           ",White,Blue);
    GUI_Text(2,2,cadena,White,Blue);

    sprintf(cadena,"C888 %02X%02X%02X",cr,cg,cb);
    //imprime valor RGB888 en hexadecimal de 24 bits

    GUI_Text(2,18,"           ",White,Blue);
    GUI_Text(2,18,cadena,White,Blue);

    sprintf(cadena," R %d",cr);
          //imprime valor R 0-255

    GUI_Text(2,34,"           ",White,Blue);
    GUI_Text(2,34,cadena,White,Blue);

    sprintf(cadena," G %d",cg);
          //imprime valor G 0-255

    GUI_Text(2,50,"           ",White,Blue);
    GUI_Text(2,50,cadena,White,Blue);

    sprintf(cadena," B %d",cb);         
  //imprime valor B 0-255

    GUI_Text(2,66,"           ",White,Blue);
    GUI_Text(2,66,cadena,White,Blue);

    if(x>88)
                                                //rellena 5 rectángulos con los últimos 5 colores seleccionados

        {
        LCD_RectangleFill(5,211,82,22,LCD_GetPoint(7,185));
     //dibuja 5º rectángulo de color anterior

        LCD_RectangleFill(5,180,82,22,LCD_GetPoint(7,154));
     //dibuja 4º rectángulo de color anterior

        LCD_RectangleFill(5,149,82,22,LCD_GetPoint(7,123));
     //dibuja 3º rectángulo de color anterior

        LCD_RectangleFill(5,118,82,22,LCD_GetPoint(7,92));       
//dibuja 2º rectángulo de color anterior

        LCD_RectangleFill(5,87,82,22,color);
                                      //dibuja primer rectángulo lleno del color elegido

        }
    }

//========================================================================

void PrintMatrix(void)
     // imprime matriz de 11x12 rectángulos donde dibujar las escalas de colores definidos

    {
     uint16_t r;
    for(r=0;r<13;r++)
        {
        LCD_Rectangle(92,2+(r*18),225,18,1,Black);
        }
    for(r=1;r<9;r++)
        {
        LCD_DrawLine(92+(r*25),2,92+(r*25),237,Black);
        }
        LCD_Rectangle(2,84,87,28,2,Black);
        LCD_Rectangle(2,115,87,28,2,Black);
        LCD_Rectangle(2,146,87,28,2,Black);
        LCD_Rectangle(2,177,87,28,2,Black);
        LCD_Rectangle(2,208,87,28,2,Black);
        }

//========================================================================

void PrintColors(void)
     // crea 12 escalas de color más una de grises y rellena los rectángulos anteriores

    {
    int f,v,z,t;

    for(f=1;f<10;f++)
        {
        v=255-(f*51);
        z=255-((f-5)*51);
        if(v<0){v=0;}
        if(z<0){v=0;}

        if(f<6){LCD_RectangleFill((f*25)+69,4,22,14,RGB565CONVERT(255,v,v));}
                       // escala Red ( Rojo )

        if(f>5){LCD_RectangleFill((f*25)+69,4,22,14,RGB565CONVERT(z,0,0));}

        if(f<6){LCD_RectangleFill((f*25)+69,22,22,14,RGB565CONVERT(255,(255+v)/2,v));}  
  // escala Orange ( Naranja )

        if(f>5){LCD_RectangleFill((f*25)+69,22,22,14,RGB565CONVERT(z,z/2,0));}

        if(f<6){LCD_RectangleFill((f*25)+69,40,22,14,RGB565CONVERT(255,255,v));}
                // escala Yellow ( Amarillo )

        if(f>5){LCD_RectangleFill((f*25)+69,40,22,14,RGB565CONVERT(z,z,0));}

        if(f<6){LCD_RectangleFill((f*25)+69,58,22,14,RGB565CONVERT((255+v)/2,255,v));}   
// escala Lemon ( Limón )

        if(f>5){LCD_RectangleFill((f*25)+69,58,22,14,RGB565CONVERT(z/2,z,0));}

        if(f<6){LCD_RectangleFill((f*25)+69,76,22,14,RGB565CONVERT(v,255,v));}                     
// escala Green ( Verde )

        if(f>5){LCD_RectangleFill((f*25)+69,76,22,14,RGB565CONVERT(0,z,0));}

        if(f<6){LCD_RectangleFill((f*25)+69,94,22,14,RGB565CONVERT(v,255,(255+v)/2));}
   // escala Turquoise ( Turquesa )

        if(f>5){LCD_RectangleFill((f*25)+69,94,22,14,RGB565CONVERT(0,z,z/2));}

        if(f<6){LCD_RectangleFill((f*25)+69,112,22,14,RGB565CONVERT(v,255,255));}             
  // escala Cyan ( Cyan )

        if(f>5){LCD_RectangleFill((f*25)+69,112,22,14,RGB565CONVERT(0,z,z));}

        if(f<6){LCD_RectangleFill((f*25)+69,130,22,14,RGB565CONVERT(v,(255+v)/2,255));}  // escala Indigo ( Añil )

        if(f>5){LCD_RectangleFill((f*25)+69,130,22,14,RGB565CONVERT(0,z/2,z));}

        if(f<6){LCD_RectangleFill((f*25)+69,148,22,14,RGB565CONVERT(v,v,255));}                    // escala Blue ( Azul )
        if(f>5){LCD_RectangleFill((f*25)+69,148,22,14,RGB565CONVERT(0,0,z));}

        if(f<6){LCD_RectangleFill((f*25)+69,166,22,14,RGB565CONVERT((255+v)/2,v,255));} // escala Violet ( Violeta )
        if(f>5){LCD_RectangleFill((f*25)+69,166,22,14,RGB565CONVERT(z/2,0,z));}

        if(f<6){LCD_RectangleFill((f*25)+69,184,22,14,RGB565CONVERT(255,v,255));}
             // escala Magenta (Magenta)

        if(f>5){LCD_RectangleFill((f*25)+69,184,22,14,RGB565CONVERT(z,0,z));}

        if(f<6){LCD_RectangleFill((f*25)+69,202,22,14,RGB565CONVERT(255,v,(255+v)/2));}
// escala Purple ( Morado )

        if(f>5){LCD_RectangleFill((f*25)+69,202,22,14,RGB565CONVERT(z,0,z/2));}
        }

    for(f=0;f<9;f++)
        {
        t=255-(f*32);
        if(t<0){t=0;}
        LCD_RectangleFill((f*25)+94,220,22,14,RGB565CONVERT(t,t,t));    // escala Grey ( Gris )

        }
    }


Este programa es sensiblemente más sencillo que el anterior. El bucle principal sólo contiene siete instrucciones, y el trabajo lo realizan tres funciones privadas, arrojando el resultado que vemos en la imagen siguiente:

Generador de gama cromática por colores definidos para la Mini-STM32



El manejo del programa también es más sencillo. En él distinguimos tres partes:

1) El pequeño recuadro superior-izquierda de color azul que muestra los valores numéricos del color. El superior, rotulado como C565 es el valor hexadecimal de 16 bits, es decir, el que deberemos utilizar en nuestros programas para definir cualquier nuevo color que deseemos. El siguiente es el valor hexadecimal del mismo colore pero en 24 bits, es decir, el formato normal de Windows, y después viene los valores absolutos del Rojo, Verde y Azul.

2) Los 5 rectángulos situados uno encima de otro en la parte inferior-izquierda muestran los cinco últimos colores que hayamos seleccionado, por este motivo, al arrancar el programa aparecerán inicialmente en color blanco. El último color seleccionado ocupará siempre el puesto superior de la pila, cuyos valores numéricos serán precisamente los visibles en su recuadro correspondiente. Dicha selección empujará hacia abajo el color anterior, a igual que éste hará con el penúltimo y así sucesivamente.
Los cinco colores de la pila son "consultables" pero no "seleccionables", me refiero a que podemos saber el valor numérico de cada uno de ellos pulsando con el puntero sobre el mismo, pero esto no causará ninguna otra alteración en la propia pila de colores.

3) El conjunto de 108 colores definidos más 9 gradaciones de gris que ocupan la totalidad del centro y de la parte derecha de la pantalla LCD. Estos colores están creados por las rutinas internas del programa en base a ciertas escalas de valores y son todos ellos seleccionables, debiendo tener cuidado en pulsar sobre el centro del cuadro, puesto que tanto el marco negro de los cuadros como el borde blanco separador puede falsear la selección.

___________________________________


 
   Descripción secuencial del programa "Generador de gama cromática por colores definidos"

1) Después de las declaraciones e inicializaciones de rigor, se llaman en secuencia las tres funciones privadas (que son distintas a las utilizadas en el programa anterior), denominadas PrintMatrix( ), PrintColorts( ) y ShowVals( ), cuya misión es por el mismo orden dibujar los recuadros negros separadores de los colores definidos, calcular y dibujar estos colores definidos y mostrar los valores RGB:

2) El bucle infinito "while(1)" es en este caso muy breve, y sólo lee las coordenadas del Touch Panel y muestra los valores del color seleccionado, así como el propio color en la pila de rectángulos de la izquierda.

3) Antes de que se cierre el bucle anterior hay otro "while(p==1)" anidado en el mismo, que mantendrá el programa bloqueado mientras no levantemos el marcador de selección de la pantalla sensible. El motivo es evitar que al seleccionar un color, nos efectúe un par de miles de selecciones por segundo y nos rellene los cinco rectángulos de la pila con el mismo color, aparte de causar un molesto parpadeo en el cuadro de valores numéricos.


   Las funciones privadas de este programa

4) La void ShowVals(void), cuando seleccionamos un color, la función realiza los cálculos para hallar sus valores RGB, por separado y combinados en los dos formatos hexadecimales de 24 y 16 bits, los imprime y rellena de este color el rectángulo superior de la pila, habiendo desplazado previamente hacia abajo los colores existentes.

En esta parte del programa he utilizado por primera vez la función de las librerías ARM originales denominada LCD_GetPoint( ), que al entrarle las coordenadas de pantalla "x" e "y" nos devuelve el valor de color del punto en cuestión. E
sta función me evita el tener que escribir un algoritmo de exploración bastante complejo para reconocer los 117 cuadrados e identificarlos después por su color, que en realidad es lo único que necesitamos. Pero el problema es que a veces falla en su respuesta y nos da un color equivocado, especialmente si hemos seleccionado varios puntos seguidos en poco tiempo.
La solución ha sido un poco empírica pero funciona bien, y se trata de efectuar unas 100 lecturas en una coordenada fija (por ejemplo la 1,1) antes de proceder a la lectura real.

5) La void PrintMatrix(void), esta función traza la matriz de 117 cuadrados en forma de 13 filas por 9 columnas que después se rellenarán de color.

6) La void PrintColors(void), esta función utiliza una escala de valores entre 0 y 255 para crear las 109 gradaciones de color y los 9 tonos de gris. En teoría, los 12 colores "centrales" creados, son: Rojo, Naranja, Amarillo, Limón, Verde, Turquesa, Cyan, Añil, Azul, Violeta, Magenta y Morado

___________________________________


   Tabla de nuevos colores creados a partir del "Generador de gama cromática por colores definidos" y su inclusión en el proyecto

Con los valores obtenidos he aprovechado para definir 117 nuevos colores en la librería GLCD.h, y por tanto, a partir de ahora pueden ser utilizados en los programas. La relación completa de estos colores aparece en la tabla que viene a continuación.

Tabla de nuevos colores definidos para Mini-STM32 (valor hexadecimal de 16 bits 5+6+5)

   1 2
3
4
5 Base 6
7
8
9
 
 Red
FE79
FCD3
FB2C
F986
F800 C800
9800
6000
3000
 Rojo
 Orange
FF39
FE73
FD8C
FCC6
FBE0
CB20
9A60
6180
30C0
 Naranja
 Yellow
FFF9
FFF3
FFEC
FFE6
FFE0
CE60
9CC0
6320
3180
 Amarillo
 Lemon
E7F9
CFF3
B7EC
9FE6 7FE0
6660
4CC0
3320
1980
 Limón
 Green
CFF9
9FF3
67EC
37E6
07E0
0660
04C0
0320
0180
 Verde
 Turquoise
CFFC
9FF9
67F6
37F3
07EF
066E
04C9
0326
0183
 Turquesa
 Cyan
CFFF
9FFF
67FF
37FF
07FF
067B
04F3
032C
0186
 Cyan
 Indigo
CF3F
9E7F
65BF
34FF
03FF
033B
0273
01AC
00C6
 Añil
 Blue
CE7F
9CFF
633F
319F
001F
0019
0013
000C
0006
 Azul
 Violet
E67F
CCFF
B33F
999F
781F
601B
4813
300E
1806
 Violeta
 Magenta
FE7F
FCFF
FB3F
F99F
F81F
C81B
9813
600C
3006
 Magenta
 Purple
FE7E
FCF9
FB36
F993
F80F
C80E
9809
6006
3003
 Morado
 Grey
FFFF
DEFB
BDF7
9CF3
7BEF
5AEB
39E7
18E3
0000
 Gris

Para seguir con la generalidad de las librerías suministradas por ARM, he definido las etiquetas de estos nuevos colores en inglés, con los nombres respectivos que aparecen en la columna izquierda de la tabla. Cada color tiene 9 variantes que corresponden a grados de luminosidad, de tal forma que por ejemplo en el caso del rojo el más claro es el Red1, y el más oscuro el Red9, siendo el Red5 el valor base o medio, que corresponde al Red definido anteriormente en esta librería, y que he mantenido por compatibilidad con programas ya escritos. La escala de grises va desde el blanco, que aquí se llama Grey1, a negro, que es el Grey9, naturalmente, también se mantienen las etiquetas de White y Black con los mismo valores que los dos anteriores.

Y una vez vistos los colores, en la próxima entrega de este tutorial seguiré aún con algunos temas gráficos, antes de continuar con algo distinto, probablemente con la configuración y manejo de las entradas conversoras analógico-digitales.


Continuará...




Ir a página principal
Ir al índice del tema
Ir a página anterior de este tema

 Visitas a la web 


 
      Esta web está optimizada para Mozilla Firefox 3, y testeada con Explorer 7, Opera 9 y Chrome