Raspberry Pi und Arduino verbinden

(siehe: Setup des RPi)

Verwendete Bauteile

USB-Verbindung (kabelgebunden)

Aufbau

Verbindung eines Raspberry Pi mit einem Arduino per USB-Kabel
Abb.: Verbindung eines Raspberry Pi mit einem Arduino per USB-Kabel (A-Stecker auf B-Stecker)

Arduino-Sketch

Zunächst wird der Arduino ganz normal über den PC angeschlossen und folgender Sketch programmiert und hochgeladen:

void setup()
{
  Serial.begin(9600);
}

void loop()
{
  if (Serial.available()) {
    byte ch = Serial.read();
    Serial.println(ch, DEC);
  }
}

Raspberry Pi einrichten

Bevor man den Arduino an den RPi anschließt lässt man sich zunächst die Portnamen ausgeben:
ls /dev/tty*
Nun schließt man den Arduino an einen USB-Anschluss des RPi an und listet sich die Portnamen erneut auf. Der neu hinzugekommene Port ist die Arduino-Verbindung. (bei mir: "/dev/ttyACM0")

Nun wird das folgende Python-Skript eingegeben und ausgeführt:

import serial
import time

# adapt name (baud rate has to be the same than in the arduino sketch)
s = serial.Serial('/dev/ttyACM0', 9600)
s.open()

# Arduino resets after a serial connection
print "Waiting 5s for Arduino..."
time.sleep(5)

s.write("test")
try:
    while True:
        response = s.readline()
        print(response)
except KeyboardInterrupt:
    s.close()
except:
    s.close()
Ausgabe des Resultates im SSH-Client
Abb.: Ausgabe des Resultates im SSH-Client

Serielle GPIO-Kommunikation

GPIO-Anschlüsse am Raspberry Pi 3+
Abb.: GPIO-Anschlüsse am Raspberry Pi 3+

Ein anderer einen RPi und einen Arduino miteinander kommunizieren zu lassen, ist der serielle Port (UART). Das aber die GPIOs des RPi mit 3,3V laufen und die PINs des Arduino UNO 5V vertragen, benötigt man entweder einen Bidirektionaler Pegelwandler oder man behilft sich mit einem einfachen Spannungsteiler (wie hier im Aufbau).

Aufbau

Verbindung eines Raspberry Pi mit einem Arduino mit seriellen GPIO-Anschlüssen
Abb.: Verbindung eines Raspberry Pi mit einem Arduino mit seriellen GPIO-Anschlüssen

Arduino-Sketch

#define PIN_LED_GREEN 6
#define PIN_LED_RED   7

void setup()
{
    Serial.begin(9600);
    pinMode(PIN_LED_GREEN, OUTPUT);
    pinMode(PIN_LED_RED,   OUTPUT);
    digitalWrite(PIN_LED_GREEN, LOW);
    digitalWrite(PIN_LED_RED, LOW);
}

void loop()
{
    if (Serial.available()) {
        byte ch = Serial.read();
        Serial.print(ch, DEC);
        Serial.print(": ");
        switch (ch) {
            case 100: // "d"
                digitalWrite(PIN_LED_GREEN, HIGH);
                Serial.println("GREEN on");
                break;
            case 101: // "e"
                digitalWrite(PIN_LED_GREEN, LOW);
                Serial.println("GREEN off");
                break;
            case 110: // "n"
                digitalWrite(PIN_LED_RED, HIGH);
                Serial.println("RED on");
                break;
            case 111: // "o"
                digitalWrite(PIN_LED_RED, LOW);
                Serial.println("RED off");
                break;
            default:
                Serial.println("-");
                break;
        }
    }
}

RPi-Vorbereitungen

Nun muss der RPi zum Verwenden der GPIO als UART-Pins vorbereitet werden.
In der Datei /boot/config.txt werden folgende Einträge modifiziert bzw. hinzugefügt:
enable_uart=1
dtoverlay=pi3-disable-bt

Mit Letzerem wird Bluetooth deaktiviert. (falls dies wieder benötigt wird, dann muss diese Option wieder entfernt werden)
Nun wird die Datei /boot/cmdline.txt editiert und folgende Zeichenfolge entfernt:
console=serial0,115200 (Der Rest muss bleiben, weil sonst Fehler mit hochfahren entstehen können)
Nun wird noch die RPi-Konfiguration aufgerufen:
sudo raspi-config
Hier werden unter Interfacing options die Option Serial angewählt und No für eine serielle Login-Konsole geantwortet und Yes, um die seriellen Ports zu aktivieren.
Jetzt muss der RPi neugestartet werden:
sudo reboot

