Raspberry PI – GPIO input com Python

raspberry-pi-gpio-python
raspberry-pi-gpio-python

Introdução

 

A primeira parte da série de interação com o GPIO (General Purpose Input Output) do Raspberry PI no modo Output possui os passos fundamentais para esta segunda etapa como a preparação do ambiente. Nesta segunda etapa vamos ver o modo Input, e para a prática será utilizado o Raspberry PI B, protoboard, pushbutton e alguns resistores. Serão mencionados os possíveis modos de trabalho com Input utilizando resistores de pull-up e pull-down, internos ou externos, e recursos como detecção de borda, debounce por software e uma “interrupção” baseada na detecção por borda.

 

 

Configuração do ambiente host

 

  • Board: Raspberry PI B;

  • Distribuição: Raspbian – Debian Wheezy (2014-01-07);

  • Kernel 3.12.22;

  • Python 2.7.3;

  • RPi.GPIO 0.5.7.

 

 

RPi.GPIO

 

Já vimos na primeira parte da série as funções RPi.GPIO.setmode(), RPi.GPIO.setup(), RPi.GPIO.output(), RPi.GPIO.input() e RPi.GPIO.cleanup(), e agora vamos ver algumas funções e parâmetros que tornam o modo input muito interessante.

 

  • RPi.GPIO.RISING => Borda de subida, quando passa de 0V para 3.3V;
  • RPi.GPIO.FALLING => Borda de descida, quando passa de 3.3V para 0V;
  • RPi.GPIO.BOTH => Os dois estados, ocorre ação tanto na subida [0V → 3.3V] quanto na descida [3.3V → 0V];
  • RPi.GPIO.LOW => Nivel lógico baixo [low] ou 0V;
  • RPi.GPIO.HIGH => Nivel lógico alto [high] ou 3.3V;
  • RPi.GPIO.PUD_UP => Pino Input em modo pull-up;
  • RPi.GPIO.PUD_DOWN => Pino Input em modo pull-down;
  • RPi.GPIO.PUD_OFF => Padrão.

 

  • RPi.GPIO.wait_for_edge() => Bloqueia a execução até que o botão seja pressionado ou a ação setada aconteça;
  • RPi.GPIO.event_detected() => Guarda o estado de um evento no pino, e quando for verificado no loop, indica se houve ou não mudança no pino. Pode ser utilizado dentro do loop e não irá perder a informação;
  • RPi.GPIO.add_event_detect() => Adiciona um evento baseado no pino, se o evento irá ocorrer na borda de descida [FALLING], subida [RISING] ou em ambos [BOTH]. Adiciona uma função para ser chamada e aceita parâmetro de tempo debounce;
  • RPi.GPIO.remove_event_detect() => Permite remover um evento em qualquer parte do código se não for mais utilizado.

 

A Figura 1 ilustra os comportamentos que ocorrerão no decorrer do artigo ao acionar o pushbutton.

 

LOWtoHIGH_with_bouncing_PortalEmbarcados
Figura 1 - Detalhes sobre a mudança do nível lógico com chaves mecânicas

 

 

Olhando a Figura 1, fica fácil entender os parâmetros LOW (representado por 0V), HIGH (como 3.3V), Edge Rising ou RISING (transição de 0V a 3.3V), Edge Falling ou FALLING (transição de 3.3V a 0V) e o efeito bouncing. Esse último, se você não conhece, pode ver o artigo Leitura de chaves mecânicas e o processo de debounce, escrito pelo Rodrigo Almedia, indicando como contornar o problema via hardware e software, e neste artigo iremos estudar a solução via software.

 

 

PushButton com pull-down interno

 

EsquematicoRaspberryPIPushButtonPullDownInterno
Figura 2 - Esquema de ligação do PushButton em pull-down interno

 

 

O primeiro exemplo prático será adicionar um pushbutton. Uma de suas extremidades será conectada ao 3.3V (pino 1) e a outra ao pino 16 (ou GPIO 23) da Raspberry Pi no modo BCM, como na Figura 2. Configuraremos via software utilizando RPi.GPIO o pino 16 (GPIO 23) no modo INPUT e com pull-down interno.

 

Código:

 

Executando o código:

 

 

PushButton com pull-up interno

 

EsquematicoRaspberryPIPushButtonPullUpInterno
Figura 3 - Esquema de ligação do PushButton em pull-up interno

 

 

No segundo exemplo prático o mesmo PushButton será utilizado, trocando apenas a extremidade de 3.3V (pino 1) para 0V GND (pino 6), como na Figura 3. Configuraremos via software utilizando RPi.GPIO o pino 16 (GPIO 23) no modo INPUT e com pull-up interno.

 

Código:

 

O nosso código acima é praticamente o mesmo do exemplo anterior com algumas alterações como: o setup() do GPIO 23 como pull-up; o teste que verifica o estado do pino faz uso da constante gpio.LOW, que poderia ser 0, seguindo a analogia do exemplo anterior; o botão, quando pressionado, faz o programa parar.

 

Executando o código:

 

 

PushButton com  pull-down externo

 

EsquematicoRaspberryPIPushButtonPullDownExterno
Figura 4 - Esquema de ligação do PushButton em pull-down externo

 

 

