Kampis Elektroecke

UART & USB

Raspberry Pi

Hier zeige ich, wie der UART vom Raspberry Pi verwendet werden kann. Hierbei ist zu beachten, dass der Raspberry Pi 3,3 V Pegel führt und keinesfalls ohne Pegelwandlung mit einem Gerät kommunizieren werden darf, welches höhere Pegel verwendet.

Für meine Versuche habe ich ein FT232 Modul von FTDI benutzt um den UART auf USB umwandeln zu können. Die Pins für den UART befinden sich auf der 26-pol bzw. 40-pol Stiftleiste. Die Belegung der Stiftleiste kann hier eingesehen werden.

UART konfigurieren:

Bevor der UART verwendet werden kann, muss die Baudrate eingestellt werden. Dies wird mit dem Befehl stty gemacht und sieht wie folgt aus:

$ sudo stty 19200 -F /dev/serial0

Dieser Befehl stellt den Treiber für den UART (serial0) beim Raspberry Pi auf eine Baudrate von 19200 ein. Die Syntax für den Befehl stty lautet:

$ stty -F [Device]

Wir haben den Befehl nur um die Baudrate 19200, welche als Parameter übergeben wird, erweitert. Das Device ist bei uns der serielle Schnittstellentreiber serial0, welcher den Pfad /dev/serial0 besitzt.

UART vom Betriebssystem abmelden:

Wenn ihr das Raspberry Pi mittels UART an den PC anschließt und es rebootet werdet ihr feststellen, dass der komplette Bootvorgang inklusive Login über das Terminal ausgegeben wird.
Dies ist besonders störend wenn ein Mikrocontroller o. ä. über UART mit dem Raspberry Pi kommunizieren soll. Um diese Funktionen zu deaktivieren, müsst ihr die raspi-config öffnen

$ sudo raspi-config

und unter Interfacing Options die serielle Schnittstelle aktivieren und den Anmeldepromt deaktivieren:

Anschließend rebootet ihr das Raspberry Pi. Jetzt sollte beim Bootvorgang nichts mehr über den UART ausgegeben werden.


Achtung:

Anschließend wird über den UART kein Anmeldeprompt mehr ausgegeben!


Texte mittels Konsole senden:

Nachdem wir den Schnittstellentreiber eingestellt haben, versuchen wir uns mal daran ein paar Texte zu versenden. Als erstes verbinden wir den UART von dem Raspberry Pi mit dem Computer. Anschließend starten wir ein Terminalprogramm (z.B. PuTTY), stellen es auf den richtigen COM-Port ein und setzen die Baudrate auf die eben eingestellten 19200.

Wenn ihr nun in der Konsole vom Raspberry Pi (entweder direkt auf dem Raspberry Pi oder mittels PuTTY) diese Zeile eingebt

$ echo Text >> /dev/serial0

solltet ihr in eurem Terminalprogramm das Wort Text sehen können. Mittels echo wollen wir den nachfolgenden Text ausgeben. Das >> gibt aber an, dass der Text nicht ausgegeben, sondern das dieser Text stattdessen in eine bestimmte Datei umgeleitet werden soll. In unserem Fall wird der Text also zu dem Schnittstellentreiber vom Raspberry Pi geschoben und dieser gibt ihn anschließend aus.

Texte mittels Konsole Empfangen:

Mit diesem Wissen können wir uns nun mit dem Empfangen von Texten beschäftigen. Anhand der oberen Beispiele könnt ihr erkennen, dass das Senden anscheinend genau so funktioniert wie das Schreiben in eine Datei. Im Umkehrschluss sollte das Empfangen wie das Lesen aus einer Datei funktionieren.

Der Inhalt einer Datei kann durch den Befehl cat ausgelesen werden.

$ cat /home/pi/Desktop/MeineDatei

ein. Anschließend sollte dann der Inhalt der Datei MeineDatei ausgegeben werden, sprich es wird ein Hallo zurück gegeben. Jeder empfangene Text steht erstmal im Schnittstellentreiber und da wir davon ausgehen können, dass das Empfangen wie das Lesen aus einer Datei funktioniert, probieren wir mal:

$ cat /dev/serial0 >> /tmp/Text

Mit dem Befehl cat wird die Datei /dev/serial0, also in unserem Fall der Schnittstellentreiber für den UART, ausgelesen. Durch die Ergänzung >> /tmp/Text wird der Inhalt aus dem Schnittstellentreiber in eine Datei namens Text im Verzeichnis /tmp kopiert. Falls diese Datei noch nicht vorhanden ist, wird sie erstellt und anschließend beschrieben.

