Ports benutzen (GCC)

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

Ü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 (0x3F8,0x2F8,0x378,...) ansteuern, allerdings ist das nicht portabel und funktioniert nur mit Root-Rechten.

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
  • einfaches Portieren des Codes auf MacOSX, FreeBSD, ...

Für den weiteren Artikel werden C/C++ Kenntnisse vorausgesetzt, denn die meisten Funktionen werden mit C-Code erklärt.

Allgemein

Was ist ein Port? Es ist zweideutig!

  • Eine Schnittstelle, etwa ein Parallelport oder ein serielles Port. Aus heutiger Sicht sollte man es vermeiden, direkt darauf zuzugreifen, egal welches Betriebssystem.
  • Ein E/A-Port, welches mit x86 in- und out-Assemblerbefehlen zugegriffen werden muss. Typischerweise auf einer Einsteckkarte befindlich, und eher ein Thema für die Kerneltreiberprogrammierung.

Der Mischmasch (oder Murks) kommt erst zu Tage, weil das Parallelport (erster Punkt) häufig mit E/A-Befehlen (zweiter Punkt) angesprochen wird. Unter Windows geht's auch nicht anders, unter Linux schon. Da Windows wegen der fehlenden API E/A-Befehle erfordert, hat sich Wildwuchs breitgemacht. Einigermaßen zukunftssicher ist hierbei nur die Verwendung von inpout32.dll. Parallelports verschwinden langsam, sind aber immer noch des Bastlers Nummer 1 wenn es um Peripheriekommunikation geht.

Zugriffsrechte

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

noway:/# ll /dev/ttyUSB? /dev/ttyS? /dev/parport?
crw-rw----    1 root     lp        99,   0 Feb 28 16:00 /dev/parport0
crw-rw----    1 root     lp        99,   1 Feb 28 16:00 /dev/parport1
crw-rw----    1 root     lp        99,   2 Feb 28 16:00 /dev/parport2
crw-rw----    1 root     lp        99,   3 Feb 28 16:00 /dev/parport3
crw-rw----    1 root     dialout    4,  64 Jan 22 01:11 /dev/ttyS0
crw-rw----    1 root     dialout    4,  65 Jan 22 01:11 /dev/ttyS1
crw-rw----    1 root     dialout    4,  66 Jan 22 01:11 /dev/ttyS2
crw-rw----    1 root     dialout    4,  67 Jan 22 01:11 /dev/ttyS3
crw-rw----    1 root     dialout  188,   0 Jan 22 01:11 /dev/ttyUSB0
crw-rw----    1 root     dialout  188,   1 Jan 22 01:11 /dev/ttyUSB1
crw-rw----    1 root     dialout  188,   2 Jan 22 01:11 /dev/ttyUSB2
crw-rw----    1 root     dialout  188,   3 Jan 22 01:11 /dev/ttyUSB3

Damit der User auf die Schnittstellen zugreifen kann, muss er in die Gruppen "lp" und "dialout" eingetragen werden. Wie das funktioniert kann man hier nachlesen: http://www.tuxhausen.de/kurs_user.html

Schnittstellen öffnen und schliessen

Schnittstelle mit open(2) öffnen

Bevor man auf eine Schnittstelle zugreifen kann muss man diese mit open(2) öffnen:

#include <fcntl.h>

int port;
port = open ("/dev/ttyS0", O_RDWR);
if (port == -1)
{
  // FEHLER: Port konnte nicht geöffnet werden!
}

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

close (port);

Schnittstelle mit fopen(3) öffnen

Öffnen:

#include <stdio.h>
...
FILE* port;
port = fopen ("/dev/ttyS0", "rw");
if (port == NULL)
{
  // ein FEHLER ist aufgetreten
}

Schliessen:

fclose (port);

Warum open(2) und nicht fopen(3)?

Der Zugriff mittels open(2) ist vorzuziehen, da hierbei deutlich flexiblere IO-Möglichkeiten (z. B. select, poll) zur Verfügung stehen, die sonst nur mittels Umweg über fileno(3) zu erreichen sind. Ferner kann die libc Schreibzugriffe mit fputs o.ä. Puffern, so dass man, um sicher zu stellen, dass die Daten auch tatsächlich übertragen wurden, fflush(3) aufrufen muss.

