Como usar a GPIO da Raspberry Pi usando Python.

Fernando Souza
Vacatronics
Published in
8 min readFeb 3, 2020

Este é um tutorial sobre como usar a GPIO da Raspberry Pi usando a biblioteca Python.

Introdução

Uma das características mais poderosa da Raspberry Pi é a barra de GPIO (Entradas e Saídas de Propósito Geral). De uma forma simples, pense neles como chaves que podem ser ligadas/desligadas por você (entradas) ou pela RPi (saídas).

Esses pinos são a interface da RPi com o mundo externo e a quantidade de pinos disponíveis varia de acordo com o modelo. Como a maioria dos tutoriais de nosso site vai utilizar esses pinos, é interessante aprender a configurar e usar tudo o que oferece.

Raspberry Pi 1 (esquerda) e Raspberry Pi 3 (direita)

Materiais necessários

  • Raspberry Pi com sistema instalado (neste tutorial foi usada a versão Zero W)
  • Led
  • Resistor 100 Ohm
  • Jumpers
  • Protoboard

Layout

A quantidade de pinos depende do modelo, mas varia entre 26 para a RPi 1 modelo A/B e 40 para a RPi 0, RPi 1 modelo A+/B+, RPi 2 B, RPi 3 B/B+ e RPi 4.

Layout dos pinos de GPIO para a RPi 1, 2 e 3 modelos A+/B+/B (esquerda) e RPi 1 modelo A/B (direita)

Como você pode perceber, há mais do que somente pinos de GPIO.

  • GPIO: são os pinos gerais de entrada e saída. O nível de saída é de 3.3V e um máximo de 50mA, portanto evite colocar uma carga muito grande, o que pode danificar o pino e até mesmo a placa. Um LED, ok. Um motor, nem pensar. Para o caso de ser usado como entradas, esse pinos podem ser configurados com um resistor de pull-up/pull-down, para auxiliar na detecção do nível.
  • I2C (Inter-Integrated Circuit): esses pinos permitem se conectar e conversar com hardwares que suportem o protocolo I2C. Tipicamente são necessários 2 pinos.
  • SPI (Serial Peripheral Interface Bus): esses pinos permitem sem conectar e conversar com hardwares que contêm SPI. Bem parecido com o I2C, mas usa um protocolo diferente.
  • UART (Universal Asynchronous Receiver/Trasmitter): pinos para se conversar com outros dispositivos usando serial.

Os pinos de potência são usados para alimentar outros dispositivos e são puxados diretamente da Raspberry Pi. Existem dois níveis:

  • 3.3V: limitado a 50mA.
  • 5.0V: puxa a corrente diretamente da alimentação USB, portanto vai depender da fonte usada. Por exemplo, se for usada uma fonte de 1A, pode ser fornecido até 300mA, uma vez que a placa vai consumir cerca de 700mA.
  • GND são os pinos de terra.

Pode parecer complicado a primeira vista, mas com o tempo isso se torna natural.

Configurando os pinos

Vamos mostrar de forma breve como configurar os pinos para você poder usá-los na Raspberry Pi.

Caso você tenha a última versão do Raspbian, você já pode sair programando a sua placa diretamente. Mas, caso esteja usando pela primeira vez, é bom atualizar o sistema.

sudo apt update
sudo apt upgrade

E depois instalar a versão mais recente da biblioteca python RPi.GPIO :

sudo apt install rpi.gpio

Essa biblioteca facilita o uso dos pinos de GPIO e tem diversos recursos, que vamos ver com mais detalhes adiante.

Conexão

Todos os exemplos usados neste tutorial vão usar a conexão abaixo.

Configuração

Primeiramente, importamos a biblioteca para uso dentro do código.

import RPi.GPIO as GPIO

A partir de então, vamos usar GPIO como acesso a todas as funções da biblioteca.

Depois, precisamos configurar o modo de acesso a placa. Basicamente, existem dois métodos:

  • GPIO: é a forma como a RPi “vê” os pinos. Os números não fazem nenhum sentido, é simplesmente como os pinos estão conectados diretamente ao chiṕ da Broadcom. Provavelmente, para identificar corretamente os pinos você vai precisar de alguma ajuda (normalmente, caso esteja usando o extensor, ele já vem impresso esse modo também). Para a biblioteca, esse modo é identificado como GPIO.BCM.
  • Físico: a outra forma é simplesmente contando o pino fisicamente. O pino 1 se refere ao pino superior esquerdo (mais próximo ao SD Card). A figura abaixo mostra o pinos na “forma física”. Para a biblioteca, esse modo é identificado como GPIO.BOARD.

Qual modo você vai usar depende do que você se sente mais confortável. Caso esteja conectando diretamente a RPi, o modo físico é mais fácil. Para fazer a configuração, basta usar a função GPIO.setmode([mode]).

