CODE AMBER

Die serielle Schnittstelle (UART) in Skripten programmieren

P1050970In meinem letzten Beitrag habe ich den neuen GPIO-Header des RasPi B+ beschrieben. In der Übersicht zur Belegung der Pins habe ich die Pins hervorgehoben, die über eine Sonderbelegung verfügen. Im Einzelnen sind das die Pins für I2C, UART und SPI. Hier ein kurzer Überblick, was hinter diesen Bezeichnungen steckt:

  • UART ist eine Schnittstelle, über die zwei Bauteile seriell miteinander kommunizieren können. Seriell heißt hier, dass die Zeichen jeweils einzeln hintereinander über die Leitung geschickt werden. Die Schnittstelle ist recht einfach und relativ robust. Die üblichen seriellen Schnittstellen am PC übertragen bis zu 115 200 Zeichen (Baud) pro Sekunde. Bei seriellen Terminals ist mit „Zeichen“ ein Bit und nicht ein Byte gemeint.
  • I2C ist ein Protokoll, das für die Kommunikation zwischen Mikrocontrollern entwickelt wurde. Das Protokoll ermöglicht einem Chip (dem I2C-Master) die Kommunikation mit über 1000 anderen Chips (den I2C-Slaves) über (nur) zwei Leitungen. Dabei werden je nach Version zwischen 100 kBit/s bis zu 5 MBit/s erreicht. (Siehe dazu den Beitrag zur Echtzeituhr)
  • SPI ist ebenfalls ein Protokoll für die Kommunikation zwischen zwei Mikrocontrollern. Auch hier gibt es einen Master und etliche Slaves. Allerdings werden bei SPI die Partner (in der Regel) direkt verdrahtet, so dass jeder Slave neben den drei gemeinsamen Leitungen (MOSI, MISO, SCLK) eine eigene Leitung (CE) braucht. Mit CE0 und CE1 hat der GPIO-Header also Leitungen für 2 SPI-Slaves. SPI ist so schnell, wie die Chips getaktet sind, also bis in den MHz-Bereich (also MBit/s).

Während I2C und SPI hauptsächlich für die Kommunikation mit Mikrocontrollern genutzt wird, ist UART auch gut für Anwendungen mit interaktiven Ein- und Ausgaben. Ich benutze UART beim RasPi meist für die Kommunikation mit einem Arduino oder einem XBee.

Die serielle Schnittstelle UART

Der RasPi kann über die GPIO-Ports nur digitale Signale lesen und schreiben (Siehe dazu den Beitrag zum LCD Display). Denn die Ports lassen sich nur an- und ausschalten. Für analoge Messungen wie Temperaturen oder Spannungen werden externe Baulemente oder Mikrocontrolller gebraucht. Wenn gleich noch ein wenig Logik für eine Vorverarbeitung der Messung untergebracht werden soll, nutze ich dafür einen Arduino, weil der sich besonders einfach programmieren lässt. Wenn das Programm etwas taugt, übertrage ich es auf einen Amtel-Controller, der ja im Kern des Arduino steckt. Einen Arduino gibt es in einer Nano-Version, die gegenüber einem Arduino Uno platz- und stromsparend ist:

DSC_0201Der Arduino spricht auch UART, so dass er dem RasPi die Messwerte über die serielle Schnittstelle schicken kann. Gleichzeitig können vom RasPi Parameter zurückgeschickt werden, die von der Anwendung auf dem Arduino interpretiert werden.

Im folgenden Beispiel soll der Arduino Nano einen Photowiderstand auslesen. Unterschreitet der Messwert einen bestimmten Wert, soll eine LED angeschaltet werden. Die Messwerte sollen über die serielle Schnittstelle an den RasPi übertragen werden. Wenn der RasPi ein entsprechendes Kommando schickt, soll der Messwert invertiert werden.

Die Schaltung ist in der folgenden Abbildung dargestellt:

Serial Nano_SteckplatineSerial Nano_Schaltplan

Dabei ist eine Besonderheit zu beachten: Der RasPi verträgt nur 3.3V auf den UART-Ports, der Arduino schickt auf dem TX-Draht aber 5V. Um den RX-Port vor der Überspannung zu schützen, habe ich einen Spannungsteiler eingebaut. Der besteht lediglich aus zwei Widerständen in Reihe zwischen dem RX-Port und GND. Die Größen sind so gewählt, dass ca. 3 V beim RX-Port des RasPi ankommen. Ich habe einfach einen 4,7 kOhm und einen 10 kOhm genommen und den RX-Port dazwischen geklemmt.

Den Arduino programmiert man über den USB-Anschluss mit Hilfe der Arduino-IDE. Das Programm für den Arduino wird in C geschrieben und ist quasi selbsterklärend:

