huborarduino.com

La web de Hubor para la simulación de Arduino con Proteus

Banner Guia Programacion Arduino Con Proteus

[Proteus versión 8.1]

En la lección de hoy vamos a abordar la utilización de un display de 7 segmentos desde nuestro ARDUINO .

El display de 7 segmentos es un dispositivo de salida que se utiliza para la representacion de valores numéricos. Su nombre proviene de su construcción basada en la utilización de siete leds con unas determinadas formas y conexiones internas, estratégicamente ubicados de tal forma que forman el número '8' y, opcionalmente, con un octavo led para el punto decimal.

Lec21 001

Cada uno de los segmentos que forman la pantalla están marcados con las ocho primeras letras del alfabeto ( de la 'a' a la 'g'), y se montan de forma que permiten activar cada segmento por separado, consiguiendo formar cualquier dígito numérico. En el caso de que incluyan el punto decimal, éste diodo se nombra como DP.

Lec21 002

Estos dispositivos de pueden encontar en dos configuraciones posibles, según los pines de los leds que tengan unidos: ánodo común o cátodo común. 

Para comprender el funcionamiento de un display de siete segmentos de cátodo común, vamos a utilizar el siguiente montaje:

Lec21 003

Puesto que se trata de un dispositivo con el cátodo común, hemos puesto a tierra el pin común. A cada uno de los otros pines les hemos conectado una resistencia de 220 ohms en serie con un interruptor y conectado al potencial de +5V. Actuando sobre cada uno de los pulsadores podemos ver cómo se enciende el segmento correspondiente. En la imagen siguiente vemos como se ilumina el segmento 'e' al cerrar el interruptor correspondiente.

Lec21 004

Cómo es lógico, si cerramos los interruptores correspondientes a los segmentos a,b,c,d y g tendremos representado el número 3.

Lec21 005

Y de la misma forma, se pueden representar el resto de números.

Cuando utilicemos un dispositivo de ánodo común, el funcionamiento será similar, con la única excepción de que tendremos que alimentar el pin común con los +5V y realizar el montaje de resistencias e interruptores unidos a tierra.

Lec21 006

El principal inconveniente de la utilización de los displays de 7 segmentos es que necesitan un gran número de líneas para su gobierno. Un control directo de un display de siete segmentos desde nuestro ARDUINO supondría utilizar siete pines (ocho si contamos el punto decimal) para gobernar un solo dispositivo.

Con una sencilla operación de multiplicación podemos comprobar que es imposible utilizar cuatro dísplays de 7 segmentos desde nuestro ARDUINO porque necesitaríamos 28 pines.

Por eso, la solución habitual es utilizar integrados que nos ayudan a reducir el número de pines utilizados de nuestro ARDUINO para gobernar los displays de 7 segmentos. En el siguiente montaje podemos ver la utilización de un integrado 4511 para gobernar un display del tipo cátodo común utilizando sólo cuatro pines.

Lec21 007

El 4511 es un decodificador BCD a 7-Segmentos de bajo coste (existen versiones que cuestan unos pocos céntimos de euro). Recibe la información del dígito a mostrar en codificación octal (4 bits) a través de los cuatros pines denominados A,B,C y D. Gobierna los siete segmentos del display por medio de los siete pines de salida marcados como QA a QG.

El pin rotulado LT (lamp test) sirve para hacer una prueba de lámpara, es decir, que si conectamos este pin a tierra se iluminan los 7 segmentos y podemos comprobar que todos funcionan correctamente. Para un funcionamiento normal lo debemos conectar a +5V.

El pin rotulado BL (blank) sirve para inhabilitar el display y que se queden todos los segmentos apagados. Para inhabilitar el display debemos conectarlo a tierra y para que funcione normalmente conectarlo a +5V.

Por último, el pin rotulado LE (latch enable) permite congelar el display mostrando un determinado valor escrito en los pines de entrada del integrado. Su uso se realiza con la siguiente secuencia de trabajo. Ponemos el pin LE a tierra, utilizamos los pines A, B, C y D para indicar el número a mostrar en código octal y ponemos el pin LE a +5V. Mientras el pin LE esté conectado a +5V se ignorarán todos los cambios que se produzcan en los pines A, B, C y D manteniendo el mismo valor mostrado en el display. 

Más tarde veremos un ejemplo de uso de este pin para gobernar más de un display desde nuestro ARDUINO utilizando el menor número de pines posible. 

Por ahora, vamos a conectar nuestro integrado 4511 como se mostraba en la última figura.

El código que ejecutaremos en nuestro ARDUINO para mostrar un contador incremental de 0 a 9 con un nuevo incremento cada segundo se muestra a continuación.

Lec21 008

Lec21 009

El programa utiliza las funciones iniTemp() y chkTmp() que ya vimos en lecciones anteriores y que sirven para controlar la ejecución de las líneas de código convenientes cada segundo.

