Visualizador de siete segmentos o SSD (seven-segment display). |
Los visualizadores de siete segmentos sirven para desplegar números decimales en relojes digitales, medidores electrónicos, calculadoras básicas y otros dispositivos electrónicos que requieren mostrar información numérica.
Reloj digital con dígitos de siete segmentos. |
En esta entrada discutiremos la manera de programar en Python un SSD conectado a un Arduino.
Ficha técnica del SSD
El proyecto que se presentará más adelante utiliza un SSD con número de parte LTS-4801G, el cual despliega dígitos de 10 mm de altura con segmentos en color verde. La siguiente imagen es una versión esquemática de este componente:Segmentos y pines de un SSD. |
Del esquema se puede observar que cada segmento está identificado por una letra de la A a la G, y P para el segmento correspondiente al punto decimal. El SSD tiene diez pines numerados del 1 al 10. Cada uno de los ocho segmentos está asociado a un pin en particular:
- Pin 1: Segmento G
- Pin 2: Segmento F
- Pin 4: Segmento E
- Pin 5: Segmento D
- Pin 6: Segmento P
- Pin 7: Segmento C
- Pin 9: Segmento B
- Pin 10: Segmento A
En los de tipo de ánodo común, todos los ánodos de los segmentos están unidos internamente a un pin común que debe ser conectado a potencial positivo (valor lógico 1). El encendido de cada segmento individual se realiza aplicando potencial negativo (valor lógico 0) por el pin correspondiente a través de una resistencia que limite el paso de la corriente.El SSD para nuestro proyecto es de ánodo común.
En los de tipo de cátodo común, todos los cátodos de los segmentos están unidos internamente a un pin común que debe ser conectado a potencial negativo (valor lógico 0). El encendido de cada segmento individual se realiza aplicando potencial positivo (valor lógico 1) por el pin correspondiente a través de una resistencia que limite el paso de la corriente.
Diseño de los dígitos
Cada uno de los siete segmentos puede estar encendido o apagado. Esto quiere decir que un SSD puede tener 27 = 128 estados diferentes (256 si consideramos el segmento del punto decimal). Sin embargo no todos estos estados son de nuestro interés. Para nuestro proyecto deseamos únicamente desplegar los dieciséis dígitos hexadecimales: del 0 al 9 y de la A a la F. La siguiente imagen muestra el diseño convencional de cada uno de estos dígitos. Los segmentos encendidos se muestran en negro, mientras que los apagados están en gris:Diseño de los dígitos hexadecimales usando siete segmentos. |
Hay que notar que los diseños de la b y la d se encuentran en minúsculas ya que no se pueden representar en mayúsculas sin que se confundan con algún otro dígito.
Una forma compacta de representar en Python estos diseños consiste en usar números binarios, en donde un bit 0 representa un segmento apagado y un bit 1 representa un segmento encendido. A cada bit de un total de ocho (numerados del 0 al 7) le asociamos un segmento específico del SSD, tal como se muestra en la siguiente figura:
Correspondencia entre bits y segmentos. |
Por ejemplo, al dígito “4” le corresponde el número binario
0b01100110
(0b
en Python 3 es el prefijo para las literales numéricas en base binaria) ya que los segmentos A, D, E y P deben estar apagados, mientras que los segmentos B, C, F y G deben estar encendidos.A partir de la disposición anterior podemos codificar el diseño de todos los dígitos hexadecimales usando números binarios:
Al momento de escribir el software para desplegar estos diseños será necesario implementar un poco de lógica de manipulación de bits para decodificar estos números binarios.
Dígito 0: 0b11111100
Dígito 1: 0b01100000
Dígito 2: 0b11011010
Dígito 3: 0b11110010
Dígito 4: 0b01100110
Dígito 5: 0b10110110
Dígito 6: 0b10111110
Dígito 7: 0b11100000
Dígito 8: 0b11111110
Dígito 9: 0b11110110
Dígito A: 0b11101110
Dígito B: 0b00111110
Dígito C: 0b10011100
Dígito D: 0b01111010
Dígito E: 0b10011110
Dígito F: 0b10001110
Armando el proyecto
El proyecto a desarrollar consistirá de un contador hexadecimal conceptualmente similar al contador binario que construimos anteriormente usando la Raspberry Pi. Utilizaremos el SSD para desplegar el valor actual del contador. Tendremos también un botón, y cada vez que lo presionemos se incrementará en uno el contador. El contador estará inicializado en 0. Al llegar al valor máximo (F hexadecimal), se reiniciará nuevamente en 0.Esta es la lista completa de componentes que vamos a requerir para nuestro proyecto:
- Arduino Uno.
- SSD de ánodo común.
- Protoboard.
- Botón o pulsador (push button).
- Ocho resistencias de 330Ω (bandas naranja, naranja, café).
- Una resistencia de 10KΩ (bandas café, negro, naranja).
- Cables conectores.
Vista de protoboard Fritzing para el contador hexadecimal. |
El pin de 5V del Arduino se conecta al pin 3 o al pin 8 del SSD. Como ya mencionamos, los pines 3 y 8 corresponden al ánodo común del visualizador. Si en su lugar usáramos un SSD de cátodo común, entonces conectaríamos el pin 3 o el pin 8 del componente a un pin de tierra (GND) del Arduino.
Cada pin asociado a un segmento del SSD debe quedar conectado, con una resistencia de 330Ω de por medio, a un pin digital del Arduino. Estas son las conexiones que se muestran en la figura anterior:
- El pin digital 2 del Arduino se conecta al pin 1 del SSD.
- El pin digital 3 del Arduino se conecta al pin 2 del SSD.
- El pin digital 4 del Arduino se conecta al pin 4 del SSD.
- El pin digital 5 del Arduino se conecta al pin 5 del SSD.
- El pin digital 6 del Arduino se conecta al pin 6 del SSD.
- El pin digital 7 del Arduino se conecta al pin 7 del SSD.
- El pin digital 8 del Arduino se conecta al pin 9 del SSD.
- El pin digital 9 del Arduino se conecta al pin 10 del SSD.
El botón y la resistencia de 10KΩ se conectan tal como se explicó en “Cómo programar a tu Arduino”. La única diferencia para nuestro proyecto es que la patita superior del botón se conecta al pin 10 del Arduino.
Una vez armado nuestro proyecto podemos proceder a programar su funcionalidad.
El software
En términos generales, debemos seguir las mismas indicaciones que se explicaron en “Cómo programar a tu Arduino”. Si aún no le hemos hecho, debemos descargar Firmata en el Arduino e instalar la biblioteca pyFirmata en la computadora anfitriona.NOTA: Todo el código presentado aquí fue probado con Python 3.4.
Las instrucciones para importar el paquete
pyfirmata
y crear el objeto que representa nuestra placa (board) de Arduino son las usuales:
import pyfirmata placa = pyfirmata.Arduino('/dev/ttyACM0')No hay que olvidar ajustar la cadena de caracteres que indica el puerto serie que utiliza nuestra plataforma (
'/dev/ttyACM0'
en mi caso, ya que estoy usando Linux) para poder conectarse al Arduino.Para almacenar los números binarios que representan los diseños de los dieciséis dígitos hexadecimales definimos una lista llamada
patron
:
patron = [ # ABCDEFGP <-- Segmentos # -------- 0b11111100, # 0 0b01100000, # 1 0b11011010, # 2 0b11110010, # 3 0b01100110, # 4 0b10110110, # 5 0b10111110, # 6 0b11100000, # 7 0b11111110, # 8 0b11110110, # 9 0b11101110, # A 0b00111110, # b 0b10011100, # C 0b01111010, # d 0b10011110, # E 0b10001110 # F ]Reutilizaremos la función
binario()
de la entrada “Contador binario” para convertir los números anteriores a una lista de ocho bits con el fin de simplificar su posterior procesamiento:
def binario(n): resultado = [] for i in range(8): resultado.append(n & 1) n >>= 1 return resultadoDado que deseamos usar ocho pines digitales de salida (los pines 2 al 9) en nuestro Arduino, debemos activarlos para tal fin. Lo más conveniente es colocar los objetos que representan los pines en una lista:
salida = [ placa.get_pin('d:6:o'), # Seg_P/Ard_6/SSD_6 placa.get_pin('d:2:o'), # Seg_G/Ard_2/SSD_1 placa.get_pin('d:3:o'), # Seg_F/Ard_3/SSD_2 placa.get_pin('d:4:o'), # Seg_E/Ard_4/SSD_4 placa.get_pin('d:5:o'), # Seg_D/Ard_5/SSD_5 placa.get_pin('d:7:o'), # Seg_C/Ard_7/SSD_7 placa.get_pin('d:8:o'), # Seg_B/Ard_8/SSD_9 placa.get_pin('d:9:o') # Seg_A/Ard_9/SSD_10 ]El argumento para el método
get_pin()
establece que el pin del Arduino con el número indicado es digital (d
) y de salida out (o
). El comentario al final de las líneas identifica a cada objeto con su correspondiente segmento, número de pin de Arduino y número de pin del SSD.Cada elemento de la lista
salida
está asociado por su posición a un bit particular de un número binario de ocho bits conforme a lo descrito en la sección “Diseño de los dígitos” de arriba. Por ejemplo, recordemos que el dígito “4” tiene codificado su diseño en el número binario 0b01100110
. Esto quiere decir que sus bits 0, 3, 4 y 7 valen cero, mientras que sus bits 1, 2, 5 y 6 valen uno. Por tanto, para desplegar el dígito “4” en el SSD necesitamos mandar:- Una señal de apagado a los elementos
salida[0]
,salida[3]
,salida[4]
ysalida[7]
. - Una señal de encendido a los elementos
salida[1]
,salida[2]
,salida[5]
ysalida[6]
.
def despliega_digito(digito): d = patron[digito] if 0 <= digito <= 15 else 0b00000000 for pin, bit in zip(salida, binario(d)): pin.write(not bit)A partir de la lista
patron
obtenemos d
, que es el número binario correspondiente al diseño de digito
, siempre y cuando este último tenga un valor entre el 0 y el 15. De lo contrario d
queda con 0b00000000
, que implica apagar todos los segmentos del SSD. Posteriormente, usando un for
junto con la función zip()
, recorremos simultáneamente la lista salida
(que tiene los ocho objetos que representan nuestros pines de salida) y la secuencia resultante de convertir d
a la lista de ocho bits devuelta por la función binario()
. En cada iteración tomamos el valor de bit
para decidir si encendemos o apagamos el segmento correspondiente al objeto pin
de la iteración en curso.
Dado que estamos usando un SSD de ánodo común, para encender un segmento se debe enviar un 0 lógico (potencial negativo) a través del pin correspondiente, o un 1 lógico (potencial positivo) en caso de que se quiera apagar. Estos valores son justamente los opuestos a los que estamos manejando en nuestros diseños representados como números binarios. Por esta razón al argumento del método
write()
se le aplica el operador not
, precisamente para invertir su valor. Dicho operador se debe omitir si el SSD fuera de cátodo común.El último pin del Arduino que necesitamos activar es el 10. Este es un pin digital (
d
) de entrada in (i
):
entrada = placa.get_pin('d:10:i')
Finalmente, el código principal de nuestro programa es un ciclo infinito que se encarga de detectar cuando el usuario presiona el botón. Cuando eso ocurre, el contador se incrementa y se actualiza el valor desplegado en el SSD. Pero antes de ejecutar el ciclo, el contador se inicializa en cero y se despliega dicho valor en el visualizador.
contador = 0 despliega_digito(contador) while True: if entrada.read(): contador = (contador + 1) % 16 despliega_digito(contador) placa.pass_time(0.2)Así queda el programa completo después de integrar todo lo anterior:
#!/usr/bin/env python3 # Archivo: ssd.py import pyfirmata placa = pyfirmata.Arduino('/dev/ttyACM0') pyfirmata.util.Iterator(placa).start() entrada = placa.get_pin('d:10:i') entrada.enable_reporting() salida = [ placa.get_pin('d:6:o'), # Seg_P/Ard_6/SSD_6 placa.get_pin('d:2:o'), # Seg_G/Ard_2/SSD_1 placa.get_pin('d:3:o'), # Seg_F/Ard_3/SSD_2 placa.get_pin('d:4:o'), # Seg_E/Ard_4/SSD_4 placa.get_pin('d:5:o'), # Seg_D/Ard_5/SSD_5 placa.get_pin('d:7:o'), # Seg_C/Ard_7/SSD_7 placa.get_pin('d:8:o'), # Seg_B/Ard_8/SSD_9 placa.get_pin('d:9:o') # Seg_A/Ard_9/SSD_10 ] patron = [ # ABCDEFGP <-- Segmentos # -------- 0b11111100, # 0 0b01100000, # 1 0b11011010, # 2 0b11110010, # 3 0b01100110, # 4 0b10110110, # 5 0b10111110, # 6 0b11100000, # 7 0b11111110, # 8 0b11110110, # 9 0b11101110, # A 0b00111110, # b 0b10011100, # C 0b01111010, # d 0b10011110, # E 0b10001110 # F ] def binario(n): """Devuelve como lista el valor binario de n. La lista resultante es de la forma: [bit0, bit1, bit2, bit3, bit4, bit5, bit6, bit7] Los bit8 en adelante son ignorados. """ resultado = [] for i in range(8): resultado.append(n & 1) n >>= 1 return resultado def despliega_digito(digito): """Despliega en el SSD el digito indicado. Si digito es menor a 0 o mayor a 15 apaga todos los segmentos del SSD. """ d = patron[digito] if 0 <= digito <= 15 else 0b00000000 for pin, bit in zip(salida, binario(d)): # El operador 'not' de la siguiente instrucción se # necesita debido a que el SSD es de ánodo común. # Dicho operador se debe omitir si el SSD es de # cátodo común. pin.write(not bit) try: contador = 0 despliega_digito(contador) while True: if entrada.read(): contador = (contador + 1) % 16 despliega_digito(contador) placa.pass_time(0.2) except KeyboardInterrupt: # Terminar programa cuando se presione Ctrl-C. pass finally: despliega_digito(-1) placa.exit()Para correr el programa se necesita tener el Arduino conectado por el puerto USB a la computadora anfitriona y ejecutar el siguiente comando desde una terminal en el mismo directorio donde se encuentra el archivo
ssd.py
:
python3 ssd.pyLa siguiente foto muestra cómo se ve el proyecto después de correr el programa y presionar quince veces el botón:
El programa corre hasta que presionemos Ctrl-C para terminar.