LCD 44780 – Librería para dsPIC usando Timer

10 febrero, 2007

Librería para controlar un LCD compatible Hitachi 44780 con un dsPIC mediante el Timer, lo que nos permite aprovechar los tiempos muertos del LCD en otras tareas.


A continuación os presento una librería para manejar un display LCD compatible Hitachi 44780 en configuración de 4 bits mediante un dsPIC (30F o 33F) utilizando el Timer.

Como sabéis, el LCD es un dispositivo extremadamente lento si lo comparamos con un dsPIC. Sin ir más lejos, para imprimir un carácter el proceso es el siguiente:

  • enviamos el nibble alto y ponemos el pin enable a 1
  • esperamos 1us.
  • ponemos el pin enable a 0
  • esperamos 37us.
  • enviamos el Nibble bajo y ponemos el pin enable a 1
  • esperamos 1us.
  • ponemos el pin enable a 0
  • esperamos 37us.

Puede comprobarse que se pierden 76us. como mínimo, a los que hay que sumar el tiempo que tarde el micro en obtener la información y ponerla en el puerto, que ocupa 78 instrucciones. Un dsPIC trabajando a 50MIPS es capaz de ejecutar en ese periodo 50 x 76 + 78 = 3.878 instrucciones.

La principal ventaja que tiene la utilización del Timer es que el micro sigue ejecutando otras tareas mientras se esperan los plazos que he mencionado antes, por lo que el tiempo de proceso que robamos al dsPIC son sólo esas 78 instrucciones. Vamos, que al dsPIC entre nibble y nibble le da tiempo de tomarse tres cervezas y un ron.

La reducción de la carga de trabajo por tanto es de un 98%

Otras ventajas de la librería es que es Multi-Timer y Multi-Puerto; puede ser fácilmente configurada para utilizar cualquiera de los 9 Timer y cualquier puerto desde el B hasta el J. Además podemos configurar si queremos el byte alto o el byte bajo del puerto que seleccionemos.

Configuración

Para configurar la librería sólo hay que modificar los siguientes parámetros:

#define LCD_Filas 2 // Número de filas del LCD: 1,2
#define LCD_Columnas 16 // Número de columnas del LCD: 8,16,20
#define MAX_EVENTOS 50 // Tamaño máximo de la cola de trabajo
#define USA_TIMER_1 // Selección del timer a utilizar
#define USA_PUERTO_F // Selección del puerto a utilizar
#define USA_PUERTO_BAJO // Selección del byte a utilizar
#define MIPS 50 // Millones de instrucciones por segundo
#define UsaUSART // Se define sólo si vamos a usar la USART y el LCD a la vez
  • LCD_Filas: colocamos un 1 para LCD de 1 fila y un 2 para todos los demás
  • LCD_Columnas: número de caracteres de ancho. Válidos 8, 16 o 20.
  • MAX_EVENTOS: tamaño de la cola de trabajo del LCD. En cada aplicación será conveniente una cifra u otra, dependiendo del uso que se haga del LCD y de la memoria disponible del micro.
  • USA_TIMER_x: ponemos en X un número del 1 al 9 indicando cuál es el Timer que queremos utilizar para el LCD.
  • USA_PUERTO_x: ponemos en X la letra del puerto que queremos utilizar. No todos son válidos, y dependerá de los que tenga disponibles el dsPIC que estemos utilizando.
  • USA_PUERTO_BAJO/ALTO: colocaremos USA_PUERTO_BAJO para utilizar los bits 0 a 7 del puerto seleccionado y USA_PUERTO_ALTO para utilizar los bits 8 a 15.
  • MIPS: millones de instrucciones por segundo indicativos de la frecuencia de trabajo del micro.
  • UsaUSART: sólo es necesario ponerlo si vamos a simultanear la salida del printf con el LCD y la USART

Utilización

El modo de trabajo de la librería es la creación de un buffer de los comandos / caracteres que queremos enviar al LCD. Estos datos se van almacenando en un array que la interrupción del Timer irá leyendo y procesando al ritmo que el LCD requiere. Puesto que este ritmo no es homogéneo (1us y 37us) en la misma interrupción se modifica la configuración del periodo del Timer y se prepara el retardo para el siguiente ciclo.

Las funciones que la librería pone a tu disposición son:

  • LCD_Inicializacion(): imprescindible llamar a esta función al principio, para preparar el LCD y el Timer.
  • LCD_EscribeCaracter (char)
  • LCD_EnviaComando (char)
  • LCD_BorraPantalla()
  • LCD_Goto (x,y)
  • LCD_EscribeCadena (string)
  • LCD_EscribeConstante (constante)
  • LCD_DefineCaracter (direccion,fuente): define un nuevo diseño para un caracter de la CGRAM. Direccion es el puntero del caracter y Fuente es una constante de 8 bytes con la forma del nuevo diseño.
  • LCD_EscribeNumero (valor, enteros, decimales): imprime el número Valor formateado con un número de dígitos enteros y un número de dígitos decimales. Coloca un punto en los miles y una coma para separar enteros de decimales.

La librería ha sido probada a distintas velocidades y he comprobado que funciona perfectamente por encima de 25MIPS. A velocidades inferiores hace cosas raras, porque el tiempo de proceso de la interrupción equivale a ese 1us de espera que requiere el LCD. Se podría ajustar programándola de otra manera, pero dejo ese guante lanzado para quien lo quiera recoger.

Además de estas funciones, se ha incluido compatibilidad con el printf del lenguaje C, para lo cual hay que utilizar una variable global que nos permitirá seleccionar si queremos la salida por el LCD o por la USART mediante:

SalidaPor = SalidaLCD;

o bien

SalidaPor = SalidaUSART;

Interrupción

A continuación pego el corazón de la librería, la función de Interrupción del Timer. No sé cómo me dejé convencer por un amigo catalán para programarla en ASM con el objetivo de ahorrar ciclos. Ha sido duro y difícil pero finalmente he conseguido que la interrupción sólo consuma 23 ciclos en la ida y 16 en la vuelta.

He procurado dejar todos los comentarios en la propia función por lo que no digo nada más y la pego a continuación:

Descarga

La librería está disponible para su descarga en la zona de Descargas, o a través de este enlace.

El ejemplo de la foto se consigue con este programa de pruebas:

#include <p33FJ64MC706.h>
#define __33FJ64MC706_H
_FOSCSEL(3);
_FOSC (194);
_FICD (223);
#include "LCD_HD44780.h"

char yo[] = {'N','o','c','t','u','r','n','o',' ','-',' ','2','0','0','6',''};
const elrebujito[] = {'e','l','r','e','b','u','j','i','t','o','.','e','s',''};

int main(void){
unsigned char i;
CLKDIVbits.PLLPRE=10;
CLKDIVbits.PLLPOST=1;
PLLFBD=238;
AD1PCFGL=0xFFFF;

LCD_Inicializacion();
LCD_Goto (1,1);
LCD_EscribeCadena(yo);
LCD_Goto (4,2);
LCD_EscribeConstante(elrebujito);
while(1);
}

Share

Etiquetas: , , , ,