Natürlich funktionieren beide Methoden.

Die Namen der Schnittstellen

Die Schnittstellen die man benutzen kann sind unter anderem:

RS-232 Schnittstellen /dev/ttyS0 /dev/ttyS1 /dev/ttySx
USB-RS232 Schnittstellen /dev/ttyUSB0 /dev/ttyUSB1 /dev/ttyUSBx
Parallele Schnittstellen /dev/parport0 /dev/parport1 /dev/parportx
USB-parallelen Schnittstellen /dev/usblp0 /dev/usblp1 /dev/usblpx
I2C-/SM-Bus /dev/i2c-0 /dev/i2c-1 /dev/i2c-x

Serielle Schnittstelle

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

Der Zugriff auf die serielle Schnittstelle erfolgt entweder:

  • auf Protokollebene, oder
  • auf Pinebene (Pin1 -> an, Pin2 -> aus, ...)

Die Pinebene

Die Pins der Seriellen Schnittstelle können ohne vorherige Konfiguration gelesen/gesetzt werden. Der Zugriff auf die Pins erfolgt über ioctl(2). Dabei muss beachtet werden dass dieser Zugriff ohne Interrupts und ohne FIFO erfolgt, daher ist es eine polling-only Lösung, aber für die Programmierung eines Chip's über ISP oder die Ansteuerung eines Schieberegisters reicht es allemal.

Die Pins DCD,DSR,CTS,RI lesen

Die Eingangspins werden mit ioctl(2) gelesen:

#include <sys/ioctl.h>

int i;
ioctl (port, TIOCMGET, &i);

// Jetzt kann abgefragt werden welche Pins gesetzt sind:

if ( (i & TIOCM_CD) == TIOCM_CD) // Pin DCD
{
  // am Pin liegt Spannung an (3 bis 12V)
}
else
{
  // am Pin liegt keine Spannung an (0 bis -12V)
}

if ((i & TIOCM_DSR) == TIOCM_DSR) // Pin DSR
 ...
if ((i & TIOCM_CTS) == TIOCM_CTS) // Pin CTS
 ...
if ((i & TIOCM_RI ) == TIOCM_RI)  // Pin RI
 ...

Die Pins RTS,DTR setzen/löschen

Aktiviert wird RTS,DTR so:

int i = 0;
if (...) i |= TIOCM_RTS; // Pin RTS wird aktiviert (12V)
if (...) i |= TIOCM_DTR; // Pin DTR wird aktiviert (12V)
ioctl (port, TIOCMBIS, &i);

Und deaktiviert so:

int i = 0;
if (...) i |= TIOCM_RTS; // Pin RTS wird deaktiviert (-12V)
if (...) i |= TIOCM_DTR; // Pin DTR wird deaktiviert (-12V)
ioctl (port, TIOCMBIC, &i);

Den Pin TX setzen/löschen

Aktiviert wird TX so:

ioctl( port, TIOCSBRK, NULL );

Und deaktiviert so:

ioctl( port, TIOCCBRK, NULL );

Die Protokollebene

Üblicherweise steuert man die serielle Schnittstelle nicht auf der Pinebene an, sondern auf der Protokollebene. Dabei übernimmt die Hardware die Aufgabe, die Pins zu steuern. Um die Schnittstelle auf der Protokollebene 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(3). Vorher allerdings nicht vergessen, die alten Einstellungen mit tcgetattr(3) zu sichern, um sie bei Beendigung des Programmes wiederherzustellen. Dies 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.

Konfiguration lesen
struct termios config;
// int tcgetattr (int fd, struct termios *termios_p);
if (tcgetattr (port, &config) == -1)
{
  // error
}
Konfiguration schreiben
struct termios config;
// int tcsetattr ( int fd, int optional_actions, struct termios *termios_p );
if (tcsetattr (port, TCSANOW, &config) == -1)
{
  // error
}
Eigene Konfiguration erstellen

Auszug aus <bits/termios.h>:

