Blog der Heimetli Software AG

Aktuelle Blinker für den Raspberry

Beim Raspberry ist alles im Fluss. Was letztes Jahr noch gültig war ist heute schon veraltet. Um wieder mal auf einen sauberen Stand zu kommen habe ich Blinkprogramme in diversen Sprachen realisiert.

Setup

Die Programme liefen auf einem Raspberry 4, mit einem frisch installierten Raspberry PI OS 32Bit.

An GPIO 18 waren ein 560 Ohm Widerstand in Serie mit einer LED gegen Masse angeschlossen.

Python

Mit der Standard-Installation kam ein Python 3.9. Das ist zwar nicht die aktuellste Version aber auch nicht extrem alt. Der Aufruf von python startet jetzt Python 3.

Es ist kein Wunder dass Python auf dem Raspberry so beliebt ist. Die Libraries sind bei der Standard-Installation schon dabei und die Scripts brauchen keine besonderen Rechte.

RPi.GPIO

Wird immer wieder als veraltet beschimpft, das Script lief aber auf Anhieb:

#!/usr/bin/env python3

from RPi import GPIO
import time

PIN = 18

GPIO.setmode( GPIO.BCM )
GPIO.setup( PIN, GPIO.OUT )

try:
    while True:
        GPIO.output( PIN, True )
        time.sleep( 1 )
        GPIO.output( PIN, False )
        time.sleep( 1 )
except KeyboardInterrupt:
    pass
finally:         
    GPIO.setup( PIN, GPIO.IN )
    GPIO.cleanup()

gpiozero

Soll die empfohlene Version sein. Auch diese Scripts liefen auf Anhieb:

#!/usr/bin/env python3

from gpiozero import LED
import time

led = LED( 18 )

try:
    while True:
        led.on()
        time.sleep( 1 )
        led.off()
        time.sleep( 1 )
except KeyboardInterrupt:
    pass
finally:
    led.close()

Es geht sogar noch einfacher:

#!/usr/bin/env python3

from gpiozero import LED
import time

led = LED( 18 )

try:
    led.blink( 1, 1, background=False )
except KeyboardInterrupt:
    pass
finally:
    led.close()

bash

sysfs soll deprecated sein, aber auch dieses Script lief problemlos:

#!/bin/bash

# Define the pin for the blinker
PIN=18

# Handle ctrl-c
function shutdown() {
   echo in > /sys/class/gpio/gpio$PIN/direction
   echo $PIN > /sys/class/gpio/unexport
   exit 0
}

trap shutdown SIGINT

# Export it
echo $PIN > /sys/class/gpio/export

sleep 0.2

# Set the pin as output
echo out > /sys/class/gpio/gpio$PIN/direction

# Loop forever
while true
do
   # Turn the LED on
   echo 1 > /sys/class/gpio/gpio$PIN/value
   sleep 1
   # Turn the LED off
   echo 0 > /sys/class/gpio/gpio$PIN/value
   sleep 1
done

C/C++

Auf dem aktuellen OS fehlt wiringpi, und man findet nur noch veraltete Anleitungen zur Installation der Library. pigpio war installiert und deshalb wird es hier auch genutzt.

#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <unistd.h>

#include <pigpio.h>

#define PIN     18
#define DELAY 1000

void cleanup( int )
{
   gpioSetMode( PIN, PI_INPUT ) ;
   gpioTerminate() ;
   exit( 1 ) ;
}

int main()
{
   if( gpioInitialise() < 0 )
   {
      printf( "Fehler beim Initialisieren von pigpio\n" ) ;
      return 1 ;
   }

   signal( SIGINT, cleanup ) ;

   gpioSetMode( PIN, PI_OUTPUT ) ;

   for( ;; )
   {
      gpioWrite( PIN, PI_HIGH ) ;
      gpioSleep( PI_TIME_RELATIVE, 1, 0 ) ;

      gpioWrite( PIN, PI_LOW ) ;
      gpioSleep( PI_TIME_RELATIVE, 1, 0 ) ;
   }

}

