Problematik der Druckeransteuerung

Annotation:

Diese Facharbeit beschäftigt sich mit der Problematik der Druckeransteuerung im Allgemeinen und deren technischer Realisierung mit Hilfe eines in der Programmiersprache PASCAL geschriebenen Programmes. Es soll eine beliebige Datei (ASCII-codiert) gedruckt werden. Das Programm ist von der graphischen Oberfläche her bewußt einfach gehalten, um den Nutzer nicht vom Wesentlichen abzulenken.

Gliederung:

1 Benutzer-Dokumentation

1.1 Zweck und Anwendungsbereich

1.2 Anweisungen

2 Entwickler-Dokumentation

2.1 Lösungsideen und Algoritmen

3 Zusammenfassung

1.1 Zweck und Anwendungsbereich

Dieses Druckprogramm ist nur f√ľr den Schul- und Hausgebrauch geeignet, obwohl es leicht zu bedienen und einfach aufgebaut ist, verf√ľgt es aber nicht √ľber einstellbare Druckoptionen. Dieses Programm wurde im Informatikunterricht und teils in Heimarbeit, unter der Projektaufgabe "Entwickeln und testen sie ein Pascal-Programm, mit dessen Hilfe ASCII-Textdateien auf einem Drucker durch direkte Druckeransteuerung ausgedruckt werden k√∂nnen," entwickelt und geschrieben. In diesem Pascal-Programm wurden die geforderten Richtlinien erf√ľllt, sowie einige der m√∂glichen Erweiterungen eingebunden.

Spezifikationen :

- Das Daten√ľbertragungsprotokoll zum Drucker ist ADQ-Handshake.

- Es wird auf DIN A4-Einzelblätter mit insgesamt 58 Zeilen/Druckseite gedruckt.

- Nach dem Druck jeder Seite, jedoch nicht nach der letzten, ist auf dem Bildschirm eine

Meldung auszugeben, mit der der Benutzer aufgefordert wird, ein neues Blatt in den

Drucker einzulegen sowie der Hinweis, dass erst dann weitergedruckt wird, wenn die

ESC-Taste - und nur diese - gedr√ľckt wurde.

Erweiterungen :

· die Textzeilen sind fortlaufend numeriert

· auf Seite 1 wird der Dateiname ausgedruckt

· des weiteren wird das aktuelle Systemdatum auf Seite 1 ausgedruckt

¬∑ ebenfalls n√ľtzlich bei der Archivierung ist die fortlaufende Seitennumerierung mit Angabe

der Gesamtanzahl der Seiten und der Drucker wird nach dem Druck einer Datei auf seine Standardeinstellungen zur√ľckgesetzt

1.2 Anweisungen

Bei der Benutzung dieses Druck-Programms braucht der Anwender nur sehr wenig zu beachten, da es nur wenige, daf√ľr aber eindeutige Anweisungen gibt. Aus diesem Grund ist ein leichtes, problemloses Arbeiten m√∂glich.

Voraussetzung f√ľr den Ausdruck ist, dass der Drucker eingeschaltet und das bei Programmstart Papier im Drucker ist. Ansonsten meldet sich das Programm mit einer Fehlermeldung und der Aufforderung den Drucker einzuschalten bzw. Papier einzulegen. Das Programm wird nach diesen Fehlermeldungen beendet und kann nach Behebung der Fehler erneut gestartet werden.

Die Arbeitsanweisungen beschr√§nken sich auf das Eingeben des Dateinamens, der zum Ausdruck gew√ľnschten Datei, sowie dem Blatteinlegen. Der Dateiname darf nicht mehr als 8 Zeichen und die Dateiendung nicht mehr als 3 Zeichen lang sein. Das sind jedoch Beschr√§nkungen der FAT (File Allocation Table = Dateizuordnungstabelle) von DOS. Erst mit VFAT unter Windows 95 bzw. mit NTFS, dem File System von Windows NT k√∂nnten theoretisch auch mehr Dateizeichen verwendet werden. Microsoft bietet zum Zweck der Erweiterung der Funktionalit√§t von DOS-Programmen unter Windows ab Version 95 ein Support Pack f√ľr Programmierer an, um dann auch mit mehr als 8 Zeichen zu arbeiten. Die Eingabe des Dateinamens wird dann mit <Enter> best√§tigt.

2 Entwickler-Dokumentation

2.1 Lösungsideen und Teilalgorithmen