int lightPin = 7; // = A7
int ledPin   = 2; // = D2
byte flag = 0;
boolean inverse = false;

void setup()
{
    Serial.begin(9600);
    pinMode( ledPin, OUTPUT );
}

void loop()
{
    int light = analogRead(lightPin);
    if (Serial.available()) {
      flag = Serial.read();
      if (flag == 'i') {
        inverse = ! inverse;
        Serial.println();
        Serial.println("Invertiere Messwert.");
      }
    }    
    if (inverse) light = 1024 - light;
    Serial.println(light);
    if (light < 500) {  
      digitalWrite(ledPin, HIGH);
    } else {
      digitalWrite(ledPin, LOW);
    }
   delay(1000);
}

Der Arduino misst also am Analog-Anschluss A7 eine Spannung, die sich je nach Lichteinfall auf den Photowiderstand ändert. Die Spannung wird ins Verhältnis zur Referenzspannung gesetzt. Dabei kommen Werte zwischen 0 und 1024 heraus. Diese Werte überträgt der Arduino über seine serielle Schnittstelle. Die LED geht an, wenn zu wenig Licht gemessen wird. Sollte ein ‚i‘ über die serielle Schnittstelle empfangen werden, dann werden die Messwerte invertiert, das heißt, von 1024 abgezogen. Dann geht die LED aus, wenn zu wenig Licht auf den Photowiderstand trifft.

Auf der Seite des RasPi kann man sich mit einem seriellen Terminal die Messwerte anschauen. Screen ist ein Terminal für die Kommandozeile und kann mit folgendem Aufruf auf dem RasPi installiert werden:

sudo apt-get install screen

Mit ’screen /dev/ttyAMA0 9600′ kann man einen Blick auf die eintrudelnden Messwerte werfen:

Bildschirmfoto von »2014-08-17 23:17:30«Ein einfaches Ruby-Script kann so aussehen:

require 'serialport'
sp = SerialPort.new("/dev/ttyAMA0", 9600, 8, 1, SerialPort::NONE)
open("/dev/tty", "r+") { |tty|
  tty.sync = true
  Thread.new {
    while true do
      tty.printf("%c", sp.getc)
    end
  }
  while (l = $stdin.getc) do
    sp.write(l.sub("\n", "\r"))
  end
}
sp.close

Das Ruby-Skript bindet das gem serialport mit ein. Dafür muss das gem vorher installiert werden:

sudo gem install serialport

Hier muss jedoch das ‚i‘ mit einem Zeilenumbruch (ENTER) auf den Weg geschickt werden, da sonst das Einlesen im Skript nicht beendet wird. Das Ergebnis sieht ähnlich wie beim seriellen Terminal mit screen aus:

Bildschirmfoto von »2014-08-17 23:20:58«

2 Kommentare

  1. Jonas

    Hi! Kannst du erklären wie du auf die Widerstandswerte deines Spannungsteilers gekommen bist? Ich versuche das nachzurechnen aber komme partout nicht dahinter.
    Gruß Jonas

    • mnasarek

      Aus dem serial port des arduino kommen 5V. Wenn man den Port über einen Widerstand mit GND (-) verbindet, fallen über den Widerstand die 5V ab. Wenn man zwei Widerstände hintereinander schaltet, und die Spannung über einen Widerstand (z.B. zwischen dem 5V Port und dem Verbindungspunkt) misst, dann ist das nur ein Teil der gesamten Spannung. Denn zwischen dem Verbindungspunkt und dem GND besteht noch ein Spannungspotential, das der zweite Widerstand aufrecht erhält. Er bremst ja quasi den Strom und schließt ihn nicht kurz. Wie groß die Spannungen über den Widerständen sind, hängt lustigerweise nicht von ihrem Wert ab, sondern wie sich die Werte zueinander verhalten. Sind sie gleich groß, ist auch der Spannungsabfall über beiden gleich groß, die Spannung am Verbindungspunkt ist also die Hälfte. Ist der eine doppelt so groß (10k) wie der andere (5k) – also 2/3 vom Gesamtwiderstand – dann fällt auch 2/3 von der Gesamtspannung über ihn ab. 2/3 von 5V sind 3,3V. Wenn man also einen Raspi Port mit 5V ansprechen will, schließt man den RasPi Port an den Verbindungspunkt zweier Widerstände mit 10k (RasPi und GND) und 5k (RasPi und 5V) an. Es kommt trotz der hohen Werte noch genug Strom an, und es wird nicht zu viel Strom direct am GND vergeudet.

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert

© 2024 Raspberry Pi Lab

Theme von Anders NorénHoch ↑

Cookie Consent mit Real Cookie Banner