struct termios
{
  tcflag_t c_iflag;           /* input mode flags */
  tcflag_t c_oflag;           /* output mode flags */
  tcflag_t c_cflag;           /* control mode flags */
  tcflag_t c_lflag;           /* local mode flags */
  cc_t c_line;                /* line discipline */
  cc_t c_cc[NCCS];            /* control characters */
  speed_t c_ispeed;           /* input speed */
  speed_t c_ospeed;           /* output speed */
};
struct termios config;            // struct erstellen
bzero (&config, sizeof(config));  // struct nullen

config.c_iflag = ;                // flags setzen
config.c_oflag = ;
config.c_cflag = ;
config.c_lflag = ;
config.c_cc[x] = ;

cfsetospeed (&config, B9600);     // baudrate setzen

// jetzt kann die konfiguration der schnittstelle zugewiesen werden
if (tcsetattr (port, TCSANOW, &config) == -1)
{
  // error
}

Daten lesen/schreiben

Mit read(2) kann man nun Daten von der Schnittstelle lesen. Wenn keine Daten anliegen und man read(2) aufruft, blockiert der Aufruf den weiteren Programmablauf. Dies kann man durch benutzen von select(2) verhindern.

int bytes;
char buffer[x];
bytes = read (port, buffer, sizeof(buffer)); 
// read(2) gibt die Anzahl der gelesenen Bytes zurück

Möchte man Daten über die Schnittstelle senden, muss man dafür write(2) verwenden. Dieser Aufruf blockt für gewöhnlich nicht.

int bytes;
int size;
char buffer[x];
bytes = write (port, buffer, size); 
// write(2) gibt die Anzahl der tatsächlich geschriebenen Bytes zurück
if (bytes != size) ... // Fehler

Parallele Schnittstelle

Die parallele Schnittstelle besitzt 8 Datenleitungen, 9 Steuerleitungen und 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.

Die benötigte Include-Datei heisst: <linux/ppdev.h>

Der Parallelport kann, wie die serielle Schnittstelle auch, in verschiedenen Modi angesprochen werden, dazu gehören:

  • Die Pinebene, nur bei sehr alter Hardware unidirektional, sonst immer bidirektional.
  • Die Protokollebene, dazu gehören die Protokolle SPP, EPP und ECP.

Die Pinebene

Wer früher den Parallelport unter DOS programmiert hat, wird sicher noch die Register kennen. Unter Linux wird auf diese Register aber nicht mehr direkt zugegriffen. Weil der Kernel jetzt den direkten Zugriff auf die Register steuert, muss man ihm über ioctl() sagen, was er machen soll.

Die Bits im Register und die dazugehörigen Pins

Registername Bit im Register Type Pin-Nummer Name
data 7 I/O 9 data bit 7
6 8 data bit 6
5 7 data bit 5
4 6 data bit 4
3 5 data bit 3
2 4 data bit 2
1 3 data bit 1
0 2 data bit 0
status 7 I 11 busy#
6 10 ack#
5 12 paper empty
4 13 printer is selected
3 15 error#
2 - - Interrupt has occurred
1
0
control 7 - -
6
5
4 enable Interrupt
3 O 17 select printer
2 16 initialize printer#
1 14 automatic line feed
0 1 strobe

data:

Pin  9, I/O, Bit 7 = data bit 7
Pin  8, I/O, Bit 6 = data bit 6
Pin  7, I/O, Bit 5 = data bit 5
Pin  6, I/O, Bit 4 = data bit 4
Pin  5, I/O, Bit 3 = data bit 3
Pin  4, I/O, Bit 2 = data bit 2
Pin  3, I/O, Bit 1 = data bit 1
Pin  2, I/O, Bit 0 = data bit 0

status:

Pin 11, I, Bit 7 = busy#
Pin 10, I, Bit 6 = ack#
Pin 12, I, Bit 5 = paper empty
Pin 13, I, Bit 4 = printer is selected
Pin 15, I, Bit 3 = error#
           Bit 2 = Interrupt has occurred
           Bit 1 = ?
           Bit 0 = ?

control:

           Bit 7 = ?
           Bit 6 = ?
           Bit 5 = ?
           Bit 4 = enable Interrupt