Utilizamos una matriz llamada digitos, de 10 x 4 posiciones, para codificar las diez cifras en octal y facilitar la activación y desactivación de las cuatro salidas que utilizamos para controlar el integrado 4511. Usamos la variable Contador para almacenar el número a mostrar en cada nuevo ciclo.

Al combinar el uso de la matriz digitos con la variable contador, resulta sencillo escribir el código necesario para mostrar la cifra indicada en cada bucle activando las salidas correspondientes para cada nuevo número a mostrar con unas sencillas instrucciones if..else por cada una de los cuatro pines de entrada del integrado 4511.

El resultado es un contador incremental en el display de siete segmentos.

Lec21 015

 

Lec21 016

Veamos ahora como podemos controlar cuatro displays con sólo ocho pines de nuestro ARDUINO utilizando el pin LE de cada integrado 4511. El esquema de conexionado de los cuatro displays se muestra en la siguiente imagen.

Lec21 010

El código de nuestro nuevo programa se muestra a continuación.

Lec21 011

Lec21 012

Lec21 013

Lec21 014

El funcionamiento es muy similar al código que ya vimos para controlar un único display.

La diferencia principal radica en que utilizamos cuatro pines para controlar el pin LE de cada uno de los integrados 4511 y que nuestra variable contador ahora se ha convertido en una matriz de cuatro posiciones para contener ahora los cuatro dígitos de nuestro contador.

Con la utilizanción de los pines LE podemos compartir los mismos cuatro pines de salida de nuestro ARDUINO para enviar la información del dígito que queremos mostrar en cada uno de los cuatro displays.

Como se puede observar la técnica consiste en activar el pin LE del integrado 4511 que gobierna el display que nos interesa excitar, escribir el código octal de la cifra a mostrar en ese display y volver a desactivar el pin LE. Y repetir esta operación para cada uno de los otros tres conjuntos de integrado y display que utilizamos para cada uno de los tres dígitos restantes.

De esta manera cada integrado 4511 se encarga de mantener el display que controla con el digíto que deseamos mostrar mientras utilizamos los mismos pines de salida para ir enviando la información al resto de los integrados.

Gracias a esta técnica, con sólo ocho pines podemos gobernar cuatro displays de siete segmentos. Además este código nos otorga una ventaja adicional. El tiempo de carga de trabajo de nuestro ARDUINO es muy limitado, puesto que con ayuda del uso de las funciones temporales, sólamente tenemos ocupado al microcontralador unos pocos milisegundos cada ciclo de escritura. De esta manera podemos utilizar displays de siete segmentos para mostrar información del proceso controlado por nuestro ARDUINO dejando a éste libre para realizar otras tareas de control.

El programa es un contador incremental con una frecuencia de un segundo empezando en el número 987 (el número desde el que comienza la cuenta se configura en las líneas del código 42 a 45).

Lec21 017

Como siempre, esperamos que esta lección os haya resultado interesante y que encontréis aplicaciones para el uso de displays de 7 segmentos dentro de vuestros proyectos.

 

[Proteus versión 8.2]

En varias de las lecciones de este curso hemos utilizado una serie de funciones auxiliares que nos facilitaron la utilización de temporizadores, básculas set-reset, control de un motor, etc. Aunque estas funciones que hemos utilizado repetidamente, por ejemplo las funciones iniTemp() y chkTemp(), siempre contienen el mismo código, nos hemos visto obligados a escribirlas una y otra vez en cada nuevo programa que construíamos.

Por supuesto, que podemos utilizar las facilidades que nos brindan los procesadores de textos actuales para copiar y pegar el código de unos proyectos a otros. Pero, tendríamos que acordarnos en qué proyecto las usamos para ir a su código y realizar el proceso de copia. Y, a medida que va pasando el tiempo, esta tarea puede terminar siendo una labor de búsqueda pesada y difícil.

En general, todos los programadores acaban utilizando una serie de funciones de forma bastante repetitiva en todos sus proyectos. Por eso surge el concepto de librería (en algunos países también se le conoce con el nombre de biblioteca). Una librería es un fichero (o una serie de ellos) que contiene una serie de funciones que pueden ser enlazadas y utilizadas por nuestro proyecto.

Nuestro entorno de desarrollo ya viene con una gran cantidad de librerías disponibles para utilizar en nuestros proyectos. Algunas ya las hemos ido utilizando a lo largo de este curso. Sin embargo en esta lección queremos dar un paso más allá que la mera utilización de librerías de terceras personas. Nuestro objetivo es aprender a construir nuestra propia librería con una serie de funciones básicas y a utilizarlas en uno de nuestros proyectos. Por supuesto que cada usuario podrá incluir más funciones o eliminar aquellas que él no considere útiles para adaptar la librería a sus necesidades particulares.

