Micropython: Controlando un módulo de display con 74HC595

Los displays de siete segmentos siguen encontrando aplicación en algunos proyectos, a pesar de sus limitaciones. En este artículo te explico como conectar un módulo de este tipo, controlado con el circuito integrado 74HC595, a una placa Raspberry Pi Pico y como utilizarlo empleando Micropython.

Introducción

En la actualidad tenemos a nuestra disposición una gran cantidad de displays de distintas características y funciones: LCD, OLED, e-paper, gráficos o de caracteres. La mayoría tienen mejores prestaciones o calidad que los tradicionales display de led de 7 segmentos, sin embargo estos siguen encontrando su lugar en algunos proyectos. Si queremos mostrar algún valor numérico sin gastar demasiado o mejor aún, si queremos darle algún aspecto “retro” a nuestro proyecto, un display de leds es una excelente opción.

A la hora de emplear un display de 7 segmentos también tenemos mas de una opción para elegir: podemos conectar varios dígitos y construir nuestro propio circuito de multiplexado, controlando rápidamente el encendido de cada uno para generar la ilusión de que están todos prendidos o podemos elegir un módulo que incluya un controlador que haga ese trabajo por nosotros. Dentro de esta segunda categoría podemos encontrar distintas placas, como las que emplean el popular controlador TM1637 o las que se basan en el shift register 74HC595.

El 74HC595

El circuito integrado 74HC595 es una combinación de un shift register (o registro de desplazamiento) de 8 bits y un latch, tambien de 8 bits con salida three-state (de tres estados).

Fig. 1. El 74HC595

Los datos digitales entran al shift register en formato serie usando un pin de datos (A) y otro de reloj (SHIFT CLOCK). Para transferir los datos del shift register al latch y almacenarlos se emplea otro pin (LATCH CLOCK). Si queremos que el contenido del latch esté accesible en las salidas, OUTPUT ENABLE debe estar a un nivel BAJO, de lo contrario, las salidas quedan en tercer estado o alta impedancia. Finalmente, tenemos un reset (RESET) que borra el contenido del shift register si se lo fuerza a nivel BAJO.

En la siguiente imagen se puede apreciar un diagrama en bloques del 74CH595 extraído de su hoja de datos de la marca ON semiconductor:

Fig. 2. Diagrama en bloques interno del 74HC595

Este circuito integrado tiene múltiples aplicaciones, como por ejemplo expandir la capacidad de entrada/salida de un micro o placa (GPIO), ya que con 3 pines (uno de datos y dos de clock) podemos controlar 8 salidas independientes.

Además, este IC tiene una característica muy interesante, que es la facilidad para conectar varios de ellos en “cascada”, para aumentar aún mas la cantidad de salidas disponibles. Basta con conectar la salida serie (SQ) de uno con la entrada serie del siguiente (A). Así, usando siempre sólo 3 pines podemos tener gran cantidad de salidas en paralelo.

En lo que sigue te explico como conectar una placa de display que emplea estos circuitos integrados a una Raspberry Pi Pico y como mostrar distintos valores y textos empleando un módulo de Micropython.

El hardware

Placas

Para la demostración utilizaré dos placas que tengo disponibles, una de 4 dígitos y otra de 8 dígitos. En realidad estas placas pueden conectarse una a continuación de la otra para obtener una cantidad mayor de dígitos (gracias a la capacidad del 74HC595 de conectarse en cascada) y lo único que debemos hacer en el código es indicar la cantidad de dígitos que se quieren controlar, como veremos mas adelante.

Fig. 3. Las placas de 4 y 8 dígitos

Circuito interno

En la imagen de abajo (Fig. 4) se puede apreciar el circuito interno de la placa de 4 dígitos. Contiene dos integrados 74HC595. El de arriba (U5) controla los segmentos individuales de los display y el de abajo (U6) controla cual de los cuatro dígitos se enciende.

Fig. 4. Circuito interno de la placa de 4 dígitos

Los dígitos deben estar multiplexados, lo que significa que cada uno se enciende por un breve período de tiempo y se lo vuelve a encender antes de que el ojo se de cuenta de que se ha apagado (un tiempo menor a 20 milisegundos). La técnica de multiplexado es bastante antigua pero tiene sus complicaciones, si les interesa háganmelo saber y escribo un artículo específicamente sobre el tema.

En el circuito anterior se puede notar que U6 tiene 4 salidas libres, que son las que aprovecha la placa de 8 dígitos, cuyo circuito interno puede verse en la Fig. 5 a continuación.

Fig. 5. Circuito interno de la placa de 8 dígitos

Conexiones

Independientemente de la cantidad de dígitos, las placas tienen 5 contactos: dos de alimentación, uno de datos y dos de clock o reloj.

Fig. 6. Pines del display

VCC y GND: Alimentación (3V a 5V)

SCLK: Clock para entrada de datos (SHIFT CLOCK)