Pin 17, O, Bit 3 = select printer
Pin 16, O, Bit 2 = initialize printer#
Pin 14, O, Bit 1 = automatic line feed
Pin  1, O, Bit 0 = strobe

Parallelport öffnen

Das Öffnen der Parallelschnittstelle gestaltet sich ein wenig anders, als das Öffnen der seriellen Schnittstelle. Da an den Parallelport mehrere Geräte gleichzeitig angeschlossen werden können, und Linux das auch unterstüzt, braucht man eine Methode, mit der sich mehrere Programme die Schnittstelle teilen können. Dafür öffnet man die Schnittstelle, genau wie die serielle, erst mit open(2). Danach muss man ppdev sagen, dass man die Schnittstelle auch benutzen mag, das geschieht mit dem PPCLAIM ioctl-call.

int port;
port = open( "/dev/parport0", O_RDWR );
ioctl( port, PPCLAIM, NULL );

Parallelport schliessen

ioctl( port, PPRELEASE, NULL );
close( port );

Parallelport lesen/schreiben

Der Zugriff auf den Port erfolgt über seine Register, zu diesen gehören:

  1. Das "data" Register,
  2. "status" Register,
  3. "control" Register.
Register lesen
unsigned char r;
ioctl( port, PPRCONTROL, &r ); // liest das "control" Register
ioctl( port, PPRSTATUS , &r ); // liest das "status"  Register
ioctl( port, PPRDATA   , &r ); // liest das "data"    Register
Register schreiben
unsigned char r;
r = 0xXX;
ioctl( port, PPWCONTROL, &r ); // schreibt das "control" Register
ioctl( port, PPWDATA   , &r ); // schreibt das "data"    Register
"read modify write" umgehen

Wenn man nur ein paar Bits setzen/löschen möchte, könnte man erst den Registerinhalt lesen, die Bits ändern, und den Inhalt wieder schreiben.

Das geht aber besser, weil der Kernel dafür selbst eine Funktion anbietet:

/*
 struct ppdev_frob_struct {
        unsigned char mask;
        unsigned char val;
 };
*/

ppdev_frob_struct frob;
frob.mask = 0xXX;
frob.val  = 0xXX;
ioctl( port, PPFCONTROL, &frob ); // ändert Bits im "control" Register
                                  // new_control = (old_control & ~mask) | val;

Diese Funktion ist nur für das control Register verfügbar.

Parallelport Tri-State-Modus aktivieren

Bei deaktiviertem Tri-State-Modus treibt der Port die Datenleitungen. Dabei ist der Zustand vom data Register abhängig.

Wenn man nun den Tri-State-Modus aktiviert, treibt der Port die Datenleitungen nicht mehr. Nun kann man den Zustand der Datenleitungen über das data Register lesen.

int i;
i = 0; // Tri-State '''aus''' (Der PC treibt die Data-Leitungen)
i = 1; // Tri-State '''an'''  (Der PC treibt die Data-Leitungen '''nicht''')
ioctl( port, PPDATADIR, &i );

Die Protokollebene SPP

(to do)

Die Protokollebene EPP (IEEE 1284)

(to do)

Weblinks

  • parapin makes it easy to write C code under Linux that controls individual pins on a PC parallel port. This kind of control is very useful for electronics projects that use the PC's parallel port as a generic digital I/O interface. (Linux, LGPL)

Der I2C Bus & SMBus

Für den Linuxkernel gibt es auch I2C und SMBus Treiber, in Kernelversion 2.5 und 2.6 sind diese schon drin. Für Version 2.4 muss man diese extra installieren.

Wer es nicht so genau wissen möchte, kann sich einfach merken, das der SMBus ein I2C-Bus ist. Wer den SMBus aber ansteuern möchte, muss sich mit den kleinen Unterschieden aueinandersetzen. Hierfür wird auf das AN476 von Maxim verwiesen: http://www.maxim-ic.com/appnotes.cfm/appnote_number/476

Software

I2C u. SMBus Treiber installieren (Kernel 2.4)

Auf meinem Debian läuft ein selbstkompilierter Kernel, deswegen musste ich die Pakete i2c-source und sensors-source installieren. Voraussetzung ist das die Kernelquellen installiert sind.

