Aus Raspberry Pi Geek 04/2018

Mit der Programmiersprache Go die GPIO des RasPi ansteuern (Seite 3)

Listing 7

 

 +-----+-----+--------+------+---+---Pi 3---+---+------+--------+-----+-----+
 | BCM | wPi |  Name  | Mode | V | Physical | V | Mode |  Name  | wPi | BCM |
 +-----+-----+--------+------+---+----++----+---+------+--------+-----+-----+
 |     |     |   3.3v |      |   |  1 || 2  |   |      | 5v     |     |     |
 |   2 |   8 |   SDA1 | ALT0 | 1 |  3 || 4  |   |      | 5v     |     |     |
 |   3 |   9 |   SCL1 | ALT0 | 1 |  5 || 6  |   |      | 0v     |     |     |
 |   4 |   7 |  GPIO7 |   IN | 1 |  7 || 8  | 0 | IN   | TxD    | 15  | 14  |
 |     |     |     0v |      |   |  9 || 10 | 1 | IN   | RxD    | 16  | 15  |
 |  17 |   0 |  GPIO0 |   IN | 0 | 11 || 12 | 0 | IN   | GPIO1  | 1   | 18  |
 |  27 |   2 |  GPIO2 |   IN | 0 | 13 || 14 |   |      | 0v     |     |     |
 |  22 |   3 |  GPIO3 |   IN | 0 | 15 || 16 | 0 | IN   | GPIO4  | 4   | 23  |
 |     |     |   3.3v |      |   | 17 || 18 | 0 | IN   | GPIO5  | 5   | 24  |
 |  10 |  12 |   MOSI | ALT0 | 0 | 19 || 20 |   |      | 0v     |     |     |
 |   9 |  13 |   MISO | ALT0 | 0 | 21 || 22 | 0 | IN   | GPIO6  | 6   | 25  |
 |  11 |  14 |   SCLK | ALT0 | 0 | 23 || 24 | 1 | OUT  | CE0    | 10  | 8   |
 |     |     |     0v |      |   | 25 || 26 | 1 | OUT  | CE1    | 11  | 7   |
 |   0 |  30 |   SDA0 |   IN | 1 | 27 || 28 | 1 | IN   | SCL0   | 31  | 1   |
 |   5 |  21 | GPIO21 |   IN | 1 | 29 || 30 |   |      | 0v     |     |     |
 |   6 |  22 | GPIO22 |   IN | 1 | 31 || 32 | 0 | IN   | GPIO26 | 26  | 12  |
 |  13 |  23 | GPIO23 |   IN | 0 | 33 || 34 |   |      | 0v     |     |     |
 |  19 |  24 | GPIO24 |   IN | 0 | 35 || 36 | 0 | IN   | GPIO27 | 27  | 16  |
 |  26 |  25 | GPIO25 |   IN | 0 | 37 || 38 | 0 | IN   | GPIO28 | 28  | 20  |
 |     |     |     0v |      |   | 39 || 40 | 0 | IN   | GPIO29 | 29  | 21  |
 +-----+-----+--------+------+---+----++----+---+------+--------+-----+-----+
 | BCM | wPi |  Name  | Mode | V | Physical | V | Mode |  Name  | wPi | BCM |
 +-----+-----+--------+------+---+---Pi 3---+---+------+--------+-----+-----+

Die Bibliothek unterstützt eine begrenzte Anzahl an möglichen Operationen auf einem Pin. Die Tabelle “Funktionen” listet diese auf und gibt eine kurze Erläuterung. Um einen Pin zu definieren, rufen Sie die Methode Pin(Nummer) auf dem Rpio-Objekt auf. Das Objekt öffnen Sie zuvor mit Open(). Nach dem Einsatz schließen Sie es mit Close() wieder.

Funktionen

Funktion

Beschreibung

Output() 

Pin als Output definieren

High() 

Output-Pin auf High-Pegel setzen

Low() 

Output-Pin auf Low-Pegel setzen

Toggle() 

aktuellen Wert des Output-Pins umkehren

Input() 

Pin als Input definieren

Read() 

aktuellen Wert des Input-Pins auslesen

PullUp() 

internen Pullup-Widerstand aktivieren (Input-Pin hat beschaltet High-Pegel)

PullDown() 

internen Pulldown-Widerstand aktivieren (Input-Pin hat beschaltet Low-Pegel)

PullOff() 

interne Widerstände deaktivieren (Pin extern beschaltet oder Pegel undefiniert)

Listing 8 vermittelt einen ersten Eindruck, wie Sie mit Go auf die GPIO des RasPi zugreifen. In Go ordnen Sie Programme immer Packages zu. Möchten Sie sie ausführen, setzt das voraus, dass sie wie im Beispiel dem Package main zugeordnet sind. Auf die Package-Definition folgen die Importe, mit einer zu C oder Java leicht unterschiedlichen Syntax.

Listing 8

 

// blink.go
package main
import (
  "fmt"
  "github.com/stianeikeland/go-rpio"
  "time"
)
func main() {
  if err := rpio.Open(); err != nil { fmt.Println(err) }
  defer rpio.Close()
  var pin = rpio.Pin(10)
  pin.Output()
  for {
    pin.Toggle()
    time.Sleep(time.Second)
  }
}