RCLK: Clock para guardar en latch (LATCH CLOCK)

DIO: Entrada serie de datos (A)

La alimentación del 74HC595 puede estar entre los 2 y 6V, así que se lo puede emplear tanto en micros o placas que funcionen con 3V como con 5V. Los pines de clock y datos (SCLK, RCLK y DIO) se deben conectar a 3 pines de GPIO de la Pico.

Circuito de prueba

En la siguiente imagen se puede ver el circuito que utilicé para probar la conexión con el display.

La alimentación del mismo se toma de la salida del 3V de la Pico (pin 36) y GND (pin 38). La señal SCLK se conecta a GPIO2 (pin 4), RCLK a GPIO3 (pin 5) y DIO a GPIO3 (pin 6).

Fig. 7. Circuito de prueba

El software

Para cargar datos en los 74HC595 de la placa y así prender los distintos dígitos puedes escribir tu propio driver analizando la hoja de datos o puedes recurrir a un módulo ya existente.

Si optas por la segunda opción, puedes usar un módulo que está disponible en este repositorio

Para utilizarlo, lo primero que debes hacer es descargarlo del repositorio y guardarlo en el sistema de archivos de la Pico. Lo ideal sería que lo hagas dentro de una carpeta llamada LIB, para mantener todo ordenado.

Una vez copiado en la placa, lo puedes importar en tu código empleando import:

import TM74HC595

Este módulo contiene la clase TM74HC595.TM74HC595Controller así que lo siguiente que debes hacer es crear un objeto de esa clase. Al hacerlo, tienes que especificar los pines donde están conectados SCLK, RCLK y DIO así como la cantidad de dígitos del display.

En el circuito de pruebas de la Fig. 7, las señales SCLK, RCLK y DIO se conectan a los pines GPIO2, GPIO3 y GPIO4 y si la placa tiene 4 dígitos, el constructor del objeto queda de la siguiente forma:

display = TM74HC595.TM74HC595Controller(sclk=2, rclk=3, dio=4, num_displays=4)

Este objeto display tendrá solo dos métodos: test, que hace una rutina de prueba del display y show_sequence, que muestra una serie de caracteres que pueden representar un texto o un número.

Para comprobar que el circuito esté correctamente armado puedes usar primero el método test. El código sería el siguiente:

import TM74HC595

display = TM74HC595.TM74HC595Controller(sclk=2, rclk=3, dio=4, num_displays=4)

display.test ()

El programa de test muestra el dígito “8” en varias posiciones, luego una cuenta con números negativos y positivos y al finalizar muestra el texto “dOnE”

Fig. 8. Fin de la prueba

Una vez comprobado el funcionamiento del display veamos como emplear el otro método, show_sequence, que tiene el siguiente formato:

display.show_secuence (sequence, redraw=100, clear=True, start_at=0)

sequence: caracteres a mostrar en el display

redraw: cantidad de veces que se muestran los caracteres de sequence

clear: Si es True, al terminar de mostrar los caracteres se borra el display

start_at: Posición del display (digito) donde se empiezan a mostrar los caracteres (0=izquierda)

Por ejemplo, para mostrar el texto “Hola” debes usar el siguiente código:

import TM74HC595

display = TM74HC595.TM74HC595Controller(sclk=2, rclk=3, dio=4, num_displays=4)

display.show_sequence("HoLA", 2000, start_at=0)
Fig. 9. Texto “Hola”

No todos los caracteres se pueden mostrar en los dígitos de 7 segmentos, estos son los que están definidos en el módulo:

_CHARS = {
'0': 0xC0, '1': 0xF9, '2': 0xA4, '3': 0xB0, '4': 0x99, '5': 0x92, '6': 0x82,
'7': 0xF8, '8': 0x80, '9': 0x90, 'A': 0x88, 'B': 0x80, 'b': 0x83, 'c': 0xA7,
'C': 0xC6, 'd': 0xA1, 'D': 0xC0, 'E': 0x86, 'F': 0x8E, 'G': 0xC2, 'H': 0x89,
'i': 0xFB, 'I': 0xF9, 'j': 0xF3, 'J': 0xF1, 'L': 0xC3, 'n': 0xAB, 'o': 0xA3,
'O': 0xC0, 'P': 0x8C, 'q': 0x98, 'r': 0xCe, 'R': 0x88, 'S': 0x92, 't': 0x87,
'u': 0xE3, 'U': 0xC1, 'v': 0xE3, 'V': 0xC1, 'Y': 0x91, '‾': 0xFE, '-': 0xBF,
'_': 0xF7, ' ': 0xFF
}

Si quieres mostrar valores numéricos, primero debes pasarlos a string.

Por ejemplo, si tienes una variable con el valor de temperatura medido por un sensor y lo quieres imprimir en el display, el código sería como el siguiente:

import TM74HC595

display = TM74HC595.TM74HC595Controller(sclk=2, rclk=3, dio=4, num_displays=4)