O próximo exemplo é utilizando resistores externos para configurar como pull-up ou pull-down e, como na Figura 4, vamos utilizar 2 resistores: um de 1k e outro de 10k. A configuração que foi utilizada é o resistor de 1k entre o GPIO e o PushButton e o 10k entre GPIO e o GND, caracterizando ser pull-down.

 

Código:

 

Executando o código:

 

 

PushButton com pull-up externo

 

EsquematicoRaspberryPIPushButtonPullUpExterno
Figura 5 - Esquema de ligação do PushButton em pull-up externo

 

 

O esquema final da Figura 5, praticamente o mesmo que o anterior, apenas com a alteração do resistor 10k que é entre VCC (3.3V) com GPIO e o PushButton agora é entre o pino do GPIO e o GND, caracterizando ser pull-up. A mesma ideia deve-se seguir no código.

 

Código:

 

Executando o código:

 

Não errei o código não, é que utilizando resistores externos altera-se apenas a linha do if de gpio.HIGH para gpio.LOW. No caso ainda dei uma valorizada, onde troquei gpio.LOW por 0.

 

 

Eventos e Interrupções

 

Os exemplos utilizados até agora foram legais e interessantes, porém na prática sabemos que é um pouco inconveniente aguardar o loop ou, como no exemplo que fizemos, utilizarmos um delay de 1s. Em alguns casos isso é um absurdo e pode ser que a ação de pressionar o botão não seja capturada, sendo uma falha grave e que pode ser facilmente contornada com as funções de "detecção de eventos" event_detect do RPi.GPIO, que tem uma grande relação com Edge Rising (Borda de Subida), Edge Falling (Borda de Descida) ou Both (Ambos sentidos). Utilizaremos o esquemático da Figura 2 por ser mais simples de montar, o PushButton com pull-down e vamos ao código.

 

Código:

 

Executando o código:

 

Você pode testar, e pode ver que independente do momento que pressionar o pushbutton, na ação dele ser pressionado (RISING), indo de 0V para 3.3V, como estamos com pull-down, ele irá “guardar” esta mudança de estado. Na próxima vez que for executado o loop, este evento será tratado, no nosso caso sendo chamada a função action_press_button() e saindo do programa.

 

E se por acaso quiséssemos que a ação ocorresse ao soltar o pushbutton e não ao pressionar o mesmo?

 

Código:

 

Executando o código:

 

Não mudou nada na saída do código, tirando que o programa só parou quando pressionamos e soltamos o PushButton. Enquanto o botão estiver pressionado, nada acontece. O mesmo pode ser feito com BOTH, que a ação ocorrerá ao pressionar e soltar.

Outra opção interessante no event_detect() é poder adicionar uma função a ser chamada assim que ocorrer a mudança de estado, utilizando o parâmetro callback. Seria a correspondência de uma "Interrupção", porém eu não gosto muito deste termo e prefiro aceitar o de uma chamada em paralelo ou execução já que uma segunda thread é disparada neste caso. Vamos ver!

 

Código:

 

Executando o código:

 

Usando callback no add_event_detect(), podemos ver que existem “prioridades” na chamada, porque assim que o evento ocorre é lançada uma segunda thread para a chamada. Após isso vem a continuação do loop e depois é atendida nossa mudança de estado no próprio loop como antes. Assim conseguimos prioridade no tratamento de input independente do tamanho e tempo de nosso loop, caracterizando a interrupção dita. Comentando sobre a opção de utilizar o debounce via software, como na linha 30, com ou sem o callback, podemos definir o parâmetro bouncetime, que é um valor de tempo em ms para ser ignorado na detecção da borda.

 

A função remove_event_detect(), pode ser chamada e passado como parâmetro o pino. A qualquer momento o evento sobre o mesmo pino passa a não ser mais válido e você pode remover a ação sobre a borda naquele pino. Vamos ver no próximo código.

 

Código:

 

Executando o código:

 

E por último o wait_for_edge(), que podemos parar a execução do programa até que a mudança no pino ocorra, também sendo válido para a mudança RISING, FALLING ou BOTH.

 

Código:

 

Executando o código:

 

 

Conclusão

 

Podemos ver mais uma vez como Python é uma ferramenta fantástica para prototipagem. Com poucas linhas e utilizando o RPi.GPIO conseguimos manipular de diversas maneiras o GPIO do Raspberry Pi no modo input.

 

 

O que vem por aí?

 

No próximo artigo vamos continuar brincando com o GPIO do Raspberry Pi, só que desta vez partindo para PWM.

 

Proprietário da B2Open onde oferecemos consultoria, treinamentos e desenvolvimento em Sistemas Embarcados. Entusiasta a filosofia open-source, mais de 10 anos de experiências em Linux e FOSS. Em sistemas embarcado do firmware baremetal ao Linux Embedded, e há aproximadamente 8 anos desenvolvendo em (C, Python, Qt e muito Shell Script), além de profiling, hardening e tuning para targets com Linux Embarcado. Graduado em Engenharia da Computação pela UNICEP com ênfase em robótica e sistemas embarcados.