martes, 15 de noviembre de 2011

Visualización de un mensaje en el LCD



Vamos a visualizar un mensaje de dos líneas en el LCD alfanumérico 2x16, mediante una máquina de estados Moore.

Proceso de trabajo:

Algoritmo de la máquina de estados:
- Secuencia de inicio.
- Enviar instrucción de ‘Pantalla ON/OFF’ de manera que ponemos la pantalla en ON ‘D=1’, el cursor en ON, ‘C=1’ y el parpadeo del cursor en ON ‘B=1’.
- Colocar el cursor en la posición de inicio con la instrucción ‘Cursor a casa’.
- Mandar los datos de la primera línea.
- Cambiar de línea.
- Mandar los datos de la segunda línea.

La máquina va a necesitar de dos contadores, uno de 3 bit’s y otro de 5 bit’s. Los usaremos para contar el número de registros y datos respectivamente.

Los puertos bidireccionales van a necesitar buffer´s 3-state para controlar su función, entrada o salida.


Creación de un nuevo proyecto:

Creamos un nuevo proyecto y seleccionamos esquemático.


Seleccionamos las características de nuestro CPLD:
-Seleccionamos la familia del CPLD, XC9500 CPLDs.
-El modelo, XC9572.
-El  encapsulado, PC84.
-La  velocidad de trabajo del CPLD, -7.
-El sintetizador.
-El simulador.
-El lenguaje de programación, VHDL.


En la siguiente ventana añadimos el fichero fuente.


Seleccionamos schematic y damos nombre al archivo


Aceptamos todos los apartados siguientes y se nos crea el proyecto.


Creación del componente:

Añadimos un fichero fuente State Diagram donde crearemos la máquina de estados:


Se nos abrirá un subprograma llamado StateCAD donde creamos la máquina de estados.
En OptionsVariables añadimos los puertos de entrada y salida:


- Escribimos el nombre.
- Seleccionamos el tipo: reloj, entrada o salida; la salida puede ser asíncrona (OUT:COM) o en nuestro caso síncrona (OUT:REG).
- Modo activo.
- Si va a ser un pin o un nodo.

Los pines que debemos agregar son los siguientes:

Control de LCD a través de la máquina de estados:
- RS: Salida. (Control de selección de modo).
- Habilitar: Salida. (Habilitación del módulo).
- Read_write: Salida. (Control de lectura/escritura en el módulo).
- D0_O, D1_O, D2_O, D3_O, D4_O, D5_O, D6_O, D7_O: Salida
- D0_I, D1_I, D2_I, D3_I, D4_I, D5_I, D6_I, D7_I: Entrada
- Three_state: Salida. (Control pines bidireccionales).

Las líneas Dx son bidireccionales y tendrán que tener dos funciones: de entrada y salida. Las controlaremos con un buffer 3-state que trabaja en bajo activo.


Entrada de datos de los contadores:
- Q0_r, Q1_r, Q2_r: Entradas. (Entradas de control del nº de comandos o registros mandados al LCD).
- Q0_d, Q1_d, Q2_d, Q3_d, Q4_d: Entradas. (Entradas de control del nº de datos mandados al LCD).
- Puesta_0: Salida. (Salida de inicialización de los contadores).
- Reloj_dato: Salida. (Reloj del contador de datos).
- Reloj_registro: Salida. (Reloj del contador de comandos).


Estos son los pines que agregamos:


Algoritmo:

Vamos a explicar las partes de las que consta el algoritmo:

- Secuencia de inicio:

El LCD necesita recibir al inicio el código 00111000 tres veces seguidas con un intervalo de 5 mS. El LCD queda borrado y el cursor en la primera posición. Además, se configura el interfaz de 8 bit’s ‘DL=1’, dos líneas ‘Líneas=1’ y 5x7 puntos ‘Font=1’.

Así quedaría resuelta la secuencia de inicio:


Estado 0:
Añadimos el reset asíncrono en bajo activo y le damos el valor 0.
- Salidas: tendremos todas las salidas a 0, incluyendo la salida triestado que trabaja en bajo activo y nos deja en alta impedancia las salidas Dx.
- Transiciones: Al estado 1 sin condiciones.


