Ports benutzen (GCC)

Aus der Mikrocontroller.net Artikelsammlung, mit Beiträgen verschiedener Autoren (siehe Versionsgeschichte)
Wechseln zu: Navigation, Suche

Einleitung

Über die Ansteuerung der Schnittstellen unter Linux findet man im Internet überall etwas anderes, die einen sagen man soll die Schnittstellen über ihre I/O-Adresse (0x378,...) ansteuern.

Hier bleiben zwei Fragen offen:

- Kann ich USB-RS232-Adapter benutzen? -- Nein, USB-RS232-Adapter werden nicht über I/O-Adressen angesteuert.
- Brauche ich Root-Berechtigung? -- Ja, ohne Root-Berechtigung kann man nicht auf I/O-Adressen zugreifen.


Die hier vorgestellte Methode ermöglicht folgendes:

- zugriff auf Schnittstellen ohne Root-Berechtigung
- zugriff auf alle parallelen oder seriellen Schnittstellen, egal ob USB oder nicht
- portieren des Codes auf MacOSX, freebsd, ...

Allgemein

Zugriffsrechte:

Damit man auf die Schnittstellen zugreifen kann braucht man die passende Berechtigung. Auf meinem Debian-System sehen die Zugriffsrechte so aus:

noway:/# l /dev/ttyUSB0 /dev/ttyS0 /dev/parport0
crw-rw----    1 root     lp        99,   0 Feb 28 16:00 /dev/parport0
crw-rw----    1 root     dialout    4,  64 Jan 22 01:11 /dev/ttyS0
crw-rw----    1 root     dialout  188,   0 Jan 22 01:11 /dev/ttyUSB0

Damit der user auf die Schnittstellen zugreifen kann, muss er in die Gruppen "lp" und "dialout" eingetragen werden.


("Bevor man auf irgendeinen IO-Port vom Userspace zugreifen kann, muss man ioperm(2) aufrufen. Dazu benötigt das Programm allerdings root- oder SUID-Root-Privilegien." <- (nicht korrekt, geht ohne)) Ich programmiere seit 7 Jahren unter Linux und anderen Unix-Systemen (in C). Mir ist noch nie aufgefallen, dass Zugriffe direkt über IO-Ports ohne einen Aufruf von ioperm(2) oder ähnlichem gehen. Wäre nämlich ne ziemliche Sicherheitslücke! Da kannst die Sicherheit gleich vergessen ... Zugriffe über Files in /dev sind natürlich was anderes, die laufen ja auch durch den Kernel, während der Kernel bei Direktzugriffen (nach vorherigem Aufruf eben von ioperm) keine Überprüfung der Daten vornimmt!

Und ich programmiere seit 14 Jahren, seit 7 in C++ und seit 5 unter Linux, mir ist die Funktion von ioperm durchaus bekannt. Und das "nicht korrekt, geht ohne" sollte sich dabei auf den Schnittstellenzugriff beziehen. Wenn Du aber schon seit 7 Jahren unter Linux programmierst dann wirst Du zu der Behauptung, dass der Zugriff auf IO-Ports von userspace aus schlampiger ist als der gesamte Windowskernel, sicher zustimmen. Aber Du hättest spätestens dann gesehen dass diese Sache hier nichts mit ioperm am Hut hat als ich sagte dass man damit auch USB-RS232 Adapter ansteuern kann. Ausserdem vermeide ich den direkten Hardwarezugriff wo es geht, daher mag ich ioperm überhaupt nicht.

Ist schon klar, dass das mit ioperm übelst ist. Mit USB-Hardware ist da mal nix. ioperm ist nur was für X-Server und Konsorten (auch wenn's da AFAIK noch einen anderen Mechanismus gibt).

Schnittstellen öffnen und schließen

Bevor man auf eine Schnittstelle zugreifen kann muss man diese öffnen:

int port;
port = open("/dev/ttyS0", O_RDWR);

oder

#include <stdio.h>
...
FILE* port;
port = fopen("/dev/ttyS0", O_RDWR);

Die Schnittstellen die man hier öffnen kann sind unter anderem:

- die RS-232s im System: /dev/ttyS0, /dev/ttyS1, ...
- die USB-RS232s: /dev/ttyUSB0, /dev/ttyUSB1, ...
- die parallelen Schnittstellen: /dev/parport0, /dev/parport1, ...
die RS-232s im System /dev/ttyS0 /dev/ttyS1 /dev/ttySx
die USB-RS232s /dev/ttyUSB0 /dev/ttyUSB1 /dev/ttyUSBx
die parallelen Schnittstellen /dev/parport0 /dev/parport1 /dev/parportx


Wenn das Programm beendet wird sollte man diese auch wieder schliessen:

close( port );

Serielle Schnittstelle

Die Serielle Schnittstelle besitzt 3 Ausgangspins (TX,RTS,CTS) und 4 Eingangspins (RX,DTR,DSR,RI).

Jetzt kann man diese Pins einzeln setzen und abfragen, oder sie als RS232 Schnittstelle benutzen.

Pins einzeln verwenden

...

Als RS232 verwenden

Um die Schnittstelle "normal" zu benutzen muss man:

- die Schnittstelle öffnen
- die Schnittstelle konfigurieren
- die Daten mit read(2) lesen und mit write(2) schreiben
- die Schnittstelle schließen

Konfigurieren

Vor der Benutzung muss die RS232-Schnittstelle erstmal konfiguriert werden. Dazu verwendet man tcsetattr(2). Vorher allerdings nicht vergessen, die alten Einstellungen mit tcgetattr(2) zu sichern um sie bei Beendigung des Programmes wiederherzustellen .Sollte zwar eigentlich nicht nötig sein, aber es gibt fehlerhafte Programme, die nicht mehr funktionieren, wenn man exotische Einstellungen getätigt hat und den Zustand der seriellen Schnittstelle nicht wiederhergestellt hat.

...

Daten lesen/schreiben

Um daten zu lesen, oder zu schreiben, muss man den Port eben lesend oder schreibend öffnen.

...
  FILE* port;
  port = fopen("/dev/ttyS0","w"); // zum schreiben öffnen
...
...
  FILE* port;
  port = fopen("/dev/ttyS0","r"); // zum lesen öffnen
...

Dieses ist auch in kombination ( fopen(...,"rw")) möglich, um lesend und schreibend zugriff zu erlangen.

Parallele Schnittstelle

Die Parallele Schnittstelle besitzt 8 Datenleitungen und 9 Steuerleitungen, sowie 8 Massepins.

Die Datenleitungen können bidirektional verwendet werden (hängt allerdings von den Einstellungen im BIOS-Setup ab, Printer oder SPP reicht nicht; Bidirectional, ECP oder EPP ist erforderlich), die Steuerleitungen haben aber unabhängig von der BIOS-Einstellung eine festgelegte Richtung.

...