En primer lugar, tenemos que tener en cuenta una cosa importante para facilitar la utilización de nuestras librerías en nuevos proyectos. El lugar donde coloquemos nuestra librería nos facilitará su uso desde nuestro entorno de desarrollo. En concreto, el sistema de desarrollo de ARDUINO busca, por defecto, todas las librerías que se encuentran en el directorio 'libraries' de la carpeta donde tengamos instalado el entorno ARDUINO. En nuestro caso (windows 7 64bits) la carpeta se encuentra en la siguiente ruta:

Lec22 001

Y contiene las siguientes librerías:

Lec22 002

Como es lógico, en cada ordenador encontraremos una lista diferente según el número de librerías de terceros que hayamos instalado.

Nosotros, vamos a crear una librería llamada Hubor. Si el usuario quiere cambiar el nombre de su librería por uno que se adecúe más a sus gustos, sólo tiene que seguir todos los pasos de esta lección cambiando 'Hubor' por el nombre elegido en todos ellos. Lo importante es que mantengamos la coherencia a lo largo de todo el proceso para que su utilización sea intuitiva y sencilla.

La primera tarea consiste en crear un directorio de nombre 'Hubor' en la mencionada carpeta de librerías. Dentro de esta carpeta que acabamos de crear tenemos que escribir dos ficheros de texto. Uno de ellos lo llamaremos 'Hubor.cpp' y el otro 'Hubor.h'. Por ahora están vacíos, pero más tarde iremos añadiendo los códigos necesarios. El primero contendrá el código en lenguaje 'c' de nuestras funciones. El segundo es un fichero de cabecera con información para el compilador (normalmente, una declaración directa de clases, subrutinas, variables, u otros identificadores) para el uso de la librería.

El código completo del archivo Hubor.cpp se puede descargar desde este enlace: Fichero Hubor.cpp. Este fichero contiene el código de las siguientes funciones: iniTemp(), chkTemp(), flancoSub(), flancoBaj(), bascula_r(), bascula_s(), pulso(), pulso_mem(), parpadeo(), retraso() y ctrlMotor(). En el código, delante de cada función, figura una pequeña explicación del funcionamiento de cada una de ellas y de la forma de utilizarla dentro de nuestro código. A efectos de esta lección, vamos a concentrarnos en el comienzo del archivo con el código de las dos primeras funciones, de sobra conocidas para quien siga este curso puesto que las hemos utilizado en varias lecciones. El resto de las funciones siguen un procedimiento de construcción similar.

Lec22 003

Es importante observar que nuestro fichero, después de los comentarios con la información de la librería, contiene dos sentencias #include. Cuando utilizamos una sentencia include, le estamos indicando al compilador que incluya en ese punto el archivo correspondiente y lo compile con el resto de los ficheros fuente que forman nuestro programa. Puesto que sólo le indicamos el nombre del archivo, el compilador entiende que lo tiene que buscar en el mismo directorio donde se encuentra el archivo que lo está llamando (en nuestro caso la carpeta Hubor que acabamos de crear y que es dónde está situado el archivo Hubor.ccp) o en alguno de los directorios definidos por el compilador como lugares de búsqueda por defecto.

Por lo tanto, con estas dos sentencias #include estamos diciendo al compilador que incluya en este punto los ficheros 'Hubor.h' y 'Arduino.h'. el primero es el fichero de cabecera que acabamos de crear para nuestra librería y el segundo contiene una serie de definiciones utilizadas de forma estándar por el entorno de programación ARDUINO. En realidad, estas definiciones incluidas en el fichero 'Arduino.h' las hemos estado utilizando en todos nuestros proyectos hasta ahora. Cuando creamos un programa en ARDUINO, el compilador enlaza a este fichero por defecto de forma automática para nosotros. Pero cuando construímos una librería no lo hace y, por ese motivo, se lo tenemos que indicar expresamente.

El resto del fichero es el código de todas las funciones, tal y como lo hubierámos utilizado en cualquiera de nuestros proyectos.

A continuación vamos a escribir el código del fichero de cabecera 'Hubor.h'. Lo podemos descargar desde el siguiente enlace: Fichero Hubor.h. Como ya dijimos antes, contiene las definiciones para ayudar al compilador a utilizar la librería.

Lec22 004

En la línea 15 utilizamos una sentencia #include como la que acabamos de ver en el fichero Hubor.cpp para incluir el fichero con las definiciones estándar utilizadas por el entorno ARDUINO.

En las líneas 17 a 19 definimos los operadores lógicos para su utilización en nuestro código.

En la linea 21 declaramos la estructura MotorDatosControl que ya vimos en la Lección 19 y que se utiliza en la función ctrlMotor() para intercambiar datos.

Y, por último, de las líneas 35 a la 45 se incluyen los prototipos de todas las funciones incluídas en la librería. Un prototipo es una declaración de una función que se lleva a cabo con dos propósitos principales: evitar conversiones erróneas de valores (al definir el tipo de dato que utilizamos para cada parámetro pasado a la función y el tipo de dato que devuelve la propia función) y evitar errores en el número de argumentos pasados a la función.