Die gestellte Aufgabe aus dem Bereich der Technischen Informatik befa√üt sich mit dem Thema der direkten Druckeransteuerung √ľber die Centronics-Schnittstelle. Diese Schnittstelle ist eine spezielle parallele Schnittstelle, bei der die Daten bit-parallel auf 8 parallelen Datenleitungen √ľbertragen werden. F√ľr die √úbertragungung der Zeichen vom Computer zum Drucker wurde in diesem Druck-Programm ein einfaches, aber erprobtes √úbertragungsprotokoll, das ADQ-Handshake oder ADQ-Protokoll verwendet. Obwohl der Aufbau der CENTRONICS-Schnittstelle die Realisierung unterschiedlicher √úbertragungsprotokolle zul√§sst, so ist das ADQ-Handshake doch eines der zuverl√§ssigsten und wurde auch verwendet, damit die Arbeit mit dem Programm problemlos erfolgen kann.

Zun√§chst habe ich mich mit dem Aufbau der Druckerschnittstelle und den Zust√§nden ausgew√§hlter Register-Signale besch√§ftigt, worauf erste kleine Pascal-Programme folgten, die durch Bitmanipulation in Bytes Zugriff auf die Register der Schnittstelle erhielten. Diese Programme nutzen selbstentwickelte Bit-Filter, die Bit-Masken einsetzen. Dabei verwendet man die in PASCAL zul√§ssige Verkn√ľpfung von Bytes mit Hilfe der logischen Operatoren AND, OR sowie XOR. Um die Codierung dieser Programme in PASCAL zu erleichtern, sollte man L√∂sungsalgorithmen aufstellen, in denen eindeutig der Programmablauf mit eigenen Worten beschrieben ist.

Um eine komplette und umfangreiche Datei fehlerfrei auszudrucken, waren die Prozeduren Zeilenvorschub und Seitenvorschub notwendig. Alle globalen Variablen des Programms sind im Programmkopf vereinbart worden, weil mehrere Prozeduren mit ihnen arbeiten. Dagegen sind viele Variablen lokal deklariert, da die Prozeduren und Funktionen ähnliche Programmabläufe haben, und man deshalb Variablennamen mehrmals verwenden kann, ohne das Komplikationen auftreten.

Ich habe mir zur Aufgabe gestellt, die wichtigsten Prozeduren zu erl√§utern, da ein PASCAL-Programm meistens aus mehreren Prozeduren besteht, die miteinander verkn√ľpft zusammenarbeiten. Den Anfang macht hierbei die Prozedur strobeimpuls.

Quelltext:

procedure strobeimpuls;

var steuer_byte,ergebnis_byte,maske:byte;

begin

maske:=1;

steuer_byte:=port[890];

ergebnis_byte:=(steuer_byte XOR maske);

port[890]:=ergebnis_byte;

delay(10);

port[890]:=steuer_byte;

end;

Diese Prozedur ist charakteristisch f√ľr das Druck-Programm, da sie eine der wichtigsten im ganzen Programm ist und da sie nach dem Prinzip der Bitmanipulation arbeiten.Die Aufgabe der Prozedur liegt in der Aussendung eines Signals, das dem Drucker mitteilt, dass ein Datenwort zu "Weiterverarbeitung" bereits im Datenregister vorhanden ist.

Die Realisierung erfolgt, indem der PC dem Drucker mitteilt, dass er das Steuerbyte A0 mindestens 10 Millisekunden lang auf Eins setzt, somit einen Bitwechsel vollf√ľhrt, der ein Signal darstellt.

In der ersten Zeile wird formal der Prozedurname festgelegt, ihm folgt in der zweiten Zeile

die Deklaration der zu benutzenden Variabeln steuer_byte, ergebnis_byte und der Bitmaske des Typus byte. Die Anweisungen beginnen mit dem Setzen der Bitmaske auf 1. Dann wird aus dem Steuerregister mit der Adresse 890 dez das steuer_byte ausgelesen. Da die Maske 1 ist, wird nun mit Hilfe der Operation XOR das ergebnis_byte auf jeden Fall auf 1 gesetzt. Das ergebnis_byte wird nun in das Steuerregister mit der Adresse 890 dez zur√ľckgeschrieben. Eine Pause von 10 ms erm√∂glicht dem PC die Auswertung und Reaktion auf das ergebnis_byte. Der Strobeimpuls wird generiert, womit die Aufgabe ein Signal abzugeben erf√ľllt wurde. Anschlie√üend wird das Byte steuer_byte in das Steuerregister mit der Adresse 890 dez zur√ľckgeschrieben.

