You are on page 1of 12

Hlio Sousa Mendona

Pginas da Atividade Docente e de Investigao

6. GPIO
Interface GPIO

As placas Raspberry Pi possuem uma interface GPIO (General Purpose Input/Output) para ligao a componentes
eletrnicos externos.

Esta interface composta por 40pinos tal como a seguinte imagem mostra:

Entre estes pinos possvel encontrar:

pinos de alimentao: GND, 5V e 3.3V


pinos de canaisde comunicao: UART, I2C e SPI
pinos genricos de entrada/sada

Nesta pgina iremos abordar precisamente o uso destes ltimos.

Cuidadoseltricos a ter

Os pinos denidos como sadas apresentamtenses de cerca de 0V no caso do nvel lgico 0, e cerca de 3,3V para o
nvel lgico 1. Este valor de tenso, mesmo quando ligado a um dispositivo alimentado com5V, continua em geral a ser
visto como um valor lgico 1.
Por seu lado as correntes no devero superar os 16mA por pino (50mA no cmputo geral de todos os pinos). Por
exemplo, ao ligarmos um LED (cuja tenso de conduo de cerca de 2V) com uma resistncia de 1k, a corrente
envolvida seria de 1,3mA que estando bem abaixo do limite citado continua a acender sucientemente o LED.

Caso se pretendam correntes maiores (por exemplo para controlar um rel) teremos que recorrer a circuito baseado
num transstor.

No caso das entradas preciso ter o cuidado de no se ultrapassar a tenso de 3,3V. Casoo sinal a ligar a uma entrada
est na gama 0..5V, ser necessrio usarumadaptador de nveis. ou um simples divisor de tenso (entre uma
resistncia de 1,8k e outra de 3,3k).

Biblioteca pigpio

Para se usar os pinos presentes na interface GPIO das placas Raspberry Pi iremos usar abibliotecapigpio. Essa
bilbioteca possui um mdulo Pythonque solicitatodas as funcionalidades decontrolodesse interface, a um programa
(pigpiod) que corre em background na placa. Os recursos requeridos por esse programa (daemon) podem ser visto
atravs do comando:
top

Existem solues alternativas como por exemplo o packageRPi.GPIO. Contudo a biblioteca pigpio possui caractersticas
interessantes, nomeadamente a possibilidade de poder ser usada de forma remota. Ou seja, possvel controlar o
interface da placa mesmo estando o programa Python a correr num computador remoto, bastando para tal que se
estabelea uma ligao de rede placa. No nosso caso, tal como foi explicado aqui, a ligao faz-se pelo IP10.0.0.1XX.

Para isso ser necessrio instalar a biblioteca pigpio tambm no computador. No caso do Windows isso faz-seabrindo
uma janela PowerShell e executando o comando:
pip install http://abyz.co.uk/rpi/pigpio/pigpio.zip

Isto vai adicionar a biblioteca na pastaC:\Python27\Lib\site-packages.

Projeto GPIO

Vamos agora criar um projeto Pythonno Eclipse designado GPIO e que servir para demonstrar as diversas
funcionalidades associadas aos pinos deentrada/sada presentes na interface GPIO.

Com a perspetiva PyDev ativa, fazer:

File > New > PyDev Project


Project name: GPIO
Finish
File > New > File
File name: GPIO.py
Finish

Editar o cheiro GPIO.py com o seguinte cdigo, no esquecendo de editar o IP para o da placa de cada grupo:

1 import platform
2 import pigpio
3
4 if platform.uname()[4][0:3] == "arm":
5 pi = pigpio.pi()
6 else:
7 pi = pigpio.pi("10.0.0.1XX") # altere o IP para o da sua placa
8
9 print("pigpio v{} @ {}".format(pi.get_pigpio_version(), platform.uname()[0]))
10
11 pi.stop()

Para executar o programa, fazer:

Run > Run > Python Run

A resposta comprova que o programa correu no PC Windows:


pigpio v31 @ Windows

De seguida faa copy/paste do cheiro GPIO.py para a pasta edm da placa Raspberry Pi (usando a perspetiva Remote
System Explorer).