Y ya tenemos todo listo para utilizar nuestra librería 'Hubor.h' en cualquier nuevo proyecto. Vamos a crear el siguiente montaje:

Lec22 005

Donde utilizaremos nuestro Arduino con cuatro entradas (tres pulsadores y un interruptor) y siete salidas para gobernar otros tantos leds.

El código de nuestro programa será el siguiente:

Lec22 006

Lec22 007

Observe que la manera de poder utilizar todas las funciones almacenadas en nuestra librería no puede ser más sencilla. Sólo con utilizar en la línea 10 la sentencia #include correspondiente ya las tenemos todas disponibles.

El resto de código ya no tiene que tener secretos a esta altura del curso. Primero definimos las variables de trabajo que vamos a utilizar. Luego la configuracion de los piines que vamos a usar como entradas y salidas en la función setup(). Por último el código de trabajo que se repetirá de forma cíclica en la función loop().

En la primera parte leemos los valores de las entradas. En la segunda, utilizamos las diferentes funciones de la librería. En la tercera, escribimos las salidas. Y en la cuarta y última parte, usamos las funciones de tiempo chkTemp() e iniTemp() para enviar información cada segundo al exterior. Como en este caso no utilizamos las comunicaciones, hemos utilizado este espacio para cambiar de valor una variable llamada flag1 que utilizamos para encender y apagar cada segundo el led incluído en la placa base de ARDUINO y conectado al pin IO13.

Si ejecutamos nuestro proyecto podemos ver como funciona cada una de las funciones de la librería. En este punto hay que hacer una salvedad importante. Para que Proteus vuelva a leer todas las librerías disponibles en el directorio 'libreries' de la carpeta 'Arduino' en lugar de compilar nuestro proyecto como siempre con la opción 'construir proyecto', necesitaremos utilizar la opción 'reconstruir el proyecto'. Una vez hecho esto la primera vez, ya podemos utilizar la opción 'construir proyecto' como siempre.

Lec22 008

Veamos con detalle el uso de las funciones:

Lec22 009

flancoSub() detecta el flanco de subida al pulsar el botón arranque1. Ese pulso de subida lo utilizamos para alimentar el set de la función bascula_r() y por lo tanto se activa la salida1. Cuando actuemos sobre el interruptor parada1 que utilizamos para alimentar el reset de la función bascula_r se desactiva la salida1.

flancoBaj() detecta el flanco de bajada al pulsar el botón arranque2. Ese pulso al cesar la señal lo utilizamos para alimentar el set de la función bascula_s() y por lo tanto se activa la salida2. Cuando actuemos sobre el interruptor parada1 que utilizamos para alimentar el reset de la función bascula_s se desactiva la salidas.

La diferencia entre bascula_r() y bascula_s() es la dominancia del set o el reset en caso de que ambas señales lleguen al mismo tiempo. Podemos comprobar su funcionamiento diferente ejercitando con este ejemplo.

pulso() genera un pulso de duración igual a 5000mseg cuando se recibe la señal del pulsador arranque2 y lo muestra en la salida3.

pulso_mem() genera un pulso de duración igual a 5000mseg cuando se recibe la señal del pulsador arranque2 y lo muestra en la salida4. 

La diferencia entre pulso() y pulso_mem() es que la primera interrumpe la salida si cesa la señal de entrada mientras que la segunda memoriza la orden de entrada y la sigue generando después de cesar el disparador. Para interrumpir el pulso antes de alcanzar el tiempo podemos utilizar el parámetro reset de la función (en este caso parada1).

parpadeo() genera una intermitencia sobre la salida5 mientras esté activa la entrada arranque3.

Por último, retraso() activa la salida6 1500mseg después de que se produzca la entrada3. Si la entrada cesa antes de que pasen los 1500mseg no se llegará a generar la salida6.

Por supuesto, que el lector ya está en condiciones de construir la librería con las funciones que él desee. Además podrá ir incorporando con el tiempo nuevas funciones acumulando trabajo para el futuro.

Esperamos que esta leccion haya resultado interesante y que la utilización de librerías sea una práctica habitual en los próximos proyectos.

 

 

[Proteus versión 8.3]

En la lección 21 vimos en profundidad la utilización de displays de 7 segmentos. También aprendimos cómo utilizar los integrados 4511 para controlar varios displays de 7 segmentos. Sin embargo, si queremos construir un cartel luminoso formado por múltiples displays de 7 segmentos, es más cómodo utilizar el integrado MAX7219.

Este integrado nos permite controlar filas de 8 unidades de displays de 7 segementos y puede conectarse con nuestro Arduino utilizando un sistema de comunicación vía serie que sólo ocupa tres pines de nuestro controlador. Además, igual que el ejemplo que vimos con los integrados 4511, podemos utilizar varios integrados MAX7219 enlazando unos con otros, para aumentar el número de displays controlados. Por esta razón, en la práctica utilizar carteles luminosos formados por múltiples conjuntos de 8 unidades de displays de 7 segmentos practicamente exige que la mejor solución sea el uso de los integrados MAX7219. En la página www.openhacks.com podemos encontrar esta imágen con un ejemplo dónde se utiliza tres conjuntos de displays desde un Arduino.

