Introducción
Un microprocesador, microcontrolador u otro tipo de circuito integrado dispone de una cantidad de pines orientados a realizar distintas funciones. Por ejemplo, para la alimentación, un oscilador, buses de datos, etc.
El tipo de pines que nos ocupa se denomina GPIOs. Siendo las iniciales de General-Purpose Input/Output, la s final es para indicar que hablamos en plural. Traducido es entradas/salidas de propósito general. De propósito general significa que no se han diseñado para una tarea específica y podrán ser usados para cualquiera que deseemos (dentro de ciertas limitaciones).
Son estos los pines que podremos manejar fácilmente desde nuestro programa para realizar dichas tareas.
Uso y configuración
Siendo los GPIOs capaces de funcionar de distintas maneras hemos realizar un primer paso de configuración donde indicaremos cómo queremos usar el pin. El más importante sería indicar si lo vamos a usar como entrada o como salida.
A partir de ahí, lo que haremos será leer datos del pin, si se ha configurado como entrada, o escribir datos en el pin, si ha sido como salida. Podremos configurarlos y usarlos de una de las siguientes formas:
Registros
Los registros son un tipo de variables especiales del programa que nos permiten interactuar con el hardware. Su uso es sencillo, hay que escribir en ellas para realizar un control y leer de ellas para obtener un estado.
Por ejemplo, tendríamos los registros TRISA, LATA y PORTA para interactuar con los GPIOs del puerto A en las familias de uCs PIC de Microchip.
Funciones de librería
No suele ser conveniente trabajar directamente sobre los registros. Ya que, por ejemplo, si un día cambiamos de arquitectura, tendríamos que reescribir todo ese código adaptandolo al formato de los nuevos registros.
Por eso mismo en muchos casos las librerías del compilador suelen ofrecernos funciones para trabajar con ellos. De forma que si cambiamos de arquitectura nuestras llamadas a las funciones permanecen igual y es el código interno de la librería el que será distinto, adaptado al nuevo hardware.
Sirvan de ejemplo las conocidas pinMode(), digitalWrite() y digitalRead() que tenemos en Arduino.
Pines de salida
El que un pin sea de salida significa que es este quien pone el “dato” (a nivel físico: la tensión y/o la corriente) para los demás elementos que están conectados a este pin. Los cuales tendrán que ser de entrada para poder leerlo. Para realizar esta circuitería de salida suelen emplearse 2 tipos de configuraciones:
Push-Pull
Se caracterizan por disponer de 2 transistores “apilados” (seguramente por eso también recibe el nombre de totem-pole) como etapa final (p.e. CMOS).
El funcionamiento es sencillo: activando solo* el canal P tendríamos el 1 y activando solo* el canal N tendríamos el 0. En la imagen vemos en una línea roja el camino entre la alimentación y los transistores para que esto suceda. El recuadro abierto azul indica los límites entre el integrado y el exterior.
* Es muy importante señalar que, en este tipo de circuitos, si ambos transistores estuvieran activos a la vez se produciría un cortocircuito!!! Pero tranquilos, al estar integrados en el uC existe una circuitería interna extra que lo evita. Aún así, tenedlo en mente por si un día realizáis vosotros un circuito de este estilo con transistores discretos.
¿Y que sucedería si estuvieran ambos transistores desactivados? Pues dos cosas:
- La primera os la cuento en breve.
- Y la segunda la dejamos para la próxima entrega.
Drenador abierto
Una salida en drenador abierto (en CMOS, o colector abierto si es TTL) consiste en su etapa final de solo un transistor de canal N. Con el canal N podremos dar el 0 lógico, pero nos falta algo para poder obtener el 1, para ello suele emplearse una resistencia de pull-up.
Vuelvo a mostrar con línea roja el camino seguido para ambos estados. He añadido una línea magenta que indica un camino extra de corriente para el 0 debida a la resistencia de pull-up (es el precio que hay que pagar, aunque puede ser aprovechado). Por eso suelen emplearse en lógica negativa, cuando la mayor parte del tiempo esté a reposo en Vdd/Vpullup evitando esa corriente.
El cálculo de esta resistencia de pull-up podría dar para otro estudio. Aunque, en general, para la mayoría de las aplicaciones se suele usar un valor 10K sin problemas.
Un pin en drenador abierto nos ofrece, principalmente, 2 ventajas:
Tensión de salida para el 1 distinta de Vdd
En la imagen he nombrado a propósito de forma distinta Vdd y Vpullup por una razón: no es necesario que sean iguales, aunque en muchos casos lo sean. Lo que nos permite poder controlar elementos de tensiones distintas a la que funciona nuestro microprocesador. Un ejemplo típico sería el bus I²C donde, por ejemplo, podemos controlar directamente con un uC de 3.3V integrados periféricos que funcionen a 5V.
Esta Vpullup puede tener un valor superior que Vdd. Pero también habrá que tener en cuenta que existirá un valor máximo que no se podrá superar, sería preciso mirar cual es para cada integrado en concreto.
AND cableada
Esto sonará a magia, pero se puede realizar la función AND sin poner un circuito de puerta AND. Simplemente conectando todas las salidas de drenador abiertas juntas con una resistencia de pull-up. A este circuito se le denomina AND cableada.
Una puerta AND tiene su salida a 1 cuando todas las entradas están a 1. Y tiene su salida a 0 cuando alguna de las entradas están a 0. En este circuito cuando todos los transistores están desconectados es la resistencia de pull-up quien provee el 1. Sin embargo, en cuanto uno solo de los transistores esta activo cierra el circuito y la corriente corre por la resistencia, dando el 0 a la salida.
Esto con salidas push-pull no podría realizarse pues se produciría cortocircuito cuando alguna salida no fuera igual a las demás.
¿Push-Pull o Drenador abierto? La dos!!!
Observando ambos circuitos se aprecia que un drenador abierto es un push-pull al que se le ha quitado el canal P superior. O mejor dicho, no se le ha puesto. Así que ahora relanzo la pregunta hecha al hablar del push-pull: ¿Que sucedería si estuvieran ambos transistores desactivados?
Efectivamente!!! se comportaría como un 1 de un drenador abierto, siempre y cuando pongamos la resistencia de pull-up.
Esto es aprovechado por algunos microcontroladores para permitirnos configurar los GPIOs con cualquiera de los dos comportamientos. Como esto requiere circuitería extra, generalmente no es implementado en todos los GPIOs sino solo en unos cuantos.
Lógica negativa
Aunque llevaba un tiempo pensando en escribir sobre los GPIOs, ha sido esta conversación en Twitter la que me ha dado el empujoncito necesario para ponerme en marcha.
Al hablar de lógica (and, or, true, false…) se emplean para los valores de 1 y 0 la tensión de alimentación y masa, respectivamente. Esto se hace por conveniencia y lo llamamos lógica positiva. Aunque también se puede acordar interpretarlo al revés y es lo que se conoce como lógica negativa.
- Positiva: Vdd para indicar un 1 y 0V para indicar un 0.
- Negativa: 0V para indicar un 1 y Vdd para indicar un 0.
Para determinadas tareas, como el ejemplo del LED comentado en Twitter, a menudo se emplea la lógica negativa por 2 razones:
- En la fabricación de la tecnología CMOS el canal N suele aguantar más corriente que el canal P equivalente. Por lo que en una configuración push-pull la lógica negativa puede darnos un poco más de potencia. Aunque hay que tener en cuenta un par de cosas por las que la lógica negativa no sería necesaria:
- La corriente de carga es inferior a la máxima del canal P. En ese caso daría igual si usáramos lógica positiva o negativa.
- Algunos microcontroladores implementan ambos canales asimétricos para que el P aguante la misma corriente que el N.
- Se ha empleado una salida en drenador abierto. En este caso al no existir canal P no podría activarse nada con lógica positiva. Bueno, podría llegar a hacerse pero no sería eficaz. De esta forma el control final resulta ser el propio sistema de pull-up (resistencia + LED).
Bueno, ya vale de hablar de GPIOs por hoy. En la próxima entrada hablaremos de los circuitos de entrada y triestados.
muy buena info, estoy trabado en mi proyecto de vumetro, quiero usar un lm3915 y amplificarlo con un lm2803, necesito una resistencia de pull-up para cada canal supongo. la idea es ponerle un driver al vumetro para que soporte mas led. saludos