Danach folgt die Funktion main(). In Go leiten Sie Funktionen mit dem Schlüsselwort func ein. Die nächste Zeile initialisiert die GPIO. Geht dabei etwas schief, erhalten Sie eine Fehlermeldung.

In der nächsten Zeile sorgt das Schlüsselwort defer dafür, dass das Programm die dahinterstehende Anweisung beim Verlassen der aktuellen Funktion auf jeden Fall ausführt. Über diesen Mechanismus räumen Sie nach dem Beenden der aktuellen Funktion auf. Es ist dabei egal, ob die Funktion regulär oder mit einem Fehler endet. Im Beispiel wird die GPIO also auf jeden Fall wieder sauber geschlossen. Die nächsten beiden Zeilen definieren den BCM-Pin 10 als Output.

Mithilfe einer For-Schleife bauen Sie nun eine Endlosschleife, in der das Skript bei jedem Durchlauf den logischen Zustand des I/O-Pins umkehrt und eine Sekunde pausiert. Nachdem Sie das Programm mit go run blink.go im Terminal gestartet haben, blinkt also die erste rote LED im Testaufbau so lange, bis Sie das Programm mit [Strg]+[C] wieder abbrechen.

Das nächste Programm aus Listing 9 zeigt, wie leicht sich mit Go Nebenläufigkeit realisieren lässt. Hier stecken die Anweisungen zum Ansteuern der LED in einer Funktion; die Wartezeit bis zum Umkehren des Status generiert die Funktion über einen Zufallsgenerator. Letzteren initialisiert das Skript aus der Math-Bibliothek bei jedem Start des Programms neu – und erzeugt jedes Mal exakt dieselbe Folge von “Zufallszahlen”. Für echte Zufallszahlen müssten Sie den (wesentlich komplizierter anzusteuernden) Generator aus der Crypt-Library verwenden. Für unser simples Beispiel tut es der Generator aus der Math-Library aber voll und ganz. Die Funktion blink() realisiert eine Endlosschleife, die sich nur über einen Abbruch des Programms beenden lässt.

Listing 9

 

// gpio.go
package main
import (
  "fmt"
  "github.com/stianeikeland/go-rpio"
  "time"
  "math/rand"
  )
func blink(p rpio.Pin) {
  for {
    p.Toggle()
    var r int
    r = rand.Intn(1000)
    time.Sleep(time.Duration(r)*time.Millisecond)
  }
}
func main() {
  if err := rpio.Open(); err != nil { fmt.Println(err) }
  defer rpio.Close()
  pins := [12]int{17,18,27,22,23,24,25,4,2,3,8,7}
  var gpio[12] rpio.Pin
  for i:=0 ; i<12 ; i++ {
    gpio[i] = rpio.Pin(pins[i])
    gpio[i].Output()
  }
  for i:=0 ; i<12 ; i++ {
    go blink(gpio[i])
  }
  //for {}
  time.Sleep(time.Second*10)
}

Viele der Bestandteile in der Hauptfunktion kamen bereits im ersten Beispiel zum Einsatz. Neu ist dagegen das Array pins[]: Es enthält alle BCM-Pin-Nummern der GPIO, die das Skript nutzt. Zu Beginn des Programms sind alle Pins als Outputs definiert und werden in ein zweites Array (gpio[]) gespeichert. Dabei entspricht die Indexnummer der Pin-Bezeichnung von 0 bis 12, wie WiringPi sie voraussetzt.

Die nun folgende Schleife startet über den Aufruf go blink() zwölf konkurrierende Instanzen der Blink-Funktion, jeweils für einen unterschiedlichen Pin, und bringt so alle LEDs zum Blinken. Anschließend legt der Aufruf von Sleep() die Funktion main() für zehn Sekunden schlafen, zu guter Letzt beendet sich das Programm.

Wenn Sie anstelle des Sleep die Endlosschleife for {} einkommentieren, führt das zu einem zunächst überraschenden Ergebnis: Es blinkt keine der LEDs. Das ist damit zu erklären, dass die Endlosschleife die komplette Rechenzeit des Go-Hauptprozesses beansprucht und so für die Blink-Prozesse keine Zeit mehr zur Verfügung steht.

Fazit

Go präsentiert sich als interessante Programmiersprache, die durch die einfache Implementation von Nebenläufigkeit auf dem Raspberry Pi ihre Stärken ausspielt. Auf diese Weise lassen sich sehr einfach Programme schreiben, die auf unterschiedliche I/O-Ereignisse reagieren. Wenn Sie sich etwas intensiver mit Go auseinandersetzen wollen, sehen Sie sich die “Go Tour” auf Deutsch an [3].

Die Bibliothek go-rpio bietet zwar im Vergleich zu WiringPi einen eingeschränkten Funktionsumfang, stellt aber für einen Einstieg keine schlechte Wahl dar. Andere Go-Bibliotheken für den Raspberry Pi stellen mehr Möglichkeiten bereit, sind aber auch komplizierter in der Anwendung. 

DIESEN ARTIKEL ALS PDF KAUFEN
EXPRESS-KAUF ALS PDFUmfang: 7 HeftseitenPreis €0,99
(inkl. 19% MwSt.)
RASPBERRY PI GEEK KAUFEN
EINZELNE AUSGABE Print-Ausgaben Digitale Ausgaben
ABONNEMENTS Print-Abos Digitales Abo
TABLET & SMARTPHONE APPS Raspberry Pi Geek bei Google Play Readly Logo
Nach oben