Inhaltsverzeichnis
PiFace Control and Display (CAD) - Kurzreferenz und Beispiele
Das PiFace Control and Display (CAD) ist eine Erweiterungsplatine für den Raspberry Pi. Neben einem Display verfügt das Board über IR-Receiver, 5 Taster und einen Navigationsswitch. Die folgende Wikiseite soll den Einstieg in die Programmierung des Raspberry Pis/PiFace CADs mit Python erleichtern. Sie besteht aus einer kleinen Referenz aller wichtigen Funktionen und einigen Beispielen.
Hardwarevoraussetzungen: Raspberry Pi | PiFace Control and Display (CAD)
Softwarevoraussetzungen: Texteditor
Schwierigkeitsgrad: Einfach
Ausgetestet mit folgenden Betriebssystemen: Raspbian
PiFace Control and Display
Die zum Board gehörige Python Library (in den Raspbian Paketquellen verfügbar) bietet unter anderem folgende Funktionalitäten:
- das Display kann selbstverständlich angesteuert werden
- über LIRC können von einer IR-Fernbedienung gesendete „Befehle“ empfangen werden
- die 5 Taster können abgefragt werden
- der Navigationsschalter besteht aus drei Tastern, die einzeln abgefragt werden können
- auf die Taster können Interrupts gelegt werden, sodass beim Drücken ein bestimmter Programmteil ausgeführt wird
Ressourcen zum PiFace CAD
Einrichtung
Die Einrichtung des CADs ist in der offiziellen Einrichtungsanleitung sehr gut beschrieben. Deshalb wird an dieser Stelle nur der grobe Ablauf beschrieben. Die Python Library ist in dem Paket python3-pifacecad
(Python 3) bzw. python-pifacecad
(Python 2) enthalten:
pi@raspberrypi:~$ sudo apt-get install python{,3}-pifacecad
Nachdem SPI aktiviert und ein Reboot durchgeführt wurde, kann mit sysinfo.py
ein kleines Beispiel ausprobiert werden:
pi@raspberrypi:~$ python3 /usr/share/doc/python3-pifacecad/examples/sysinfo.py
Zu guter letzt muss noch LIRC eingerichtet werden.
Erklärung der wichtigsten Funktionen
Die Library einbinden & nutzen
Hier ein kleines Beispiel zu Nutzung der Library.
# Import der Library und Anlegen des Objekts import pifacecad # Library einbinden cad = pifacecad.PiFaceCAD() # nun kann über cad. auf die Funktionen der Library zurückgegriffen werden # Weiter gehts cad.lcd.blink_off() # Unterstrich bei Blinkendem Cursor aus cad.lcd.cursor_off() # & Cursor auschalten cad.lcd.clear() # das Display leeren cad.lcd.backlight_on() # das Backlight einschalten cad.lcd.write("Hello World!") # Hello World! ausgeben
Das Display ansprechen
Nachdem die Library eigebunden wurde, hier die wichtigsten Befehle um das Display anzusteuern. Eine vollständige Übersicht findet sich hier.
# Import der Library und Anlegen des Objekts import pifacecad cad = pifacecad.PiFaceCAD() # Die wichtigsten Befehle cad.lcd.blink_off() # Unterstrich bei Blinkendem Cursor aus cad.lcd.blink_on() # Unterstrich bei Blinkendem Cursor ein cad.lcd.cursor_off() # Cursor auschalten cad.lcd.cursor_on() # Cursor einschalten cad.lcd.backlight_on() # das Backlight einschalten cad.lcd.backlight_off() # das Backlight ausschalten cad.lcd.display_on() # das Display einschalten cad.lcd.display_off() # das Display ausschalten cad.lcd.clear() # das Display leeren cad.lcd.write("str") # str ausgeben; Wichtig: String übergeben! notfalls mit str() umwandeln cad.lcd.setcursor(1,0) # den Zeiger auf die 2te Spalte (1,) und in die 1te Zeile (,0) setzen # Eine benutzerdefiniertes Bitmap laden & anzeigen # siehe auch: https://piface.github.io/pifacecad/creating_custom_bitmaps.html # Generator: http://www.quinapalus.com/hd44780udg.html SYMBOL = pifacecad.LCDBitmap([1,3,15,15,15,3,1,0]) cad.lcd.store_custom_bitmap(0, SPEAKER) cad.lcd.write_custom_bitmap(0) # das benutzerdefinierte Bitmap auf das Display "zeichnen"
Die Taster abfragen
Die 8 vorhandenen Taster können einzeln abgefragt werden.
# Import der Library und Anlegen des Objekts import pifacecad cad = pifacecad.PiFaceCAD() # die Taster abfragen cad.switches[3].value # Taster 3 (der 4te) abfragen; 1 wenn gedrückt, 0 wenn nicht cad.switch_port.value # Tasterwert abfragen
Interrupts definieren
Um nicht ununterbrochen den Stand der Taster abfragen zu müssen (Polling), besteht die Möglichkeit sog. Interrupts zu definieren. D.h. bei Drücken eines Tasters reagiert der Pi automatisch.
# Import der Library und Anlegen des Objekts import pifacecad cad = pifacecad.PiFaceCAD() # eine Funktion erstellen, die bei einem Interrupt ausgeführt wird def handlePin(event): event.chip.lcd.clear() event.chip.lcd.write("button 0") # den Listener erstellen listener = pifacecad.SwitchEventListener(chip=cad) listener.register(0, pifacecad.IODIR_FALLING_EDGE, handlePin) # ...und aktivieren listener.activate()
Statt den Listener für jeden der 8 Taster (0 bis 7) einzeln anzulegen, kann auch eine Funktion definiert werden, die von allen Tastern „aufgerufen“ wird und dann z.b. intern eine Fallunterscheidung vornimmt.
# Import der Library und Anlegen des Objekts import pifacecad cad = pifacecad.PiFaceCAD() # eine Funktion, die in der Variable event.pin_num den gedrückten Pin erkennt definieren def handlePin(event): event.chip.lcd.clear() event.chip.lcd.write("button ") event.chip.lcd.write(str(event.pin_num)) # gibt den gedrückten Pin aus; str() wandelt event.pin_num (ein Integer) in einen String # Listener für alle Pins erstellen & aktivieren listener = pifacecad.SwitchEventListener(chip=cad) for i in range(8): listener.register(i, pifacecad.IODIR_FALLING_EDGE, handlePin) listener.activate()
Beispiele
Diese Beispiele müssen auf dem Pi gespeichert werden und wie folgt ausgeführt werden:
pi@raspberrypi:~$ python3 beispiel.py # Beispiel durch Pfad zum Beispiel ersetzen
Hello World
- helloWorld.py
import pifacecad cad = pifacecad.PiFaceCAD() cad.lcd.blink_off() cad.lcd.cursor_off() cad.lcd.clear() cad.lcd.backlight_on() cad.lcd.write("Hello World!")
Gedrückter Button ausgeben
Dieser Code gibt den gerade gedrückten Button auf dem Display aus.
- testcadbuttons.py
#!/usr/bin/env python3 import pifacecad # Init the CAD def initCad(): cad.lcd.blink_off() cad.lcd.cursor_off() cad.lcd.clear() cad.lcd.backlight_on() # Handle pushed pins def handlePin(event): event.chip.lcd.clear() event.chip.lcd.write("Pressed button:") event.chip.lcd.set_cursor(0, 1) event.chip.lcd.write(str(event.pin_num)) cad = pifacecad.PiFaceCAD() initCad() listener = pifacecad.SwitchEventListener(chip=cad) for i in range(8): listener.register(i, pifacecad.IODIR_FALLING_EDGE, handlePin) listener.activate()
Kleiner unvollständiger MPD Client
Der folgende MPD Client ist stark verienfacht und nicht vollständig. Insbesondere sei darauf hingwiesen, dass der Status (Play/Pause) nicht von MPD bezogen wird und auch noch keine Titelanzeige implementiert wurde.
- mpdclientmin.py
#!/usr/bin/env python3 # based on http://www.element14.com/community/community/raspberry-pi/raspberrypi_projects/blog/2014/01/18/internet-radio-with-raspberry-pi-piface-cad-and-mpdmpc import pifacecad import os import sys import subprocess from time import sleep backlight = 1 status = 1 # Init the CAD def initCad(): cad.lcd.blink_off() cad.lcd.cursor_off() cad.lcd.clear() cad.lcd.backlight_on() # Get volume from MPD def mpdVolume(): volume = subprocess.check_output("mpc status | grep volume", shell=True, stderr=subprocess.STDOUT) volume = volume.decode() volume = volume[7:volume.find("%")+1] cad.lcd.clear() cad.lcd.set_cursor(10, 1) cad.lcd.write_custom_bitmap(0) cad.lcd.write(volume) # Handle pushed pins def handlePin(event): global status global backlight if(event.pin_num == 0): os.system('mpc stop') elif(event.pin_num == 1): os.system('mpc prev') elif(event.pin_num == 2): os.system('mpc next') elif(event.pin_num == 3): if(status == 1): os.system('mpc pause') status = 0 else: os.system('mpc play') status = 1 elif(event.pin_num == 4): if(backlight == 1): event.chip.lcd.backlight_off() backlight = 0 else: event.chip.lcd.backlight_on() backlight = 1 elif(event.pin_num == 5): os.system('mpc volume 0') mpdVolume() elif(event.pin_num == 6): os.system('mpc volume -10') mpdVolume() elif(event.pin_num == 7): os.system('mpc volume +10') mpdVolume() else: sleep(1) cad = pifacecad.PiFaceCAD() initCad() listener = pifacecad.SwitchEventListener(chip=cad) for i in range(8): listener.register(i, pifacecad.IODIR_FALLING_EDGE, handlePin) listener.activate()
Umfangreicher MPD Client
Im folgenden ist der Code für einen (fast) vollständigen MPD Client ersichtlich. Der Client verfügt unter anderem über eine (sich derzeit noch nicht selbst aktualisierenden) Titalanzeige. Der Code besteht aus zwei Dateien: dem „Hauptprogramm“ und der Klasse MPD
. Beide Dateien in ein Verzeichnis legen und nur mpdclient.py
mit Python 3 ausführen.
- mpdclient.py
#!/usr/bin/env python3 import pifacecad import os import sys import subprocess from time import sleep from Mpd import * backlight = 1 # Init the CAD def initCad(): SPEAKER = pifacecad.LCDBitmap([1,3,15,15,15,3,1,0]) PLAY = pifacecad.LCDBitmap([0,8,12,14,12,8,0,0]) STOP = pifacecad.LCDBitmap([0,31,31,31,31,31,0,0]) PLAYLIST = pifacecad.LCDBitmap([2,3,2,2,14,30,12,0]) cad.lcd.store_custom_bitmap(0, SPEAKER) cad.lcd.store_custom_bitmap(1, PLAY) cad.lcd.store_custom_bitmap(2, STOP) cad.lcd.store_custom_bitmap(3, PLAYLIST) cad.lcd.blink_off() cad.lcd.cursor_off() cad.lcd.clear() cad.lcd.backlight_on() # Handle pushed pins def handlePin(event): global backlight if(event.pin_num == 0): mpdTool.displayCurrent() elif(event.pin_num == 1): mpdTool.playPrev() elif(event.pin_num == 2): mpdTool.playNext() elif(event.pin_num == 3): mpdTool.playPause() elif(event.pin_num == 4): if(backlight == 1): event.chip.lcd.backlight_off() backlight = 0 else: event.chip.lcd.backlight_on() backlight = 1 elif(event.pin_num == 5): mpdTool.volumeMute() elif(event.pin_num == 6): mpdTool.volumeDown() elif(event.pin_num == 7): mpdTool.volumeUp() else: sleep(1) cad = pifacecad.PiFaceCAD() initCad() listener = pifacecad.SwitchEventListener(chip=cad) mpdTool = Mpd(cad) for i in range(8): listener.register(i, pifacecad.IODIR_FALLING_EDGE, handlePin) listener.activate() mpdTool.displayCurrent()
- Mpd.py
#!/usr/bin/env python3 import pifacecad import os import sys import subprocess #from time import sleep class Mpd(object): # Init def __init__ (self, cadTmp): self.cad = cadTmp self.isMuted = 0 self.lastVolume = "0" ### # Get Values from MPD ## # Get volume from MPD def _getVolume(self): tmp = subprocess.check_output("mpc status | grep volume", shell=True, stderr=subprocess.STDOUT) tmp = tmp.decode() tmp = tmp[7:tmp.find("%")] return tmp # Get status from MPD def _getStatus(self): tmp = subprocess.check_output("mpc", shell=True, stderr=subprocess.STDOUT) tmp = tmp.decode() if(tmp.find("[paused]") == -1): return 1 else: return 0 # Get current playing title from MPD def _getCurrent(self): tmp = subprocess.check_output("mpc | head -n1", shell=True, stderr=subprocess.STDOUT) tmp = tmp.decode() current = {'artist': "none", 'title': "none"} current['artist'] = tmp[0:tmp.find("-") -1] current['title'] = tmp[tmp.find("-")+2:] return current ### # Display Commands ## # Display playing title def displayCurrent(self): self.cad.lcd.clear() self.cad.lcd.set_cursor(0, 0) status = self._getStatus() if(status == 1): self.cad.lcd.write_custom_bitmap(1) else: self.cad.lcd.write_custom_bitmap(2) disp = self._getCurrent() self.cad.lcd.set_cursor(1, 0) self.cad.lcd.write(disp['artist']) self.cad.lcd.set_cursor(0, 1) self.cad.lcd.write(disp['title']) # Display volume def displayVolume(self): self.cad.lcd.clear() self.cad.lcd.set_cursor(10, 1) self.cad.lcd.write_custom_bitmap(0) tmp = self._getVolume() + "%" self.cad.lcd.write(tmp) ### # Simple Commands ## # Volume Up def volumeUp(self): os.system("mpc volume +10") self.displayVolume() # Volume Down def volumeDown(self): os.system("mpc volume -10") self.displayVolume() # Volume Mute def volumeMute(self): if(self.isMuted == 1): command = "mpc volume " + self.lastVolume os.system(command) self.isMuted = 0 else: self.lastVolume = self._getVolume() os.system("mpc volume 0") self.isMuted = 1 self.displayVolume() # Next def playNext(self): os.system("mpc next") self.displayCurrent() # Prev def playPrev(self): os.system("mpc prev") self.displayCurrent() # Play Pause def playPause(self): status = self._getStatus() if(status == 1): os.system("mpc pause") else: os.system("mpc play") self.displayCurrent()
— chrisge 2016/03/24 13:17