Raspberry Pi – Sterowanie portami GPIO w Pythonie

Kiedy postawiliśmy już system na malince oraz zabezpieczyliśmy kartę pamięci przed zbyt szybkim zużyciem pora na krótki wstęp do sterowania portami GPIO. W dzisiejszym artykule poznamy podstawową składnię języka Python (np. jak stworzyć zmienną, funkcję lub napisać pętlę) a także dowiemy się w jaki sposób Python może pomóc nam sterować portami GPIO (czyli np. zaświecić diodę LED lub wykryć wciśnięcie przycisku).

Podstawy Pythona

Aby uruchomić interpreter Pythona, który będzie na żywo przetwarzał nasze polecenia wystarczy wpisać w konsoli Raspberry polecenie python. Aby opuścić program możemy wywołać funkcję exit()

Komentarze

Komentarz zaczyna się znakiem # (pod warunkiem, że nie jest on pomiędzy cudzysłowami – wtedy jest to normalnie część stringa)

# oto przykładowy komentarz :)
x = 5 # to też jest komentarz
y = "# to nie jest komentarz :("

Zmienne

Python jest językiem typowanym dynamicznie, dlatego przy tworzeniu zmiennej nie musimy podawać jej typu.

calkowita = 5
zmiennoprzecinkowa 9.6
ciag_znakow = "To jest ciag znakow"
ciag_znakow2 = 'To tez jest ciag znakow'

Należy zauważyć, że stringi w Pythonie możemy wpisywać używająć cudzysłowu ( ” ) lub apostrofu ( ’ ).

Wcięcia, wcięcia jeszcze raz wcięcia

Przed omówieniem pętli i funkcji warto zwrócić uwagę na to, że w Pythonie nie używamy średników ani klamerek otwierających i zamykających bloki kodu { }. Zamiast tego używamy odpowiedniej indentacji. W ten sposób mając np. dwie zagnieżdżone pętle zawartość pierwszej będzie wcięta jednym tabem, natomiast zawartość drugiej dwoma tabami. Za chwilę zobaczycie o co chodzi na realnym przykładzie :)

Pętla for

Pętla for w Pythonie jest w zasadzie pętlą foreach znaną z innych języków. Iteruje ona po danym zbiorze, a nie według warunku pętli.

Dla zademonstrowania o co chodzi użyjemy funkcji range(x), która zwraca nam zbiór liczb całkowitych od 0 do x-1.

>>> range(5)
[0, 1, 2, 3, 4]

Tworząc pętlę for iterującą zmienną x od 0 do 4 w języku Python wpiszemy następującą formułkę:

for x in range(5):
  print x

Jak widać linijka print x jest wcięta jedną tabulacją.

Gdybyśmy chcieli zagnieździć w sobie dwie pętle for ciało drugiej pętli musiałoby być wcięte o kolejny tabulator:

output = ""
for x in range(3):
  for y in range(4):
    output += str(x*y) + " "
  print output
  output = ""

W ten sposób na wyjściu uzyskamy

0 0 0 0 
0 1 2 3 
0 2 4 6

Funkcja range może przyjmować także więcej parametrów. Jeżeli przekażemy jej dwa argumenty x oraz y to zwróci zbiór liczb całkowitych od x do y-1.

>>> range(1,5)
[1, 2, 3, 4]

W przypadku wywołania range(x, y, z) otrzymamy zbiór od x do y-1 z krokiem do z.

>>> range(1, 10, 2)
[1, 3, 5, 7, 9]

Z racji tego, że for jest foreachem i może przyjmować dowolny zbiór spróbujmy takiej sztuczki:

zbior = [1,1,2,3,5,8,13]
output = ""
for x in zbior:
  output += str(x) + " "
print output

Jak się zapewne domyślacie na wyjściu otrzymamy

1 1 2 3 5 8 13

Tak jak w przypadku innych języków z pętli możemy wyjść przed jej planowanym końcem słówkiem kluczowym break, oraz przejść do kolejnej iteracji słowem continue.

Ponadto możemy użyć klauzuli else na końcu pętli. Wykona się ona w przypadku kiedy zbiór po którym pętla iteruje się wyczerpie, ale nie kiedy pętla została przerwana przez break.

Przykładowo wykonując kod

for x in range(5):
  print x
  break
else:
  print "Koniec zbioru"

Program wypisze nam na wyjście tylko 0. Jeżeli jednak zakomentujemy linijkę ze słowem break to na wyjściu otrzymamy

0
1
2
3
4
Koniec zbioru

Instrukcja warunkowa

Chcąc sprawdzić jakiś warunek wystarczy, że napiszemy

x = 10
if x > 5:
  print "x jest wiekszy od 5"

i już :) Jeżeli jednak chcemy nieco rozbudować naszą instrukcję warunkową możemy użyć klauzul elif oraz else.

x = 10
if x > 5:
  print "x jest wiekszy od 5"
elif x < 5:
  print "x jest mniejszy od 5"
else:
  print "x jest rowny 5"

Pętla while

Pętla while także może zawierać klauzulę else. Wykona się ona w przypadku kiedy warunek pętli będzie fałszywy, nie wykona się natomiast kiedy sami przerwiemy pętlę.

x = 5
while x < 10:
  print x
  x += 1
  break
else:
  print "Warunek petli falszywy"

Wynik: 5

Kiedy zakomentujemy break na wyjściu otrzymamy

5
6
7
8
9
Warunek petli falszywy

Funkcje

Własną funkcję możemy utworzyć według następującej składni: def nazwa_funkcji(argument1, argument2):