Lec24 001a

Una muestra de la utilización práctica de este tipo de montajes, podría ser la creación de un panel de avisos de varias filas como el que se muestra en la imagen siguiente:

Lec24 002

El elemento básico de esta lección es el integrado MAX7219 de la casa  Maxim. La información técnica sobre el mismo se puede encontrar en el siguiente enlace: https://www.sparkfun.com/datasheets/Components/General/COM-09622-MAX7219-MAX7221.pdf. Básicamente se trata de un integrado que nos permite controlar ocho displays de siete segmentos (también se puede utilizar para matrices de leds de 8x8, pero eso no es objeto de esta lección). Se comunica con el microcontrolador que lo gobierna mediante el uso de un protocolo de comunicaciones serie SPI, QSPI o MICROWIRE. Incluye un decodificador BCD, lo que nos permite no tener que dibujar una matriz por cada caracter que queramos usar, resultando muy fácil escribir mayúsculas, minúsculas, dígitos y otros signos. Almacena en memoria RAM el valor de cada dígito, lo que posibilita que podamos escribir sólo el dígito que varía y que no sea necesario enviar en cada escritura todos los valores de los ocho dígitos. Y, por último, incluye en su diseño sistemas para la reducción de las emisiones electromagnéticas. En la siguiente imagen se muestra el conexionado estandar de este integrado.

Lec24 003

Nosotros vamos a utilizar dos integrados para controlar 16 displays. De esta manera el lector podrá conocer cómo se puede utilizar más de un integrado en sus diseños y no será complicado crear proyectos a partir de este ejemplo dónde se utilicen tres o más. El montaje completo tiene este aspecto.

Lec24 004

Veamos los detalles por separado para comprenderlos bien. Hemos utilizado cuatro bloques de cuatro dígitos de displays de siete segmentos cada uno de ellos con cátodo común (el modelo en proteus denominado 7SEG-MPX4-CC). Hemos unido dos bloques a un integrado MAX7219 y los otros dos bloques al otro. El conexionado de cada integrado con sus dos bloques de displays se muestra a continuación.

Lec24 005

Se unen los pines de cada segmento (A, B, C, D, E, F, G, DP) de cada bloque en paralelo con los pines de igual nombre del integrado. Y se unen los cuatro pines de cada bloque de displays (los ocho en total) con los pines numerados DIG0 - DIG7 del integrado.

A continuación vemos el detalle de cómo se une cada uno de los integrados con nuestro Arduino.

Lec24 006

El pin CLK se une con el pin IO13 de nuestro Arduino. El pin LOAD con el pin IO10 y el pin DIN con el pin IO11. Si sólo usáramos un integrado, aquí hubiera acabado nuestro trabajo. Pero como queremos utilizar dos, el segundo integrado debe conectarse de la siguiente manera.

Lec24 007

Los pines CLK y LOAD se conectan en paralelo con el primer integrado, uniéndolos a los mismos pines del Arduino. Pero en el segundo integrado el pin DIN debe conectarse con el pin DOUT del primer integrado. De esta forma generamos la cadena de integrados unos detrás de otro. Si quisierámos unir un tercer integrado MAX7219, conectaríamos el pin DOUT del segundo integrado con el pin DIN del tercero. Y así sucesivamente. Nosotros hemos utilizado un terminal con el mismo nombre (LINK_MAX) para enlazar los dos integrados y simplificar el cableado. Recordemos que Proteus enlaza automáticamente los terminales del mismo nombre.

Lec24 008

Nuestro diseño no tiene más complicación. Realmente es sencilla la implementación de rótulos de filas de displays de siete segmentos con ayuda de los integrados MAX7219.

No queremos terminar esta sección de conexionado sin mencionar que en el mundo real (ya sabemos que la simulación en Proteus siempre tiende a simplificarnos la tarea), hay que utilizar una resistencia y un condensador en cada integrado. Consultar la hoja de datos del integrado para ver un esquema completo de ejemplo:

Lec24 009

Es el momento ahora de escribir el código que deseamos ejecutar en nuestro Arduino. Como es habitual en el mundo Arduino, existe una librería que nos hará la vida muy sencilla en el uso de este tipo de integrados. En este caso, Eberhard Fahle ha escrito la librería que tiene el nombre de HCMAX7219 y puede ser descargada desde este enlace: https://github.com/HobbyComponents/HCMAX7219. La información sobre el uso de esta librería la podemos encontrar en este enlace: http://forum.hobbycomponents.com/viewtopic.php?f=58&t=1794.