apt-get install i2c-source lm-sensors-source

Danach liegen in /usr/src/ zwei *.tar Dateien:

noway:/usr/src# ll
-rw-r--r--   1 root root 146976 Apr 15  2005 i2c.tar.gz
-rw-r--r--   1 root root 924605 Sep 12  2005 lm-sensors.tar.gz

Diese muss man nun auspacken, danach in das Verzeichniss modules/i2c wechseln, und make ausführen:

noway:/usr/src# cd modules/i2c
noway:/usr/src/modules/i2c# make
noway:/usr/src/modules/i2c# make install
noway:/usr/src/modules/i2c# cd ../..

Und das gleiche nochmal für das lm-sensors-source Paket.

noway:/usr/src# cd modules/lm-sensors
noway:/usr/src/modules/lm-sensors# make
noway:/usr/src/modules/lm-sensors# make install

Danach wird man um diese Programme reicher:

i2cdetect
i2cdump
i2cset
isadump
isaset
sensors-detect
sensors
...

Jetzt sollte man die /dev/ Einträge erstellen:

noway:~# cd /dev
noway:/dev# ./MAKEDEV i2c
noway:/dev# l i2c-*
crw-------  1 root root 89, 0 Mar 17 21:00 i2c-0
crw-------  1 root root 89, 1 Mar 17 21:00 i2c-1
crw-------  1 root root 89, 2 Mar 17 21:00 i2c-2
crw-------  1 root root 89, 3 Mar 17 21:00 i2c-3
crw-------  1 root root 89, 4 Mar 17 21:00 i2c-4
crw-------  1 root root 89, 5 Mar 17 21:00 i2c-5
crw-------  1 root root 89, 6 Mar 17 21:00 i2c-6
crw-------  1 root root 89, 7 Mar 17 21:00 i2c-7

Damit kann jetzt nur "root" etwas anfangen. Damit die normalen Benutzer den Bus benutzen können, muss man eine neue Gruppe erstellen und die Zugriffsrechte anpassen:

noway:/dev# groupadd i2c
noway:/dev# chmod 660 i2c-*
noway:/dev# chgrp i2c i2c-*

Danach sollte es so aussehen:

noway:/dev# l i2c-*
crw-rw----  1 root i2c 89, 0 Mar 17 21:00 i2c-0
crw-rw----  1 root i2c 89, 1 Mar 17 21:00 i2c-1
crw-rw----  1 root i2c 89, 2 Mar 17 21:00 i2c-2
crw-rw----  1 root i2c 89, 3 Mar 17 21:00 i2c-3
crw-rw----  1 root i2c 89, 4 Mar 17 21:00 i2c-4
crw-rw----  1 root i2c 89, 5 Mar 17 21:00 i2c-5
crw-rw----  1 root i2c 89, 6 Mar 17 21:00 i2c-6
crw-rw----  1 root i2c 89, 7 Mar 17 21:00 i2c-7

Jetzt muss man sensors-detect aufrufen. Danach sollte für den SMBus das richtige Modul geladen sein. Mit "modprobe i2c-pport" kann man das Parallelport-I2C-Modul laden.

Welche Busse nun verfügbar sind, kann man mit "cat /proc/bus/i2c" erfahren.

Mit i2cdetect kann man jetzt die verfügbaren Busse scannen:

noway:~# i2cdetect -l
i2c-0   smbus           SMBus Via Pro adapter at e800           Non-I2C SMBus adapter
i2c-1   i2c             Primitive Parallel port adaptor         Bit-shift algorithm
noway:~# i2cdetect -y 0
     0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f
00:          XX XX XX XX XX XX XX XX XX XX XX XX XX
10: XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX
20: XX XX XX XX XX XX XX XX XX XX XX XX XX UU XX XX
30: XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX
40: XX XX XX XX XX XX XX XX UU UU XX XX XX XX XX XX
50: 50 XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX
60: XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX
70: XX XX XX XX XX XX XX XX
noway:~# i2cdetect -y 1
     0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f
00:          XX XX XX XX XX XX XX XX XX XX XX XX XX
10: XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX
20: XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX
30: XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX
40: XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX
50: XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX
60: XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX
70: XX XX XX XX XX XX XX XX