Um das ganze zu testen, gebt ihr einfach einen Text oder ein paar Buchstaben im Terminal ein. Wenn ihr anschließend die Datei Text im Verzeichnis /tmp öffnet, dann solltet ihr dort euren eingegebenen Text sehen.

Webzugriff:

Natürlich kann der UART auch mittels Webzugriff bedient werden. Dies ist allerdings nicht ganz so einfach wie der Zugriff über die Konsole. Ich zeige euch wie ihr mit Hilfe eines C-Programmes und PHP Nachrichten die ihr in einem Webinterface eingebt, über den UART wieder ausgeben könnt. Da der Zugriff auf die Datei für den UART Root-Rechte benötigt und wir nicht jedes mal ein Passwort eingeben können, müssen wir dies abstellen. Dazu tippen wir

$ sudo visudo

in die Konsole ein. Dadurch wird die Datei sudoers.tmp geöffnet. An diese Datei hängt ihr folgende Zeile an:

www-data ALL=(ALL) NOPASSWD: /Programme/UART_Senden

Diese Zeile sorgt dafür, dass der User www-data, sprich der Webserver, kein Passwort für die Ausführung der Datei /Programme/UART_Empfangen benötigt.

Anschließend wird die Änderung über die Tastenkombination Strg + O gespeichert. Jetzt muss noch der User dialout zu der Gruppe www-data hinzugefügt werden, damit der Schnittstellentreiber vom Webserver verwendet werden kann:

$ sudo adduser www-data dialout

Werfen wir nun einen Blick auf das Webinterface…

Die Funktion

if(isset($_POST["Eingabe"]))
{
    $Befehl="sudo /var/Programme/UART_Senden ".$_POST["Eingabe"];
    $Output = shell_exec($befehl);
};

prüft, nachdem auf den Senden-Button gedrückt wurde, ob die Variable Eingabe überhaupt existiert und ob der Inhalt ungleich 0 ist, sprich ein Text in der Variable steht. Wenn dies der Fall ist, werden folgende Zeilen ausgeführt:

$Befehl="sudo /var/Programme/UART_Senden ".$_POST["Eingabe"];
$Output = shell_exec($befehl);

In die Variable Befehl wird der String sudo /var/Programme/UART_Senden [gesendeter Text] gespeichert. Anschließend wird mittels shell_exec der Befehl, welcher in der Variable $befehl steht, ausgeführt. Wenn also in dem Textfeld Hallo eingegeben wird und auf Senden gedrückt wird, wird folgender Befehl ausgeführt:

$ sudo /var/Programme/UART_Senden Hallo

Das Hallo ist in diesem Fall ein Parameter, welcher beim Programmaufruf mit in das Programm übergeben wird.

Fehlt nur noch das dazugehörige C-Programm…

In dem C-Programm muss zuerst die serielle Schnittstelle initialisiert werden. Dies soll über eine Funktion namens UART_Init geschehen:

int UART_Init(void)	
{
    File = open(UART, O_WRONLY | O_NOCTTY);
    if(File < 0)
    {
        printf("Can not open serial0! %s\n", UART);
        exit(-1);
    }

    memset(&newtio, 0, sizeof(newtio));
    newtio.c_cflag = BAUDRATE | CS8 | CLOCAL | CREAD;
    newtio.c_iflag = IGNPAR;
    newtio.c_oflag = 0;
    newtio.c_lflag = 0;
    newtio.c_cc[VTIME] = 0;
    newtio.c_cc[VMIN] = 1;
    tcflush(File, TCIFLUSH);
    tcsetattr(File, TCSANOW, &newtio);

    return File;
}

Diese Funktion öffnet zuerst die serielle Schnittelle.

File = open(UART, O_RDONLY | O_NOCTTY);
if(File < 0)
{
    printf("Can not open serial0! %s\n", UART);
    exit(-1);
}

Da bei Linux alles über Dateien läuft, wird der UART ebenfalls über eine Datei angesprochen und gesteuert. Die erste Zeile öffnet also eine Datei mit dem Namen MODEMDEVICE, welcher weiter oben deklariert wurde. Da wir nur Schreiben möchten wird zusätzlich der Parameter O_WRONLY eingefügt. Der Rückgabewert, also die Index, den die geöffnete Datei bekommt, wird unter fd gespeichert. Der Rest des Unterprogrammes stellt die Baudrate, Handshake usw. ein. Die Baudrate wird in diesem Programm auf 115200 gesetzt.

Das Hauptprogramm übernimmt das Senden von Daten und sieht folgendermaßen aus:

int main(int argc, char** argv)
{
    char LineEnd[] = "\r\n";
    int res;
    UART_Init();
    if(argc >= 1)
    {
        res = write(File, argv[1], strlen(argv[1]));
        write(File, LineEnd, 2);
    }

    printf("Text empfangen\n");

    close(File);
    return 0;
}

Als erstes werden die Parameter, welche wir beim Aufruf des C-Programmes mit in das Programm übergeben haben unter dem Array argv gespeichert. Die Variable argc beinhaltet die Anzahl der Parameter. Bei dem verwendeten Funktionsaufruf sehen argc und argv also so aus:

argc = 2

argv[0] = /var/Programme/UART
argv[1] = Hallo

Diese Variablen können nun ganz normal im Programm genutzt werden. Das Senden des Textes erfolgt dann über die write-Funktion für Dateien:

if(argc >= 1)
{
    res = write(File, argv[1], strlen(argv[1]));
    write(File, LineEnd, 2);
}

Diese Funktion prüft ob argc größer als 1 ist. Wenn dies der Fall ist wurde ein Parameter in das C-Programm übergeben. An erster Stelle erwartet diese Funktion einen Index auf die geöffnete Datei. Dieser wird durch die Variable File dargestellt.

Anschließend wird gesagt, was in die Datei geschrieben werden soll. Da wir den Text, welchen wir im Webinterface in der Textbox eingegeben haben am UART ausgegeben haben wollen, setzen wir dafür die erste Stelle des Array argv ein. Anschließend muss der Befehl noch wissen wie viele Bytes er in die Datei schreiben sollen. Dies stellen wir fest, indem wir die Länge des Strings bestimmen. Dies funktioniert mittels strlen(argv[1]) ermittelt. Auf das Wort Hallo übertragen, gibt die Funktion also den Wert 5 zurück. 

Unter res wird anschließend die Anzahl der Bytes, die geschrieben wurden, gespeichert. Dieser Wert kann nun z. B. mit strlen(argv[1]) verglichen werden, um zu prüfen ob auch alles geschrieben wurde. Als letztes passiert dasselbe Spiel noch einmal um ein Zeilenende zu übertragen:

write(File, LineEnd, 2);

Damit schreiben wir noch ein CR + LF in den UART. Die Zeile

printf("Text empfangen\n");

gibt den Text Text empfangen aus. Die Funktion zum Aufruf des C-Programmes in dem PHP-Code sah so aus:

$Output = shell_exec($Befehl);

Alles was nach dem shell_exec ausgegeben wird, wird unter Output gespeichert. Dieser Text wir dann in dem Webinterface ausgegeben, so sieht man direkt das ein Text empfangen wurde.

Am Ende des C-Programmes wird dann noch mit

close(File);

die Datei des UART geschlossen. Wenn alles richtig gemacht wurde, wird beim drücken auf den Knopf Senden im Terminal der Text ausgegeben den ihr ins Textfeld eingegeben habt.

Das Empfangsprogramm wird während des Bootvorgangs gestartet und überwacht anschließend im Hintergrund die UART-Schnittstelle. Das Hauptprogramm

while(1)
{
    Character = Receive();
    if((Character == 13))
    {
        Message[Length++] = 0x0D;
        WriteFile();
    }
    else if(Zeichen > 13)
    {
        Message[Length++] = Zeichen;
        if(Laenge > 254)
        {
            WriteFile();
        }
    }
}

besteht aus zwei getrennten Abfragen, welche die Zeichenauswertung übernehmen.

Als erstes wird das aktuelle Zeichen unter der Variable Character gespeichert, nachdem es durch die Funktion Receive ausgelesen wurde.

Das empfangene Zeichen wird anschließend in der ersten if-Abfrage untersucht:

if((Character == 13))
{
    Recieve[Length++] = 0x0D;
    WriteFile();
}

Sobald das empfangene Zeichen ein CR ist, wird ein CR an der aktuellen Position des Empfangsstring Message angehängt. Anschließend wird die Position des Strings um eins erhöht (Length++). Als letztes wird die Funktion WriteFile aufgerufen. Die nachfolgende Abfrage

else if(Character > 13)
{
    Message[Length++] = Character;
    if(Length > 254)
    {
        WriteFile();
    }
}

prüft ob das Zeichen größer als 13, sprich von einem CR verschieden, ist. Wenn es das ist wird das aktuelle Zeichen an der aktuellen Position des Strings gespeichert und die Position um eins erhöht. Dies geschieht solange bis die Länge des Strings nicht größer als 254 ist (da mein Array nur 255 Bytes groß ist). Wenn dies der Fall ist, wird ebenfalls die Funktion WriteFile aufgerufen.

