GPIO mit C-Programmen nutzen
Infos und Sicherheitshinweise
Mit Hilfe der GPIO-Anschlüsse (General Perpose Input and Output) des RaspberryPis lassen sich elektronische Ausgänge digital schalten bzw. Schalter/Zustände über Eingänge digital abfragen. Es lassen sich damit sogar über verschiedene spezielle Schnittstellenprotokolle andere elektronische Komponenten ansteuern.
Der Zugriff auf die GPIO-Schnittstelle ist von verschiedenen Programmiersprachen aus möglich: Python, C, Scratch, Perl, … und auch über die Shell (Kommandozeile), allerdings müssen dafür spezielle Bibliotheken eingesetzt werden.
ACHTUNG: Beim Beschalten dieser GPIO-Pins ist extreme Vorsicht geboten! Die Ein- und Ausgänge sind auf exakt 3,3 V ausgelegt, wobei in Summe eine Gesamtstromstärke von 50 mA nicht überschritten werden darf. Zusätzliche ist eine Spannung von 5 V für externe Komponenten verfügbar, deren höchste Stromstärke vom verwendeten Netzteil begrenzt ist, wobei die 700 mA (Mod. B) bzw. 300 mA (Mod. A) des RaspberryPis selbst berücksichtig werden muss.
Vor der Aktivierung einer Schaltung bitte alle Anschlüsse noch einmal kontrollieren, insbesondere auf richtige Polung, Kurzschlüsse, Überspannungen und zu starke Belastung der GPIOs achten!
Ein kleiner Fehler kann das ganze Board zerstören!
Wir werden im Folgenden mit der Programmiersprache C bzw. C++ arbeiten.
Der GNU-C-Compiler
Der GNU-C-Compiler-Suite ist Bestandteil jeder Linux-Distribution und ist bei Raspian bereits vorinstalliert. Möchte man eine C-Quelldatei namens helloworld.c kompilieren, ist folgende Eingabe auf der Kommandozeile notwendig, wobei man sich im selben Ordner befinden muss.
gcc -Wall -o helloworld helloworld.c
Danach lässt sich die kompilierte Datei ausführen:
./helloworld
Hinweis: die Zeichen ./ am Anfang bedeuten, dass im aktuellen Ordner nach der ausführbaren Datei gesucht werden soll. Unter Linux haben ausführbare Dateien keine spezielle Dateiendnung wie unter Windows (zB .exe).
Möchte man eine C++-Quelldatei namens hallowelt.cpp kompilieren, ist folgende Eingabe notwendig:
g++ -Wall -o hallowelt hallowelt.cpp
Danach lässt sich die kompilierte Datei ausführen:
./hallowelt
Die WiringPi-Library installieren
Für C/C++ gibt es eine Bibliothek namens WiringPi, die den Zugriff auf die GPIO-Pins ermöglicht. Sie stammt von Gordon Henderson und ist unter https://projects.drogon.net/raspberry-pi/wiringpi/ zu finden – zum Download und mit ausführlicher Dokumentation.
Um sie mit gcc bzw. g++ nutzen zu können muss sie über Git heruntergeladen werden:
Git installieren, wenn noch nicht vorhanden:
sudo apt-get install git-core
Zuerst ins Homeverzeichnis wechseln und dann herunterladen:
cd ~ git clone git://git.drogon.net/wiringPi
Danach ist ein Ordner wiringPi entstanden, in dem es mit der Installation weitergeht:
cd wiringPi git pull origin ./build
Danach kann in jeder C/C++-Quelldatei auf diese Bibliothek verwiesen werden:
#include <wiringPi.h>
Beim Kompilieren ist allerdings eine spezielle Compileroption zu verwenden:
gcc -o dateiname dateiname.c -lwiringPi
bzw.
g++ -o dateiname dateiname.c -lwiringPi
Da der Zugriff auf die GPIO Administratorrechte erfordert, muss ein solches Programm mit sudo aufgerufen werden:
sudo ./dateiname
Blinkende LED
Um unsere Installation zu testen und um ein erstes Erfolgserlebnis zuhaben, schließen wir eine Leuchtdiode (LED) über die GPIO an den RaspberryPi an und lassen sie blinken. LEDs müssen immer über einen Vorwiderstand betrieben werden. Für die 3,3 V, die der GPIO Ausgang liefert habe ich hier 470 Ohm gewählt.
Die Masse liegt am dritten Pin der rechten Reihe an, die geschaltet Ausgang am 6. Pin der rechten Reihe, der für die wiringPi-Bibliothek die Nummer 1 trägt.
Hier das noch sehr einfach C++-Programm:
#include <wiringPi.h> #include <iostream> #include <string> using namespace std; #define LEUCHTDIODE 1 // wirinPi Pin 1 #define PAUSE 500 int main(int argc, char **argv) { int i; wiringPiSetup(); pinMode(LEUCHTDIODE, OUTPUT); cout << "Erster Versuch mit LED" << endl; for (i=0;i<10;i++) { cout << i << endl; digitalWrite(LEUCHTDIODE, HIGH); delay(PAUSE); digitalWrite(LEUCHTDIODE, LOW); delay(PAUSE); } cout << "Das wars - bye!" << endl; return 0; }
Natürlich würde ein „reinem“ Programm in C so ähnlich aussehen, die Ausgaben auf dem Bildschirm müssen dementsprechend anders codiert werden.
Hinweis: Zur Erstellung der Steckbrett-Grafik und des Schaltplanes habe ich die freie Software fritzing (http://fritzing.org) verwendet. Manche Schaltpläne habe ich auch schon in der ebenfalls freien Software TinyCAD (http://tinycad.sourceforge.net/) erstellt.
LED mit Schalter steuern
Die GPIO-Anschlüsse können auch als Eingänge genutzt werden. Im folgenden Beispiel soll mit Hilfe eines Tasters eine LED ein- und ausgeschaltet werden.
In dieser Schaltung wird durch Drücken des Tasters auf den Eingang der Wert 0 (Spannung 0 V) gelegt. In ungedrücktem Zustand sorgt eine interne Schaltung (Fachbegriff pull up) dafür, dass auf dem Eingang der Wert 1 (Spannung 3,3 V) liegt. Diese wird durch den Funktionsaufruf pullUpDnControl(TASTER,PUD_UP); aktiviert.
#include <wiringPi.h> #include <iostream> #include <string> using namespace std; #define LEUCHTDIODE 1 // wiringPi Pin 1 #define TASTER 4 // wiringPi Pin 4 #define PAUSE 200 int main(int argc, char **argv) { bool status=false; bool alt=true; bool neu=true; wiringPiSetup(); pinMode(LEUCHTDIODE, OUTPUT); digitalWrite(LEUCHTDIODE,LOW); pinMode(TASTER,INPUT); pullUpDnControl(TASTER,PUD_UP); cout << "LED mit Taster" << endl; cout << "Drück den Taster!" << endl; for (;;) { neu=digitalRead(TASTER); if (alt==true and neu==false) { if (status==false) { digitalWrite(LEUCHTDIODE, HIGH); cout << "ein" << endl; status=true; } else { digitalWrite(LEUCHTDIODE, LOW); cout << "aus" << endl; status=false; } alt=false; delay(PAUSE); } else if (alt==false and neu==true) { alt=true; delay(PAUSE); } } return 0; }
Das waren nur zwei einfache Beispiele, wie die GPIO-Anschlüsse als Ein- und als Ausgänge genutzt werden können.
Die Aufstellung aller in der WiringPi-Bibliothek zur Verfügung stehenden Funktionen findet man unter https://projects.drogon.net/raspberry-pi/wiringpi/functions/.
Insbesondere ist die Zuordnung der einzelnen Pins auf der RaspberryPi-Platine zur den Pin-Nummern, die für WiringPi verwendet werden eine wichtig Information. Insbesonder dessen, da sie von der Nummerierung der RaspberryPi-Foundation abweicht. Die Aufstellung dazu findet man auf https://projects.drogon.net/raspberry-pi/wiringpi/pins/.
Um den Überblick zu behalten und um auch immer den richtigen Pin zu erwischen, habe ich mir eine einfache Schablone erstellt, die ich ausgeschnitten und mit durchlöcherten Kästchen in den mittleren Spalten auf die GPIO-Pins aufsetze. Hier ein PDF mit dieser Schablone zum Download (in Originalgröße ausdrucken!).
Einige Pins haben spezielle Funktionen, ein Auflistung findet man hier https://projects.drogon.net/raspberry-pi/wiringpi/special-pin-functions/.
Generell sind auf der Seite von Gordon Henderson, dem Autor der Bibliothek WiringPi, unter https://projects.drogon.net/raspberry-pi/wiringpi/ eine umfangreiche Dokumentation und Programmierbeispiele zu finden, die eine Hilfestellung für eigene Programmieraufgaben sein können. Viel Erfolg!