Parallel Port: LED blinkt

From ConeleK Electronic Wiki
Jump to: navigation, search

In Arbeit

Einleitung

Inhalt
LED an Parallel Port eines PC

Dieser Artikel beschreibt, wie man über den Parallel Port eines PCs eine LED ansteuert. Hierzu dient ein minimaler HW-Aufbau auf einer Steckplatine. Dieser wird über ein handelsübliches 25-poliges Kabel mit dem parallelen Interface eines PC verbunden. Weiterhin wird ein winziges C-Programm beschrieben, welches das Blinksignal erzeugt.

Schaltung und Programm sind bewusst so einfach wie möglich gehalten, um einen schnellen Einstieg zu gewährleisten. Dies ist der erste Schritt, für weitere Experimente mit dem Parallel-Port.

Der Parallel-Port eignet sich hervorragend dazu, externe Schaltungen anzusteuern oder externe Sensoren über entsprechende Schaltungen auszulesen. Dies ist unter Linux mit wenig Aufwand an Hardware und SW möglich. Immerhin stehen pro paralleler Schnittstelle

  • 4 Steuerleitungen
  • 5 Statusleitungen
  • 8 Datenleitungen

zur Verfügung.


Voraussetzungen

Inhalt

Um diese Projekt durchführen zu könne, bedarf es gewisser Voraussetzungen.


Betriebssystem

Als PC-Betriebssystem kommt hier Linux (Kubuntu 11.10) zum Einsatz. Ich denke, es sollte aber auch mit anderen Distributionen funktionieren. Für Windows 7 habe ich keine einfache Möglichkeit gefunden, direkt auf die parallele Schnittstelle zuzugreifen. Wer eine einfache Möglichkeit kennt, könnte mir eine Mail oder einen Link schicken, ich würde mich freuen [1].

Parallele Schnittstelle

Der PC muss eine parallele Schnittstelle besitzen, die im Adressbereich bis 0x3FF angesiedelt ist, wenn das Programm so wie es unten steht, verwendet werden soll. Dies liegt an der Funktion ioperm(), die nur für diesen Adressbereich ausgelegt ist. Für den Einsatz von Parallel-Port-Erweiterungskarten, die irgendwo im Adressbereich bis 0xFFFF (65536) liegen, muss die Funktion iopl() verwendet werden. Mit USB/Parallelport-Adaptern funktioniert das Programm nicht, diese werden anders angesteuert.

Welche Adresse der Parallel-Port hat kann folgendermaßen festgestellt werden:

dmesg | grep parport
[    7.445613] parport_pc 00:06: reported by Plug and Play ACPI
[    7.445741] parport0: PC-style at 0x378 (0x778), irq 7, dma 3 [PCSPP,TRISTATE,COMPAT,EPP,ECP,DMA]
[    7.537237] lp0: using parport0 (interrupt-driven).

Der Parallelport heißt in diesem Fall parport0 und hat die Adresse 0x378.

Die folgende Tabelle zeigt eine Belegung des 25-poligen Steckers der parallelen-Schnittstelle. In dieser Anwendung wird lediglich

  • PIN2 data0
  • PIN24 Signal Ground

benutzt.

Tabelle: Belegung des Parallel-Ports

Pin Name Richtung Funktion
1 STROBE > Strobe
2 data0 <> Address, Data or RLE Data Bit 0
3 data1 <> Address, Data or RLE Data Bit 1
4 data2 <> Address, Data or RLE Data Bit 2
5 data3 <> Address, Data or RLE Data Bit 3
6 data4 <> Address, Data or RLE Data Bit 4
7 data5 <> Address, Data or RLE Data Bit 5
8 data6 <> Address, Data or RLE Data Bit 6
9 data7 <> Address, Data or RLE Data Bit 7
10 ACK < Acknowledge
11 BUSY < Busy
12 PError < Paper End
13 Select < Select
14 AutoFd > Autofeed
15 Fault < Error
16 Init > Initialize
17 SelectIn > Select In
18 GND Signal Ground
19 GND Signal Ground
20 GND Signal Ground
21 GND Signal Ground
22 GND Signal Ground
23 GND Signal Ground
24 GND Signal Ground
25 GND Signal Ground

Quelle: [2]

  • > vom PC zum Gerät
  • < vom Gerät zum PC
  • <> bidirektionale Signalleitung.

Programmiersprache / Entwicklungsumgebung

Es kommt ausschließlich kostenlose SW zum Einsatz, wie sie auf jedem Linux System entweder vorinstalliert ist, oder über das Paketmanagement leicht nachinstalliert werden kann. Die Programmiersprache ist C. Der Quellcode wird mit dem Compiler gcc übersetzt.

Test, ob gcc installiert ist:

gcc -v

Wenn gcc installiert ist erfolgt eine ausführliche Übersicht über die Konfiguration des Compilers, wenn nicht, gibt es eine Fehlermeldung. Bei Ubuntu / Kubuntu ist gcc nicht standardmäßig installiert. Die Ausgabe auf der Konsole sieht etwa so aus, wenn gcc installiert ist.