Estado 1:
- Salidas: reloj_registro a 1 para aumentar la cuenta en el contador de comandos. Las demás salidas se quedan por defecto en 0.
- Transiciones: Al estado 2 sin condiciones.


Estado 2:
- Salidas: Habilitamos el LCD y lo ponemos en modo de lectura, así podremos leer el flag ‘BUSY’ para saber si está ocupado.
- Transiciones: Al estado 3 sin condiciones.


Estado 3:
- Salidas: Mantenemos las salidas anteriores y nos quedamos en este estado hasta que el LCD deje de estar ocupado.
- Transiciones: Al estado 4 si D7_I= 0.


Estado 4:
- Salidas: Deshabilitamos el LCD y nos vamos al estado 5, para mandar el comando de inicio.
- Transiciones: Al estado 5 si: (Q0_R='1' & Q1_R='0' & Q2_R='0') || (Q0_R='0' & Q1_R='1' & Q2_R='0') || (Q0_R='1' & Q1_R='1' & Q2_R='0').


Estado 5:
- Salidas: Habilitamos el LCD y dejamos las señales ‘Dx_O’ del autómata comunicado al puerto ‘Dx’ del LCD, todo ello para mandar el código de la condición de inicio 00111000. Por este estado pasaremos 3 veces.
- Transiciones: Al estado 9 sin condiciones.
Podemos cambiar el color de los estados con la herramienta señalada, nosotros ponemos en verde los estados donde introducimos datos:


Estado 9:
Si no hemos terminado de mandar los códigos de la condición de inicio volvemos al estado 0.
- Transiciones: Al estado 0 si: (Q0_R='1' & Q1_R='0' & Q2_R='0') || (Q0_R='0' & Q1_R='1' & Q2_R='0') || (Q0_R='1' & Q1_R='1' & Q2_R='0').


- Pantalla ON-OFF:

Tras los 3 comandos de la condición de inicio vamos a mandar uno que deje la pantalla en ON ‘D= 1’, el cursor en ON ‘C= 1’ y el parpadeo del cursor en ON ‘B= 1’. Añadiremos un estado (6) para realizar esta instrucción.


Estado 6:
- Salidas: Habilitamos el LCD y dejamos las señales Dx_O del autómata comunicado al puerto ‘Dx’ del LCD, todo ello para mandar el código de pantalla ON/OFF 00001111.
- Transiciones: Del estado 4 si (Q0_R='0' & Q1_R='0' & Q2_R='1').
Al estado 9 sin condiciones.
Debemos agregar la condición del estado 9 para que vuelva al estado 0 tras poner la pantalla en ON:
Al estado 0 si: (Q0_R='0' & Q1_R='0' & Q2_R='1').


- Cursor a casa:

Tras el comando pantalla ON/OFF, mandamos el comando cursor a casa consiguiendo, con ello, que el cursor se coloque en la posición de inicio.
Añadiremos un estado (7) para realizar esta instrucción.


Estado 7:
- Salidas: Habilitamos el LCD y dejamos las señales Dx_O del autómata comunicado al puerto Dx del LCD, todo ello para mandar el código de cursor a casa 00000010.
- Transiciones: Del estado 4 si (Q0_R='1' & Q1_R='0' & Q2_R='1').
Al estado 9 sin condiciones.
Desde el estado 9 pasaremos al estado 10 para comenzar a mandar el mensaje de la primera línea.
Al estado 10 si: (Q0_R='1' & Q1_R='0' & Q2_R='1').


- Mandar los datos de la primera línea:

Mandaremos los datos de uno en uno a la primera línea del LCD.


Estado 10:
- Salidas: Ponemos las salida reloj_dato a 1 para aumentar la cuenta en el contador de datos.
- Transiciones: Al estado 11 sin condiciones.


Estado 11:
- Salidas: Habilitamos el LCD y lo ponemos en modo de lectura, así podremos leer el flag BUSY para saber si está ocupado.
- Transiciones: Al estado 12 sin condiciones.


Estado 12:
- Salidas: Mantenemos las salidas anteriores.
- Transiciones: Nos quedamos en este estado hasta que el LCD deje de estar ocupado.
Al estado 13 si D7_I= 0.