Przykładowo funkcja wypisująca na wyjście wynik mnożenia liczb a i b, zwraca ten wynik w postaci liczby oraz jej wywołanie:

def pomnoz(a, b):
  wynik = a * b
  print str(a) + " x " + str(b) + " = " + str(wynik)
  return wynik

pomnoz(3,4)
wynik = pomnoz(5,5)
print wynik

Wynik tych operacji to:

3 x 4 = 12
5 x 5 = 25
25

Plik wykonywalny pythona

Aby używac Pythona nie musimy za każdym razem uruchamiać interpretera i wpisywać w nim ręcznie wszystkich poleceń. Możemy utworzyć plik z rozszerzeniem .py oraz nadać mu prawa do wykonywania, a następnie wykonać za pomocą komendy python nazwa_skryptu

Przykład:

krupson@raspberrypi:~ $ echo "print 'Hello World'" > hello_world.py
krupson@raspberrypi:~ $ chmod +x hello_world.py 
krupson@raspberrypi:~ $ python hello_world.py 
Hello World

 

Sterowanie GPIO w RaspberryPi

Znamy już podstawy pythona na tyle, żeby móc wysterować porty wejścia wyjścia w malince.

Pierwsze co musimy zrobić w naszym pliku ze skryptem to zaimportowanie biblioteki do sterowania portami GPIO. W tym celu na początku piszemy

import RPi.GPIO as GPIO

Dzięki temu będziemy mogli się dostać do metod klasy RPi.GPIO odwołując się do nich przez GPIO.nazwa_metody.

Następnie musimy ustalić tryb w jakim będziemy odwoływali się do pinów. Może to być:

  • GPIO.BOARD – odwołanie bezpośrednio do numeru pinu w złączu, zalecam ten tryb ze względu na to, że jest uniwersalny dla wszystkich malinek.
  • GPIO.BCM – odwołanie do numeru pinu na procesorze – może być różne w różnych wersjach Raspberry.

tryb ustawiamy za pomocą GPIO.setmode(GPIO.BOARD)

Teraz możemy wybrać któryś z pinów i ustalić czy będzie wjeściem, czy wyjściem (odpowiednik funkcji pinMode() z Arduino).

przycisk = 36
dioda = 40

GPIO.setup(przycisk, GPIO.IN) #pin 36 bedzie wejsciem
GPIO.setup(dioda, GPIO.OUT) #pin 40 bedzie wyjsciem

Możemy także ustawić pin jako wejście z rezystorem podciągającym lub ściągającym. WYstarczy wywołać

GPIO.setup(numer_pinu, GPIO.IN, pull_up_down=GPIO.PUD_UP) # Rezystor podciagajacy do +3V3
  # lub
GPIO.setup(numer_pinu, GPIO.IN, pull_up_down=GPIO.PUD_DOWN) # Rezystor sciagajacy do masy

Stan pinu wyjściowego możemy ustalić przy pomocy

GPIO.output(numer_pinu, GPIO.HIGH) # stan wysoki
    # lub
GPIO.output(numer_pinu, GPIO.LOW) # stan niski

Natomiast odczytujemy w następujący sposób:

GPIO.input(numer_pinu)

Wynik tej metody możemy porównać do GPIO.HIGH lub GPIO.LOW.

Po wszystkim możemy po sobie posprzątać resetując ustawienia GPIO do domyślnych za pomocą

GPIO.cleanup()

opcjonalnie podając numer pinu, który chcemy przywrócić do stanu domyślnego. Jeżeli tego nie zrobimy wyzerowane zostaną wszystkie piny.

Przykładowy program

Dla zademonstrowania działania portów GPIO na żywym organizmie napisałem prosty program, który sprawdzi czy przycisk jest wciśnięty. Jeżeli tak to zaświeci diodę i będzie czekał na puszczenie przycisku. Wtedy zgasi diodę i zakończy działanie. Jeżeli przycisk nie będzie wciśnięty to tylko o tym poinformuje i natychmiast zakończy działanie.

import RPi.GPIO as GPIO
import time

ledPin = 40
btnPin = 5

GPIO.setmode(GPIO.BOARD)

GPIO.setup(ledPin, GPIO.OUT)
GPIO.setup(btnPin, GPIO.IN)

btnState = GPIO.input(btnPin)

if btnState:
        print 'Przycisk nie jest wcisniety'
else:
        print 'Przycisk jest wcisniety'

GPIO.output(ledPin, not btnState)

while GPIO.input(btnPin) == GPIO.LOW:
        pass

GPIO.cleanup()
print 'Koniec programu'

Przycisk podłączyłem do pinu 5 podciągając go rezystorem do pinu 3.3V. Dioda LED podłączona jest do pinu numer 40.

Należy pamiętać, aby pod żadnym pozorem nie podłączyć do żadnego pinu Raspberry napięcia 5V. Natychmiast zabije to dany pin.

PROTIP: Piny 5V sąsiadują ze zobą, więc żeby przypadkiem nie podłączyć tam nic tworząc połączenia można założyć na nie zworkę i zdejmować ją tylko wtedy, gdy świadomie potrzebujemy użyć napięcia 5V. Niestety wpadłem na ten pomysł dopiero po tym jak nieumyślnie upaliłem dwa piny w swojej malinie :D

Na poniższej grafice przedstawiono numery pinów zgodnie z trybem GPIO.BOARD:

Grafika pochodzi ze strony https://www.raspberrypi.org/documentation/usage/gpio-plus-and-raspi2/ gdzie możecie poczytać więcej o GPIO w Raspberry.