3.11. Eliminação de ressalto

Um interruptor é representado como um contacto ideal aberto ou fechado, mas os contactos de um interruptor real não transitam de forma limpa entre os dois estados. Eles vibram – estabelecem e quebram o contacto elétrico muitas vezes num espaço de poucos milissegundos antes de estabilizarem. Uma entrada GPIO a ler o pino vê isso como uma rajada de transições; um ciclo de polling descuidado conta várias «pressões» para uma única pressão real, e um handler de interrupção executa várias vezes por cada pressão real.

An idealised scope trace showing a switch input signal. The signal starts high (open switch), drops low, bounces back and forth several times within a few milliseconds, then settles low (closed switch).

Um interruptor com ressalto produz uma rajada de transições rápidas antes de estabilizar.

Eliminação de ressalto é a prática de filtrar a vibração para que cada pressão física seja registada como um único evento. Duas abordagens resolvem este problema – software (uma regra de temporização no firmware) ou hardware (um filtro de baixo custo no fio). Não são mutuamente exclusivas.

3.11.1. Eliminação de ressalto por software

A ideia é registar quando a entrada mudou pela última vez e rejeitar alterações posteriores dentro de uma janela temporal curta a partir desse instante. O ressalto de contacto dura tipicamente menos de 10 ms; uma pressão real demora 50 – 100 ms; uma janela de 30 – 50 ms captura todos os ressaltos sem bloquear as pressões reais.

Num ciclo de polling, leia o pino, compare com o último valor estável, e aceite apenas uma alteração após a janela de eliminação de ressalto ter decorrido:

import time
from machine import Pin

button = Pin("P0", Pin.IN, Pin.PULL_UP)
last_state  = 1
last_change = 0
DEBOUNCE_MS = 50

while True:
    now = time.ticks_ms()
    state = button.value()
    if state != last_state and time.ticks_diff(now, last_change) > DEBOUNCE_MS:
        last_change = now
        last_state = state
        if state == 0:
            do_action()
    time.sleep_ms(10)

Para leituras por interrupção, aplique a mesma regra de temporização dentro do handler e depois transfira a pressão real para o contexto principal através de micropython.schedule() (ver Entrada GPIO):

import time
import micropython
from machine import Pin

button = Pin("P0", Pin.IN, Pin.PULL_UP)
last_irq = 0
DEBOUNCE_MS = 50

def handle_press(pin):
    do_action()

def on_press(pin):
    global last_irq
    now = time.ticks_ms()
    if time.ticks_diff(now, last_irq) < DEBOUNCE_MS:
        return
    last_irq = now
    micropython.schedule(handle_press, pin)

button.irq(handler=on_press, trigger=Pin.IRQ_FALLING)

A ISR filtra os ressaltos por timestamp e coloca o callback na fila; handle_press executa de volta no contexto principal, onde a alocação e E/S lenta são seguras.

3.11.2. Eliminação de ressalto por hardware

A eliminação de ressalto por hardware filtra a vibração eletricamente, antes de chegar ao pino. A ferramenta padrão é um condensador.

Um condensador é um componente de dois terminais que armazena carga elétrica. Fisicamente, é composto por duas placas condutoras mantidas a uma pequena distância, separadas por um isolante (o dielétrico).

A capacitor drawn as two parallel horizontal plates with a dielectric (insulator) between them. A lead connects each plate to an external terminal -- A on top, B on bottom. Equal and opposite charges +Q and -Q accumulate on the two plates when a voltage V is applied across the terminals.

Um condensador de placas paralelas: dois condutores separados por uma camada isolante.

Aplicar uma tensão nos seus terminais induz cargas iguais e opostas nas duas placas; a relação é

Q = C × V

onde Q é a carga armazenada (coulombs), V é a tensão no condensador e C é a sua capacitância (farads). A capacitância é fixada pela construção do componente; maior capacitância significa mais carga armazenada à mesma tensão.

A consequência: um condensador não pode alterar a sua tensão instantaneamente. A carga que entra ou sai tem de passar pela resistência presente no caminho, e essa resistência determina a rapidez com que a tensão pode mudar.

3.11.2.1. Constante de tempo RC

Carregar um condensador através de uma resistência produz uma subida exponencial suave em direção à tensão de alimentação, não um degrau. O tempo característico dessa subida é a constante de tempo RC:

τ = R × C

Após um τ, o condensador atingiu cerca de 63 % da tensão de alimentação. Após 5 τ, está acima de 99 % – «totalmente carregado» para efeitos práticos.

A graph showing a capacitor's voltage rising along an exponential curve from 0 V toward the supply rail. The time τ = RC is marked on the x-axis where the curve reaches 63 % of the supply voltage.

Um condensador carrega segundo uma curva exponencial. τ = RC é o tempo para atingir 63 % da tensão final.

A descarga através de uma resistência segue a imagem espelhada: a tensão cai exponencialmente desde o valor inicial em direção a zero, descendo para 37 % da tensão inicial após um τ, e para menos de 1 % após 5 τ.

A graph showing a capacitor's voltage falling along an exponential curve from Vmax toward 0 V. The time τ = RC is marked on the x-axis where the curve drops to 37 % of the starting voltage.

Um condensador descarrega segundo um decaimento exponencial. τ = RC é o tempo para descer para 37 % da tensão inicial.

3.11.2.2. O circuito de eliminação de ressalto

Um condensador entre um pino de entrada e a massa, alimentado através de uma resistência em série, forma um filtro passa-baixo. Picos rápidos não têm tempo para carregar ou descarregar o condensador através dessa resistência; o pino mantém-se próximo da tensão que tinha antes do pico. Alterações lentas – uma pressão deliberada – carregam ou descarregam o condensador e a leitura acompanha.

R1 puxa o lado alto do interruptor até Vcc, produzindo um sinal de interruptor bruto com ressalto. R2 e C filtram depois esse sinal passa-baixo até ao pino:

A switch input with hardware debouncing. Vcc connects through a 10 kΩ pull-up resistor down to a junction. That junction connects to ground through the switch on one branch, and through a 10 kΩ series resistor to the Pin on the other branch. A 100 nF capacitor between Pin and ground completes the low-pass filter.

Eliminação de ressalto por hardware: R2 e C aplicam um filtro passa-baixo ao sinal bruto do interruptor antes de este chegar ao pino.

Valores típicos: R1 = 10 (pull-up), R2 = 10 (série), C = 100 nF.

Quando o interruptor está aberto, a corrente flui Vcc → R1R2 → cap (em série), carregando o cap até Vcc com τ_charge = (R1 + R2) × C = 2 ms.

Quando o interruptor fecha, o nó do interruptor fixa-se à massa e o cap descarrega através de R2 apenas para essa massa com τ_discharge = R2 × C = 1 ms.

Ambas as transições são filtradas por RC. Como o cap está no seu próprio nó, a jusante de R2 a partir do interruptor, oscila de forma limpa entre Vcc (aberto) e 0 V (fechado) – nenhuma corrente tem de fluir através de R1 em estado estacionário em nenhum dos casos.

3.11.3. Escolher entre eles

  • Software é a opção predefinida. Não tem custos em componentes, o limiar é fácil de ajustar e funciona em qualquer pino que a CPU leia.

  • Hardware vale a pena quando o ressalto atinge algo que não seja o código de polling da CPU – uma interrupção que não deve disparar duas vezes, um contador de hardware, um periférico sem filtro próprio.

A eliminação de ressalto por software e por hardware coexistem pacificamente: um pequeno filtro RC suprime os piores picos, e uma janela de eliminação de ressalto por software trata do que sobrar.