Už tomu je 10 let, co redakce pořídila Počítač Raspberry Pi. A tak je načase udělat nějaký nový příspěvek. Oprášili jsme starý typ a pořídili nový výkonnější. Jde o Raspberry Pi 5 s 16GB RaAM a 512GB SSD v pouzdru PIRONMAN 5. Nainstalovaný je Linux UBUNTU 25.10.
V tomto článku najdete návod na vytvoření obvodu ze tří LED, které budete ovládat jako semafor.


Upozornění
NEZAPOJUJ LED BEZ ODPORU
To bylo napsanéna mé dětské elektronické stavebnici LOGITRONIK 01. Tak na to prosím myslete při zapojování, jinak se LED zničí.
Co mimo samotného Raspberry Pi potřebujete
- 3 LED (červenou, žlutou, zelenou)
- 3 odpory 220 až 330 Ω
- propojovací kabely
- nepájivé pole
- volitelně i GPIO Extension Board spolu s 40 žilovým GPIO plochým kabelem pro snadnější propojení GPIO k nepájivému poli
Použitý software
- Python 3 (ten už pravděpodobně bude nainstalovaný spolu s Ubuntu)
- VSCodium (s rozšířeními Python, Python Debugger a Python Environments)
- balíčky s knihovnami python3-tk, python3-gpiozero, python3-lgpio
Balíčky si nainstalují v teminálu:
sudo apt update
sudo apt install -y python3-tk python3-gpiozero python3-lgpio
Principy programu
- Základní vytvoření a nastavení grafickým okna s tlačítky v knihovně
tkinter - Práce s GPIO piny
- Vytvoření a nastavení jednoho vlákna ve kterém běží funkce blikání tak, aby nedošlo k zamrznutí hlavního okna
- Bezpečné zavření grafického okna, kdy jsou bezpečně vypnuty všechny výstupy.
- Funkce spouštěné tlačítky nejprve vypnou všechny led až pak zapnou požadovaný stav, aby jednotlivé režimy nebyly v kolizi.
Hlavní importy
Na začátku kódu je potřeba importovat knihovny a třídy.
import tkinter as tk
from gpiozero import LED
from time import sleep
import threading
import tkinter as tknačte knihovnu pro grafické okno. Zkratkaas tkznamená, že v kódu se pak místotkinter.Tk()píše kratšítk.Tk().from gpiozero import LEDvezme jen tříduLEDz knihovnygpiozero. Ta umí zapnout, vypnout a řídit LED přes GPIO.from time import sleeppřidá funkcisleep(), která pozastaví program na zadaný počet sekund.import threadingpřidá práci s vlákny, tedy možnost dělat blikání na pozadí, aby se nezaseklo GUI.
Nastavení pinů
GREEN_PIN = 22
YELLOW_PIN = 27
RED_PIN = 17
Tyto tři řádky pro větší přehlednost ukládají čísla GPIO pinů do proměnných. Pokud jsou LED připojeny k jinému pinu, stačí upravit číslo pinu zde.
Vytvoření objektů LED
green = LED(GREEN_PIN)
yellow = LED(YELLOW_PIN)
red = LED(RED_PIN)
Tady se vytvoří tři objekty reprezentující tři LED diody. Každý objekt je navázaný na konkrétní GPIO pin, takže lze volat například green.on() nebo red.off(). Zde se nastavuje, které fyzické piny bude knihovna ovládat.
Řídicí proměnné pro blikání
blink_thread = None
blink_stop = threading.Event()
blink_thread = Nonejen připraví proměnnou, do které se později uloží vlákno pro blikání.blink_stop = threading.Event()vytvoří „signál“, kterým se dá blikání bezpečně zastavit. Když se tento signál nastaví, smyčka pro blikání skončí.
Funkce all_off()
def all_off():
blink_stop.set()
green.off()
yellow.off()
red.off()
Tahle funkce vypne vše. Nejprve blink_stop.set() řekne vláknu s blikáním, že má skončit. Pak green.off(), yellow.off() a red.off() vypnou všechny LED. Je to důležité, protože tím zabráníš tomu, aby běželo blikání současně s jiným stavem světel.
Funkce pro jednotlivé stavy semaforu
def set_green():
all_off()
green.on()
- Nejprve vypne všechno.
- Pak zapne jen zelenou LED.
Stejně fungují i ostatní:
def set_yellow():
all_off()
yellow.on()
Zapne jen žlutou.
def set_red():
all_off()
red.on()
Zapne jen červenou.
def set_red_yellow():
all_off()
red.on()
yellow.on()
Zapne současně červenou a žlutou. To odpovídá stavu před změnou na zelenou u semaforu.
Funkce pro blikání žluté
def blink_yellow():
global blink_thread
all_off()
blink_stop.clear()
global blink_threadnastaví, že uvnitř funkce de bude pracovat s proměnnou mimo funkci.all_off()vypne předchozí stav.blink_stop.clear()zruší stop signál, aby blikání mohlo začít.
Pak následuje vnitřní funkce:
def worker():
while not blink_stop.is_set():
yellow.on()
sleep(0.5)
yellow.off()
sleep(0.5)
Tady se děje samotné blikání:
while not blink_stop.is_set():opakuje cyklus, dokud není požadavek na zastavení.yellow.on()rozsvítí žlutou LED.sleep(0.5)počká půl sekundy.yellow.off()LED zhasne.sleep(0.5)zase počká půl sekundy.
blink_thread = threading.Thread(target=worker, daemon=True)
blink_thread.start()
threading.Thread(...)vytvoří nové vlákno, které poběží souběžně s oknem.daemon=Trueznamená, že vlákno skončí spolu s programem.start()vlákno skutečně spustí.
Bez vlákna by okno při blikání „zamrzlo“, protože hlavní program by byl pořád v nekonečné smyčce.
Okno Tkinter
A nyní se vytvoří okno aplikace s tlačítky pro ovládání semaforu.
root = tk.Tk()
Vytvoří hlavní okno aplikace.
root.title("Semafor GPIO")
Nastaví titulek okna.
root.geometry("320x260")
Určí velikost okna.
root.resizable(False, False)
Zakáže změnu velikosti okna myší.
Tlačítka
Vzor pro vytvoření tlačítka je následující:
btn1 = tk.Button(root, text="Žlutá bliká", width=28, command=blink_yellow)
Tento příkaz vytvoří tlačítko.
rootje rodičovské okno.text="Žlutá bliká"je popisek tlačítka.width=28nastaví šířku tlačítka.command=blink_yellowříká, že po kliknutí se má spustit funkceblink_yellow().
Podobně se nastaví i ostatní tlačítka s jejich vlastním popisem a voláním příslušné funkce.
Umístění tlačítek
btn1.pack(pady=4)
pack() vloží tlačítko do okna a pady=4 přidá svislý okraj 4 pixely nahoře i dole. Stejný zápis se opakuje pro všechna tlačítka.
Zavření okna
def on_close():
all_off()
root.destroy()
Po zavření okna tato funkce nejdřív vypne LED a pak root.destroy() korektně ukončí celé GUI.
root.protocol("WM_DELETE_WINDOW", on_close)
Po kliknutí na křížek okna, místo standardního zavření se má zavolat on_close().
Spuštění GUI
root.mainloop()
To je hlavní smyčka Tkinteru. Bez ní by se okno hned zavřelo. Tato smyčka čeká na události, jako je kliknutí na tlačítko nebo zavření okna.
Celý kód
import tkinter as tk
from gpiozero import LED
from time import sleep
import threading
GREEN_PIN = 22
YELLOW_PIN = 27
RED_PIN = 17
green = LED(GREEN_PIN)
yellow = LED(YELLOW_PIN)
red = LED(RED_PIN)
blink_thread = None
blink_stop = threading.Event()
def all_off():
blink_stop.set()
green.off()
yellow.off()
red.off()
def set_green():
all_off()
green.on()
def set_yellow():
all_off()
yellow.on()
def set_red():
all_off()
red.on()
def set_red_yellow():
all_off()
red.on()
yellow.on()
def blink_yellow():
global blink_thread
all_off()
blink_stop.clear()
def worker():
while not blink_stop.is_set():
yellow.on()
sleep(0.5)
yellow.off()
sleep(0.5)
blink_thread = threading.Thread(target=worker, daemon=True)
blink_thread.start()
def on_close():
all_off()
root.destroy()
root = tk.Tk()
root.title("Semafor GPIO")
root.geometry("320x260")
root.resizable(False, False)
btn1 = tk.Button(root, text="Žlutá bliká", width=28, command=blink_yellow)
btn2 = tk.Button(root, text="Zelená svítí", width=28, command=set_green)
btn3 = tk.Button(root, text="Žlutá svítí", width=28, command=set_yellow)
btn4 = tk.Button(root, text="Červená svítí", width=28, command=set_red)
btn5 = tk.Button(root, text="Červená a žlutá svítí", width=28, command=set_red_yellow)
btn6 = tk.Button(root, text="Vypnout všechny LED", width=28, command=all_off)
btn1.pack(pady=4)
btn2.pack(pady=4)
btn3.pack(pady=4)
btn4.pack(pady=4)
btn5.pack(pady=4)
btn6.pack(pady=4)
root.protocol("WM_DELETE_WINDOW", on_close)
root.mainloop()
Schema zapojení