temperatura = 25  #Fijamos a un valor constante para probar

display.show_sequence(str(temperatura)+"oC", 2000, start_at=0)
Fig. 10. Impresión de un valor numerico

En el ejemplo anterior utilicé una “o” como símbolo de grados centígrados. En realidad debería estar en la parte superior del display, pero ese carácter no está definido en el módulo. Esto no es un inconveniente ya que lo podemos agregar con facilidad.

La definición de caracteres no es otra cosa que un diccionario de nombre _CHARS. Este diccionario contiene una serie de entradas, cada una de las cuales consiste en una clave y un valor. La clave es el caracter y el valor asociado, un número en hexadecimal que es lo que debemos escribir en un dígito de 7 segmentos para que se encienda ese caracter.

Ese número hexadecimal también se puede representar en binario y en ese caso un “0” indica que el segmento se debe enceder y un “1” que el segmento se debe mantener apagado.

Recordemos que los segmentos se denominan con una letra desde la “a” hasta la “g”, como se ve a continuación:

Fig. 11. Denominación de cada segmento

La relación entre los valores que escribimos y los segmentos que se encienden es la siguiente:

bit76543210
segmentodpgfedcba

Entonces, si queremos encender el caracter “º” debemos prender los segmentos de la parte superior del “8”, es decir “a”, “b”, “f” y “g” y mantener los otros apagados. El número binario que debemos escribir para lograr eso es “10011100” que en hexadecimal corresponde al “9C”.

En el diccionario _CHARS agregamos entonces una entrada al final con el caracter y el valor hexa:

class TM74HC595Controller:
    _CHARS = {
    '0': 0xC0, '1': 0xF9, '2': 0xA4, '3': 0xB0, '4': 0x99, '5': 0x92, '6': 0x82,
    '7': 0xF8, '8': 0x80, '9': 0x90, 'A': 0x88, 'B': 0x80, 'b': 0x83, 'c': 0xA7,
    'C': 0xC6, 'd': 0xA1, 'D': 0xC0, 'E': 0x86, 'F': 0x8E, 'G': 0xC2, 'H': 0x89,
    'i': 0xFB, 'I': 0xF9, 'j': 0xF3, 'J': 0xF1, 'L': 0xC3, 'n': 0xAB, 'o': 0xA3,
    'O': 0xC0, 'P': 0x8C, 'q': 0x98, 'r': 0xCe, 'R': 0x88, 'S': 0x92, 't': 0x87,
    'u': 0xE3, 'U': 0xC1, 'v': 0xE3, 'V': 0xC1, 'Y': 0x91, '‾': 0xFE, '-': 0xBF,
    '_': 0xF7, ' ': 0xFF, 'º': 0x9C
    }

El código modificado con este caracter:

import TM74HC595

display = TM74HC595.TM74HC595Controller(sclk=2, rclk=3, dio=4, num_displays=4)

temperatura = 25  #Fijamos a un valor constante para probar

display.show_sequence(str(temperatura)+"ºC", 20000, start_at=0)

Ahora sí aparece bien el símbolo de “grados”:

Fig. 12. El nuevo caracter en el display

Para finalizar, un ejemplo con un display de 8 dígitos. La conexión es exactamente la misma y en el código debes poner num_displays=8 en el constructor:

import TM74HC595

display = TM74HC595.TM74HC595Controller(sclk=2, rclk=3, dio=4, num_displays=8)

btf = "OC261985"

display.show_sequence(btf, 5000, start_at=0)
Fig. 13. Ejemplo con un display de 8 dígitos

Para este caso me faltó un digito para la “T” de Octubre (aunque de todos modos no se hubiera mostrado correctamente, el tablero del DeLorean evidentemente usaba displays alfanuméricos con mas segmentos) 🙂

Conclusiones

Los display de 7 segmentos tienen limitaciones, porque aunque pueden mostrar correctamente valores numéricos, están muy limitados al momento de mostrar otros caracteres. Sin embargo, todavía son útiles para algunas aplicaciones.

En este artículo vimos el funcionamiento interno de dos placas de display basadas en el 74HC595, como conectarlas a una Raspberry Pi Pico y como imprimir distintos valores empleando Micropython y un módulo que podemos descargar de Github. También vimos como definir un caracter que no estaba originalmente en el módulo y como controlar una placa de 8 dígitos.

En realidad, la mayor parte de lo que hemos visto aquí es aplicable a otras placas compatibles con Micropython, como las que tienen un ESP32 o un ESP8266.

Espero que la información les haya sido de utilidad y que la puedan aprovechar en sus proyectos. Como siempre, cualquier duda o sugerencia la pueden dejar mas abajo en la sección de comentarios.

Hasta la próxima!

Deja un comentario

Este sitio usa Akismet para reducir el spam. Aprende cómo se procesan los datos de tus comentarios.

Habilitar notificaciones OK No, gracias