Nun kann die Kommunikation zwischen RPi und Arduino ausprobiert werden.
Dazu wird folgendes Software-Paket verwendet:
sudo apt-get install minicom
Dann kann man folgenden Aufruf durchführen und mit der Tastatur über die seriellen GPIOs mit dem Arduino kommunizieren:
minicom -b 9600 -D /dev/ttyAMA0
Um den minicom-Client wieder zu verlassen drückt man CTRL + SHIFT + a und dann q

Ausgabe des Resultates im SSH-Client
Abb.: Ausgabe des Resultates im SSH-Client

I²C-Kommunikation

Der Vorteil an der Kommunikation über I²C ist, das diese Verbindung über die GPIO-Pins stattfinden, die serielle Schnittstelle nicht belegt wird und sogar mit mehreren Clients (z.B. Arduinos oder Sensor-Module) angesprochen werden können.

Raspberry Pi Arduino Uno
GND (z.B. PIN #6) GND
GPIO 2 (SDA) A4 (SDA)
GPIO 3 (SCL) A4 (SCL)
I²C-Anschlüsse am Raspberry Pi 3+
Abb.: I²C-Anschlüsse am Raspberry Pi 3+

Aufbau

Verbindung eines Raspberry Pi mit einem Arduino über I²C
Abb.: Verbindung eines Raspberry Pi mit einem Arduino über I²C

In diesem Versuchs-Aufbau benötigen wird keinen Pegelwandler oder externe Pullup-Widerstände, da hier der RPi den Master darstellt und dieser in seinen Ausgängen schon interne Pullup-Widerstände verwendet. In einer Produktiv-Umgebung ist aber ein Pegelwandler zu empfehlen.

Arduino-Sketch

In dem folgenden Sketch wird die Wire.h-Library verwendet. Dies ist in der Arduino-IDE schon integriert.

#include <Wire.h>

#define I2C_ADDRESS 0x05

#define PIN_LED_GREEN 6
#define PIN_LED_RED   7

byte nr = 0;

void setup()
{
    Serial.begin(9600);
    Wire.begin(I2C_ADDRESS);

    pinMode(PIN_LED_GREEN, OUTPUT);
    pinMode(PIN_LED_RED,   OUTPUT);
    digitalWrite(PIN_LED_GREEN, LOW);
    digitalWrite(PIN_LED_RED,   LOW);

    Wire.onReceive(receiveI2CData);
    Wire.onRequest(sendI2cData);
}

void loop() {}

void receiveI2CData(int byteCount)
{
    while (Wire.available()) {
        nr = Wire.read();
        Serial.print(String(nr) + ": ");

        switch (nr) {
            case 1:
                digitalWrite(PIN_LED_GREEN, HIGH);
                Serial.println("GREEN on");
                break;
            case 2:
                digitalWrite(PIN_LED_GREEN, LOW);
                Serial.println("GREEN off");
                break;
            case 3:
                digitalWrite(PIN_LED_RED, HIGH);
                Serial.println("RED on");
                break;
            case 4:
                digitalWrite(PIN_LED_RED, LOW);
                Serial.println("RED off");
                break;
            default:
                Serial.println("-");
                break;
        }
    }
}

void sendI2cData()
{
    Wire.write(nr);
}

RPi-Vorbereitungen

Zunächst muss I²C aktiviert werden:
sudo raspi-config
Hier werden unter Interfacing options die Option I2C angewählt und Yes für die Aktivierung von I²C geantwortet.
Dann werden noch die Hilfsprogramme installiert:
sudo apt-get install i2c-tools
Zusätzlich benötigt man für das folgende Python-Skript noch eine Library:
apt-get install python-smbus Jetzt muss der RPi neugestartet werden:
sudo reboot
Nun prüft man auf I²C-Devices:
ls /dev/i2c*
Nun sollte mindestens ein I²C-Device auftauchen, z.B.
/dev/i2c-1

Man kann nun einen Scan nach der vom Arduino verwendeten I²C-Adresse durchführen:
i2cdetect -y 1

Erkennung der I²C-Adresse (0x05) vom Arduino durch den RPi
Abb.: Erkennung der I²C-Adresse (0x05) vom Arduino durch den RPi

Wird nun das folgende Python-Skript ausgeführt, so kann der RPi die LEDs auf dem Arduino steuern:

import smbus
import time
bus = smbus.SMBus(1)

address = 0x05

def writeNumber(value):
    bus.write_byte(address, value)
    return -1

def readNumber():
    number = bus.read_byte(address)
    return number

while True:
    inp = input("Number between 1 and 9: ")
    if not inp:
        continue

    writeNumber(inp)
    print "RPi sends: ", inp
    time.sleep(1)

    recv = readNumber()
    print "Arduino sends: ", recv
zurück