Controle GPIO da Raspberry Pi e Python – Parte 4

Este é um tutorial sobre como usar a GPIO da Raspberry Pi usando a biblioteca Python. Ele foi dividido em quatro partes para facilitar o acesso:

  • Parte 1: introdução e configuração
  • Parte 2: acesso às entradas e saídas
  • Parte 3: aguardando eventos
  • Parte 4: callbacks

Introdução

No artigo anterior, vimos como usar a função GPIO.wait_for_edge() para aguardar o estado de uma entrada sem precisar fazer o polling, o que trás vantagens no uso de recursos do processador.

Mas também temos alguns problemas. Você deve ter percebido que a detecção de um botão se dava apenas se o outro botão tivesse sido detectado ou o tempo de espera, no caso de 2 segundos, tivesse passado. Esse caso, para apenas 2 botões, pode não parecer tão ruim, mas se adicionarmos complexidade ao nosso programa isso pode causar muitos problemas ou mesmo fazer com o que o programa não funcione corretamente.

Para nossa alegria, a biblioteca GPIO possui um mecanismo de callback que vai fazer com que nosso programa se torne realmente multi-thread e consigamos fazer outros processamento durante a leitura do GPIO.

Eventos

A função GPIO.event_detected([pin]) pode ser usada dentro de um loop com outras lógicas. Mas, ao contrário do polling, não vai perder qualquer evento que tenha ocorrido antes de a verificação ser feita. Isso pode ser bem útil quando se estiver usando uma lógica com tratamento de GUI, por exemplo, usando PyQT ou Pygame.

Essa função deve ser usada juntamente com GPIO.add_event_detect([pin], [borda]), para cadastrar esse a detecção do evento desejado para o determinado pino.

GPIO.add_event_detect(18, GPIO.RISING)
faz_alguma_coisa()
if GPIO.event_detected(18):
    print('Botao pressionado...')

Callback

Ao invés de verificar se o evento aconteceu e poder demorar muito para reagir, a biblioteca provê uma forma de se indicar uma função que será chamada automaticamente na medida que o evento acontecer. Essa função recebe um único parametro (o pino que foi detectado o evento) e é passada via parâmetro callback.

def callback(channel):
    print('Botao pressionado em', channel)
 
GPIO.add_event_detect(18, GPIO.RISING, callback=callback)

Debouncing

Caso implemente dessa forma, você vai perceber que o callback vai ser chamado algumas vezes. Isso é o resultado do chamado efeito bouncing do botão. Não vamos entrar muito em detalhes sobre isso, mas há algumas maneiras de se evitar isso:

  • Via hardware (adicionando um capacitor sem série com o botão, por exemplo).
  • Via software.
  • Com ambos.

Para evitar via software, basta adicionar o parametro bouncetime à função, passando o tempo de análise em milissegundos.

def callback(channel):
    print('Botao pressionado em', channel)
 
GPIO.add_event_detect(18, GPIO.RISING, callback=callback, bouncetime=200)

Materiais necessários

  • Raspberry Pi com sistema operacional Raspbian já instalado (vamos usar o a RPi 2 modelo B, mas pode ser utilizado outro, caso queira)
  • Led
  • Resistor 100 Ohm
  • Push button
  • Jumpers
  • Protoboard

Conexão

Estamos o usando o mesmo circuito do exemplo anterior (que pode ser visto aqui também).

  • Conectar o lado positivo LED (anodo) ao pino 12 (GPIO 18) da RPi. O lado negativo conectar ao resistor e o outro lado do resistor ao terra (GND).
  • Conectar o lado positivo do outro LED (anodo) ao pino 16 (GPIO 23) da RPi. O lado negativo conectar ao resistor e o outro lado do resistor ao terra (GND).
  • Conectar um lado do push button ao pino 18 (GPIO 24) da RPi e o outro lado ao terra (GND).
  • Conectar um lado do outro push button ao pino 22 (GPIO 25) e o outro lado ao 3.3V.

Programando

Vamos alterar o nosso programa agora para incluir a função de callback. Você pode incluir quantas funções quiser. Como temos 2 botões, vamos usar uma função para cada botão, mas pode usar uma função apenas para vários pinos.

import RPi.GPIO as GPIO
import time
 
LedPin1 = 12    # pin12 --- led
LedPin2 = 16    # pin16 --- led
BtnPin1 = 18    # pin18 --- button
BtnPin2 = 22    # pin22 --- button
 
GPIO.setmode(GPIO.BOARD)       # Pinagem física
GPIO.setup([LedPin1, LedPin2], GPIO.OUT)   # Pino de led como saída
GPIO.setup(BtnPin1, GPIO.IN, pull_up_down=GPIO.PUD_UP)    # Pino do botão como saída e aciona o pull-up
GPIO.setup(BtnPin2, GPIO.IN, pull_up_down=GPIO.PUD_DOWN) 
GPIO.output([LedPin1, LedPin2], GPIO.LOW) # Desliga o led
 
out1 = False
out2 = False
 
# Funcao de callback para botao 1
def callback_bt_1(channel):
    global out1
    print('Botao 1 pressionado...')
    out1 = not out1
    GPIO.output(LedPin1, out1)
 
# Funcao de callback para botao 2
def callback_bt_2(channel):
    global out2
    print('Botao 2 pressionado...')
    out2 = not out2
    GPIO.output(LedPin2, out2)
 
# Registra funcoes de callback
GPIO.add_event_detect(BtnPin1, GPIO.RISING, callback=callback_bt_1, bouncetime=200)
GPIO.add_event_detect(BtnPin2, GPIO.RISING, callback=callback_bt_2, bouncetime=200)
 
# Loop principal
print('Pressione Ctrl+C para sair')
try:
    while True:
        print('Aguardando evento...')
        time.sleep(5)
except KeyboardInterrupt:
    # Ctrl+C foi pressionado
    pass
 
GPIO.output([LedPin1, LedPin2], 0)
GPIO.cleanup()  # Limpa configuração

Ao rodar o programa e apertar os botões, você deve ter uma saída parecida com essa:

Conclusão

Esse foi o tutorial sobre o uso do GPIO da Raspberry Pi com Python. Espero que tenham aprendido alguma coisa e tenha sido útil de alguma forma.

Deixe uma resposta

O seu endereço de e-mail não será publicado. Campos obrigatórios são marcados com *