Multiplexación de entradas: Más pines con pocos recursos

Todos hemos pasado por esto: nos quedamos sin pines GPIO en nuestro microcontrolador favorito. Cambiar a uno con más pines no siempre es posible debido a restricciones de espacio o presupuesto. Quizás no queríamos portar el código a un nuevo hardware o simplemente buscábamos el desafío de ingeniería para lograrlo con menos recursos.

Recientemente me enfrenté a esta situación. Tenía seis interruptores pero solo dos pines GPIO disponibles. Otro requisito era detectar no solo pulsaciones individuales, sino también dos botones presionados simultáneamente, algo necesario para un dispositivo de mano. Dado que usamos dos pulgares, es fácil presionar dos botones a la vez. Por ejemplo, en un D-Pad con cuatro botones (arriba, abajo, izquierda y derecha), uno puede ingresar diagonales presionando dos botones adyacentes. No necesitaba detectar más de dos botones simultáneos.

Encontré una solución nueva que no he visto publicada anteriormente. Con la esperanza de ayudar a otros, presento aquí una revisión de las opciones disponibles y mi propuesta original.

Un aspecto clave de mi aplicación fue el uso de memoria Flash. Trabajo principalmente con microcontroladores pequeños, como la serie ATtiny, donde solo disponemos de 1kB o 2kB. Una solución que requiera menos memoria es preferible si todo lo demás es igual.

Soluciones existentes

I2C

Puedes usar un chip expansor de puertos I2C, como el PCF8574 o MCP23008. Necesitarás dos pines en el microcontrolador para establecer la interfaz I2C. Estos expansores proporcionan 8 pines GPIO adicionales. Existen chips de 16 puertos, como el MCP23017. Además, puedes conectar varios chips a las mismas líneas I2C configurando diferentes direcciones para cada uno.

Esta solución es ideal si necesitas muchos pines GPIO extra. Sin embargo, tiene un costo: necesitas un chip adicional, la velocidad del bus I2C es limitada (típicamente 100kHz o 400kHz) y requieres una librería I2C, lo que consume una cantidad considerable de memoria Flash. En mi sistema, requirió 190 bytes de Flash adicional para leer un expansor de 8 bits usando la librería I2C de software en BASCOM AVR. Si tu microcontrolador tiene I2C por hardware, esto podría variar, o si ya usas la librería I2C para otras funciones, el costo incremental sería menor.

En mi caso, esto no aplicaba. El gasto de memoria Flash solo para atender un expansor I2C no valía la pena, considerando que es relativamente lento y complica el hardware con un componente adicional.

Registro de desplazamiento (Shift Register)

Otra solución que requiere un chip adicional es usar registros de desplazamiento. Chips comunes son el 74HC165 (8 entradas adicionales) o el 74HC595 (8 salidas adicionales). Esto revela una desventaja: no puedes mezclar pines de entrada y salida como en un expansor I2C. Dependiendo del chip, obtienes 8 entradas o 8 salidas. Puedes conectar en cascada chips del mismo tipo si necesitas más de 8.

Un registro de desplazamiento necesita 3 pines del microcontrolador: uno para el latch (cerrojo) de los valores de entrada al registro interno, el segundo para la señal de reloj que desplaza los bits, y el tercero para los datos. Existen técnicas para reducir esto a 2 o incluso 1 pin. Para reducirlo a 2, se combinan las líneas de reloj y latch con un elemento de retardo RC: pulsos rápidos alcanzan el reloj pero no el latch, mientras que pulsos largos sí lo hacen. Para reducirlo a 1 pin, se conecta la salida de datos en serie con una resistencia a la línea de reloj/latch; el pin se alterna entre salida para avanzar el reloj y entrada para leer el bit.

Los requisitos de memoria Flash de un registro de desplazamiento son menores que los de un I2C porque no hay sobrecarga de protocolo. Es considerablemente más rápido que la solución I2C. La técnica de 1 pin es un poco más lenta y requiere más Flash, pero esta solución sigue necesitando un chip adicional, algo que quería evitar.

Matriz

Para evitar chips adicionales, se pueden organizar los interruptores en una matriz y escanear filas o columnas. El problema es que, para un número pequeño de interruptores, el ahorro de pines es mínimo. Por ejemplo, para mis 6 interruptores, podría usar una matriz de 2×3, lo que requiere 5 pines en lugar de los 6 necesarios si estuvieran conectados directamente. Es un ahorro de solo 1 pin, insuficiente para mi caso donde solo tenía 2 pines disponibles.

Una matriz es buena opción si tienes muchos interruptores, digamos 16: una matriz de 4×4 ahorraría 8 pines. Puede detectar dos pulsaciones simultáneas de forma fiable, pero para más pulsaciones, se necesitan diodos para evitar caminos parásitos a través de la matriz.

Charlieplexing

El Charlieplexing se usa a menudo para multiplexar LEDs, pero también puede aplicarse a interruptores. El ahorro de pines es mayor que en una matriz regular: con 3 pines se podrían controlar 6 interruptores. La relación es n(n-1), donde n es el número de pines.

Como solo tengo 2 pines, el Charlieplexing no era viable. Otro problema es que requiere añadir diodos en serie con los interruptores y no permite detectar de forma fiable pulsaciones simultáneas, por lo que rara vez se usa en el lado de la entrada.

Digital a Analógico (DAC)

Si los pines disponibles pueden configurarse como entradas analógicas, se puede implementar otra forma de multiplexar: cada interruptor o combinación se asocia a un nivel de voltaje. El microcontrolador lee ese voltaje mediante un ADC y lo convierte para determinar qué botones fueron presionados. Una ventaja es que solo un pin es necesario para varios interruptores.

Existen formas de generar este voltaje analógico dependiente de los interruptores. Una es usar un chip DAC, como el DAC0808. Una ventaja es que cada bit de entrada del DAC se asocia directamente a un interruptor, haciendo la decodificación trivial. Sin embargo, esto solo funciona para los bits más significativos; los menos significativos pueden verse alterados por el ruido y requiere un chip adicional.

Existen formas más sencillas de producir un voltaje dependiente de los interruptores.

Escalera resistiva (Resistive Ladder)

Una forma común es configurar un divisor de voltaje resistivo (dos resistencias en serie entre alimentación y tierra) y hacer que los interruptores alteren una de las resistencias, por ejemplo, conectando resistencias adicionales en paralelo, cambiando así el voltaje de salida.

Para tres interruptores, esto puede hacerse con 4 resistencias, siendo una opción muy eficiente.

Vía Make Magazine.