Go

Der Go-Compiler muss erst installiert werden, und für die GPIOs braucht es ein Package. Das Package wird automatisch geholt, da muss man sich gar nicht drum kümmern.

package main

import (
	"fmt"
	"time"
    "os"
    "os/signal"

    "github.com/stianeikeland/go-rpio"
)

func main() {
	if err := rpio.Open(); err != nil {
		fmt.Println(err)
		os.Exit(1)
	}

	defer rpio.Close()

	pin := rpio.Pin(18)
	pin.Output()

        channel := make(chan os.Signal, 2)
        signal.Notify(channel,os.Interrupt)

        go func() {
           for _ = range channel {
              pin.Input()
              rpio.Close()
              os.Exit(1)
           }
        }()

        for {
           pin.High()
           time.Sleep(1*time.Second)
           pin.Low()
           time.Sleep(1*time.Second)
        }
  }

Java

Java stellte sich als mühsam heraus. Ein Java-Programm vom letzten Jahr musste fast vollständig neu geschrieben werden, obwohl es wie vorher pi4j verwendet. Eine Installationsanleitung für pi4j gibt es nicht mehr, das soll Gradle übernehmen.

Java und Gradle mussten erst installiert werden. Java scheint einigermassen aktuell zu sein, Gradle kam aber in der Version 4.4.1!

import com.pi4j.Pi4J;
import com.pi4j.io.gpio.digital.DigitalOutput;
import com.pi4j.io.gpio.digital.DigitalState;

public class Blinker
{
   private static final int PIN_LED = 18 ;

   public static void main( String[] args )
   {
      // The 'Pi4J' static class includes a few helper context
      // creators for the most common use cases.  The 'newAutoContext()'
      // method will automatically load all available Pi4J
      // extensions found in the application's classpath which
      // may include 'Platforms' and 'I/O Providers'
      var pi4j = Pi4J.newAutoContext() ;

      // Here we will create I/O interfaces for a (GPIO) digital output
      // pin. We define the 'provider' to use PiGpio to control
      // the GPIO.
      var ledConfig = DigitalOutput.newConfigBuilder( pi4j )
                .id( "led" )
                .name( "Blinker" )
                .address( PIN_LED )
                .shutdown( DigitalState.LOW )
                .initial( DigitalState.LOW )
                .provider( "pigpio-digital-output" ) ;
      var led = pi4j.create( ledConfig ) ;

      try
      {
         for( ;; )
         {
            led.high() ;
            Thread.sleep( 1000 ) ;
            led.low() ;
            Thread.sleep( 1000 ) ;
         }
      }
      catch( Exception e )
      {
         // Ignore all exceptions
      }

      // Shutdown Pi4J
      pi4j.shutdown() ; 
   }
}

JavaScript

node, npm und das Modul rpi-gpio mussten installiert werden weil sie auf dem Raspberry PI OS nicht vorhanden waren. Das Script läuft mit den normalen User-Privilegien.

const rpi  = require( "rpi-gpio" )
const gpio = rpi.promise

async function blinker()
{ 
   const sleep = (sec) => new Promise( r => setTimeout(r,sec*1000) ) ;

   const PIN = 18 ;

   process.on( "SIGINT", async () => {
      await gpio.write( PIN, false ) ;
      await gpio.setup( PIN, gpio.DIR_IN ) ;
      process.exit( 1 ) ;
   } ) ;

   rpi.setMode( rpi.MODE_BCM ) ;
   await gpio.setup( PIN, gpio.DIR_OUT ) ;

   for( ;; )
   {
      await gpio.write( PIN, true ) ;
      await sleep( 1 ) ;
      await gpio.write( PIN, false ) ;
      await sleep( 1 ) ;
   }
}

blinker() ;