Estabeleauma ligao SSH com a placa e execute o comando:


python ~/edm/GPIO.py

Aresposta mostra que desta vez o programa correu no sistema operativo Linux da placa:
pigpio v31 @Linux

Entradas/sadas

As vrias funcionalidades associadas ao uso das portas de entrada/sada sero seguidamente demonstradas atravs do
seguinte circuito, composto por dois botes (Bp e Bi) e trs LEDs (Lr: vermelho, Ly: amarelo, e Lg: verde):
Sadas

Vamos comear por ligar o LED Lr durante 3segundo:

1 import platform
2 import pigpio
3 import time
4
5 if platform.uname()[4][0:3] == "arm":
6 pi = pigpio.pi()
7 else:
8 pi = pigpio.pi("10.0.0.1XX") # altere o IP para o da sua placa
9
10 Lr = 16
11 pi.set_mode(Lr, pigpio.OUTPUT)
12 pi.write(Lr, 1)
13 time.sleep(3)
14 pi.write(Lr, 0)
15
16 pi.stop()

O impulso assim gerado, quando de durao at 100s, pode ser obtido de forma mais simples e precisa recorrendo
funogpio_trigger(). No exemplo seguinte ser igualmente gerado um impulso de 50s no pino ligado ao LED Lr:

1 import platform
2 import pigpio
3 import time
4
5 if platform.uname()[4][0:3] == "arm":
6 pi = pigpio.pi()
7 else:
8 pi = pigpio.pi("10.0.0.1XX") # altere o IP para o da sua placa
9
10 Lr = 16
11 pi.set_mode(Lr, pigpio.OUTPUT)
12 pi.gpio_trigger(Lr, 50, 1)
13 pi.write(Lr, 1)
14 time.sleep(3)
15 pi.write(Lr, 0)
16
17 pi.stop()

Desta forma evita-se a necessidade de implementar a sequncia ligar/delay/desligar (ou vice-versa). Observe no
osciloscpio o sinal assim produzido para o LED Lr.

Entradas

Vamos agora s ligar o LED Lr aps se premir o boto Bp (ativo ao nvel baixo):

1 import platform
2 import pigpio
3 import time
4
5 if platform.uname()[4][0:3] == "arm":
6 pi = pigpio.pi()
7 else:
8 pi = pigpio.pi("10.0.0.1XX") # altere o IP para o da sua placa
9
10 Bp = 23
11 pi.set_mode(Bp, pigpio.INPUT)
12 while pi.read(Bp):
13 time.sleep(.05)
14
15 Lr = 16
16 pi.set_mode(Lr, pigpio.OUTPUT)
17 pi.write(Lr, 1)
18 time.sleep(3)
19 pi.write(Lr, 0)
20
21 pi.stop()

De notar a importncia de dentro do ciclo while colocar um sleep (em lugar dum simples pass) para que assim o
microprocessador no que demasiado sobrecarregado. Comprove esta situao recorrendo ao comando top depois
de executar o programa na placa.

Uma forma alternativade aguardar pela ocorrncia duma transio recorrer funowait_for_edge():

1 import platform
2 import pigpio
3 import time
4
5 if platform.uname()[4][0:3] == "arm":
6 pi = pigpio.pi()
7 else:
8 pi = pigpio.pi("10.0.0.1XX") # altere o IP para o da sua placa
9
10 Bp = 23
11 pi.set_mode(Bp, pigpio.INPUT)
12 while not pi.wait_for_edge(Bp, pigpio.FALLING_EDGE, 30):
13 pass
14
15 Lr = 16
16 pi.set_mode(Lr, pigpio.OUTPUT)
17 pi.write(Lr, 1)
18 time.sleep(3)
19 pi.write(Lr, 0)
20
21 pi.stop()

De notar a existncia dum timeout (30 segundos neste caso) ao m do qual, caso no ocorra a transio pretendida, a
funo retorna Falso.

Pull-Ups/Downs

No circuito apresentado s a presena da resistncia de pull-up no boto Bp permite obter um nvel lgico denido
quando ele no est premido. contudo possvel dispensar essa resistncia caso se indique ao microprocessador para
a colocar internamente no pino correspondente:

