Ampliación de Entradas/Salidas para PIC

El PIC con el que estoy aprendiendo es un PIC16F876A que está un poco limitado en cuanto a entradas y salidas. Con este diseño se puede ampliar todo lo que se quiera, siempre que se tenga memoria para almacenar los datos y tiempo de ciclo para leerlos. 

Hay muchas técnicas para ampliar el número de entradas y salidas de un micro: circuitos dedicados como el i8255, registros paralelo como el SN74lS273 para salidas y triestado como el SN74LS244 para entradas etc. Algunos sistemas necesitan demasiadas patas y cableado, el multiplexado no permite comunicar muchas entradas y salidas simultáneamente, cada uno tiene sus ventajas e inconvenientes. Este circuito ya lo he utilizado antes con otros micros, su fiabilidad está fuera de toda duda. Se trata de un conjunto de registros paralelo/serie para leer los datos de las entradas y otro de serie/paralelo para escribir datos en las salidas. Estos registros de desplazamiento son CMOS serie B convencionales, muy baratos. Para conectarlo al PIC bastan 5 pines libres, aunque hay otras configuraciones que usan más. En este ejemplo he usado 4 CD4014 para las entradas y 4 CD4094 para las salidas, que proporcionan un total de 32 bits de entrada y otros 32 de salida. Sería como tener un PIC de más de 64 patas...

Este es el esquema en PNG del circuito:

El funcionamiento es el siguiente: para leer los datos primero se pone a nivel alto la señal LOAD_CD4014 y a continuación se aplica un pulso alto a CLK_CD4014, despues se pone a nivel bajo LOAD_CD4014. Con esta operación hemos hecho que los registros CD4014 memoricen en sus latch internos los datos que había presentes en sus entradas paralelas P1 a P8. Tras este primer pulso el estado de DATO_CD4014 es el estado de P8 del primer CD4014. Ahora vamos aplicando pulsos altos a CLK_CD4014 con LOAD_CD4014 a nivel bajo. De esta forma, a cada pulso, los CD4014 desplazan sus datos de Pn a Pn+1. Al primer pulso sale por DATO_CD4014 el dato leído de P7, después P6 etc. Por la entrada SI de cada CD4014 introducimos el dato saliente Q8 del CD4014 siguiente en la cadena. Los datos atraviesan en serie los registros que tienen a su derecha hasta llegar al PIC, donde el programa los va agrupando de nuevo en bytes, en mi programa uso el array "DatosCD4014[NumeroCD4014]".

Este es un ejemplo de como hacerlo:

// Primero carga TODOS los datos en paralelo en los registros
output_high(LOAD_CD4014); // LOAD activo
output_high(CLK_CD4014); // CLK activo, carga los datos en paralelo
output_low(CLK_CD4014); // CLK inactivo
output_low(LOAD_CD4014); // LOAD inactivo

// Ahora vamos leyendo en serie en grupos de 8 bits N veces
for (bytes = 0; bytes < NumeroCD4014; bytes++)
{
    data = 0;
    for (bits = 0; bits < 8; bits++)
    {
        data <<=1; // Roto una posición a la izquierda para ir colocando en su sitio los datos leídos por el bit 0
        if (input (DATA_CD4014)) data|=0x01; // El dato se coloca en el bit 0 mediante la máscara 0x01
        output_high(CLK_CD4014); // CLK activo, desplaza
        output_low(CLK_CD4014); // CLK inactivo
    }
    DatosCD4014[bytes] = data; // Copiamos el dato compuesto al array

}

Las salidas funcionan de forma parecida: Se pone en DATO_CD4094 el dato que queremos enviar al ultimo bit de los CD4094. Se aplica un pulso alto en CLK_CD4094 y este dato pasa al registro interno Q1, el dato que había en Q1 a Q2 etc. El dato que había en QS se envía al siguiente CD4094. De esta forma tras 64 pulsos (en este caso de 4 registros) el primer dato introducido ha llegado hasta Q8 del último CD4094. Sin embargo los datos no están presentes en las salidas, que permanecen fijas con los últimos datos cargados, se encuentran en unos registros internos. Al aplicar un pulso alto en LOAD_CD4094 estos datos pasan de los registros internos a los registros de salida y aparecen, todos a la vez, en las patas Q8 a Q1 de los CD4094 para ser usados.

Esto puede hacerse así:

for (bytes = NumeroCD4094; bytes > 0; )
{
    data = DatosCD4094[--bytes]; // Pre-decremento, la cuenta comienza en NumeroCD4094-1
    for (bits = 0; bits < 8; bits++)
    {
        if (data & 0x80) output_high(DATA_CD4094); // Saco el dato del bit 7 mediante la máscara 0x80
        else output_low(DATA_CD4094);
        output_high(CLK_CD4094); // CLK activo, desplaza
        output_low(CLK_CD4094); // CLK inactivo
        data <<=1;  // Roto una posición a la izquierda para poner en el bit 7 el siguiente dato que quiero sacar
    }
}
// Ahora transfiero los datos enviados a las salidas
output_high(LOAD_CD4094); // LOAD activo
output_low(LOAD_CD4094); // LOAD inactivo

Otra ventaja de este sistema es que es fácilmente ampliable, basta con añadir más registros a la cadena. Por ejemplo pueden unirse varios módulos uniendo el conecto SL10 de un módulo con el conector SL9 del siguiente, ampliándolo así en  grupos de 32+32 entradas/salidas. Evidentemente el primer bloque de entradas/salidas numerado como '0' en el primer módulo será el número '4' en el segundo, el número '8' en el tercero y el resto de numeraciones variará usando la misma lógica.

Será necesario cambiar los siguientes valores en el fichero shifth_io.h para adecuarlos al número real de circuitos que usemos:

#define NumeroCD4014 4 // Numero de CD4014 en serie
#define NumeroCD4094 4 // Numero de CD4094 en serie

Este es el esquema con Eagle 4,15 del circuito anterior, por si alguien quiere construirlo.

Este es un programa en C (compilable con CCS 3.236) para PIC16F876A que muestra como funciona el circuito del ejemplo y contiene las funciones de lectura y escritura de los registros CD40x4 en el fichero "shift_io.c". Está bastante comentado como para comprender su funcionamiento. Para utilizarlo en otras aplicaciones solo hay que poner en "hardware.h" y en "shift_io.h" los valores adecuados según nuestro hardware e incluir en el programa principal #include "shift_io.c".

Como yo utilizo pulsos de clock muy cortos podrían ser demasiado estrechos para algunos CMOS convencionales  debido a la alta velocidad del PIC. Dependiendo de la longitud de los cables y la capacidades parásitas podría ser interesante ampliarlos duplicando las instrucciones de output (port).  

Evidentemente aunque aquí he propuesto utilizarlo con PIC puede utilizarse con cualquier otro micro. Yo lo ha utilizado en muchos proyectos con i8051, con unos resultados muy buenos. Ya solo queda diseñar la parte de potencia para las salidas CD4094 y la parte de adaptación de señales de entrada para CD4014, si queremos conectarlo a circuitos NO CMOS... 

Inicio.

mailto:helitp@arrakis.es