Estado 13:
- Salidas: Ponemos el LCD en modo dato.
- Transiciones: Pasamos a los distintos estados que contienen cada uno de los 16 caracteres de la primera línea, dependiendo de cómo se encuentre el contador de datos.

Al estado 14 si (Q0_D='1' & Q1_D='0' & Q2_D='0' & Q3_D='0' & Q4_D='0')
Al estado 15 si (Q0_D='0' & Q1_D='1' & Q2_D='0' & Q3_D='0' & Q4_D='0')
Al estado 16 si (Q0_D='1' & Q1_D='1' & Q2_D='0' & Q3_D='0' & Q4_D='0')
Al estado 17 si (Q0_D='0' & Q1_D='0' & Q2_D='1' & Q3_D='0' & Q4_D='0')
Al estado 18 si (Q0_D='1' & Q1_D='0' & Q2_D='1' & Q3_D='0' & Q4_D='0')
Al estado 19 si (Q0_D='0' & Q1_D='1' & Q2_D='1' & Q3_D='0' & Q4_D='0')
Al estado 20 si (Q0_D='1' & Q1_D='1' & Q2_D='1' & Q3_D='0' & Q4_D='0')
Al estado 21 si (Q0_D='0' & Q1_D='0' & Q2_D='0' & Q3_D='1' & Q4_D='0')
Al estado 22 si (Q0_D='1' & Q1_D='0' & Q2_D='0' & Q3_D='1' & Q4_D='0')
Al estado 23 si (Q0_D='0' & Q1_D='1' & Q2_D='0' & Q3_D='1' & Q4_D='0')
Al estado 24 si (Q0_D='1' & Q1_D='1' & Q2_D='0' & Q3_D='1' & Q4_D='0')
Al estado 25 si (Q0_D='0' & Q1_D='0' & Q2_D='1' & Q3_D='1' & Q4_D='0')
Al estado 26 si (Q0_D='1' & Q1_D='0' & Q2_D='1' & Q3_D='1' & Q4_D='0')
Al estado 27 si (Q0_D='0' & Q1_D='1' & Q2_D='1' & Q3_D='1' & Q4_D='0')
Al estado 28 si (Q0_D='1' & Q1_D='1' & Q2_D='1' & Q3_D='1' & Q4_D='0')
Al estado 29 si (Q0_D='0' & Q1_D='0' & Q2_D='0' & Q3_D='0' & Q4_D='1')


Estados 14-29:
- Salidas: Aquí introduciremos los datos de cada carácter:
Estado 14: D (01000100)
Estado 15: a  (01100001)
Estado 16: n  (01101110)
Estado 17: i   (01101001)
Estado 18: e  (01100101)
Estado 19: l   (01101100)
Estado 20:     (00100000)
Estado 21: d  (01100100)
Estado 22: e  (01100101)
Estado 23:     (00100000)
Estado 24: C (01000011)
Estado 25: o  (01101111)
Estado 26: s  (01110011)
Estado 27:     (00100000)
Estado 28: S  (01010011)
Estado 29: R  (01010010)
- Transiciones: Al estado 38 sin condiciones.


Elegí los caracteres basándome en la siguiente tabla:


Estado 38:
- Salidas: Todas a 0.
- Transiciones: Al estado 39 sin condiciones.