Nuestro código es tan sencillo gracias a la utilización de la librería que no consideramos necesario añadir muchas explicaciones. Simplemente, señalar que utilizamos tres funciones. HCMAX7219.print7Seg() para enviar la cadena de caracteres a los integrados. HCMAX7219.Refresh() para refrescar los caracteres que se visualizan en los displays. Y HCMAX7219.Clear() para limpiar el buffer de datos de los integrados al acabar.

Lec24 010b

Nos falta un punto muy importante para que nuestro programa funcione bien. La librería está por defecto escrita para gestionar un sólo integrado MAX7219 con ocho displays, pero preparada para cambiar el número de integrados a utilizar con una parametrización muy sencilla. Para indicarle que queremos utilizar más de un integrado, tenemos que ir a la carpeta donde se encuentran las librerías de Arduino (en la carpeta libraries del directorio dónde se aloja el compilador). Abrimos la carpeta de nuestra librería (HCMAX7219) y modificaremos el fichero llamado HCMAX7219.h. Buscamos la sección USER CONFIGURATION.

Lec24 013

Modificaremos la definición NUMBEROFDRIVERS para indicar el número de integrados que estamos usando (en nuestro caso 2).

Y ya podemos compilar nuestro proyecto y arrancar la simulación.

El resultado es nuestro mensaje desplazándose por los diferentes displays generando la sensación de un rótulo en movimiento.

Lec24 011

Lec24 012

Esperamos, como en las ocasiones anteriores, que esta lección os permita implementar en vuestros diseños filas de displays de 7 segmentos utilizando los integrados MAX7219.

 

 

[Proteus versión 8.2]

En la lección 16 estudiamos la forma de utilizar un display LCD de texto en nuestros proyectos ARDUINO. En aquella ocasión ya definimos un display LCD (siglas del inglés liquid crystal display) o pantalla de cristal líquido, como una pantalla delgada y plana formada por un número de píxeles, en color o monocromos, colocados delante de una fuente de luz o reflectora. Su principal ventaja es que utiliza cantidades muy pequeñas de energía eléctrica.

También vimos que existen pantallas muy variadas en el mercado. Las hay de colores diferentes (monocromo verde, monocromo ámbar o color). Unas tienen capacidad para mostrar sólo caracteres de  texto y otras admiten gráficos. La lección 16 se dedicó a la familia de pantallas que sólo eran capaces de mostrar caracteres de texto. En esta ocasión queremos introducirnos en el uso de las que tienen capacidades gráficas.

Lec23 001

Antes de empezar con la lección hay que hacer dos salvedades importantes. En primer lugar, hay que saber que existen muchos tipos diferentes de pantallas gráficas y que su gobierno puede diferir mucho de unas a otras. Cuando vayamos a elegir la pantalla para nuestro proyecto hay que tener en cuenta dos cuestiones: la pantalla propiamente dicha (su tamaño, color o monocromo, resolución, etc) y el chip con la que se controla. Hay diferentes tipos de controlador y su programación es diferente. Nosotros vamos a ver en esta lección el control de una pantalla monocromo de 128 x 64 pixels y basada en el controlador SAMSUNG KS0108.

Lec23 002

En segundo lugar, es importante tener en cuenta una cosa. La programación de una pantalla gráfica es considerablemente más compleja que el de una pantalla de texto. En esta lección vamos a explicar los conceptos más básicos y realizaremos sencillos dibujos de líneas, polígonos y caracteres. Llegar a realizar una pantalla gráfica completa y profesional puede ser una tarea bastante laboriosa y que nos lleve mucho tiempo.

Para controlar nuestra pantalla gráfica vamos a utilizar una librería para ARDUINO disponible en la página oficial en el siguiente enlace: KS0108 Graphics LCD library. Como ya hemos visto en anteriores lecciones cuando utilizamos librerías de terceros tenemos que colocarla en el directorio 'libraries' de la carpeta donde hayamos instalado nuestro entorno de desarrollo ARDUINO. En esta ocasión, la librería se creará en la carpeta llamada KS0108.

Lec23 004

Para simular nuestra pantalla gráfica, Proteus nos facilita varios modelos. Nosotros vamos a utilizar el llamado LGM12641BS1R. En la siguiente pantalla se muestra su representación gráfica y la forma en que lo tenemos que conectar a nuestro equipo ARDUINO.

Lec23 003

Es importante tener en cuenta que hemos puesto la señal de reset (RST) conectada directamente al potencial de +5V. De esta manera la pantalla está encendida en todo momento. El resto de los pines se han conectado a los pines de nuestro ARDUINO según las especificaciones de la librería que estamos utilizando. El esquema eléctrico completo es el siguiente:

Lec23 005

Veamos ahora el software. Vamos a empezar con un programa muy sencillo para poder ir introduciéndonos poco a poco en el control de una pantalla gráfica. Siguiendo con la costrumbre que vamos adquiriendo en lecciones anteriores partimos de un armazón básico que nos sirve de estructura para todos los programas.

Lec23 006

Lec23 007

