Raspberry PI – GPIO input com Python

modo Input

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.

 

modo Input
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

 

modo Input
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:

#! /usr/bin/python
# -*- coding: utf-8 -*-

import RPi.GPIO as gpio
import time

gpio.setmode(gpio.BCM)

gpio.setup(23, gpio.IN, pull_up_down = gpio.PUD_DOWN)

while True:
	if(gpio.input(23) == 1):
		print(“Botão pressionado”)
	else:
		print(“Botao desligado”)
	
	time.sleep(1)

gpio.cleanup()
exit()

 

Executando o código:

[email protected] ~/python/rpio/ $ sudo python pushbutton_pulldown_interno.py
Botão desligado
Botão desligado
Botão desligado
Botão pressionado
Botão pressionado
Botão desligado
Botão desligado

 

 

PushButton com pull-up interno

 

modo Input
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:

#! /usr/bin/python
# -*- coding: utf-8 -*-

import RPi.GPIO as gpio
import time


gpio.setmode(gpio.BCM)

# Com pull-up interno
gpio.setup(23, gpio.IN, pull_up_down = gpio.PUD_UP)

while True:
	if gpio.input(23) == gpio.LOW:
		print(“Botão acionado”)
		break
	else:
		printf(“Botão desligado”)

	time.sleep(1)

gpio.cleanup()
exit()

 

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:

[email protected] ~/python/rpio/ $ sudo python pushbutton_pullup_interno.py
Botao desligado
Botao desligado
Botao desligado
Botao pressionado

 

 

PushButton com  pull-down externo

 

modo Input
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:

#! /usr/bin/python
# -*- coding: utf-8 -*-

import RPi.GPIO as gpio
import time


""" Global """
PIN=23	# Usando modo BCM


""" Funcoes """
def action_press_button(gpio_pin):
	print “O botão no pino %d foi pressionado!” % gpio_pin
	print “Saindo...”


""" Configurando GPIO """
# Configurando o modo dos pinos como BCM
gpio.setmode(gpio.BCM)

# Configurando PIN como INPUT
gpio.setup(PIN, gpio.IN)


while True:
	if gpio.input(PIN) == gpio.HIGH:
		action_press_button(PIN)
		break
	else:
		print “Botão desligado”
	
	time.sleep(1)


gpio.cleanup()
exit()

 

Executando o código:

[email protected] ~/python/rpio/ $ sudo python pushbutton_pulldown_externo.py
Botão desligado
Botão desligado
Botão desligado
O botão no pino 23 foi pressionado!
Saindo...

 

 

PushButton com pull-up externo

 

modo Input
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:

#! /usr/bin/python
# -*- coding: utf-8 -*-

import RPi.GPIO as gpio
import time


""" Global """
PIN=23	# Usando modo BCM


""" Funcoes """
def action_press_button(gpio_pin):
	print “O botão no pino %d foi pressionado!” % gpio_pin
	print “Saindo...”


""" Configurando GPIO """
# Configurando o modo dos pinos como BCM
gpio.setmode(gpio.BCM)

# Configurando PIN como INPUT
gpio.setup(PIN, gpio.IN)


while True:
	#if gpio.input(PIN) == gpio.LOW:
	if gpio.input(PIN) == 0:
		action_press_button(PIN)
		break
	else:
		print “Botão desligado”
	
	time.sleep(1)


gpio.cleanup()
exit()

 

Executando o código:

[email protected] ~/python/rpio/ $ sudo python pushbutton_pullup_externo.py
Botão desligado
Botão desligado
Botão desligado
Botão desligado
Botão desligado
O botão no pino 23 foi pressionado!
Saindo...

 

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:

# -*- coding: utf-8 -*-
#! /usr/bin/python

import RPi.GPIO as gpio
import time

""" Global """
PIN=23

""" Funcoes """
def action_press_button(gpio_pin):
	print “O botão no pino %d foi pressionado!” % gpio_pin
	print “Saindo...”