1 import platform
2 import pigpio
3 import time
4
5 if platform.uname()[4][0:3] == "arm":
6 pi = pigpio.pi()
7 else:
8 pi = pigpio.pi("10.0.0.1XX") # altere o IP para o da sua placa
9
10 Bp = 23
11 pi.set_mode(Bp, pigpio.INPUT)
12 pi.set_pull_up_down(Bp, pigpio.PUD_UP)
13 while pi.read(Bp):
14 time.sleep(.05)
15
16 Lr = 16
17 pi.set_mode(Lr, pigpio.OUTPUT)
18 pi.write(Lr, 1)
19 time.sleep(3)
20 pi.write(Lr, 0)
21
22 pi.stop()

Dependendo da forma como o boto est ligado, em vez duma resistncia de pull-up (PUD_UP), poder ser necessrio
colocar uma de pull-down (PUD_DOWN), ou no colocar nenhuma (PUD_OFF que a situao que ocorre partida).

Callbacks

svezes pode ser contudo prefervel no bloquear a execuo dum programa pela espera da alterao do estado
duma entrada, mas sim denir uma funo de callback, que ser chamada sempre que essa entrada apresentar uma
determinada transio:

ascendente (RISING_EDGE)
descendente (FALLING_EDGE)
ambas (EITHER_EDGE)

A verso seguinte do nosso programa de demonstrao ir incrementar um contador sempre que secarregar no boto
Bi:

1 import platform
2 import pigpio
3 import time
4
5 if platform.uname()[4][0:3] == "arm":
6 pi = pigpio.pi()
7 else:
8 pi = pigpio.pi("10.0.0.1XX") # altere o IP para o da sua placa
9
10 counter = 1
11
12 def onBi(gpio, level, tick):
13 global counter
14
15 print(gpio, level, tick)
16 print(counter)
17 counter = counter + 1
18
19 Bi = 24
20 pi.set_mode(Bi, pigpio.INPUT)
21 pi.callback(Bi, pigpio.FALLING_EDGE, onBi)
22
23 Bp = 23
24 pi.set_mode(Bp, pigpio.INPUT)
25 while pi.read(Bp):
26 time.sleep(.05)
27
28 Lr = 16
29 pi.set_mode(Lr, pigpio.OUTPUT)
30 pi.write(Lr, 1)
31 time.sleep(3)
32 pi.write(Lr, 0)
33
34 pi.stop()
Debouncing

Este programa padece contudo dum problema associado ao fenmeno de bouncing do boto. Um aparente bug na
biblioteca pigpio parece tambm impedir a deteo do primeiro toque no boto.

Uma soluoque contorna estes problemas seria a seguinte:

1 import platform
2 import pigpio
3 import time
4
5 if platform.uname()[4][0:3] == "arm":
6 pi = pigpio.pi()
7 else:
8 pi = pigpio.pi("10.0.0.1XX") # altere o IP para o da sua placa
9
10 counter = 1
11 lastTick = 0
12
13 def onBi(gpio, level, tick):
14 global counter
15 global lastTick
16
17 if tick - lastTick > 500000:
18 if level == 0 or lastTick == 0:
19 lastTick = tick
20 print(counter)
21 counter = counter + 1
22
23 Bi = 24
24 pi.set_mode(Bi, pigpio.INPUT)
25 pi.callback(Bi, pigpio.EITHER_EDGE, onBi)
26
27 Bp = 23
28 pi.set_mode(Bp, pigpio.INPUT)
29 while pi.read(Bp):
30 time.sleep(.05)
31
32 Lr = 16
33 pi.set_mode(Lr, pigpio.OUTPUT)
34 pi.write(Lr, 1)
35 time.sleep(3)
36 pi.write(Lr, 0)
37
38 pi.stop()

PWM

Vamos agora supor que no nal do programa se pretende gerar para oLED Lg um sinal com uma frequncia de
1000Hz, que a cada segundo vai alterando o seu duty-cycle* para: 0%, 10%, 20%, etc. at 100%.
* Percentagem do perodo em que o sinal vale 1.

