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:

Esquema dun circuito con bombilla e interruptor

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:

Pulsador conectado directamente a entrada de Arduino

Pero a construcción correcta é estoutra que leva unha resistencia que conecta o pin 2 (entrada) ao pin GND:

Pulsador conectando 'pull-down' a entrada de Arduino

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):

Pulsador conectado a unha entrada configurada 'pull-up' de Arduino

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? ;)