I2C Treiber installieren (Kernel 2.6)

Hier [1] gibt es die angepassten Sourcen für das i2c-pport Modul, dieses muss man selbst kompilieren. Der Rest funktioniert wie oben für Kernel 2.4 beschrieben.
Wichtig ist, dass man die Module lp und parport_pc auf die Blacklist setzt und den Parallelport im SPP-Modus betreibt (Bios-Einstellung). Dieser kleine Treiber benötigt keine weitere Hardware. (Quelle: [2])

I2C Bus öffnen/schliessen

Den Bus öffnet man nun genau wie die anderen Schnittstellen:

int bus;
bus = open( "/dev/i2c-0", O_RDWR );
if ( bus == -1 )
{
  // error
}
close( bus );

Die include-Datei <linux/i2c-dev.h> wird benötigt, ggf. auch <linux/i2c.h>.

I2C Bus steuern (ioctl)

An einem I2C-Bus können viele Chips angeschlossen werden, damit der Kernel weiss, mit welchem er Kontakt aufnehmen muss, braucht man diesen ioctl-call:

uint8_t slave_addr = 0xXX;
ioctl( bus, I2C_SLAVE, slave_addr );

"slave_addr" ist in diesem Fall die I2C-Adresse von dem Chip, den man ansprechen möchte.

I2C Bus lesen/schreiben

Nachdem man eine Slave-Adresse zugewiesen hat, kann man den selektierten Chip mit read(2) und write(2) ansprechen:

char buffer[256];
uint16_t bytes;
bytes = read( bus, buffer, sizeof(buffer) );

SMBus Zugriffe

Hardware

Der interne SMBus

Hier gibt es eine Beschreibung, wie man den SMBus findet: http://secure.netroedge.com/~lm78/hardhack.html

Externe I2C Busse

Parallelport-Bitbang Dongle

Für Linux gibt es ein Kernelmodul namens "i2c-pport". Das ist ein I2C-Bus über den Parallelport. Dieser Bus ist erschreckend einfach aufgebaut: es werden bis auf zwei Stecker keine Bauteile benötigt. Die notwendigen Verbindungen sehen so aus:

Parallelport I2C-Bus
14 SDA
16 SCL
18-25 GND

Das funktioniert nur deswegen, weil der Parallelport Open-Collector Ausgänge mit Pullup-Widerständen besitzt, und mehr braucht man für einen I2C-Bus nicht. Der PC kann die Leitungen SDA und SCL übrigens auch lesen.

Parallelport I2C-Bus Adapter mit PCF8584

(to do)

In den Franzis-Verlag-Büchern von 2002/2003

  • Messen, Steuern, Regeln mit Delphi ISBN 3772343643
  • Messen, Steuern, Regeln mit Visual Basic .net ISBN 3772340067
  • Messen, Steuern, Regeln mit Visual C++ ISBN 3772348955 und ISBN 3772348947

wird ein PCF8584-Adapter am EPP-Druckerport benutzt.

Verweise auf man-pages

Die manpages können online betrachtet werden unter http://www.rt.com/man/

Die Seite scheint inzwischen "Russia Today" zu gehören, die Manpages sind nur noch im Webarchiv zu finden: http://web.archive.org/web/*/http://www.rt.com/man

Dateien öffnen

-> open(2) http://www.rt.com/man/open.2.html

Dateien schliessen

-> close(2) http://www.rt.com/man/close.2.html

Dateien lesen

-> read(2) http://www.rt.com/man/read.2.html

Dateien schreiben

-> write(2) http://www.rt.com/man/write.2.html

Besonderer Dateizugriff

-> ioctl(2) http://www.rt.com/man/ioctl.2.html

Abfragen ob Daten zum lesen bereit sind

-> select(2) http://www.rt.com/man/select.2.html

Benötigte include Dateien

write(2) read(2) close(2)

#include <unistd.h>

open(2)

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

ioctl(2)

#include <sys/ioctl.h>

select(2)

#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>

für I2C und SMBus

#include <linux/i2c-dev.h>
#include <linux/i2c.h> //zumindest für 2.6.x

Siehe auch

Weblinks