Embora se pudesse pensar que tal poderia ser feito com o ligar e desligar do LED em instantestemporais controlados
pela funo sleep(), tal no seria vivel dadas as temporizaes demasiado apertadas que a frequncia em causa
implica.Em alternativa iremos sim usar a funcionalidade de gerao dum sinal PWM:

1 import platform
2 import pigpio
3 import time
4
5 if platform.uname()[4][0:3] == "arm":
6 pi = pigpio.pi()
7 else:
8 pi = pigpio.pi("10.0.0.1XX") # altere o IP para o da sua placa
9
10 Bi = 24
11 pi.set_mode(Bi, pigpio.INPUT)
12
13 Bp = 23
14 pi.set_mode(Bp, pigpio.INPUT)
15 while pi.read(Bp):
16 time.sleep(.05)
17
18 Lr = 16
19 pi.set_mode(Lr, pigpio.OUTPUT)
20 pi.write(Lr, 1)
21 time.sleep(3)
22 pi.write(Lr, 0)
23
24 Lg = 21
25 pi.set_mode(Lg, pigpio.OUTPUT)
26 pi.set_PWM_frequency(Lg, 1000)
27 for duty in range(0, 101, 10):
28 pi.set_PWM_dutycycle(Lg, int(duty*255/100))
29 print("duty-cycle = {:3d}%".format(duty))
30 time.sleep(1)
31 pi.write(Lg, 0)
32
33 pi.stop()

Sugere-se a visualizao no osciloscpio do sinal gerado. Como se pode constatar, apesar dele continuar a ser um sinal
digital, do ponto de vista de precesso da intensidade do LED pelo olho humano, d a sensao de que se trata dum
sinal analgico deamplitude igual ao valor mdio do sinal.

A gerao de sinais peridicos com uma determinada frequncia pode ser tambm usada para alimentar um altifalante
produzindo-se assim a nota musical correspondente.

Waveforms

Caso o sinal a gerar tenha caractersticas menos regulares, ser necessrio recorrer a uma outra funcionalidade
fornecida pela biblioteca pigpio: a gerao de waveforms. Para tal sero denidos os diferentes impulsos que o
compem indicando os instantes em que ocorrem.

Aseguinte verso do programa gera em paralelo com o processo PWM j descrito, um sinal para o LED Lr que simula
um bater de corao.

1 import platform
2 import pigpio
3 import time
4
5 if platform.uname()[4][0:3] == "arm":
6 pi = pigpio.pi()
7 else:
8 pi = pigpio.pi("10.0.0.1XX") # altere o IP para o da sua placa
9
10 Bi = 24
11 pi.set_mode(Bi, pigpio.INPUT)
12
13 Bp = 23
14 pi.set_mode(Bp, pigpio.INPUT)
15 while pi.read(Bp):
16 time.sleep(.05)
17
18 Lr = 16
19 pi.set_mode(Lr, pigpio.OUTPUT)
20 pi.write(Lr, 1)
21 time.sleep(3)
22 pi.write(Lr, 0)
23
24 heart = []
25 heart.append(pigpio.pulse(1<<Lr, 0, 100000))
26 heart.append(pigpio.pulse(0, 1<<Lr, 100000))
27 heart.append(pigpio.pulse(1<<Lr, 0, 100000))
28 heart.append(pigpio.pulse(0, 1<<Lr, 700000))
29 pi.wave_clear()
30 pi.wave_add_generic(heart)
31 heartWave = pi.wave_create()
32 pi.wave_send_repeat(heartWave)
33
34 Lg = 21
35 pi.set_mode(Lg, pigpio.OUTPUT)
36 pi.set_PWM_frequency(Lg, 1000)
37 for duty in range(0, 101, 10):
38 pi.set_PWM_dutycycle(Lg, duty)
39 print("duty-cycle = {:3d}%".format(duty))
40 time.sleep(1)
41 pi.write(Lg, 0)
42
43 pi.wave_tx_stop()
44 pi.wave_clear()
45 pi.write(Lr, 0)
46
47 pi.stop()

Neste exemplo a forma de onda (waveform) gerada de forma cclica (wave_send_repeat) mas podia ser gerada de
forma pontual (wave_send_once).

