Ahora voy adelantar la tarea que estará dedicada a mostrar cualquier información en el display.
Primero creo un arreglo de tipo unsigned char de longitud 4, para cada dígito del display de 7 segmentos.
Este arreglo necesita una variable como índice o puntero, y al ser sólo 4 dígitos, puede ser también char sin signo.
También necesito una variable de tipo int si signo que utilizaré para crear retardos asincrónicos en esta tarea.
typedef struct
{
/* The application's current state */
APPDISPLAY_STATES state;
/* TODO: Define any additional data used by the application. */
unsigned char arregloDisplay[0x04];
unsigned char punteroDisplay;
unsigned int retardo;
} APPDISPLAY_DATA;
Al ser un display de ánodo común, los valores a representar cada dígito serían los siguientes:
Puedo hacer una función con retorne cada valor en función de una variable en una instrucción, pero prefiero usar un arreglo en la memoria flash. Este arreglo estará en el archivo c de la tarea.
El puerto B, no es de 8 bits, es decir que se debe enmascarar lo que se va a escribir en él, para no alterar el bit8, bit 9, etc de ese puertos.
Sería algo así con un or a nivel de bytes:
LATB = 0xFFFFFF00 | valor obtenido del arreglo
Puedo usar l'abstracción de Harmony para manipular el puerto:
void GPIO_PortWrite(GPIO_PORT port, uint32_t mask, uint32_t value);
Donde
port, es el puerto,
mask, indica que bits se desea alterar y value, es el valor que se desea escribir.
La máscara debe ser 1 para los bits que se desea que sean alterados, y caso contrario 0,
En mi caso sería así:
GPIO_PortWrite(GPIO_PORT_B, 0x0000FF, valor obtenido del arreglo);
Al inicializar la tarea, el puntero de display y el valor para cada dígito los pongo en cero:
void APPDISPLAY_Initialize ( void )
{
/* Place the App state machine in its initial state. */
appdisplayData.state = APPDISPLAY_STATE_INIT;
/* TODO: Initialize your application's state machine and other
* parameters.
*/
appdisplayData.punteroDisplay = 0x00; //apunto al primer display
appdisplayData.arregloDisplay[0x00] = 0x00; //valor inicial en cero
appdisplayData.arregloDisplay[0x01] = 0x00; //valor inicial en cero
appdisplayData.arregloDisplay[0x02] = 0x00; //valor inicial en cero
appdisplayData.arregloDisplay[0x03] = 0x00; //valor inicial en cero
}
De manera empírica de otros proyectos he determinando que la frecuencia de activación de cada display puede ser de 1 ms, obviamente sería de probarlo con el hardware, pero lo dejo por ahora.
En el primer estado de la tarea que renombré ESTADO_INICIAL, capturo el valor que tenga el Core Timer, para pasar al siguiente estado que he denominado MOSTRANDO_DATOS.
void APPDISPLAY_Tasks ( void )
{
/* Check the application's current state. */
switch ( appdisplayData.state )
{
/* Application's initial state. */
case APPDISPLAY_ESTADO_INICIAL:
{
appdisplayData.retardo = CORETIMER_CounterGet();
appdisplayData.state = APPDISPLAY_ESTADO_MOSTRANDO_DATOS;
break;
}
case APPDISPLAY_ESTADO_MOSTRANDO_DATOS:
{
break;
}
/* TODO: implement your application state machine.*/
/* The default state should never be executed. */
default: break; /* TODO: Handle error in application's state machine. */
}
}
En el segundo estado de la tarea, debería esperar 1 ms para cambiar la información a cada dígito del display:
case APPDISPLAY_ESTADO_MOSTRANDO_DATOS:
{
if ((CORETIMER_CounterGet() - appdisplayData.retardo) > _1ms)
{
}
break;
}
La constante _1ms se calcula en función de los ciclos de reloj contados por el temporizador central o CORE TIMER.
Este temporizador funciona a la mitad de la frecuencia del sistema, es decir 24 MHz, es decir que cada ciclo es de 41.666 ns, por lo tanto para conseguir 1 ms, sería 1ms/41.666ns = 24000 ó 0x5DC0
Para acceder al valor que se desea mostrar, se debe recurrir al arreglo que contiene el valor mediante la variable puntero display, así:
appdisplayData.arregloDisplay[appdisplayData.punteroDisplay]
Pero este valor no es el adecuado para mostrarlo en el display, así que se recurre al arreglo creado en la memoria flash, es decir:
digitoDisplay[appdisplayData.arregloDisplay[appdisplayData.punteroDisplay]]
Para colocar este valor en el puerto B, mediante la función para escribir un número en puerto de H3 sería de la siguiente manera:
GPIO_PortWrite(GPIO_PORT_B, 0x0000FF, (uint32_t) digitoDisplay[appdisplayData.arregloDisplay[appdisplayData.punteroDisplay]]);
Y también se debe activar la base de cada transistor PNP que controla dígito del display y es algo que hasta ahora no considero.
Por defecto, en el MCC los pines RB8, RB9, RB12 y RB13 están configurados por defecto en 1 lógico (cada dígito del display apagado), pero podría ponerlos en 1 lógico al inicio de la tarea:
void APPDISPLAY_Initialize ( void )
{
/* Place the App state machine in its initial state. */
appdisplayData.state = APPDISPLAY_ESTADO_INICIAL;
/* TODO: Initialize your application's state machine and other
* parameters.
*/
/*** Apago cada uno de los dígitos del display***/
DISPLAY1_Set();
DISPLAY2_Set()
DISPLAY3_Set();
DISPLAY4_Set();
/***********************************************/
appdisplayData.punteroDisplay = 0x00; //apunto al primer display
appdisplayData.arregloDisplay[0x00] = 0x00; //valor inicial en cero
appdisplayData.arregloDisplay[0x01] = 0x00; //valor inicial en cero
appdisplayData.arregloDisplay[0x02] = 0x00; //valor inicial en cero
appdisplayData.arregloDisplay[0x03] = 0x00; //valor inicial en cero
}
Lo que necesito, es con el mismo puntero del arreglo de display, ir seleccionando los terminales RB8, RB9, RB12 y RB13.
Con la función para activar
GPIO_PortClear(GPIO_PORT_B,bit del puerto);
Entonces nuevamente escribo un arreglo en la memoria flash de 4 bytes para manipular los 4 bits.
// bit8 bit9 bi12 bit13
const unsigned short bitsDigitoDisplay[0x04] = {1<<8, 1<<9, 1<<12, 1<<13};
Entonces sería de la siguiente manera, pero aun está incompelto:
case APPDISPLAY_ESTADO_MOSTRANDO_DATOS:
{
if ((CORETIMER_CounterGet() - appdisplayData.retardo) > _1ms)
{
GPIO_PortWrite(GPIO_PORT_B, 0x0000FF, (uint32_t) digitoDisplay[appdisplayData.arregloDisplay[appdisplayData.punteroDisplay]]);
GPIO_PortClear(GPIO_PORT_B,bitsDigitoDisplay[appdisplayData.punteroDisplay]);
appdisplayData.punteroDisplay++;
}
break;
}
Necesito apagar el display previo al que se va activar:
GPIO_PortSet(GPIO_PORT_B,bitsDigitoDisplay[appdisplayData.punteroDisplay - 0x01]);
pero eso no es factible si punteroDisplay es igual a cero, por lo tanto sería así:
if (appdisplayData.punteroDisplay > 0x00)
{
GPIO_PortSet(GPIO_PORT_B,bitsDigitoDisplay[appdisplayData.punteroDisplay - 0x01]);
}
else // si appdisplayData.punteroDisplay es cero, se debe apagar el 4to dígito
{
GPIO_PortSet(GPIO_PORT_B,bitsDigitoDisplay[0x03]);
}
También es necesario verificar que al incrementar el puntero, no debe sobrepasar 3:
if (appdisplayData.punteroDisplay > 0x03)
{
appdisplayData.punteroDisplay = 0x00;
}
Luego de todo esto, la tarea debe volver a capturar un valor del CORE TIMER, para generar otro retardo.
Entonces el segundo estado de la tarea sería así:
case APPDISPLAY_ESTADO_MOSTRANDO_DATOS:
{
if ((CORETIMER_CounterGet() - appdisplayData.retardo) > _1ms)
{
if (appdisplayData.punteroDisplay > 0x00)
{
GPIO_PortSet(GPIO_PORT_B,bitsDigitoDisplay[appdisplayData.punteroDisplay - 0x01]);
}
else // si appdisplayData.punteroDisplay es cero, se debe apagar el 4to dígito
{
GPIO_PortSet(GPIO_PORT_B,bitsDigitoDisplay[0x03]);
}
GPIO_PortWrite(GPIO_PORT_B, 0x0000FF, (uint32_t) digitoDisplay[appdisplayData.arregloDisplay[appdisplayData.punteroDisplay]]);
GPIO_PortClear(GPIO_PORT_B,bitsDigitoDisplay[appdisplayData.punteroDisplay]);
appdisplayData.punteroDisplay++;
if (appdisplayData.punteroDisplay > 0x03)
{
appdisplayData.punteroDisplay = 0x00;
}
appdisplayData.retardo = CORETIMER_CounterGet(); // vuelvo a capturar otro valor del Core Timer para otro retardo
}
break;
}
Esta tarea estaría funcionando de manera independiente, cualquier valor que se desease mostrar en el display, deberá hacerse desde otra tarea o proceso modificando los valores del arreglo appdisplayData.arregloDisplay