""" Configurando GPIO """
# Configurando o modo dos pinos como BCM
gpio.setmode(gpio.BCM) 

# Configurando PIN como INPUT e modo pull-donw interno
gpio.setup(PIN, gpio.IN, pull_up_down = gpio.PUD_DOWN)

# Adicionando um evento ao GPIO 23 na mudança RISING 0V[LOW] - > 3.3V[HIGH]
gpio.add_event_detect(PIN, gpio.RISING)

while True:
	print “Polling...”

	if gpio.event_detected(PIN):
		action_press_button(PIN)
		break

	time.sleep(1)

	

gpio.cleanup()
exit()

 

Executando o código:

[email protected] ~/python/rpio/ $ sudo python pushbutton_event_detect01.py
Polling...
Polling...
Polling...
Polling...
Polling...
Polling...
Polling...
Polling...
Polling...
Polling...
Polling...
Polling...
Polling...
Polling...
O botão no pino 23 foi pressionado!
Saindo...

 

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:

# -*- coding: utf-8 -*-
#! /usr/bin/python

import RPi.GPIO as gpio
import time

""" Global """
PIN=23

""" Funcoes """
def action_press_button(gpio_pin):
	print “O botão no pino %d foi pressionado!” % gpio_pin
	print “Saindo...”


""" Configurando GPIO """
# Configurando o modo dos pinos como BCM
gpio.setmode(gpio.BCM) 

# Configurando PIN como INPUT e modo pull-donw interno
gpio.setup(PIN, gpio.IN, pull_up_down = gpio.PUD_DOWN)

# Adicionando um evento ao GPIO 23 na mudança FALLING 3.3V[HIGH] - > 0V[LOW]
gpio.add_event_detect(PIN, gpio.FALLING)

while True:
	print “Polling...”

	if gpio.event_detected(PIN):
		action_press_button(PIN)
		break

	time.sleep(1)

gpio.cleanup()
exit()

 

Executando o código:

[email protected] ~/python/rpio/ $ sudo python pushbutton_event_detect02.py
Polling...
Polling...
Polling...
Polling...
Polling...
Polling...
Polling...
Polling...
Polling...
Polling...
Polling...
Polling...
Polling...
Polling...
Polling...
Polling...
Polling...
Polling...
Polling...
Polling...
Polling...
Polling...
Polling...
Polling...
O botão no pino 23 foi pressionado!
Saindo...

 

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:

# -*- coding: utf-8 -*-
#! /usr/bin/python

import RPi.GPIO as gpio
import time

""" Global """
PIN=23

""" Funcoes """
def action_press_button_loop(gpio_pin):
	print “O botão no pino %d foi pressionado!” % gpio_pin
	print “Saindo...”

def action_press_button(gpio_pin):
	print “Tratando o botão no pino %d que foi pressionado!” % gpio_pin

""" Configurando GPIO """
# Configurando o modo dos pinos como BCM
gpio.setmode(gpio.BCM) 

# Configurando PIN como INPUT e modo pull-donw interno
gpio.setup(PIN, gpio.IN, pull_up_down = gpio.PUD_DOWN)

# Adicionando um evento ao GPIO 23 na mudança FALLING 0V[LOW] - > 3.3V[HIGH]
gpio.add_event_detect(PIN, gpio.RISING, callback=action_press_button)

# Junto com o parametro callback podemos utilizar ainda o bouncetime
# na linha abaixo estamos dizendo para ignorar nos primeiro 300ms
# gpio.add_event_detect(PIN, gpio.RISING, callback=action_press_button, bouncetime=300)

while True:
	print “Polling...”

	if gpio.event_detected(PIN):
		action_press_button_loop(PIN)
		break

	time.sleep(1)

gpio.cleanup()
exit()

 

Executando o código:

[email protected] ~/python/rpio/ $ sudo python pushbutton_event_detect03.py
Polling...
Polling...
Polling...
Polling...
Polling...
Polling...
Polling...
Tratando o botão no pino 23 que foi pressionado!
Polling...
O botão no pino 23 foi pressionado!
Saindo...

 

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:

#! /usr/bin/python
# -*- coding: utf-8 -*-

import Rpi.GPIO as gpio
import time


""" Global """
PIN=23

""" Funcoes """
def action_press_button(gpio_pin):
	print "Você pressionou o botão do pino %d e agora ele sera desativado" % gpio_pin


""" Configurando GPIO """
# Configurando o modo do GPIO como BCM
gpio.setmode(gpio.BCM)

# Configurando PIN's como INPUT e modo pull-down interno
gpio.setup(PIN, gpio.IN, pull_up_down = gpio.PUD_DOWN)

# Adicionando um evento ao GPIO 23 na mudança RISING 0V[LOW] -> 3.3V[HIGH]
gpio.add_event_detect(PIN, gpio.RISING)


while True:
	try:
		if gpio.event_detected(PIN):
		    action_press_button(PIN)
		    gpio.remove_event_detect(PIN)
		
		else:
                    print("Botão Desligado")

		time.sleep(1)
	except (KeyboardInterrupt):
		print("Saindo...")
		gpio.cleanup()
		exit()

 

Executando o código:

[email protected] ~/python/rpio/ $ sudo python pushbutton_event_detect04.py
Botão desligado
Botão desligado
Botão desligado
Você pressionou o botão no pino 23 e agora ele sera desativado
Botão desligado
Botão desligado
Botão desligado
^CSaindo...

 

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:

#! /usr/bin/python
# -*- coding: utf-8 -*-

import Rpi.GPIO as gpio
import time


""" Global """
PIN1=23

""" Configurando GPIO """
# Configurando o modo do GPIO como BCM
gpio.setmode(gpio.BCM)

# Configurando PIN's como INPUT e modo pull-down interno
gpio.setup(PIN1, gpio.IN, pull_up_down = gpio.PUD_DOWN)



while True:
	try:
		print “Inicio loop...”
		
		gpio.wait_for_edge(PIN1, gpio.RISING)
		print “Botão foi pressionado”
		gpio.wait_for_edge(PIN1, gpio.FALLING)
		print “Botão foi liberado”
		
		print “Continua loop...”
		time.sleep(1)
	except (KeyboardInterrupt):
		print “Saindo...”
		gpio.cleanup()
		exit()

 

Executando o código:

[email protected] ~/python/rpio/ $ sudo python pushbutton_event_detect05.py
Inicio loop...
Botão foi pressionado
Botão foi liberado
Continua loop...
Inicio loop...
Botão foi pressionado
Botão foi liberado
Continua loop...
Inicio loop...
Botão foi pressionado
Botão foi liberado
Continua loop...
Inicio loop...
Botão foi pressionado
Botão foi liberado
Continua loop...
^CSaindo...

 

 

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.

 

Outros artigos da série

<< Raspberry PI - GPIO output com PythonRaspberry PI - PWM com Python >>
NEWSLETTER

Receba os melhores conteúdos sobre sistemas eletrônicos embarcados, dicas, tutoriais e promoções.

Obrigado! Sua inscrição foi um sucesso.

Ops, algo deu errado. Por favor tente novamente.

Licença Creative Commons Esta obra está licenciada com uma Licença Creative Commons Atribuição-CompartilhaIgual 4.0 Internacional.

Cleiton Bueno
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.

17
Deixe um comentário

avatar
 
7 Comment threads
10 Thread replies
1 Followers
 
Most reacted comment
Hottest comment thread
5 Comment authors
JonathanEmerson AlvesRoniere RezendeCleiton BuenoRoniere Rezende Recent comment authors
  Notificações  
recentes antigos mais votados
Notificar
Jonathan
Visitante
Jonathan

Os códigos de interrupção realmente funcionam? Testei no raspberry pi 3 e apenas fica retornando polling mesmo clicando no botão.

Cleiton Bueno
Visitante
Cleiton Bueno