Die Prozedur strobeimpuls wird in meinem Programm in 50% aller Prozeduren verwendet, man ben√∂tigt diese Prozedur zum Druck jeden Zeichens, sowie zur Konfigurierung des Druckers, sie ist f√ľr mich ein kausales Hilfsmittel.

Bevor die Daten ausgedruckt werden k√∂nnen, m√ľssen sie jedoch erst einmal aus der Datei ausgelesen werden. Dies geschieht mit Hilfe der Prozedur datei_sequentiell_lesen.

Quelltext:

procedure datei_sequentiell_lesen;

var znummer, zzaehler, seite:integer;

s,seiten:string;

begin

seitenanzahl;

seite:=1;

str(seite,seiten);

wort_drucken('Seite'+' '+Seiten+' '+'von'+' '+gesamt);

zeilenvorschub;

reset(quelldatei);

znummer:=0;

while not eof(quelldatei) do

begin

znummer:=znummer+1;

str(znummer,s);

readln(quelldatei,zeile);

zeile:=s+' '+zeile;

wort_drucken(zeile);

if ((znummer MOD 58=0) AND (not eof(quelldatei)))

then

begin

seitenvorschub;

seite:=seite+1;

str(seite,seiten);

writeln('Bitte neues Blatt einlegen, wenn Drucker fertig ist!');

delay(10000);

writeln('Weiter mit Escape-Taste!');

repeat until readkey=escape;

wort_drucken('Seite'+' '+Seiten+' '+'von'+' '+gesamt);

zeilenvorschub;

clrscr;

end;

end;

if eof(quelldatei) then

begin

clrscr;

writeln('Drucken beendet');

seitenvorschub;

end;

end;

Wieder wird zun√§chst der Prozedurname festgelegt. In dieser Prozedur kommen schon einige Erweiterungen zum Einsatz. Zum Beispiel wird jede einzelne Zeile der auszulesenden Datei numeriert. Dies geschieht √ľber den Z√§hler znummer, der bei jedem Durchlauf der While not

Eof Schleife um 1 hochgesetzt wird, also bei jeder neu eingelesenen Zeile. Der Z√§hler wird √ľber den Befehl str dann noch ins String-Format √ľbersetzt, um dann zusammen mit der Zeile

ausgedruckt zu werden. Wenn der Z√§hler znummer 58 oder ein Vielfaches davon betr√§gt, wird ein Seitenvorschub gestartet; eine im Programm definierte Prozedur. Die aktuelle Seitenanzahl Seite, die zuvor auf 1 gesetzt wurde, wird nun um 1 erh√∂ht, um dann auf der n√§chsten Seite zusammen mit der in der Prozedur seitenanzahl ermittelten Gesamtseitenzahl gesamt ausgedruckt zu werden. Um dem Anwender jedoch Zeit zum Neueinlegen eines Blattes Papier zu geben, wird der Seiteneinzug solange verz√∂gert, bis der Anwender die Escape-Taste bet√§tigt hat. Dann wird der Druck der restlichen Zeilen der Datei fortgesetzt, immer mit einem Seitenvorschub und einem darauf folgenden Seiteneinzug f√ľhrt. Der Seiteneinzug ist aber nur eine Folge des Strobeimpulses, der in der Prozedur wort_drucken durchgef√ľhrt wird, um die nach dort √ľbergebene Variable zeile auszudrucken.

Hier noch einmal zum näheren Verständnis der Quelltext der Prozedur wort_drucken:

procedure wort_drucken(zeile: string) ;

var zk_laenge,i:integer;

zeichen:char;

begin

zk_laenge:=length(zeile);

For i:=1 to zk_laenge do

begin

zeichen:=zeile[i];

port[888]:=ord(zeichen);

strobeimpuls;

delay(10);

end;

zeilenvorschub;

end;

Wie sehr schön zu erkennen ist, findet sich hier unsere eingelesene Zeile aus der Prozedur datei_sequentiell_lesen wieder. Diese wird jetzt auf ihre Länge hin untersucht. Vom ersten Zeichen an bis zum letzten der Zeichenkette wird nun das jeweilige Zeichen ins Datenregister

verschoben, um von dort per Strobeimpuls an den Drucker zu wandern. Dieser f√ľhrt dann noch einen Zeilenvorschub aus, um schlie√ülich die n√§chste Zeile zu drucken. Es sei an dieser Stelle angemerkt, dass der Computer die Zeilen viel schneller aus der Datei ausliest, als diese gedruckt werden k√∂nnen. Das stellt jedoch keinen Nachteil dar, da der Puffer im Drucker gro√ü