Als erstes wird in der Funktion eine neue Datei geöffnet. :

Temp = open(FILEDEVICE, O_WRONLY | O_CREAT | O_APPEND);

Als Zusatzparameter habe ich festgelegt, dass in die Datei nur geschrieben werden soll und das diese generiert werden soll, sobald sie nicht vorhanden ist. Als nächstes wird mittels

write(Temp, Message, Length);
close(Temp);

der komplette Empfangsstring in diese Datei geschrieben und anschließend geschlossen. Jetzt werden noch die Rechte für die Datei entsprechend gesetzt

system("chmod 644 /tmp/UART_Empfangen.txt");

und der gesamte String, sowie der Zähler gelöscht:

for(Counter = 0; Counter < Length; Counter++)
{
    Message[Counter] = 0;
}

Length = 0;

Jetzt muss das Programm nur noch gestartet werden. Dies kann entweder manuell gemacht werden oder (wie ich es mache) durch ein Startskript. Das Startskript könnt ihr euch ebenfalls downloaden und anschließend müsst ihr es unter /etc/init.d speichern. Anschließend müsst ihr noch den Pfad zu dem Empfangsprogramm in dem Skript ändern und das Skript einbinden:

$ sudo update-rc.d Name des Startskripts defaults

Nach einem Reboot sollte der Text Starte UART Empfang… auf dem Bildschirm erscheinen. Wenn dies der Fall ist, ist das Programm im Hintergrund gestartet worden und verrichtet seine Arbeit. Die Datei mit den empfangenen Zeichen, könnt ihr natürlich auch per PHP auslesen. Dadurch könnt ihr per Browser nachschauen was euer Raspberry Pi empfangen hat.

Nachfolgend ein paar Beispiele für die Verwendung des UART bzw. des USB:

Auslesen von RFID-Tags
Auslesen einer GPS-Maus
Anschluss eines seriellen LCD

Alle notwendigen Dateien sind in meinem GitHub-Repository zu finden.