Olá Jonathan, com a RaspberryPI B que foi escrito o artigo funcionava, como faz pouco mais de 3 anos, e a biblioteca com certeza lançou novas versões assim como RaspberryPI precisaria testar novamente com este ambiente atualizado e verificar o que mudou, ficou devendo uma posição sobre o atual funcionamento.

Emerson Alves
Visitante
Emerson Alves

Olá Cleiton,

Você pode me tirar uma dúvida? Qual a função do "break" dentro do if?

"while True:
if gpio.input(23) == gpio.LOW:
print(“Botão acionado”)
break
else:
printf(“Botão desligado”)"

Muito obrigado!

Cleiton Bueno
Visitante
Cleiton Bueno

Olá Emerson,

o break neste caso serve para assim que o botão for pressionado sai do loop while True.

Emerson Alves
Visitante
Emerson Alves

Olá Cleiton.

Apenas gostaria de agradecer pela brilhante explicação sobre os programas para Raspberry, você conseguiu tirar bastantes dúvidas minhas. Meu próximo passo, assim como o Roniere, é integrar o display de LCD com o controlador.

Muito obrigado! Abraços.

Cleiton Bueno
Visitante
Cleiton Bueno

Obrigado Emerson, fico feliz que tenha gostado.

Um abraço.

Roniere Rezende
Visitante
Roniere Rezende

Emerson, eu já consegui colocar para funcionar o LCD caso tenha alguma dúvida pode me procurar nas redes sociais que te ajudo.
Abraço!

Emerson Alves
Visitante
Emerson Alves

Sua ajuda seria muito bem vinda Roniere. Estou trabalhando no projeto de TCC e isso vai alavancar uma boa parte do trabalho.

Roniere Rezende
Visitante
Roniere Rezende

Olá Cleiton Bueno, o seu artigo está muito bom e atendeu meus objetivos de entender como utilizar as GPIOs como entrada. Mas pesquisei aqui sobre o seu próximo artigo sobre PWM e não o encontrei. Houve sequência nos seus artigos? Abraço!

Cleiton Bueno
Visitante
Cleiton Bueno

Olá Roniere, que bom que gostou do artigo. Você tem razão era para ter uma sequencia com PWM, posso testar novamente, na época com a versão utilizada o PWM ficou muito ruim e com alto overload de CPU, não achei plausível de um artigo.

Acho que vou retestar para tentar cumprir esta promessa.

Um abraço.

Roniere Rezende
Visitante
Roniere Rezende

Cleiton, esses dias eu fiz dois códigos usando o controle PWM. Um usando dois leds, um aumentava a sua luminosidade ao mesmo tempo que o outro iria diminuindo quando chegava nos seus limites retornavam ao estado inicia.O outro, eu controlava o duty cycle usando dois botões, um para aumenta e outro para dimunuir. Ficaram bem simples e interessantes para usuários iniciantes como eu. Se quiser, posso te envio os códigos e você faz o artigo em cima deles. Ou gostaria de sugerir, um artigo falando como usar display LCD na Raspberry, é isso que estou estudando como fazer agora. Abraço!

Cleiton Bueno
Visitante
Cleiton Bueno

Legal Roniere, tenho uma proposta melhor para você, porque tu não escreve um artigo para o Embarcados? Eu ajudo na revisão.

Roniere Rezende
Visitante
Roniere Rezende

Podemos pensar nisso Cleiton. Mas podemos conversar mais reservadamente sobre isso, pode me passar alguma forma de contatar você?

Roniere Rezende
Visitante
Roniere Rezende

Cleiton, como podemos iniciar os trabalhos. Estou no seu aguardo!

trackback

[…] e, para isto, instalamos um módulo chamado RPi.GPIO, que pode ser conferido na primeira parte [1] sobre input e na segunda parte [2] sobre […]

trackback

[…] Raspberry Pi – GPIO input com Python [12], escrito por Cleiton […]

trackback

[…] PI – GPIO input com Python [18], escrito por Cleiton […]