Estado 39:
- Salidas: Deshabilitamos el LCD.
- Transiciones: Pasamos al estado 10 hasta introducir los 16 caracteres en el LCD. Una vez hecho esto, pasamos al estado 0 para cambiar de línea mandando un nuevo comando.
Al estado 10 si:
(Q0_D='1' & Q1_D='0' & Q2_D='0' & Q3_D='0' & Q4_D='0') ||
(Q0_D='0' & Q1_D='1' & Q2_D='0' & Q3_D='0' & Q4_D='0') ||
(Q0_D='1' & Q1_D='1' & Q2_D='0' & Q3_D='0' & Q4_D='0') ||
(Q0_D='0' & Q1_D='0' & Q2_D='1' & Q3_D='0' & Q4_D='0') ||
(Q0_D='1' & Q1_D='0' & Q2_D='1' & Q3_D='0' & Q4_D='0') ||
(Q0_D='0' & Q1_D='1' & Q2_D='1' & Q3_D='0' & Q4_D='0') ||
(Q0_D='1' & Q1_D='1' & Q2_D='1' & Q3_D='0' & Q4_D='0') ||
(Q0_D='0' & Q1_D='0' & Q2_D='0' & Q3_D='1' & Q4_D='0') ||
(Q0_D='1' & Q1_D='0' & Q2_D='0' & Q3_D='1' & Q4_D='0') ||
(Q0_D='0' & Q1_D='1' & Q2_D='0' & Q3_D='1' & Q4_D='0') ||
(Q0_D='1' & Q1_D='1' & Q2_D='0' & Q3_D='1' & Q4_D='0') ||
(Q0_D='0' & Q1_D='0' & Q2_D='1' & Q3_D='1' & Q4_D='0') ||
(Q0_D='1' & Q1_D='0' & Q2_D='1' & Q3_D='1' & Q4_D='0') ||
(Q0_D='0' & Q1_D='1' & Q2_D='1' & Q3_D='1' & Q4_D='0') ||
(Q0_D='1' & Q1_D='1' & Q2_D='1' & Q3_D='1' & Q4_D='0').
Al estado 0 si: (Q0_D='0' & Q1_D='0' & Q2_D='0' & Q3_D='0' & Q4_D='1').



- Cambiar de línea:

Mandamos el comando ‘dirección DDRAM’ con el código 11000000 consiguiendo que el cursor se coloque en la 1ª posición de la segunda línea.


Estado 8:
- Salidas: Habilitamos el LCD y dejamos las señales Dx_O del autómata comunicado al puerto Dx del LCD, todo ello para mandar el código de dirección DDRAM 11000000.
-Transiciones: Del estado 4 si (Q0_R='0' & Q1_R='1' & Q2_R='1').
Al estado 9 sin condiciones.



Añadimos la transición desde el estado 9 al 10 para comenzar a escribir en la segunda línea: (Q0_R='0' & Q1_R='1' & Q2_R='1').


Estado 40:
Desde este estado reiniciamos la cuenta de los contadores y volvemos al estado 0 para comenzar de nuevo la visualización. Aquí solo se caerá en el caso de perder el control del flujo del autómata.
- Transiciones: Del estado 4 si no se cumplen las condiciones.
Del estado 39 si no se cumplen las condiciones.
Al estado 0 sin condiciones.


- Mandar los datos de la segunda línea.

Mandaremos los datos de uno en uno a la segunda línea del LCD, finalizaremos la máquina de estados.


Estado 13:
- Transiciones: Pasamos a los distintos estados que contienen cada uno de los 8 caracteres de la segunda línea, dependiendo de cómo se encuentre el contador de datos.
Al estado 30 si (Q0_D='1' & Q1_D='0' & Q2_D='0' & Q3_D='0' & Q4_D='1')
Al estado 31 si (Q0_D='0' & Q1_D='1' & Q2_D='0' & Q3_D='0' & Q4_D='1')
Al estado 32 si (Q0_D='1' & Q1_D='1' & Q2_D='0' & Q3_D='0' & Q4_D='1')
Al estado 33 si (Q0_D='0' & Q1_D='0' & Q2_D='1' & Q3_D='0' & Q4_D='1')
Al estado 34 si (Q0_D='1' & Q1_D='0' & Q2_D='1' & Q3_D='0' & Q4_D='1')
Al estado 35 si (Q0_D='0' & Q1_D='1' & Q2_D='1' & Q3_D='0' & Q4_D='1')
Al estado 36 si (Q0_D='1' & Q1_D='1' & Q2_D='1' & Q3_D='0' & Q4_D='1')
Al estado 37 si (Q0_D='0' & Q1_D='0' & Q2_D='0' & Q3_D='1' & Q4_D='1').