Como vamos a utilizar la librería HUBOR que ya vimos en la lección 22 y que podemos descargar desde nuestra web, hemos incluído en la línea 14 un enlace a dicha librería. En la línea 15 llamamos a la librería ks0108 que es la encargada de controlar la pantalla gráfica basada en el controlador SAMSUNG.En la línea 16 incluimos en nuestro código el fichero "SystemFont5x7.h" que contiene la definición de una familia de caracteres de 5x7 pixels. Esta fichero viene incluído en la librería ks0108 y por eso hemos optado por él.

En la función setup() hemos escrito tres sentencias de programa. En la línea 31 inicializamos la pantalla con la función GLCD.Init() de la librería ks0108. Esta función sólo recibe un parámetro que puede tomar dos valores (NON_INVERTED y INVERTED) según deseemos que la pantalla tenga fondo claro y dibujemos en negro o tenga fondo oscuro y dibujemos en blando.

En la línea 32 seleccionamos la familia de caracteres que vamos a utilizar para escribr textos en nuestra pantalla.Como se puede observar, pasamos como parámetro precisamente la familia de caracteres que se define en el fichero "SystemFont5x7.h".

Por último, en la línea 33 utilizamos el primer comando para dibujar en nuestra pantalla gráfica. En este caso la función GLCD.DrawRect() que se encarga de dibujar un recuadro. Los parámetros que recibe esta función son cinco: coordenadas x e y del origen del recuadro, coordenadas x e y del fin del recuadro y color.

Compilemos y ejecutemos nuestro programa. El resultado en pantalla, aunque no es muy espectacular, si es muy satisfactorio para el tiempo empleado en escribir el código.

Lec23 008

Veamos ahora un segundo ejemplo. Con este código vamos a ver un ejemplo de utilización de la mayoría de las funciones que nos facilita la librería ks0108 para dibujar en nuestra pantalla gráfica. El código completo es el siguiente:

Lec23 013

Lec23 014

Lec23 015 

La lógica de funcionamiento es como sigue.

Hasta la línea 25 se encuentran las sentencias necesarias para llamar a las librerías utilizadas y definir las constantes y variables que vamos a utilizar a lo largo del programa.

En las líneas 26 a 38 se encuentra la función setup() para inicializar el equipo. En ella se realiza las llamadas necesarias para inicializar la pantalla y poner a cero las variables auxiliares.

A partir de la línea 40 se encuentra la función loop() que, como siempre, contiene las sentencias que se ejecutan de forma cíclica. Hemos divido esta función en cuatro secciones (siguiendo el esquema que ya hemos establecido como estándar en nuestras lecciones).

En el primer bloque leemos las entradas (en este caso no hay nada que leer).

En el segundo bloque, escribimos la lógica de control. En nuestro caso es muy sencilla. Con la ayuda de las funciones temporales iniTmp() y chkTmp() de la librería HUBOR, ejecutamos cada segundo unas sentencias que sirven para incrementar el contador y poner a uno el disparador que utilizaremos para saber cuando tenemos que escribir en nuestra pantalla.

En el tercer bloque que utilizamos para escribir las salidas tampoco hay nada, porque en este proyecto no utilizamos salidas a parte de las utilizadas para contral la pantalla gráfica.

En el cuarto bloque que utilizamos para controlar periféricos, se encuentran las líneas que más nos importan en esta lección y que se encargan de escribir en la pantalla. Para facilitar la visualización y comprensión de lo que escribimos en la pantalla hemos hecho lo siguiente. Cada vez que el disparador vale 1, realizamos una escritura en la pantalla y lo volvemos a poner a cero (línea 66). A continuación borramos la pantalla (línea 67).

En las líneas 68 a 115 utilizamos la estructura de control SWITCH-CASE. Como es la primera vez que la utilizamos en este curso, vamos a empezar por explicar cómo funciona. La sentencia SWITCH es una estructura de control de bifurcación múltiple estándar en el lenguaje de programación C. En un bloque SWITCH-CASE, el controlador comprueba el valor de una variable (en nuestro caso Contador1) de forma sucesiva frente a una lista de valores (cada una de las sentencias CASE). Cuando encuentra una coincidencia, se ejecuta el bloque de sentencias asociados con el CASE hasta que encuentra un BREAK. Si no se encuntra ninguna coincidencia se ejecuta el bloque DEFAULT.

Una vez que ya sabemos como funciona un bloque SWITCH-CASE vayamos ahora a ver cómo controlamos nuestra pantalla en cada incremento de nuestro contador. Cuando el contador vale 1 se ejecuta la función GCLD,DrawBitmap() de la librería KS0108. Esta función se encarga de dibujar en nuestra pantalla una imagen en formato de mapa de bits. En nuestro caso, la información de esta imagen se encuentra almacenada en el fichero ArduinoIcon.h que se suministra con la librería y que incluimos en la línea 16 de nuestro código.

Lec23 016

El resultado que se visualiza en nuestra pantalla es:

Lec23 017