Temporizaes

Por m imagine que pretende incluir a possibilidade de interromper o perodo de3 segundos durante o qual o LED Lr
foi ligado, caso se prima o boto Bi.

A linha de cdigo at aqui usadatime.sleep(3)impediria que durante esse perodo fosse lido o estado do boto pois o
processo estaria adormecido. Uma alternativa seria a implementao dum ciclo enquanto notivessem decorrido os
3 segundos (algo que se pode controlar pelos microsegundos retornados pela funoget_current_tick). Para que o
processador no que contudo sobrecarregado com a execuo contnua do whileser importante a introduo dum
pequeno sleep em cada ciclo. A durao deste sleep ser um compromisso entre tempo de resposta ao boto e
sobrecarga do processador. No seguinte exemplo o valor usado foi de 50ms:

1 import platform
2 import pigpio
3 import time
4
5 if platform.uname()[4][0:3] == "arm":
6 pi = pigpio.pi()
7 else:
8 pi = pigpio.pi("10.0.0.1XX") # altere o IP para o da sua placa
9
10 Bi = 24
11 pi.set_mode(Bi, pigpio.INPUT)
12
13 Bp = 23
14 pi.set_mode(Bp, pigpio.INPUT)
15 while pi.read(Bp):
16 time.sleep(.05)
17
18 Lr = 16
19 pi.set_mode(Lr, pigpio.OUTPUT)
20 pi.write(Lr, 1)
21 start = pi.get_current_tick()
22 while pi.get_current_tick() - start < 3000000: # 3 segundos
23 if pi.read(Bi) == 0: break
24 time.sleep(.05)
25 pi.write(Lr, 0)
26
27 pi.stop()

Projetos propostos

Seguidamente sero propostos dois projetos a desenvolver pelos estudantes com base nos conhecimentos adquiridos
ao longo desta pgina.

Semforo

Pretende-se desenvolver um programa que controle um semforo para automveis situado junto a uma passadeira
para pees.Note queos tempos referidos deseguida embora irrealistas, tornam o processo de simulao mais rpido!

O ciclo normal de funcionamento ser de 9 segundos em verde (LEDLg), 1 segundo em amarelo (Ly) e 5 segundos em
vermelho (Lr).

Caso seja premido o boto dos pees (Bp) o tempo de verde dever ser imediatamente terminado desde que j
tenham decorrido 4 segundos. Se esse tempo ainda no decorreu a passagem para amarelo dever ocorrer s aps
esses 4 segundos.

O boto Bi servir para que na central de controlo do trfego se inicie/termine o modo intermitente no semforo.
Neste modo o semforo dever ter o amarelo a piscar ciclicamente (1 segundo ligado, 1 segundo desligado).

Display

Neste projeto pretende-se ligar um display de 7 segmentos placa Raspberry Pi. Embora existam pinos disponveis
para ligar individualmente os vrios segmentos, neste caso pretende-se recorrer a um registo de deslocamento
(74HC595) o que permite o uso de apenas 3 pinos (Dat, Clk e Set).

Como o seguinte circuito mostra, iremos usar apenas uma resistncia limitadora de corrente no ctodo comum do
display em lugar duma resistncia por nodo. Desta forma a montagem ser mais simples embora se possam registar
brilhos diferentes nos segmentos.
Desenvolva uma funo Pythoncapaz de apresentar no display o nmero que lhe passado como argumento:

1 import platform
2 import pigpio
3 import time
4
5 if platform.uname()[4][0:3] == "arm":
6 pi = pigpio.pi()
7 else:
8 pi = pigpio.pi("10.0.0.1XX") # altere o IP para o da sua placa
9
10 Dat = 18
11 Clk = 14
12 Set = 15
13
14 def display(num):
15 print(num)
16 # adicione aqui o seu codigo
17
18 for n in range(0, 10):
19 display(n)
20 time.sleep(1)
21
22 pi.stop()

Recorra a esta funo para implementar no projeto semforo uma contagem decrescente durante o perodo de verde
para os pees (durante os 5 segundos em que o LED Lr est ativo).
sample

You might also like