59 Kommentare

  1. Hallo,

    ich finde die Seite super und habe schon viele Dinge (z.B. GPIO- Ansteuerung über PHP) gut verwenden können. Z.Z versuche ich den PI über die RS232 Schnittstelle an meine CControl anzubinden. Dazu habe ich ein Pythonscript geschrieben, das sollte dann über die Web-Seite aufgerufen werden. Ich habe mich an die oben angegeben Beschreibung gehalten. Das Script läuft einwandfrei auf Terminalebene. Ich schaffe es aber nicht, es über PHP auszuführen. Immer wenn ich versuche die Zeile www-data ALL=(ALL) NOPASSWD: /var/www/Python/Wetterstation.py in die sudoers.tmp mit visudo einzufügen, funktioniert sudo nicht mehr und ich bin aus dem System ausgesperrt. Es wäre super, wenn Sie mir da weiterhelfen könnten.
    Grüße Clemens Braun.

  2. Hallo,

    erst mal prima Page, hat mir schon oft geholfen.

    Jetzt will ich an einem Raspberry den USART deaktivieren. Jedes mal nachdem ich die hier beschriebenen Änderungen durchgeführt habe bleibt der Raspberry beim Booten hängen.

    Kennst du das Problem schon?

    Gruss
    Matt

    1. Hey,

      hast du das Pi eventuell übertaktet?
      Wenn ja könnte es daran liegen (hatte den Fehler auch mal).
      Aber ich wüsste nicht das es am UART liegt.

      Gruß
      Daniel

  3. Ach, falscher Gedanken zum richtigen Thema :-D.
    In der /boot/cmdline.txt stehen bei mir auch noch weitere Daten, die wohl Verweise auf die Bootdaten sind. Da diese in der gleichen Zeile wie die UART-Daten stehen hatte ich diese auch gelöscht.

    Aber habs gemerkt.

    Danke

  4. Hi,

    leider habe ich noch kein echtes RS232 Gerät am Raspi hängen, da ich och auf den TTL-Wandler warten muss. Ich bereite jedoch gerade ein Script vor.
    Was mir jedoch noch nicht ganz klar ist…
    Über den USART kommt ein String in die Datei UART_Empfang.txt
    Wir diese immer wieder überschrieben oder oder wir das Neu kommt in der UART_Empfang.txt angehängt…

  5. Hallo,

    ich muss dazu sagen, dass ich völliger Anfänger bin…
    Jetzt hab ich das folgende in ein bash-script gepackt…

    if grep -o $'\r\n' UART_Empfang.txt
    then
    echo Vollständig
    fi

    Ich möchte prüfen ob mein string bereits vollständig in der Datei UART_Empfang.txt ist.
    Mein String der über RS232 kommen soll wir mit einem CRLF abgeschlossen.

    Leider gibt er mir mein „Vollständig“ auch aus wenn ich in die UART_Empfang.txt auch nur ein paar Zeichen ohne CRLF am Ende eingebe…

    Kann mir da jemand weiterhelfen? Bzw. wie soll ich das am besten lösen?

    Danke!

    1. Hey,

      mmmh ob du das händisch machen kannst weiß ich nicht.
      Eventuell geht es mit einem kleinen Programm….getestet habe ich das aber noch nie :)

      Gruß
      Daniel

    2. Habe eine neue SD-Karte aufgesetzt und nochmal alles wie nach Anleitung probiert.
      Danach wieder nichts…. Wollte schon aufgeben. Habe aber nochmals screen probiert –> hat funktioniert. Python funktioniert noch immer nicht. Aber nun funktioniert plötzlich die wiringSerial Bibliothek von wiringPi.

  6. Erstmal ein großes Lob an dieser Seite, super Arbeit, Respekt.
    Habe schon einige Dinge von Deinen Ausführungen gut „gebrauchen“ können.
    Mein Frage:
    Wir kann ich das Programm UART_Empfangen.c so ändern, so das der
    empfangene String gleich als Hex Byteweise in der Datei gespeichert wird?
    ich hoffe Du kannst mir helfen.

    1. Falsch:)
      Also, ich sende zu RP einen Hexwert z.B. 00 06 04.
      Genau so sollte es auch in der UART_Empfang.txt stehen.
      Leider komm ich nicht mehr weiter:(

          1. Hey,

            werden die nicht dargestellt oder nicht empfangen?
            Das Terminal interpretiert die Werte 0 – 31 als Steuerzeichen und zeigt die deswegen nicht an.

            Gruß
            Daniel

    1. Hey,

      mmmh…dann musst du das C-Programm mal Schritt für Schritt durch gehen und schauen wo es happert. Lass dir einfach mal an verschiedenen Stellen den Variablenwert ausgeben.
      Sendest du auch immer ein CR + LF mit? Weil darauf achtet das Programm.

      Gruß
      Daniel

  7. Hallo ,
    Super Anleitung .
    Über das aufgerufene C-Programm kann ich problemlos Zeichen senden .
    Wie kann ich über das C-Programm(RPi) Zeichen einlesen und auf der Webseite anzeigen ?

    Gruss
    Rudi

  8. Was den RS232 anbetrifft kann man auch einen preiswerten USB Seriell Adapter verwenden z.B. Reichelt.
    Die benutzen alle den Prolific Chip der vom RasPi automatisch erkannt wird. Der serielle RS232 Port ist dann unter /dev/ttyUSB0 zu finden.
    Mit dem Package ser2net (Repository) kann man dann auch via reverse Telnet drauf zugreifen wie natürlich auch auf alle anderen tty’s.

    Gruß
    willi

  9. Hallo,
    Vielen Dank für die nachvollziehbare Aufbereitung.
    Kleiner Tip, falls der UART im RasPi zickt, folgende Zeile
    init_uart_clock=32000000
    in /boot/config.txt ergänzen.
    Dann rebooten.
    Viele Grüße
    Eagle
    Kleine Ergänzung, falls UART auf dem RasPi partout nicht will:

  10. Hallo,
    danke für das Tutorial, ich habe aber ein Problem und verstehe nicht ganz warum:
    Ich habe ein iBoard (Arduino-Klon mit 3,3V) über UART an den RPi angeschlossen.
    Hier der Code, der auf dem ATMEL ausgeführt wird:

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

    void loop() {
    Serial.println("Hallo, Welt!");
    delay(1000);
    }

    Sendet also nur immer Hallo Welt und im Serial Monitor über USB kommen die Daten auch richtig an.
    beim RPi bin genau ich dem Tutorial gefolgt, aber cat liefert nur wirres Zeug:

    pi@raspberrypi ~ $ cat /dev/ttyAMA0
    Hall�]��х�)�H�K�U��5)�Ha�i�}��7)�Hal��}��5
    Hal���U��5)��X[[ձх5)��all�HC��[[[���х5)��a����{]YC�h���UW��Ha�lo��U��Xall��U���Hallol�U���Hallo<�welt��Hall<�Welt!�Hallo<!UV��5�Hallo, Wy[]HC��allo, U�t!
    R,����u��LC��,� �U�х�
    Z-��� �U�ѤH�ﶶ� �U�х5i��?l� �U�х5+�^C

    Ich habe mit stty die Einstellungen geprüft und auch mit dem „UART-Empfangen.c“ kein Glück. Die clock habe ich auch in der /boot/config.txt eingestellt:
    init_uart_clock=32000000
    Hat jemand eine Idee oder Erfahrungen mit der Kommunikation ArduinoRPi?
    Vielen Dank im Voraus.
    Viele Grüße
    Achim

      1. Hi,
        danke für die schnelle Antwort.
        Hier meine Einstellungen:

        pi@raspberrypi ~ $ stty -F /dev/ttyAMA0
        speed 9600 baud; line = 0;
        intr = ; quit = ; erase = ; kill = ; eof = ; start = ;
        stop = ; susp = ; rprnt = ; werase = ; lnext = ; flush = ;
        min = 1; time = 0;
        -brkint -icrnl -imaxbel
        -opost -onlcr
        -isig -icanon -iexten -echo -echoe -echok -echoctl -echoke

        Ich bin mir eben nicht sicher welche Einstellungen ich genau brauche für die Kommunikation mit dem Arduino…
        Viele Grüße,
        Achim

        1. Hey,

          die Einstellungen sagen mir eigentlich gar nichts, aber für eine Kommunikation mit dem Arduino brauchst du im Grunde nur die Baudrate einstellen und das machst du mit den beiden Befehlen wie sie unter „USART konfigurieren“ stehen.
          Dann sollte es eigentlich funktionieren.

          Gruß
          Daniel

          1. Ja genau das habe ich gemacht. Ich habe mit
            sudo stty 9600 -F /dev/ttyAMA0
            die Baudrate auf 9600 gesetzt. Die anderen Ainstellungen müssten eigentlich die Standards sein, da ich daran nichts geändert habe.

    1. Habe es herausgefunden. Fühle mich ein wenig blöd, aber evtl. kann ich einem anderen Noob diese Sucherei ersparen :)
      Man sollte schon die GND-Pins verbninden, da sonst kein klares Signal herauskommt.

      1. Hey,

        den Fehler habe ich auch schon mal gemacht ;)
        Das ist ein typischer Fehler beim UART und eigentlich nicht schlimm (weil den praktisch jeder schon einmal gemacht hat…).
        Aber gut das du es selber herausgefunden hast wo das Problem liegt.
        Im Endeffekt lernt man aus sowas nur :)
        Viel Spaß mit dem UART :)

        Gruß
        Daniel

  11. Hallo,

    erstmal tolle Seite mit vielen Erklärungen.
    Ich habe ein Problem mit dem Uart. Zwar sendet er etwas, wahrscheinlich sogar das was ich eingebe, aber es ist ein kleiner Puls am Anfang der Übertragung drangehangen. Der macht natürlich die ganze Übetragung kaputt.
    Es pasiert irgendwo beim Initialisieren der Uart. Aber das wird ja bei jedem senden dann gemacht. Hast du dafür eine Erklärung?

    Grüße
    Ralf

    1. Hallo Ralf,

      das Problem habe ich auch festgestellt.
      Wie man es umgeht weiß ich leider nicht wirklich. Ich umgehe das Problem, indem ich direkt nach dem Initialisieren ein Endline (Sprich CR und LF) sende.
      Damit ist der Peak weg und vom Gerät am UART wird das einfach als ungültiger Befehl erkannt.

      Gruß
      Daniel

      1. Hey,

        ja das wäre eine Möglichkeit. Blöd wäre damit allerdings das bei jedem Sendebefehl immer erstmal ein falscher dabei ist. Da ich RS485 nutzen möchte habe ich es nun anders gelöst. Der RS485 Treiber ist vor dem Initialisieren einfach auf Empfang, bzw. ganz stumm geschaltet. Erst kurz vor der Sende Routine setze ich den Sendetreiber. Damit kommt nun gar kein störender Impuls. Wäre natürlich mit einem „verunden“ mit TX auch möglich.

        Grüße Ralf

        1. Hallo Ralf,

          ne, du hast mich falsch verstanden :)
          Du initialisierst die Schnittstelle ja einmalig beim Programmstart. Dann sende ich die eine „Leernachricht“ ab, wodurch der „Dreck“ im Sendemodul raus ist.
          Danach funktioniert die Schnittstelle einwandfrei.
          Aber deine Möglichkeit geht natürlich auch. Wenn der Treiber so eine Funktion besitzt, dann kann man sie natürlich ideal dafür verwenden.

          Gruß
          Daniel

  12. Aso, das habe ich auch probiert. Nur ging danach das senden nicht mehr, weil ihm da das Handel oder was auch immer fehlte. Ich kab nicht wirklich Linux Kenntnisse.

    Grüße Ralf

    1. Hey Ralf,

      ja du darfst die Schnittstelle halt nicht direkt danach schließen.
      Also das sieht etwa so aus (Pseudocode ;) ):

      serial.open()
      serial.send(„\n\r“)

      while True:
      Programm

      Aber deine Methode gefällt mir ehrlich gesagt etwas besser ;)
      Aber das funktioniert halt nur mit einem Wandler. Meins ist so ein bisschen gebastel, da ich keinen Wandler dran hatte.

      Gruß
      Daniel

  13. Hey! Super gut erklärt! Dafür mal danke!

    Mein Problem ist, dass wenn ich mich über ein Terminalprogramm mit dem Uart verbinde, dass ich ständig Bytes vom Uart bekomme (und zwar kontinuierlich viele, und zwar vorwiegend die Werte 255, 239), obwohl ich vom Raspberry Pi gar nichts schicke. Wenn ich dann vom Raspberry Pi etwas über Uart schicke, bekomme ich es zwischen den ganzen Bytes auch. Senden vom PC an den Raspberry geht aber nur wenn ich den RX Pin abhänge. Die Files habe ich angepasst, wie du geschrieben hast, die Baud Rate ist bei beiden gleich. Ich weiß nicht mehr weiter! :-(

  14. Hallo,

    ich verwende das C-Programm zum Empfangen von RS232-Nachrichten. Das Empfangene wird auch brav in einer .txt-Datei gespeichert. Ich kann nur diese Datei nicht mit „cat rs.txt“ ausgeben lassen. Mit dem cat-Befehl wird leider gar nichts ausgegeben. Öffne ich die Datei hingegen mit dem Editor nano kann ich alle Daten einsehen.
    Da ich die Daten gerne weiter bearbeiten würde, ist eine Ausgabe mit cat erforderlich.
    Vielleicht kannst du mir ja weiterhelfen.
    Vielen Dank!

    1. Hallo Martin,

      heißt die Datei bei dir auch „rs.txt“? Und bist du dir sicher, dass du kein Zugriffsproblem hast?
      Der cat-Befehl sollte eigentlich ganz normal funktionieren.

      Gruß
      Daniel

  15. Hallo Daniel,
    auch von mir ein großes Lob für dein Buch und die kompetente Homepage. Ich habe ein kleines Problem mit dem UART-Empfang. Das Start-Skript läuft einwandfrei, aber ich glaube, dass das C-Programm nicht funktioniert, da keine entsprechende txt-Datei angelegt wird. Ich habe den Quellcode entsprechend des Kommentars compiliert, aber es läuft nicht.
    Hast du vielleicht eine Idee?
    Gruß,
    Roman

      1. Hallo Daniel,
        sudo gcc UART_Empfangen.c -o UART_Empfangen
        liefert keine Rückmeldung, wenn ich allerdings ohne sudo starte, bekomme ich eine Fehlermeldung (/usr/bin/ld: cannot open output file permission denied collect2: ld returned 1 exit status).
        Wenn ich anschließend versuche, das C-Programm zu starten (gcc UART_Empfangen) erhalte ich dieselbe Fehlermeldung wie oben. Durch das Ausführen mit sudo verschlimmert sich das Ganze noch und ich bekomme eine lange Liste von Fehlern.
        Da ich mich mit der C-Programmierung am Pi nicht auskenne, bin ich leider ziemlich ratlos…
        Gruß,
        Roman

        1. Hallo Roman,

          das das Starten ohne sudo nicht funktioniert ist klar, da man für die serielle Schnittstelle root-Rechte benötigt.
          Kannst du mir mal einen Screenshot der Fehler schicken?

          Gruß
          Daniel

          1. Hallo Roman,

            du musst das Programm erst mit dem Aufruf in der C-Datei kompilieren und zum Ausführen musst du dann „sudo /Pfad/UART_Empfangen“ eingeben.

            Gruß
            Daniel

          2. Hallo Daniel,
            natürlich, danke für den Hinweis! Ich hatte das anfangs schon ausprobiert, war aber direkt im Verzeichnis des Programms und habe dann nur „sudo UART_Empfangen“ eingegeben, was zu einer Fehlermeldung geführt hat.
            Jedenfalls ganz herzlichen Dank für die Hilfe und schöne Grüße,

            Roman

  16. Guter Beitrag :)

    Ich habe ein Problem mit der read() Funktion. Diese gibt eine Null zurück.
    Manchmal hängt diese Funktion auch. Also ich habe vor und nach der Funktion eine Ausgabe und nur die erste Ausgabe wird ausgegeben.

    Ich besitze auch keine ínittab Datei auf meinem RP. Ich habe mich etwas schlau gemacht. Dies sei normal und man müsste das jetzt über die config.txt (aus dem boot Ordner) konfigurieren.
    Bei mir steht jetzt: enable_uart=1

    Ist das richtig? Ich programmiere zum ersten Mal einen RP :D

    Gruß
    Tobias

    PS: Ich versuche ihn mit einem RS485 zu verbinden.

    1. Hallo Tobi,

      wenn die „read()“-Funktion eine 0 zurück gibt, werden keine Daten gelesen. Das Tutorial ist schon etwas älter und mittlerweile muss man den UART über den Device Tree konfigurieren.
      Schau dir mal diese Beschreibung an:

      https://www.abelectronics.co.uk/kb/article/1035/raspberry-pi-3-serial-port-usage

      Wichtig ist vor allem, dass du aus der Datei /boot/cmdline.txt die Zeile

      console=serial0,115200

      entfernst, damit der Kernel die Schnittstelle nicht nutzt.

      Gruß
      Daniel

  17. Hi,
    ich habe mir ein UART-USB Modul gekauft und über die GPIO Anschlüsse mit dem Raspberry Pi verbunden. Wenn ich jetzt z.B. mit einem Python-Programm einen Text abschicke, dann kriege ich auf dem PC nur irgendwelche Zeichen. Die Baudrate habe ich aber richtig eingestellt. Gibt es noch irgendetwas das ich versuchen könnte?
    Danke schon mal im Voraus!

    1. Hallo Kampi,
      bin jetzt nicht sicher ob es hier weitergeht da der letzte Eintrag aus 2017 stammt, versuche es aber einfach mal. Habe versucht nach Deinen extra Klasse Erklärung meinen IR-Kopf mit USB Kabel nach dieser Anleitung auszulesen.
      Ich scheitere schon kläglich an dem Befehl :
      cat /dev/ttyAMA0 >> /tmp/Text bzw.
      cat /dev/ttyUSB0 >> /tmp/Text
      es passiert in /tmp/Text überhaupt nichts, ein
      ls -l /dev/serial/by*
      /dev/serial/by-id:insgesamt 0
      Dez 22 22:47 usb-FTDI_FT232R_USB_UART_AD01QVKZ-if00-port0 -> ../../ttyUSB0
      /dev/serial/by-path:insgesamt 0
      Dez 22 22:47 platform-20980000.usb-usb-0:1.2:1.0-port0 -> ../../ttyUSB0 und ein
      ls -l /etc/udev/rules.d/
      27 Aug 1 15:27 99-com.rules
      würde mich über eine Antwort freuen.
      LG Peter

      ergibt

      1. Hallo Peter,
        ich bin ab nächste Woche wieder Zuhause. Dann können wir mal schauen wo das Problem liegt. Kannst du mir bitte bis dahin eine E-Mail mit ein paar zusätzlichen Informationen (Beschreibung des Gerätes, was du alles gemacht hast, welche Raspberry Pi Version inkl. OS und was du gerne als Output erwartest) schicken?

        Gruß
        Daniel

        1. Hallo Daniel,
          erstmal besten Dank, daß Du versuchst Dich um mein Problem zu kümmern. Bis vor einem Monat habe ich meinen Zähler Siemens TD 3511 (Zweirichtungszaehler) per IR-Kopf und einem YPORT+ als ser2net über WLAN (von VZ-Udo) mit einem php-skript ausgelesen. Der YPORT+ ist nun defekt und wollte nun einen übrigen Raspi B 2 als Ersatz (ser2net an WLAN) einrichten. Also USB Kabel vom IR-Kopf (/dev/ttyUSB0) mit ser2net auf WLAN schicken und mit dem vorhandenen php-skript die Volkszähler Frontend Kanäle (middleware.php) in FHEM anzeigen. Nun mal die Daten :
          Haussteuerung PC (ein Mini PC mit Linux Cinnamon 17.3
          Intel Celeron CPU J1800 2,4 Ghzx2 RAM 3,7 GiB
          FHEM 5.9
          Freue mich auf nächste Woche LG Peter

Schreibe einen Kommentar

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