Cuando el contador vale 2 se ejecuta un bucle repetitivo con ayuda de la estructura de control FOR. En cada iteración del bucle ejecutamos una función GLCD.DrawCircle que se encarga de dibujar un círculo en la pantalla. Los parámetros que le tenemos que pasar a esta función son las coordenadas x e y del centro, el radio del cículo y el color con el que vamos a dibujarlo. En nuestro caso, dibujamos una serie de cículos concentrícos con centro en el punto 64,32 y de radios comprendidos entre 5 y 20 en saltos de 5 en 5.

Lec23 018

El resultado será:

Lec23 019

Cuando el contador vale 3 ejecutamos la función GLCD.DrawLine() que se encarga de dibujar una línea recta. Los parámetros que debemos pasar a esta función son las coordenadas x e y del origen de la línea, las coordenadas x e y del fin de la línea y el color.

Lec23 020

En la pantalla se visualiza:

Lec23 021

Cuando el contador vale 4 ejecutamos la función GLCD.DrawVertLine() que se encarga de dibujar una línea recta vertical. Los parámetros que debemos pasar a esta función son las coordenadas x e y del origen de la línea, la longitud de la misma y el color. En este caso volvermos a utilizar un bucle FOR para dibujar una serie de líneas desde la coordenada x = 20 hasta la coordenada x=100 en saltos de 5 en 5.

Lec23 022

En la pantalla se visualiza:

Lec23 023

Cuando el contador vale 5 ejecutamos la función GLCD.DrawHoriLine() que se encarga de dibujar una línea recta horizontal. Los parámetros que debemos pasar a esta función son las coordenadas x e y del origen de la línea, la longitud de la misma y el color.

Lec23 024

En la pantalla se visualiza:

Lec23 025

Cuando el contador vale 6 ejecutamos la función GLCD.DrawRect() que se encarga de dibujar un rectángulo. Los parámetros que debemos pasar a esta función son las coordenadas x e y del origen del recuadro, las coordenadas x e y del final y el color.

Lec23 026

En la pantalla se visualiza:

Lec23 027

Cuando el contador vale 7 ejecutamos la función GLCD.DrawRoundRect() que se encarga de dibujar un rectángulo de esquinas redondeadas. Los parámetros que debemos pasar a esta función son las coordenadas x e y del origen del rectángulo, las coordenadas x e y del final, el radio con el que se redondeará las esquinas y el color.

Lec23 028

En la pantalla se visualiza:

Lec23 029

Cuando el contador vale 8 ejecutamos la función GLCD.FillRect() que se encarga de dibujar un rectángulo con relleno. Los parámetros que debemos pasar a esta función son las coordenadas x e y del origen del rectángulo, las coordenadas x e y del final y el color.

Lec23 030

En la pantalla se visualiza:

Lec23 031

Cuando el contador vale 10 ejecutamos la función GLCD.DrawLine() que ya vimos con anterioridad y que se encarga de dibujar una línea recta. Con ayuda de un bucle FOR somos capaces de dibujar una serie de líneas con origen en un punto común (0,0) y con final en un punto de coordenada x constante (127) y coordenada y variable desde 0 a 65 en intervalos de 2 pixel de separación.

Lec23 032

En la pantalla se visualiza:

Lec23 033

Cuando el contador vale más de 9 no existe ninguna claúsula CASE que se cumpla, así que se ejecutará el bloque DEFAULT. En este bloque se utilizan varias funciones. La función GLCD.CursorTo() se encarga de situar el cursor en las coordenadas x e y correspondientes. La función GLCD.Puts() escribe una cadena de texto en el lugar donde se encuentre el cursor en este momento. La función GLCD.PrintNumber() escribe un número en la pantalla. También nos ayudamos de la función estándar de C strcpy() para escribir en la variable 'Cadena' el valor de una constante de texto.

Lec23 034

En la pantalla se visualiza en cada nuevo incremento del contador, un mensaje con el valor del contador.

Lec23 035

Lec23 036

Y con esto, terminamos nuestra lección de hoy. Ya hemos aprendido a utilizar un display gráfico. Todavía exigirá por parte del lector una buena dosis de trabajo para mostrar resultados satisfactorios en sus proyectos. Pero las bases están sólidamente fundamentadas.

El código completo de la lección se puede descargar desde este enlace: Código lección 23.

 


Esta página es propiedad de Hubor.

2014.

Guardar
Preferencias de usuario para las Cookies
Estamos utilizando las cookies para asegurarnos de que le podemos ofrecer el mejor servicio posible en este sitio web. Si rechaza el uso de las cookes, es posible que esta web no funcione como estaba previsto por el equipo de programadores.
Aceptar todo
Rechazar todo
Leer más
Estadísticas
Las cookies de preferencias permiten a la página web recordar información que cambia la forma en que la página se comporta o el aspecto que tiene, como su idioma preferido o la región en la que usted se encuentra.
Google Analytics
Aceptar
Rechazar