GPIO.setmode(GPIO.BOARD)

Antes de poder ser utilizado, cada pino deve ser setado com o modo que vai ser trabalhado (GPIO.IN para entrada ou GPIO.OUT para saída) através da função GPIO.setup([pin], [mode]). Essa função pode ser usada a qualquer momento do código e o pino pode ser alterado de função a qualquer momento.

GPIO.setup(12, GPIO.OUT)
GPIO.setup(16, GPIO.OUT)
GPIO.setup(18, GPIO.IN)
GPIO.setup(22, GPIO.IN)

Saída

Para deixar um pino como nível alto ou nível baixo, basta usar a função GPIO.output([pin], [level]). O nível pode ser definido como GPIO.HIGH, 1 ou True quando se quiser nível alto; ou GPIO.LOW, 0 ou False para quando se quiser nível baixo.

GPIO.output(12, GPIO.LOW)
GPIO.output(16, True)

O pino 12 (GPIO 18) também pode ser utilizado como saída PWM (somente ele tem essa capacidade). Para inicializar o PWM, utilize a função GPIO.PWM([pin], [frequencia]). Atribua essa função a uma variável para você poder controlar depois durante o programa. Para iniciar, use o comando pwm.start([duty cicle]).

Você pode mudar o valor da saída PWM através da função pwm.ChangeDutyCicle([duty cicle]) a qualquer momento. Para interromper, use pwm.stop.

pwm = GPIO.PWM(12, 1000)
pwm.start(75)
pwm.ChangeDutyCycle(50)
pwm.stop()

Não se esqueça de configurar o pino como saída antes de usar.

Entrada

Se um pino é configurado como entrada, você pode usar a função GPIO.input([pin]) para ler o seu valor. Essa função retorna True ou False indicando se o pino está em nível alto ou baixo, respectivamente. Você pode usar então dentro de um if para fazer a sua ação.

if GPIO.input(18):
print('Pino 18 está acionado')
else:
print('Pino 18 está baixo')

Lembra quando configuramos o pino como estrada ou saída na função GPIO.setup? Existe para essa função um terceiro parâmetro, que você pode setar um resistor de pull-up (GPIO.PUD_UP), pull-down (GPIO.PUD_DOWN).

GPIO.setup(18, GPIO.IN, pull_up_down=GPIO.PUD_UP)
GPIO.setup(22, GPIO.IN, pull_up_down=GPIO.PUD_DOWN)

Caso nada seja declarado no terceiro parâmetro, ambos os resistores são desabilitados.

Exemplo

Para assimilarmos o que aprendemos até agora, vamos fazer um programa simples para acionar um LED quando o botão for pressionado.

Acredito que o código abaixo é bem auto-explicativo com seus comentários. Copie-o e salve em um arquivo chamado bot_led.py

Execute o programa:

python bot_led.py

Pressione o botão para ver o LED acender. Você deve verificar que ocorre um atraso entre você apertar o botão e o LED realmente acender. Isso é causado pelo tempo que colocamos entre uma verificação e outra.

Interrupção

No nosso exemplo, ficávamos em um loop verificando o nível do pino de entrada (do botão) a cada um segundo para daí realizarmos a ação desejada (acender/apagar o LED).

Isso é o que chamamos de polling, o ato de ficar verificando alguma coisa continuamente. Caso você deseje que o programa reaja mais rápido, você pode definir um tempo menor de espera entre uma verificação e outra. Isso é bom caso deseje uma reação rápida, mas usa bastante o processador.

Mas deve existir um jeito melhor, não? Sim, existe. São as interrupções.

Interrupção é um jeito muito mais eficiente de lidar com a situação do tipo esperar que algo aconteça e então fazer a ação. Ela libera o recurso que você ocuparia no momento do polling e que você pode usar para outra coisa.

Na biblioteca do Pyhon, isso é resolvido se usando a função GPIO.wait_for_edge([pin], [borda], [timeout]). Você pode configurar para usar a borda de subida (GPIO.RISING), a borda de descida (GPIO.FALLING) ou ambas (GPIO.BOTH).

O parametro de timeout é opcional e serve para aguardar apenas por um certo período de tempo (e não travar o seu programa). O valor é dado em milissegundos.

if GPIO.wait_for_edge(18, GPIO.FALLING, timeout=5000):
out = not out
GPIO.output(12, out)

Corrigindo o código:

Eventos

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.

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

Exemplo final

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.

Executando:

Conclusão

Este tutorial mostrou um pouco de como usar o Python para acessar a GPIO da Raspberry Pi.

Também existe a biblioteca gpiozero que facilita bastante o acesso as GPIOs e abstrai algumas funções usadas aqui.

--

--

Fernando Souza
Vacatronics

Enthusiast of programming, electronics, technology and beer, not necessarily in that order. BuyMeACoffee: buymeacoffee.com/ustropo