genug ist, die ankommenden Daten zwischenzuspeichern.

Das war eigentlich schon der gesamte Vorgang des Druckens samt Auslesen der Informationen aus der ASCII-Datei. Der Auslesevorgang findet sich, diesmal aber ohne Druckvorgang, auch noch einmal in der Prozedur seitenanzahl. Sie dient lediglich dazu, im voraus die Gesamtanzahl der Zeilen der Datei festzustellen, um diese dann später immer mit

der aktuellen Seitenzahl auszudrucken, wenn eine neue Seite beginnt. Hier der Quelltext der Prozedur Seitenanzahl:

procedure seitenanzahl;

var zeilennummer, seitenzahl:integer;

begin

reset(quelldatei);

zeilennummer:=0;

while not eof(quelldatei) do

begin

zeilennummer:=zeilennummer+1;

readln(quelldatei);

end;

seitenzahl:=zeilennummer div 58;

if zeilennummer mod 58 <> 0 then seitenzahl:=seitenzahl+1;

str(seitenzahl, gesamt);

close(quelldatei);

end;

Dividiert man die Anzahl der Zeilen, gespeichert in der Variablen zeilennummer durch die Anzahl der Zeilen pro Seite, so ergibt sich daraus die Gesamtseitenzahl. Bei einer nicht ganzen Zahl ist die Seitenzahl entsprechend immer einen Z√§hler h√∂her. Die Prozeduren online_test (Abfrage, ob der Drucker eingeschaltet bzw. neudeutsch "online"Ist), busy (Abfrage der Verf√ľgbarkeit des Druckers) fragen mittels bestimmter Bitmasken das Statusregister des Druckers mit der Adresse 889 dez ab und sind im Hauptprogramm dem eigentlichen Druckvorgang vorgestellt, ebenso wie die Prozedur pr√ľfen.

In der Prozedur pruefen wird beim √Ėffnen der zu druckenden Datei auf das IO-Ergebnis gewartet und entsprechend seinem Wert der Vorgang weitergef√ľhrt oder mit einem Hinweis auf die nicht vorhandene Datei beeendet.

Besonders erwähnenswert ist die Prozedur datum_drucken. In ihr wird das Systemdatum mit Hilfe des Befehls getDate ausgelesen. Mittels eines Datenfeldes werden den Werten 0 bis 6, je nach Wochentag, der Variable dow, die Wochentage zugeordnet und dann zusammen mit dem Datum gedruckt. Hier der Quelltext:

procedure datum_drucken;

var

Jahr, Monat, tag:string; const Tage: array [0..6] of String[10] =('Sonntag','Montag','Dienstag',

'Mittwoch','Donnerstag','Freitag','Samstag');

var

y, m, d, dow : Word;

begin

GetDate(y,m,d,dow);

str(y,Jahr);

str(m,Monat);

str(d,Tag);

wort_drucken(Tage[dow]+','+' '+'der'+' '+

Tag+'.'+Monat+'.'+Jahr);zeilenvorschub;end;

3 Zusammenfassung

Obwohl heute sicherlich niemand mehr einen Druckertreiber f√ľr DOS schreiben w√ľrde, der derart generelle Funktionen bietet, war die Arbeit an diesem Projekt doch sehr interessant. Ob nun DOS oder Windows, die Prinzipien der Bitmaskenprogrammierung kommen in allen m√∂glichen Ger√§tetreibern und bei allen Betriebssystemen zum Einsatz.

4 vollständiger Sourcecode

program druck;

uses dos, crt;

var quelldatei:text;

quelldateiname:string[12];

zeile:string[125];

busy_wert:integer;

druck_string:string[125];

zeichen:char;

datei_vorhanden:boolean;

taste:char;

gesamt:string;

const escape=chr(27);

{--------Abfrage, ob der Drucker druckbereit ist------}

procedure busy;

var status_byte,maske,ergebnis_byte:byte;

begin

clrscr;

maske:=128;

status_byte:=port[889];

ergebnis_byte:=(status_byte and maske);

if ergebnis_byte=maske then busy_wert:=1 else busy_wert:=0;

end;

procedure strobeimpuls;

var steuer_byte,ergebnis_byte,maske:byte;

begin

maske:=1;

steuer_byte:=port[890];

ergebnis_byte:=(steuer_byte XOR maske);

port[890]:=ergebnis_byte;

delay(10);

port[890]:=steuer_byte;

end;

procedure zeilenvorschub;

