Cómo expandir los pines de Arduino

Bienvenidos a este tutorial en el que explicaremos cómo conseguir más pines útiles en nuestra placa Arduino. Todos los entusiastas de Arduino que hemos conectado casi de todo a nuestras placas, alguna vez nos hemos topado con el problema de conectar varias cosas a la vez y no tener pines para conectarlo todo. Una solución inmediata puede ser comprar una placa con más salidas y entradas disponibles como puede ser la Arduino Mega o la Due, pero no todas las soluciones requieren hacer grandes desembolsos en una placa nueva.

La solución que aquí se propone es usar un registro de desplazamiento de entrada serie y salida paralelo. En concreto usaremos el integrado 74HC595N. Con un registro de desplazamiento de estas características lo que hacemos es usar 3 pines (1 para la salida serie de datos, 1 para señal de reloj, 1 para habilitar entrada de datos) para comandar 8 salidas por cada integrado 595. Es decir, tendremos 8 salidas con 1 integrado y 16 si usamos 2 integrados, pero en ambos casos necesitamos sólo 3 pines de Arduino. Este ejemplo expande los pines de salida, pero de igual manera se pueden expandir los pines de entrada.

En mi caso concreto, sólo voy a usar un registro de desplazamiento por lo que consigo 8 salidas con 3 pines de Arduino. Como os podéis imaginar no todo son ventajas, ya que el uso de registros de desplazamiento incrementa la dificultad de comandar las salidas y hace falta que implementemos un mecanismo que traduzca lo que queremos enviar a ellas. Existe una función que ya viene hecha por nosotros que es la función shiftOut.

Este sería el esquema de como funciona un registro de desplazamiento SIPO (entrada serie y salida paralelo por sus siglas en inglés).

La función shiftOut lo que hace es pasar un valor entero que queramos a codificación binaria, de forma tal que a cada salida se le asigna un 1 o un 0. Por ejemplo, si pasamos el número 3 que en binario 1 byte sería el 00000011 entonces tendríamos las salidas S0 y S1 activadas y las salidas S2 - S7 desactivadas. También debemos indicar en la función shitOut si la información que pasamos es "Little endian" o "Big endian". Esto significa que el primer bit que pasamos es el de la cifra menor o es el de la cifra mayor. En nuestro ejemplo pasaríamos de enviar el 00000011 a pasar el 11000000, dependiendo qué opción escojamos.

El ejemplo más básico de uso de la función shiftOut es el siguiente.

//Pin conectado al pin ST_CP del 74HC595 #define Pin_activacion 9 //Pin connectado al pin SH_CP del 74HC595 #define Pin_reloj 10 ////Pin conectado al pin DS del 74HC595 #define Pin_datos 8 void setup() { pinMode(Pin_activacion, OUTPUT); pinMode(Pin_reloj, OUTPUT); pinMode(Pin_datos, OUTPUT); } void loop() { int dato = 3  //Podríamos haber hecho int dato = B00000011 digitalWrite(Pin_activacion, HIGH); shiftOut(Pin_datos, Pin_reloj, LSBFIRST, dato); digitalWrite(Pin_activacion, LOW); delay(500); }

Observamos que hemos pasado el 3 como "little endian" porque hemos usado LSBFIRST. Para usar "big endian" deberíamos haber usado MSBFIRST.

Ejemplo Práctico

Ahora que hemos explicado la teoría vamos a explicar un ejemplo práctico completo. En nuestro caso hemos conectado nuestro Arduino a un 595 y en sus salidas tenemos un display de 7 segmentos. Queremos que haga un efecto serpiente en ochos, algo así:

Lo primero que vamos a hacer es conectarlo todo. El esquema de conexiones seguido es el siguiente: Nota: Debemos tener en cuenta que nuestro 7 segmentos es ánodo común.

Una vez que hemos hecho las conexiones, vamos con la programación. Aquí lo que hemos hecho ha sido analizar que salidas del 595 se corresponde con cada uno de los segmentos, para activar cada momento de nuestra serpiente solo la salida correcta. Para simplificar el proceso hemos trabajado con números binarios. Además hay que remarcar que hemos elegido que la información sea MSBFIRST (big endian).

El código propuesto es el siguiente:

//Definimos los pines de nuestro registro # define latch_pin 9 #define data_pin 8 #define clock_pin 10 //Configuramos los pines como salidas void setup () { for (int n=8; n<11; n++) pinMode(n,OUTPUT); } void loop () { //Bucle para activar la secuencia for(int sec=0; sec<8;sec++) { digitalWrite(latch_pin,HIGH); shiftOut(data_pin,clock_pin, MSBFIRST, animacion(sec) ); delay(50); digitalWrite(latch_pin,LOW); } } //La función devuelve un numero binario que se corresponde con nuestra //animación en cada momento de la secuencia int animacion (int sec_ ){ int frame =0; switch(sec_){ case 0: frame = B00000001; break; case 1: frame = B00000010; break; case 2: frame = B01000000; break; case 3: frame = B00010000; break; case 4: frame = B00001000; break; case 5: frame = B00000100; break; case 6: frame = B01000000; break; case 7: frame = B00100000; break; } return frame; }

Resultado:

Alternativa:

Si preferimos no tener que escribir cada número como binario, podemos crear vectores o "arrays" sabiendo la correspondencia con cada uno de los segmentos designados por A,B,C,D,E,F,G. Pero necesitamos una función complicada que traduzca nuestro formato vector a un valor que se corresponda con el resultado deseado. Nuestro programa Arduino podría ser así en ese caso:

# define latch_pin 9 #define data_pin 8 #define clock_pin 10 void setup () { for (int n=8; n<11; n++) pinMode(n,OUTPUT); } //Mapeo--- A, B,C,D,E, F, G, H int uno[]={ 0, 1, 1, 0, 0, 0 , 0, 0}; int dos[]={ 1, 1, 0, 1, 1, 0, 1, 1 }; void loop () { digitalWrite(latch_pin,HIGH); shiftOut(data_pin,clock_pin, MSBFIRST, AdaptacionMapeo(dos) ); delay(50); digitalWrite(latch_pin,LOW); } int AdaptacionMapeo (int* num) { int resultado =0; for (int cifra=0; cifra<8; cifra++) { int ex=1; for(int exp=0; exp<cifra; exp++){ ex*=2; } resultado+=num[cifra]*ex; } return resultado; }

Cómo podéis ver sólo he mapeado el número 1 y el 2. ¿Os atrevéis a mapear vosotros el resto?

Espero que os haya gustado. Si tenéis cualquier duda usar los comentarios.

Nos vemos en otros tutoriales.