Entrada pull-up e pull-down en Arduino
Cando chegas á electrónica e vés da informática as cousas non son tan simples como para chegar a conclusións de que unha entrada dixital só depende de se pasa corrente ou non. Se tes empezado con Arduino e non entendes porque un botón precisa dunha resistencia conectada a GND para que funcione correctamente tal vez queiras saber o motivo eléctrico ou un truco para evitala.
Este artigo trata de electrónica básica aplicada aos circuitos que teñen que ser leídos por unha entrada dixital en Arduino. E tamén dos sistemas electrónicos ‘pull-down’ e ‘pull-up’.
Un problema sinxelo para os informáticos
Arduino ten pins de conexión que van conectados ás entradas e saídas do microcontrolador que vai montado na placa. Cada pin pode funcionar como entrada ou como saída segundo se configure por software. Este é un típico exemplo de programa que configura o pin 2 como entrada, o pin 13 como saída, e ten o cometido de estar examinando o valor da entrada para alumear o led do Arduino cando se preme o botón ‘pulsador’:
#define PIN_BUTTON 2
#define PIN_LED 13
void setup()
{
pinMode(PIN_BUTTON, INPUT);
pinMode(PIN_LED, OUTPUT);
}
void loop()
{
if (digitalRead(PIN_BUTTON) == HIGH)
{
// turn on the Arduino led
digitalWrite(PIN_LED, HIGH);
}
else
{
// turn off the Arduino led
digitalWrite(PIN_LED, LOW);
}
}
Moi similar ao que sería una ‘simulación informática’ dun circuito eléctrico cun interruptor e unha bombilla:
E dixen ben o de ‘similar’ porque no medio da bombilla (led) e do pulsador hai unha cuestión eléctrica que resolver…
A implementación eléctrica complexa para os informáticos
Con nocións básicas de electrónica, a construcción errónea do circuito eléctrico para a inmensa maioría dos ‘informáticos’ sería:
Pero a construcción correcta é estoutra que leva unha resistencia que conecta o pin 2 (entrada) ao pin GND:
A explicación físico-electrónica é que as lecturas que fai o microcontrolador do Arduino teñen que ter un valor mínimo para dicir que a corrente que está entrando no sensor equivale a un valor 1 (HIGH). Se a entrada está conectada directamente a GND entón sempre equivale a un valor 0. Pero ollo: se non está conectada a GND, calquera ‘ruido’ (electricidade estática ou derivación) pode facer que a lectura se convirta nun valor 1 aínda que o botón non estea premido.
En concreto, para un Arduino Uno (ou calquera placa que use un microcontrolador ATmega328, segundo as súas especificacións), o circuito que estea conectando á entrada ten que facer unha resistencia mínima duns 100 megaohmios (100MΩ) para que o valor de lectura sexa 0. Isto ten a vantaxe de poder ler valores cando a intensidade de corrente é moi pequena (5V / 100MΩ = 0,05µA) como, por exemplo, sensores capacitivos que usan ese efecto de derivar a corrente co obxeto que lle toca para ‘sentir’.
No caso do pulsador que nos ocupa, se non usamos unha conexión con GND, obteremos valores aleatorios 0 e 1 cando o botón non se prema. A resistencia a usar, de acordo ao parágrafo anterior, ten que ser menor de 100MΩ e maior que a resistencia que ofreza o pulsador cando se preme e pase a corrente por el. Como unha resistencia ‘pequena’ faría que se consumira máis corrente inutilmente axustamos por arriba e (pola literatura que revisei) valores de 2.2KΩ ou 10KΩ van ben para o noso circuito.
As resistencias pull-up internas programables
O que resultou do circuito correcto do punto anterior foi un sistema pull-down. Vén sendo forzar o estado da entrada a 0 conectándoa a GND. O cambio de estado a 1 virá cando o pulsador permita corrente dende VCC.
Do xeito contrario, tamén existe o pull-up que consiste en forzar o estado da entrada a 1 conectándoa a VCC e cambiando o estado a 0 cando o pulsador derive a corrente a GND (cando se preme o pulsador).
O microcontrolador do Arduino dispón de resistencias pull-up internas que poden activarse por software. O efecto é que a entrada vale 1 por defecto e o circuito hai que conectalo a GND para que o valor veña a 0.
Por que quixeramos facer pull-up na vez de pull-down? Pois din que os cambios de sinal fortuitos polo ‘ruido’ son menos frecuentes e que tamén é máis doado protexer un circuito das baixadas de tensión que das subas.
Esta sería a implementación eléctrica dun pulsador conectado á entrada dixital 2 de Arduino configurada con resistencia pull-up interna (similar á primeira imaxe salvo que esta vai conectada a GND):
A vantaxe práctica para nós é que xa non temos que usar unha resistencia extra (xa vai integrada no sensor do microcontrolador). Un compoñente menos, dúas soldaduras menos e dúas pistas menos na placa.
Programando a lóxica inversa do pull-up
Para programar en Arduino a entrada dixital 2 como pull-up é tan sinxelo como poñer ‘INPUT_PULLUP’ (en contraste con ‘INPUT’) cando se usa a función pinMode() dentro da función setup():
pinMode(PIN_BUTTON, INPUT_PULLUP);
Agora o que hai que ter en conta no código do bucle do programa é que a lectura dun 1 na entrada quere dicir que ó pulsador está sen premer e a lectura dun 0 quere dicir que estase a premer.
Este sería o código final que usa a lóxica inversa do pull-up lendo o estado do botón pulsador conectado ao pin 2 e alumeando o led do Arduino no pin 13:
#define PIN_BUTTON 2
#define PIN_LED 13
void setup()
{
pinMode(PIN_BUTTON, INPUT_PULLUP);
pinMode(PIN_LED, OUTPUT);
}
void loop()
{
if (digitalRead(PIN_BUTTON) == LOW)
{
// turn on the Arduino led
digitalWrite(PIN_LED, HIGH);
}
else
{
// turn off the Arduino led
digitalWrite(PIN_LED, LOW);
}
}
Nota hacker do programador de Arduino
Nalgún sitio, verás escrito algún código de programación de Arduino que para
configurar unha entrada como pull-up chaman a función digitalWrite(PIN, HIGH)
, normalmente dentro da función de setup().
Funciona porque coincide que a programación a nivel de bits nos portos do microcontrolador resulta a mesma configuración de rexistro. Aínda que poda parecer unha práctica hacker non é correcta porque podería fallar noutros microcontroladores que Arduino decidira montar no futuro.
Ademais, precisa de executar previamente pinMode() para configurar o pin como entrada. Para que escribir dúas liñas cando se pode facer nunha? Para que escribir nunha entrada cando só debería servir para ler? ;)