ruediger@comp1lx:~$ gcc -v
Using built-in specs.
COLLECT_GCC=gcc
COLLECT_LTO_WRAPPER=/usr/lib/gcc/x86_64-linux-gnu/4.6.1/lto-wrapper
Target: x86_64-linux-gnu
Configured with: ../src/configure -v --with-pkgversion='Ubuntu/Linaro 4.6.1-9ubuntu3' 
 --with-bugurl=file:///usr/share/doc/gcc-4.6/README.Bugs --enable-languages=c,c++,
fortran,objc,obj-c++,go --prefix=/usr --program-suffix=-4.6 --enable-shared 
--enable-linker-build-id --with-system-zlib --libexecdir=/usr/lib 
--without-included-gettext --enable-threads=posix 
--with-gxx-include-dir=/usr/include/c++/4.6 --libdir=/usr/lib --enable-nls 
--with-sysroot=/ --enable-clocale=gnu --enable-libstdcxx-debug 
--enable-libstdcxx-time=yes --enable-plugin --enable-objc-gc --disable-werror 
--with-arch-32=i686 --with-tune=generic --enable-checking=release 
--build=x86_64-linux-gnu --host=x86_64-linux-gnu --target=x86_64-linux-gnu
Thread model: posix
gcc version 4.6.1 (Ubuntu/Linaro 4.6.1-9ubuntu3


Die Installation der nötigen Pakete kann folgendermaßen durchgeführt werden:

sudo apt-get update
sudo apt-get install build-essential

Weiterhin wird noch ein Texteditor benötigt, um den Sourcecode einzugeben, oder zu ändern. Hierzu ist jeder beliebige Texteditor geeignet, der reinen Text abspeichert, wie Kate, vim, nano, Gedit. Alle beherrschen Syntax-Highlighting.

Versuchsaufbau

Inhalt
LED an Parallel Port eines PC

Der Aufbau des Projekts ist mit Hilfe der CEK-Module auf einer Steckplatine in wenigen Minuten erledigt.

  • PIN 2 (Bit 0 Datenbus) des DSUB25-Moduls wird mit dem Anschluss D1 des LED Moduls verbunden.
  • PIN 24 (Masse) wird mit PIN+ des LED-Moduls verbunden.
  • Die LEDs werden in den Sockeln des LED Moduls entgegen der normalen Richtung eingesetzt. Der Grund: das LED Modul ist ursprünglich dazu gedacht, dass die LEDs mit gemeinsamer Masse an + betrieben und gegen Masse geschaltet werden. In dieser Anwendung ist es nun umgekehrt, die Anode der Diode soll vom Parallel-Port geschaltet werden und die Kathode(n) sollen fest mit Masse verbunden sein.
  • Überprüfe den Schaltungsaufbau gründlich, doppelt oder dreifach, z.b. simuliere den Parallelport mit einer Spannungsquelle und prüfe ob die LED leuchtet und dass keine Kurzschlüsse vorhanden sind. Das Mainboard kann ansonsten beschädigt werden !!!
  • Das DSUB-25 Modul (Buchsen) wird mit einem DSUB-25-Kabel mit dem Parallelport des PC verbunden.


Programm

Inhalt

Source-Code

Im Folgenden nun der Source-Code des kleine C-Programms

 1 /*
 2 Rüdiger Kluge
 3 12.12.2011
 4 
 5 compile simple:
 6 gcc -o parallel_io_01 parallel_io_01.c
 7 
 8 compile with debug symbols:
 9 gcc -Wall -pedantic -ggdb3 -std=c99 -o parallel_io_01 parallel_io_01.c
10 
11 run:
12 sudo ./parallel_io_01
13 */
14 
15 #include <stdio.h>
16 #include <stdlib.h>
17 #include <sys/io.h>
18 #include <unistd.h>
19 
20 int main(void) 
21 {	
22 	unsigned char data = 0;		// data going to parallel port data register
23 	const unsigned long PARALLEL_PORT_DATA_REGISTER = 0x378;
24 	const unsigned long NUMBER_OF_BYTES = 2;
25 	const unsigned int TURN_ON = 1;
26 	const unsigned int DELAY = 1;	//seconds to wait
27 	
28 	ioperm(PARALLEL_PORT_DATA_REGISTER, NUMBER_OF_BYTES, TURN_ON);
29 	while(1)
30 	{
31 	    printf("%x\n",data);			// data output to console
32 	    data = ~data;				// toggle data
33 	    outb(data, PARALLEL_PORT_DATA_REGISTER); 	// output to parallel port
34 	    sleep(DELAY);	
35 	}	
36 	return EXIT_SUCCESS;
37 }


Erläuterung:

Zeile 15

#include <stdio.h>
stdio.h, Definition, Deklaration grundlegender Funktionen, Makros und Typen für die Ein-/Ausgabe. In diesem Programm wird stdio.h für die printf Funktion benötigt.


Zeile 16

#include <stdlib.h>
stdlib.h, Definition, Deklaration vieler standard C-Funktionen


Zeile 17/18

Die beiden Header-Dateien
#include <sys/io.h> #include <unistd.h>
werden für die Funktion ioperm() benötigt.


Zeile 20

Start des Programms


Zeile 22

Die Variable data enthält ein Byte, welches später an den Parallel-Port geschickt wird.


Zeile 23

PARALLEL_PORT_DATA_REGISTER enthält die Adresse des Parallel-Port-Datenregisters. Dieser entspricht dem Wert, der weiter oben mit
dmesg | parport
ermittelt wurde.


Zeile 24

NUMBER_OF_BYTES ist der Adressbereich, auf den ab Adresse PARALLEL_PORT_DATA_REGISTER Zugegriffen werden kann.


Zeile 25

TURN_ON = 1 gibt das Datenregister frei.


Zeile 26

DELAY = 1 ist der Wert für die Pause, die das Programm an dieser Stelle macht, in diesem Fall 1 Sekunde.


Zeile 28

ioperm(), mit dieser Funktion werden die Zugangsrechte des Ports gesetzt. Die Syntax lautet:


int ioperm(unsigned long from, unsigned long num, int turn_on);


Bevor auf irgend einen Port zugegriffen werden kann, muss das Recht hierfür erteilt werden. Dies geschieht durch Aufrufen der Funktion ioperm(). Diese Funktion wird in der Header-Datei unistd.h deklariert und im Kernel definiert.
unsiged long from
ist die Startadresse des Parallelports, in diesem Fall PARALLEL_PORT_DATA_REGISTER = 0x378
unsigned long num
ist die Anzahl der aufeinander folgenden Adressen, hier NUMBER_OF_BYTES = 2 (ein Byte hätte gereicht), also 0x378, 0x379.
int turn_on
gibt den Zugang zum Port frei bei turn_on = 1, oder sperrt den Zugang, bei turn_on = 0. Hier würde für turn_on die Konstante TURN_ON = 1 benutzt, also wird der Zugang freigegeben. Das Aufrufen der Funktion ioperm() erfordert root Rechte des Programms. Es muss also als root, oder mit sudo gestartet werden.
ioperm()
gewährt den Zugang auf die I/O Adressen von 0x000 - 0x3FF. Für die Ansteuerung eines standard Parallel-Ports, wie er sich auf dem Mainboard befindet, :reicht dieser Adressbereich aus. Wird jedoch eine Erweiterungskarte verwendet, muss die Funktion iopl() verwendet werden. Diese erlaubt den Zugriff auf den :gesammten I/O-Bereich bis 0xFFFF.
Weitere Informationen: man ioperm.


Zeilen 29, 30, 25

In Zeile 29 startet eine unendliche while-Schleife, die in Zeile 35 endet.


Zeile 31

Hier wird der Wert der Variablen data als Hex-Zahl ausgegeben. als Beim ersten Durchlauf der while-Schleife ist der Wert 0, beim zweiten Durchlauf FF, usw.


Zeile 32

Der jeweilige Wert von data wird binär negiert, aus 0 wird FF, aus FF wird 0.


Zeile 33

outb() gehört zu einer Familie von low-level Input-/Output-Funktionen. Es gibt verschiedene Funktionen out*, wobei outb für die Ausgabe eine Datenbytes sorgt. Die Syntax lautet:
 void outb(int port, unsigned char value)
Der erste Parameter ist die Port-Adresse, der zweite das Datenbyte, welches an den Port übergeben wird.
weitere Info: man outb


Zeile 34

Die Funktion sleep() bewirkt eine Pause, hier 1s. Kleinere Zeiten sind mit dieser Funktion leider nicht möglich. Für kürzere Zeiten könnte die Funktion nanosleep verwendet werden.
Weitere Info, über Konsole: man sleep und info coreutils 'sleep invocation'


Zeilen 36

Da das Programm in der endlosen while-Schleife läuft, muss es mit Crtl-C angehalten werden, sonst kommt es nie hier hin.


Zeilen 37

Hier endet der Programmcode.

Kompilieren und ausführen

Inhalt
  1. Den Source-Code in einen Editor kopieren und in einem Verzeichnis abspeichern, z.B. mit dem Namen parallel_io_01.c.
    Dies kann per Cut and Paste aus obigen Sourcecode geschehen, die Zeilennummern werden nicht kopiert.
  2. in das Verzeichnis wechseln
    eine Konsole öffnen, folgenden Befehl eingeben:

gcc -o parallel_io_01 parallel_io_01.c

Das ausführbare Programm heißt dann parallel_io_01. Diese Datei muss ausführbar sein, gff. die Rechte der Datei ändern.

chmod 775 parallel_io_01

  1. Das Programm ausführen:

 sudo ./parallel_io_01

(oder in einer Root-Konsole ohne sudo)

  1. Auf der Konsole erscheint dann:

ff
0
ff
0
....
usw. und die LED blinkt. :)

Siehe auch (Artikel)

Inhalt

Bezugsquellen

Inhalt
  • CEK - Module [3]
  • LED Modul 6 LEDs [4]
  • DSUB25-Buchse Interface-Modul [5]

Categorie:CEK Module Anwendungen

Einzelnachweise

Inhalt
  • Wikipedia IEEE_1284 [6]

© Rüdiger Kluge Änderungen und Irrtümer vorbehalten