Estados 30-37:
- Salidas: En cada uno de estos 8 estados habilitamos el LCD y dejamos las señales ‘Dx_O’ del autómata comunicado al puerto ‘Dx’ del LCD, mandamos el código de los caracteres de la segunda línea.
Estado 30: (   (00101000)
Estado 31: c  (01000011)
Estado 32: )   (00101001)
Estado 33:     (00100000)
Estado 34: 2  (00110010)
Estado 35: 0  (00110000)
Estado 36: 1  (00110001)
Estado 37: 1  (00110001)
- Transiciones: Al estado 38 sin condiciones.


Deshabilitamos el LCD y pasamos al estado 10 hasta introducir los 8 caracteres en el LCD. Una vez hecho esto, pasamos al estado 38 para dejar la máquina en un bucle.


Estado 39:
- Transiciones:
Al estado 10 si:
(Q0_D='1' & Q1_D='0' & Q2_D='0' & Q3_D='0' & Q4_D='1') ||
(Q0_D='0' & Q1_D='1' & Q2_D='0' & Q3_D='0' & Q4_D='1') ||
(Q0_D='1' & Q1_D='1' & Q2_D='0' & Q3_D='0' & Q4_D='1') ||
(Q0_D='0' & Q1_D='0' & Q2_D='1' & Q3_D='0' & Q4_D='1') ||
(Q0_D='1' & Q1_D='0' & Q2_D='1' & Q3_D='0' & Q4_D='1') ||
(Q0_D='0' & Q1_D='1' & Q2_D='1' & Q3_D='0' & Q4_D='1') ||
(Q0_D='1' & Q1_D='1' & Q2_D='1' & Q3_D='0' & Q4_D='1').
Al estado 38 si (Q0_D='0' & Q1_D='0' & Q2_D='0' & Q3_D='1' & Q4_D='1').





Simulación previa:

Podemos probar el funcionamiento de nuestra máquina de estados creando un test bench. Se nos abrirá el simulador de estado, podemos ir simulando estado a estado cambiando las entradas con doble clic y generando un pulso. Se nos ira poniendo en amarillo por el estado o transición que vallamos, y en verde por la que hayamos pasado.


Podemos hacer la simulación completa de la máquina de estados y comprobar que nos pase por todos los estados y transiciones.



Creación del esquema:

Generamos el código VHDL de la máquina en Generate HDL. Nos aparecerá una ventana donde nos pregunta si queremos borrara las entradas no utilizadas. Deseleccionamos todas y damos a delete.


Nos aparecerá una ventana donde nos dice que el código se ha generado con éxito.


Añadimos el documento creado a nuestro esquemático. En la ventana processes generamos el símbolo del decodificador para poder utilizarlo en el esquema principal del diseño. En la ventana Sources nos aparecerá la ruta del componente creado para poder utilizarle.



Colocamos el símbolo creado con los siguientes componentes:
1 INV
8 IBUF
8 BUFT
8 OBUFT
1 OR2
1 contador binario de 4 bit’s CB4CE
1 contador binario de 8 bit’s CB8CE
1 BUFG
Colocamos las marcas y las etiquetas correspondientes como en la siguiente imagen:


Compilamos en busca de errores:




Síntesis:

Hacemos la síntesis del esquema.


En View Technology Schematic podemos observar como se ha compilado nuestro esquema:



Asignación de los pines:


Añadimos un nuevo archivo al proyecto de tipo: Implementation Constraints File. Lo asociamos a nuestro esquema principal.


Hacemos doble clic al documento creado y se nos abrirá el PACE donde definimos los pines.



Translate y documentación:

Convertimos el esquemático en un lenguaje interno NGD. Haciendo doble clic en Translate.


Generamos el archivo Fit y comprobamos que todo esté bien.



Programación:

Por último generamos el archivo de programación .JED que le abriremos con el programa IMPACT.
Hacemos doble clic sobre Generate Programming File.


Abrimos el IMPACT, creamos un nuevo proyecto, escribimos el nombre y la dirección de la ruta:


Seleccionamos el modo de trabajo del JTAG, lo dejamos por defecto:


Añadimos el documento de programación .JED en Add Device:


Hacemos doble clic en program


Seleccionamos las siguientes opciones de programación:


Nos aparecerá un mensaje de que la programación a finalizado con éxito.


Finalmente cambiamos la tarjeta a modo ejecución y comprobamos su funcionamiento físico:

1 comentario: