La siguiente tabla muestra los valores que pueden tener los cuatro bits junto con su valor correspondiente en decimal:
Valores decimales y sus equivalentes en binario. |
Comencemos por escribir una función en Python que dado un entero n del 0 al 15, devuelva una lista con cuatro enteros que correspondan a los cuatro bits de la representación binaria de n:
def binario(n): resultado = [] for i in range(4): resultado.append(n & 1) n >>= 1 return resultadoInternamente en la computadora, los números están almacenados en binario, así que podemos inspeccionar los bits individuales de n para crear la lista con los valores que necesitamos. Los operadores
&
y >>=
del código de arriba sirven para tal efecto en dos pasos dentro del ciclo for
, el cual se repite un total de cuatro veces (una vez por cada bit que nos interesa):- La expresión
n & 1
realiza un and (conjunción) a nivel de bits entre n y 1, efectivamente obteniendo el cero o el uno contenido en el bit 0 (el bit que está más a la derecha) de la representación binaria de n, y almacenando ese valor al final de la listaresultado
usando el métodoappend()
. - La expresión
n >>= 1
desplaza todos los bits de n una posición hacia la derecha. Es decir el bit 1 original se convierte en el nuevo bit 0, el bit 2 original se convierte en el nuevo bit 1, y así sucesivamente. El bit 0 original se pierde en este proceso, pero no importa, ya que fue inspeccionado y almacenado en el paso anterior.
binario()
con argumento 1
, ésta nos devuelve la lista [1, 0, 0, 0]
. La lista resultante pudiera dar la impresión de estar invertida. Sin embargo, por simplicidad nos conviene que el bit 0 se encuentre en la primera posición de la lista, el bit 1 en la segunda, y así sucesivamente.Vale la pena notar que la función
binario()
solo considera los cuatro bits menos significativos (los bits que están más a la derecha) de su entrada n. Esto significa, en términos prácticos, que la función devuelve una lista con la representación en binario de n módulo 16. Lo anterior es útil para saber interpretar el resultado para los casos en los que n esté fuera del rango del 0 al 15.El hardware
Además de la RPi, para este proyecto requerimos los siguientes componentes:- Un protoboard.
- Un botón o pulsador (push button).
- Cuatro LEDs (diodos emisores de luz).
- Cuatro resistencias de 330Ω (bandas naranja, naranja, café).
- Siete cables conectores.
Vista de protoboard Fritzing para el contador binario. |
Usando un cable conectamos un pin de tierra (GND) de la RPi a uno de los buses para alimentación negativa (línea azul) del protoboard. El botón se coloca de tal forma que un par de patitas quede a la izquierda y el otro par a la derecha del canal central del protoboard. Conectamos una de las patitas superiores del botón a tierra (bus negativo), y una de las patitas inferiores la conectamos al pin 22 de la RPi. Colocamos los cuatro LEDs en el protoboard, en donde el cátodo (patita corta) y el ánodo (patita larga) de cada LED debe estar en su propia pista. Conectamos el cátodo de cada uno de los LEDs a una resistencia de 330Ω. El otro extremo de cada resistencia lo conectamos a tierra (bus negativo). Ahora conectamos el ánodo de cada LED a uno de los pines de la RPi:
- Pin 18 para el LED correspondiente al bit 0 (LED inferior de la figura).
- Pin 23 para el LED correspondiente al bit 1.
- Pin 24 para el LED correspondiente al bit 2.
- Pin 25 para el LED correspondiente al bit 3 (LED superior de la figura).
El software
Para controlar los LEDs, requerimos básicamente hacer lo mismo que hicimos en la entrada del LED parpadeante. Dado que son cuatro LEDs a controlar en lugar de uno, usamos una lista con los respectivos números de pin de salida. El siguiente código se encarga de establecer a los pines 18, 23, 24 y 25 de la RPi como pines de salida y además se asegura de que inicialmente se encuentren apagados:PIN_LEDS = [18, 23, 24, 25] for i in PIN_LEDS: GPIO.setup(i, GPIO.OUT, initial=GPIO.LOW)En la RPi usaremos el pin 22 para inspeccionar el estado de nuestro botón. Esto quiere decir que tenemos que configurar dicho pin como un pin de entrada para poder leer una señal LOW (0 voltios) o HIGH (3.3 voltios), según el estado del botón.
De acuerdo a la manera en que conectamos nuestros componentes, el pin 22 recibe la señal de tierra (0 voltios) solo cuando se cierra el circuito (el botón se encuentra presionado). Pero, ¿qué pasa cuando no es así? En ese caso se dice que el pin está “flotando”, lo que puede producir resultados inesperados. Para evitar este problema podemos utilizar una resistencia pull-up, con lo que efectivamente proveemos de un valor por omisión al pin cuando el circuito no está cerrado (el botón no está presionado). Lo anterior se puede lograr vía hardware (colocando una resistencia de 10KΩ entre el pin de entrada y una alimentación de 3.3 voltios) o por software configurando el pin para que utilice la resistencia pull-up interna provista por la misma RPi. El siguiente código se encarga de este último caso:
PIN_BOTON = 22
GPIO.setup(PIN_BOTON, GPIO.IN, pull_up_down=GPIO.PUD_UP)
Con esta configuración podemos usar la función input()
indicando el número de pin de entrada como argumento. En este contexto, la función devuelve LOW
(0) para indicar que el botón está presionado, o HIGH
(1) en caso contrario. Este comportamiento es inverso a lo que alguien podría inicialmente suponer.El siguiente ciclo infinito verifica en cada iteración si el botón está siendo presionado en ese preciso instante. En caso afirmativo, incrementa el contador y usa su representación binaria para prender o apagar los LEDs correspondientes:
contador = 0 while True: if GPIO.input(PIN_BOTON) == GPIO.LOW: contador = (contador + 1) % 16 for pin, bit in zip(PIN_LEDS, binario(contador)): GPIO.output(pin, bit) time.sleep(0.2)Dentro del cuerpo del
if
la instrucción:
contador = (contador + 1) % 16se utiliza para incrementar en uno a la variable
contador
. La operación de módulo (%
) 16 sirve para reiniciar contador
a cero una vez que haya llegado a su máximo valor (15). El siguiente código es equivalente, aunque menos compacto:
contador += 1 if contador == 16: contador = 0La función
zip()
que se usa dentro de la instrucción for
permite iterar simultáneamente sobre dos o más colecciones. Por ejemplo, si PIN_LEDS
es [18, 23, 24, 25]
y el resultado de binario(1)
es [1, 0, 0, 0]
, entonces la función zip()
hace que las variables pin
y bit
sean 18
y 1
en la primera iteración del for
, 23
y 0
en la segunda, y así sucesivamente.
Al final del cuerpo del
if
usamos la función sleep()
para hacer una breve pausa antes de intentar leer nuevamente el estado del botón. De no hacerlo podríamos incrementar más de una vez a contador
debido al tiempo que transcurre entre que presionamos el botón y el momento en que lo soltamos.El programa completo se muestra a continuación:
# Archivo: contador_binario.py import RPi.GPIO as GPIO import time # Usar el esquema de numeracion de pines de Broadcom SoC. GPIO.setmode(GPIO.BCM) # Inicializar pines de salida. PIN_LEDS = [18, 23, 24, 25] for i in PIN_LEDS: GPIO.setup(i, GPIO.OUT, initial=GPIO.LOW) # Inicializar pin de entrada. PIN_BOTON = 22 GPIO.setup(PIN_BOTON, GPIO.IN, pull_up_down=GPIO.PUD_UP) def binario(n): """Devuelve como lista el valor binario de n. La lista resultante es de la forma: [bit0, bit1, bit2, bit3] Los bit4 en adelante son ignorados. """ resultado = [] for i in range(4): resultado.append(n & 1) n >>= 1 return resultado contador = 0 try: while True: if GPIO.input(PIN_BOTON) == GPIO.LOW: contador = (contador + 1) % 16 for pin, bit in zip(PIN_LEDS, binario(contador)): GPIO.output(pin, bit) time.sleep(0.2) finally: GPIO.cleanup()Desde una terminal de la RPi, debemos ejecutar el siguiente comando para correr el programa:
sudo python contador_binario.pyLa siguiente foto muestra cómo se ve nuestro proyecto después de correr el programa y presionar once veces el botón:
Contador binario mostrando 1011 binario (11 decimal). |
hermano!!! que tuto!! super completo.. deberias hacer mas sobre el manejo de los GPIO de la raspberry, se nota el taento.
ResponderBorrarMuchas gracias. Espero escribir más entradas sobre la Raspberry Pi próximamante.
Borrarel código no funciona, no encuentro el error.
ResponderBorrarAyuda con el codigo, no funciona
ResponderBorrar