begin

port[888]:=10;

strobeimpuls;

end;

procedure wort_drucken(zeile: string) ;

var zk_laenge,i:integer;

zeichen:char;

begin

zk_laenge:=length(zeile);

For i:=1 to zk_laenge do

begin

zeichen:=zeile[i];

port[888]:=ord(zeichen);

strobeimpuls;

delay(10);

end;

zeilenvorschub;

end;

{------Abfrage, ob Drucker an ist-----}

procedure online_test;

var status_byte, neu_byte, maske:byte;

bit_wert,i:integer;

begin

i:=1;

repeat

clrscr;

maske:=16;

status_byte:=port[889];

neu_byte:=(status_byte AND maske);

if neu_byte=maske then bit_wert:=1 else bit_wert:=0;

if bit_wert=0 then writeln('Bitte schalten Sie den Drucker ein!');

delay (1000);

i:=i+1;

until (neu_byte=maske) or (i=15);

if neu_byte<>maske then

begin

writeln('Abbruch des Druckprogrammes');

delay(5000);

halt;

end;

end;

procedure druckerpuffer_leeren;

begin

port[888]:=13;

strobeimpuls;

end;

procedure seitenvorschub;

begin

port[888]:=12;

strobeimpuls;

end;

procedure seitenanzahl;

var zeilennummer, seitenzahl:integer;

begin

reset(quelldatei);

zeilennummer:=0;

while not eof(quelldatei) do

begin

zeilennummer:=zeilennummer+1;

readln(quelldatei);

end;

seitenzahl:=zeilennummer div 58;

if zeilennummer mod 58 <> 0 then seitenzahl:=seitenzahl+1;

str(seitenzahl, gesamt);

close(quelldatei);

end;

procedure datei_sequentiell_lesen;

var znummer, zzaehler, seite:integer;

s,seiten:string;

begin

seitenanzahl;

seite:=1;

str(seite,seiten);

wort_drucken('Seite'+' '+Seiten+' '+'von'+' '+gesamt);

zeilenvorschub;

reset(quelldatei);

znummer:=0;

while not eof(quelldatei) do

begin

znummer:=znummer+1;

str(znummer,s);

readln(quelldatei,zeile);

zeile:=s+' '+zeile;

wort_drucken(zeile);

if ((znummer MOD 58=0) AND (not eof(quelldatei)))

then

begin

seitenvorschub;

seite:=seite+1;

str(seite,seiten);

writeln('Bitte neues Blatt einlegen, wenn Drucker fertig ist!');

delay(10000);

writeln('Weiter mit Escape-Taste!');

repeat until readkey=escape;

wort_drucken('Seite'+' '+Seiten+' '+'von'+' '+gesamt);

zeilenvorschub;

clrscr;

end;

end;

if eof(quelldatei) then

begin

clrscr;

writeln('Drucken beendet');

seitenvorschub;

end;

end;

procedure pruefen (VAR quelldatei:text;

var datei_vorhanden:boolean);

begin

(*$I-*)

reset (quelldatei);

(*$I+*)

if IOresult <> 0

then

begin

datei_vorhanden:=false;

end

else

begin

datei_vorhanden:=true;

close(quelldatei);

end;

end;

procedure kopfzeile_drucken;

begin

wort_drucken(quelldateiname);

zeilenvorschub;

end;

procedure datum_drucken;

var

Jahr, Monat, tag:string;

const Tage: array [0..6] of String[10] =

('Sonntag','Montag','Dienstag',

'Mittwoch','Donnerstag','Freitag',

'Samstag');

var

y, m, d, dow : Word;

begin

GetDate(y,m,d,dow);

str(y,Jahr);

str(m,Monat);

str(d,Tag);

wort_drucken(Tage[dow]+','+' '+'der'+' '+

Tag+'.'+Monat+'.'+Jahr);

zeilenvorschub;

end;

begin

clrscr;

online_test;

write('Welche Datei soll gedruckt werden? :');readln(quelldateiname);

assign(quelldatei,quelldateiname);

pruefen(quelldatei,datei_vorhanden);

if datei_vorhanden=false then

begin

writeln('Die zu druckende Datei ist nicht da');

readln;

halt;

end;

busy;

if busy_wert=1 then

begin

kopfzeile_drucken;

datum_drucken;

datei_sequentiell_lesen;

close(quelldatei);

delay(10);

druckerpuffer_leeren;

seitenvorschub;

end;

end.

2105 Worte in "deutsch"  als "hilfreich"  bewertet