BASIC-Kurs : "Von Adam und Eva..." (Teil 1)
Sehr geehrter Leser,
pünktlich zum Anfang des neuen Jahres möchten wir
uns gleich an unsere guten Vorsätze für 1989 halten, und unser Versprechen einlösen, die Anfänger unter
Ihnen nicht zu kurz kommen zu lassen. Sie lesen nämlich im Moment gerade die ersten einleitenden Zeilen
unseres neuen BASIC-Kurses für Einsteiger. Wie der
Name dieses Kurses schon vermuten läßt, wollen wir
ganz am Anfang beginnen, so daß auch der, der noch
überhaupt keine Ahnung von der Programmierung eines
Computers hat, von Adam und Eva an alles schön mitverfolgen kann.
Beginnen wir nun mit der Frage nach dem WARUM. Warum
BASIC? Nun, BASIC ist die Abkürzung für " Beginners
Allpurpose Symbolic Instruction Code", was frei übersetzt etwa " Universeller Befehlscode mit Symbolwörtern für Anfänger" bedeutet. Und dies sagt uns schon
fast alles über den Grund und die Aufgabe von BASIC
aus, denn man wollte mit BASIC eine Computersprache erschaffen, mit der jeder normale Mensch, der etwas
Englisch versteht und logisch denken kann, einen Computer programmieren kann. Zu früheren Zeiten, als
das, was heute in einem zündholzkopfgroßen Mikrochip
untergebracht ist noch ganze Räume und Gebäude
ausfüllte, war die Programmierung von Computern noch
äußerst kompliziert, und bestand meist darin, nichtsaussagende, trockene Zahlenreihen von der Art
0101000110101 . . . in die sage und schreibe 1 KiloByte
großen Hauptspeicher der damaligen Rechner regelrecht
" hineinzumorsen" . Da dies eine sehr mühsame und langwierige Arbeit war entwickelte man mit der Zeit immer
mehr Computersprachen, die auf Grund der immer höher
werdenden Leistungsfähigkeit der Computer immer komfortabler und benutzerfreundlicher wurden, so daß das
Programmieren eine leichte Sache wurde. BASIC stellt
wohl so eine Art Endstufe dieser Entwicklung dar, was
zumindest die Einfachheit der Programmierung betrifft. Heutzutage ist ehrlich gesagt fast jede Sprache leistungsfähiger als BASIC, doch die meisten noch
lange nicht so einfach zu erlernen. Diese Sprache
eignet sich außerdem hervorragend für Anfänger die
Funktionsweise und den Bau eines Computers zu erler- nen und gibt eine unverzichtbare Grundlage für andere, schnellere Programmiersprachen. Deshalb wollen
wir nun endlich beginnen und einmal einen Blick auf
die einfachsten, trotzdem aber häufig benutzten BA-SIC- Befehle werfen. . .
Leider ist es nicht so einfach einen Kurs mit kleinen
Beispielen zu gestalten, wenn Sie selbigen gerade auf
Ihrem C64 lesen. Deshalb werde ich bei praktischen
Beispielen in Zukunft so tun, als säßen Sie gerade
nicht vor der MAGIC DISK 64, sondern nur vor einem
eingeschalteten Computer, der auf eine Eingabe wartet. Ich werde grundsätzlich das Ergebnis, das auf
Grund einer Anweisung, die wir dem Computer eingegeben haben auf dem Bildschirm erscheinen sollte hier
im Kurs aufzeigen, doch sollten Sie nicht davon Abschrecken, die aufgeführten Beispiele auch selbst
einmal auszuprobieren ( wenn Sie fertig sind mit der
MAGIC DISK 64), indem Sie sie sich ganz einfach aufschreiben, oder wenn ein Drucker vorhanden ist, einfach ausdrucken können.
Also: Bitte geben Sie einmal folgende Zeile in Ihren angeschalteten, auf eine Eingabe wartenden 64 er ein:
PRINT "DAS IST MEIN ERSTER AUSDRUCK !"
Drücken Sie nun die RETURN-Taste. Auf dem Bildschirm
erscheint nun folgendes :
DAS IST MEIN ERSTER AUSDRUCK ! READY.
Das war doch schon mal ein Erfolgserlebnis! Fassen
wir doch einmal zusammen, was passiert ist:
Sie haben eine Zeile eingegeben, an deren Anfang der
Befehl " PRINT" stand. Anschließend gaben Sie in " Gänsefüßchen" oder " Anführungsstrichen" einen Text
ein und haben die RETURN-Taste gedrückt. Nun ist unter Ihrer eingegebenen Zeile der Text, den Sie in
Anführung hatten, ausgedruckt worden, und der Computer hat sich mit " READY." wieder zurückgemeldet.
Was ist genau geschehen? Nun, der PRINT-Befehl wird, wie Sie schon richtig erkannt haben, dafür benutzt
um Texte auf dem Bildschirm auszugeben. Sie gaben
also Ihre Zeile ein und signalisierten mit der RE-TURN- Taste dem Computer, daß Sie mit Ihrer Eingabe
fertig sind und daß er Ihre Zeile bearbeiten soll.
Dieser erkannte die ersten 5 Buchstaben als einen
PRINT-Befehl, druckte den anschließenden Text und
meldete ordnungsgemäß mit " READY." seine Betriebsbereitschaft für weitere Befehle.
Sollte das oben beschriebene in Ihrem Fall nicht eingetreten sein, dann kann es nur sein, daß Sie einen
Fehler bei der Eingabe gemacht haben. Sollte also
jetzt anstatt unseres Textes die Zeilen:
?SYNTAX ERROR READY.
bei Ihnen auf dem Bildschirm stehen, so haben Sie
sich wahrscheinlich beim Eingeben unseres Beispiels
vertippt. Der Computer ist da sehr genau, denn er
versteht nur einen bestimmten Befehlssatz, bezie- hungsweise kann er mit einigen Formulierungen oder
Eingaben nichts anfangen, da er seine vorprogrammierten Befehlswörter zu erkennen versucht. Wenn man obige Fehlermeldung einmal in deutsche Übersetzt, wird
einem das sogar noch etwas klarer: Syntaktischer
Fehler. Zur Erläuterung, die Syntax einer Sprache ist
die Art und Weise, wie diese grammatikalisch und vokabular aufgebaut ist. Sie haben sich also im Dialog
mit Ihrem C64 sozusagen " versprochen", weshalb dieser
Sie auch nicht verstand. Und wir möchten ja, daß Sie
die Sprache BASIC " akzentfrei" sprechen können.
Keine Panik also, wenn der Computer bei Ihren ersten
Gehversuchen Ihnen ein paar Errormeldungen in den Weg
wirft. Sehen Sie sich Ihre Eingaben dann nochmal ganz
genau an und Sie werden bestimmt die Ursache des Fehlers finden. Manchmal ist dies etwas schwieriger, da
bei bestimmten Dingen die der Computer für Sie erledigen soll auch ganz spezielle Fehler auftreten können. Doch nicht verzagen, im C64 Bedienungshanbuch, Anhang L sind alle möglichen Fehlermeldungen zusammen
mit Ihren Ursachen aufgelistet. Hier können Sie bei
Bedarf Hilfe suchen.
Nun wieder zurück zu unserem PRINT-Befehl. Sollten
Sie ein wenig Englisch können, werden Sie erkennen, daß dieser Befehl nicht umsonst so heißt. PRINT ist
die Übersetzung für DRUCKE und sagt somit eigentlich
alles aus, was dieser Befehl tut. Dies ist, wie Sie
bald merken werden, bei allen BASIC-Befehlen so, so
daß man sich diese sehr leicht merken kann, was ja
auch der Sinn der Sache sein soll, damit ein leichtes
Programmieren ohne lange Suche nach Befehlen gewährleistet ist.
Gehen wir nun aber etwas weiter. Langweilige Texte
ausdrucken macht eh nicht soviel Spaß, zumal man ganze 7 Zeichen ( PRINT und 2 Mal ") mehr eingeben muß, will man einen Text ausdrucken. Doch der PRINT-Befehl
ist noch zu viel mehr gut, denn immerhin hat man hier
einen dicken Computer stehen, der solche kleinen Dinge, wie sie zum Beispiel ein Taschenrechner erledigt
doch mit dem " kleinen Finger" bringt. Ja, mit PRINT
können Sie rechnen, sei es, daß es Ihnen einen Text
ausdruckt, oder das Ergebnis einer Addition. Die Syn-Syntax hierzu ist denkbar einfach:
PRINT 101+35
Dieser Befehl addiert die Zahlen 101 und 35 und
druckt anschließend das Ergebnis auf dem Bildschirm
aus:
136 READY.
Sie sehen, die Eingabe erfolgt genau wie bei Textausdrücken, nur daß Sie hier die Zahlen nicht in
Anführungsstriche zu setzen brauchen, ja sie MÜSSEN
Sie sogar weglassen, denn sonst meint der Computer, Sie möchten eine Zeichenkette ausdrucken, weshalb bei
dem folgendem Befehl auch die folgende Reaktion des
Computers zu erwarten ist:
PRINT "101+35"
101+35 READY.
Ich hoffe, daß Ihnen hiermit etwas klarer geworden
ist, wie Sie zu unterscheiden haben :
⌈––––––––––––––––––––––––––⌉ |MIT "" wird Text gedruckt| |OHNE "" wird gerechnet. | ⌊––––––––––––––––––––––––––⌋
Doch weiter mit der Rechnerei. Sie können ohne weiteres auch andere Rechenfunktionen verwenden. Die 4 Grundrechenarten möchte ich hier jetzt erwähnen, obwohl auch Wurzeln oder trigonometrische Funktionen
für unseren C64 kein Problem darstellen, doch werde
ich diesen Rechenfunktionen später noch ein eigenes
Kapitel widmen. Im Moment reichen die folgenden vollkommen aus. Genau so, wie Sie bei "101+35" einen "+"- Operator eingestzt hatten, so ist dies auch bei der
Subtraktion, Multiplikation und Division möglich, hierfür müssen Sie allerdings folgende Zeichen verwenden, um dem Computer klar zu machen, was Sie von
Ihm wollen:
"+" - zum addieren "-" - zum subtrahieren "*" - zum multiplizieren "/" - zum dividieren
Somit sind folgende Zeilen auch leicht denkbar :
PRINT 222*67 PRINT 1000-100 PRINT 81/9
Probieren Sie es einmal aus, und experimentieren Sie
mal ein wenig. Grundsätzlich gilt auch für andere
Beispiele die ich geben werde, daß Sie ruhig auch
einmal eigene Versuche machen können, um sich mit den
neu erlenten Dingen in allererster Linie vertraut zu
machen, denn wie heißt es so schön:" Probieren geht
über studieren." zumal Sie mit Ihren Eingaben grundnichts an Ihrem Computer kaputt machen können, es sei
denn, Sie versuchen die Tasten mit einem Hammer zu
betätigen. . .
Bei Ihrer Rechnerei dürfen Sie sogar auch Kommazahlen
verwenden. Hierbei müssen wir uns allerdings auch
wieder ein wenig ans Englische anpassen, denn der
Computer versteht auch Kommazahlen nur in englischer
Schreibweise. Das normale Komma ist für einen anderen
Zweck reserviert. Das heißt im Klartext, daß die Zahl"3,14" für unseren kleinen Siliziumfreund so aussehen
muß:"3 .14" . Die Amerikaner benutzen grundsätzlich
den Punkt als Dezimalkomma, und hieran müssen Sie
sich gewöhnen. Richten Sie sich danach, dann machen
Rechnungen wie die Folgende keine Probleme mehr :
PRINT 2*20*3 .14
Vielleicht haben Sie ja bemerkt, daß der Kreisumfang
für einen Kreis mit dem Radius 20 cm ( oder m oder km) berechnet wurde. Denn gemäß der Kreisumfangsformel 2 mal Radius mal die Zahl Pi (π) haben wir hier die
Zahl π mit der Dezimalzahl 3,14 dargestellt, nur mit
einem Dezimalpunkt. Wie Sie sehen, können auch mehrere Rechenoperationen aneinander gehängt werden, wobei
der Computer die allgemeingültige " Punktvor- Strich"- Regel natürlich ordnungsgemäß einhält. Das
heißt, daß bei der Rechnung 20+3*100 das Ergebnis 320 herauskommt ( und nicht etwa 2300), da auf Grund dieser Regel die Multiplikation ( und auch die Division) Vorrang vor der Addition ( oder Subtraktion) hat.
Es wurde also folgendermaßen gerechnet:
1.) 3*100 (=300) 2.) 20+300 (=320)
Möchte man den anderen Weg benutzen, nämlich daß gerechnet wird:
1.) 20+3 (=23) 2.) 23*100 (=2300)
so muß man mit Klammern arbeiten, denn genau wie bei
den allgemeinen algebraischen Rechenregeln auch, kann
man mit Klammern die Prioritäten der einzelnen Rechnungen verändern. Wollen wir also 2300 herausbekommen, so müssen wir folgenden Befehl benutzen:
PRINT (20+3)*100
Anstelle von " PRINT 20+3*100", wobei nämlich 320 herauskäme.
Dies zum Rechnen mit PRINT. Doch müssen Sie schon
zugeben, daß das, was wir hier taten, alles nichts
" handfestes" war, zumal wir mit den errechneten Ergebnissen nicht weiterarbeiten konnten. Natürlich, Sie hatten diese nach Ihrer Rechnung dann auf dem
Bildschirm stehen und konnten sie dann in einer neuen PRINT-Zeile weiterverarbeiten, doch dies wird sehr
umständlich mit der Zeit. Angenommen Sie erhalten bei
einer Rechnung folgendes Ergebnis:2 .75399753 . Jetzt
müßten Sie diese Zahl nochmal gänzlich abtippen um
Ihre Rechnung durchführen zu können. Doch wie Sie
vielleicht bemerkten, beutzte ich soeben den Irrealis
(" müssten"), das heißt, daß es noch eine andere Art
der Rechnung gibt, eine bequemere Art, bei der das
nochmalige Abtippen nicht mehr nötig ist. Ich spreche
von dem Rechnen mit Variablen. Ich möchte mich nun
ein klein wenig von der Rechnerei lösen, um Ihnen
dieses äußerst wichtige Kapitel besonders verständlich darlegen zu können. Denn das Verständnis über
Variablen ist die Vorraussetzung für BASIC ( und auch
für die meisten anderen Hochsprachen) . Um Variablen
dreht sich alles in BASIC, denn sie sind ein äußerst
einfaches und praktisches Hilfsmittel. Wollen wir
beginnen:
Falls Sie sich vielleicht noch ein wenig an die
Schulzeit errinnern, oder vielleicht sogar noch Schüler sind, dann werden Sie sich bestimmt auch noch an
Rechnungen mit Unbekannten und Variablen errinnern.
Gleichungen von der Art " y =2 x" dürften Ihnen dann
nicht unbekannt sein. Genauso wie hier die Zeichen
" x" und " y" Platzhalter für eine beliebige Zahl sind, so sind die Variablen gewissermaßen Platzhalter für
unsere drei Datentypen." Gewissermaßen" deshalb, weil
sie allgemein tatsächlich Platzhalter für Zahlen oder
Texte sind, mit dem Unterschied, daß mit Ihrem Inhalt allerdings sofort gerechnet werden kann, dieser
also nicht eher imaginär ist, so wie bei den mathematschen Variablen.
Um Ihnen dies noch ein wenig besser erläutern zu können, kann man Variablen auch mit Schubladen vergleichen ( wobei jede Schublade ihren eigenen Namen besitzt, mit dem man sie ansprechen kann) und in der
jeweils bestimmte Dinge, beziehungsweise Daten enthalten sind. Möchte ich zum Beispiel einmal in die
Schublade PI hineinschauen, so öffne ich sie und kann
mir dann bei Bedarf den Zahlwert 3 .14159 dort herausholen.
Sie sehen also, daß das Ganze eigentlich äußerst einfach ist. Sie geben einer Variable einen Namen und
sagen, was in Ihr enthalten ist. Wir sprechen hier
von einer sogenannten Variablendefinition. Ab sofort
brauchen Sie solche Werte dann nicht mehr von Hand
hinzuschreiben, sondern brauchen nur noch anstatt der
getippten Zahl in Ihrer Rechnung die entspechende
Variable zu verwenden. Als kleines Beispiel möchte
ich Ihnen einmal eine kleine Rechnung zeigen, bei der
dies durchaus von Nutzen sein kann.
Angenommen, wir wollen die Oberfläche eines Zylinders
berechnen. Die Formel, die man hierfür allgemein benutzt sieht folgendermaßen aus:
o=2 rπ( r+ h),
wobei die Platzhalter ( oder neuerdings für uns die
Variablen) folgende Bedeutung haben:
r = Radius der Zylindergrundfläche, h = Höhe des Zylinders,π nimmt hier eine Sonderstellung ein. Die
Zahl PI müssen wir nämlich nicht mehr eingeben, Sie
ist in Ihrem C64 schon fest gespeichert und immer greifbar. Sogar bis auf 8 Stellen hinter dem Komma!
Ihre Taste befindet sich rechts oben, direkt neben
der RESTORE-Taste Ihres 64 ers, und Sie können Sie
mit nur mit gleichzetigem drücken der SHIFT und der
↑- Taste erreichen.
Nehmen wir nun einmal an, wir wollen in etwa die
Oberfläche einer Coladose berechnen, also wieviel
Quadratzentimeter Weißblech zur Herstellung einer
solchen Dose verbraucht werden. Eine normale Getränkedose ist allgemein 11 .5 cm hoch und hat einen
Durchmesser von 6 .5 cm. Um den Radius nun zu erhalten, den wir ja brauchen, dividieren wir einfach noch
durch 2, also 6 .5/2=3 .25 . Ich habe hier absichtlich
einmal die Operatoren und die Schreibweise des Computers gewählt, damit Sie sich ein wenig daran gewöhnen.
So, eine Höhe und einen Radius haben wir ja jetzt, wollen wir nun einmal rechnen. Wie wir ja vorhin gelernt haben, können wir unsere Formel o=2 rπ( r+ h) ganz
normal übernehmen, nur müssen wir darauf achten, daß
wir dem Computer noch die in der Formel fehlenden
Multiplikationsoperanden " unterschieben" können, da diese in der Mathematik im allgemeinen weggelassen
werden ( um eine kompaktere Schreibform zu erreichen), unser C64 sie allerdings unbedingt benötigt, da er
sonst nicht von Varablen und Zahlen unterscheiden
könnte. Dies liegt einfach daran, daß Variablennamen
auch Zahlen beinhalten können. Doch zur Nomenklatur
von Variablen später etwas mehr. Widmen wir uns nun
wieder unserem Problem, und lassen wir die in der
Formel verwendeten Variablen stehen. Geben Sie doch
dem Computer nun einmal unsere Beispielrechnung
direkt ein, indem Sie die Werte für Höhe und Radius
der Dose ganz einfach schon einsetzen. Dann kämen Sie
zu folgender Zeile :
PRINT 2*3.25*π*(3.25+11.5)
Mal abgesehen davon, daß Sie hiermit auch zu dem
richtigen Ergebnis kommen, nämlich 301 .200196 qcm, hätte man hier ein wenig sparen können, zumal man
zweimal den selben Wert eingeben mußte, nämlich 3 .25 für den Radius. Machen wir es uns also einfacher und
benutzen wir Variablen. Eine Wertzuweisung an eine
Variable ist denkbar einfach. Sie schreiben einfach den Namen der Variable hin, setzen ein Gleichheitszeichen "=" dahinter und schreiben dann den Zahlwert
hinter dieses Zeichen.
a=1 wäre also die Zuweisung des Wertes 1 an die Variable " a" . Geben Sie nun " PRINT a" ein, dann wird
der Computer Ihnen die Zahl 1 ausdrucken, Sie haben
also gerade eben in die Schublade " a" geschaut und
ihren Inhalt auf dem Bildschirm dargestellt.
In unserem Beispiel müßten Sie also folgende Zeilen
eingeben:
r=3.25 h=11.5
Hiermit haben Sie nun den Beiden Variablen " r" und
" h" ihren Wert zugewiesen. Jetzt geht es um die Formulierung der Rechnung, die genial einfach ist. Sie
müssen nur alle vorher eingesetzten Werte mit den
Variablennamen austauschen.
Statt:
PRINT 2*3.25*π*(3.25+11.5)
heißt es jetzt nur noch:
PRINT 2* r*π*( r+ h)
womit wir der Ursprungsform der mathematischen Formel
schon etwas näher wären. Das tolle daran ist, daß Sie
nun für alle Werte, die Sie einsetzen möchten, ein und dieselbe Zeile weiterverwenden können, nämlich die oben angezeigte. Sie müssen vorher nur den
Variablen andere Werte zuweisen, z. B. :
r=2.8 h=5.4
Das ganze mit den Variablen hat natürlich einen Sinn:
Später, wenn Sie Programme schreiben, sind solche
Universalanweiungen unerläßlich, zumal Sie einem das
Programmieren erleichtern und zusätzlich auch noch
unwahrscheinlich flexibel sind. . .
Wollen wir uns nun einmal ein wenig um die Variablennamen kümmern, zumal hierbei bestimmte Regeln eingehalten werden müssen, da sonst BASIC nicht mehr mitspielt, oder falsche Ergebnisse liefert.
Zusammenfassend möchte ich Ihnen diese Regeln hier
einmal Auflisten :
1 .) Eine Variable darf aus Buchstaben ( also az) und
aus Zahlen (0-9) bestehen. Sonderzeichen, wie
z. B. :" ., ; :" oder ähnliches sind NICHT erlaubt.
Das erste Zeichen einer Variable MUSS immer ein
Buchstabe sein, Sie dürfen also hierfür keine
Zahlen verwenden.
2 .) Eine Variable darf höchstens 2 Zeichen lang sein.
Sie können zwar soviel Zeichen verwenden wie Sie
wollen, doch sind grundsätzlich die ersten 2 nur
von Bedeutung. Das heißt, daß Sie eine Variable
zwar " RADIUS" nennen dürfen, doch ist diese Variable z. B. mit der Variable " RADIESCHEN", oder
" RAMBOCK" absolut identisch, weil unser 64 er halt
nur mit Hilfe der ersten 2 Zeichen die Variable unterscheidet. In diesem Fall heißen also alle 3 Variablen für unsern kleinen Freund " ra" . Gewöhnen Sie sich also auf keinen Fall eine solche
Namensgebung an, da es so leicht zu Mißverständnissen kommen kann und damit zu Programmfehlern, nach denen man ewig sucht
3 .) Ansonten gilt natürlich, daß nur in Kleinschrift
geschriebene Variablen erlaubt sind, beziehungsweise, falls Sie den Grafikzeichensatz des 64 ers
benutzen sollten - er ist direkt nach dem Einschalten vorhanden - keine Grafikzeichen. Zusammengefaßt heißt das, daß Sie niemals geSHIFTete
Zeichen verwenden dürfen, sondern nur solche, die
Sie ohne SHIFT-Taste erreichen können, und die
unter den in 1 . aufgezeigeten Zeichen sind.
Erlaubte Variablennamen wären also :
a b xx ja pi c1 c2
Nicht erlaubt sind z. B. :
s. %r &g i/ Bb aB 1c 2c
Kommen wir nun zu den Variablentypen. Falls Sie einmal ausprobiert haben sollten, folgende Anweisung zu
geben :
a= Das ist ein Text
dann werden Sie vielleicht festgestellt haben, daß
der Computer dann nach dem anschließenden " PRINT a" ganz und garnicht den Text -" Das ist ein Text" ausdruckte, sondern entweder einen SYNTAX ERROR oder
eine 0 .
Wie Sie nun vielleicht bemerkt haben, haben wir bei
unseren PRINT-Anweisungen 3 verschiedene Arten von
Ausgabedaten verwendet. Fassen wir einmal zusammen :
1 .) Wir hatten Texte ausgegeben. Diese bestanden ausmehreren beliebigen Zeichen, die wir in Anführungszeichen eingeschlossen hatten.
2 .) Wir hatten dann mit Zahlen gearbeitet, indem wir
mit ihnen rechneten und die Gesamtergenisse uns
ausgeben ließen. Hierbei handelte es sich anfänglich wohlgemerkt um ganzzahlige Zahlen. Es wurde
kein Dezimalpunkt benutzt.
3 .) Anschließend haben wir dann die sogenannten reellen Zahlen hinzugenommen. Diese sind Zahlen mit
Dezimalkomma ( beziehungsweise Dezimalpunkt, in
BASIC - Beispiel: pi =3 .14159 . . .) .
Grundsätzlich kann man nun sagen, daß es drei Arten
von Datentypen gibt: Zeichenketten, ganze Zahlen und
Kommazahlen.
Genauso müssen wir bei den Variablen unterscheiden.
Es gibt damit also 3 Variablentypen, in denen nur
jeweils eine bestimmte Art von Daten gespeichert werden darf:
1 .) Texte, bestehend aus Zeichenfolgen. Diese Texte
nennt man allgemeinhin im Computerjargon
" Strings" .
2 .) Ganze Zahlen, sogenannte Integers.
3 .) Dezimalzahlen, sogennannte " Floats", oder Floatingpoint- Variablen ( deutsch: Fließkomma-Variablen) .
Ich möchte hier noch bemerken, daß ich diese Begriffe
von nun an immer benutzen werde. Prägen Sie sie sich
also gut ein, da man mit Ihnen am besten die Typen
unterscheiden kann, ohne noch langwierige Umschrebungen liefern zu müssen.
Wie bringen wir also nun unserem C64 bei, welche der
3 Arten wir nun wünschen, zumal er sie nicht selbst
unterscheiden kann? Nun das ist sehr einfach, wir
hängen einfach noch ein bestimmtes Zeichen an den
Variablennamen an, mit dem diese Unterscheidung möglich wird, und das typisch für seine Variablenart
ist.
Für die einzelnen Variablen gibt es folgende Zeichen:
1 .) Strings wird ein "$" angehängt, so daß ein Variablenname für einen String beispielsweise anstatt
" a" nun " a$" heißt.
2 .) Integers bekommen ein "%"- Zeichen dahinter. Also
" a%" anstatt " a" .
3 .) Floats sind am einfachsten zu bilden, sie bekommen keinen Anhang. Sie sehen also, daß die Variablen, die wir in unsrem obigen Beispiel gebildet
hatten, alles Floatvariablen waren, was auch notwendig war.
Floatvariablen heißen also wirklich " a" .
Wie Sie einer Floatvariable einen Wert zuweisen, wissen Sie ja mittlerweile aus unserem Beispiel mit der
Coladose ( nämlich mit " x= Zahl")
Die Wertzuweisung von Integern verläuft analog zu
dieser Methode, da es sich hier ja auch um Zahlen
handelt. Also " x%=10" .
Bei Strings verhält sich dies allerdings ein wenig
anders. Zwar wird die Zuweisung mit " a$=" kenntlich
gemacht, doch muß der zuzuweisende Text unbedingt, wie auch bei PRINT, noch in Anführungsstriche gesetzt
werden, da sonst ja nicht von Programmtext unterschieden werden könnte. Also muß unsere Zuweisung
dann lauten:
a$=" Das ist ein Text"
Nun wäre diese Zeichenfolge auch gespeichert. Jetzt
können Sie sie auch ruhig einmal mit " PRINT a$" abrufen. Der Computer wird Ihnen nun wie erwartet den
String " Das ist ein Text" ausdrucken. Sie sehen also, daß Sie sich hierdurch sehr viel Tipparbeit ( und außerdem auch Speicherplatz) sparen können, wenn Sie
für einen häufig in einem Programm vorkommenden Satz
Strings benutzen. Natürlich sind Variablen zu noch
viel mehr nutze, obwohl eine Wertzuweisung auch
eine Menge Tipparbeit mehr bedeutet, doch um sie
dreht sich wie gesagt alles in BASIC, und ohne sie
wäre es kaum möglich, sinnvolle Programme zu schreiben. Diese Wertzuweisung hat natürlich auch nur im
Programm einen Sinn, doch dazu wollen wir allerdings
in der nächsten Ausgabe kommen.
Hier trotzdem noch eine kleine Anmerkung. Vielleicht
ist Ihnen ja aufgefallen, daß die Integers irgendwo
überflüssig sind, da Floatzahlen ja auch ganze Zahlen
darstellen können. Eine Zuweisung von der Art " y=100" ist also nicht nur möglich, sondern meist auch die am
häufigsten verwendete Methode. Sie als Anfänger dürfen ruhig so arbeiten, doch sei hier gesagt, daß das Rechnen mit Integern sehr viel schneller vom Computer
ausgeführt werden kann, als das Rechnen mit Floats.
Dies liegt darin begründet, daß die Darstellungsweise
von Floats im Computer intern sehr kompliziert ist, und viel internes hinund hergerechne verursacht, wohingegen die Integers dem Computer wieder einfacher
erscheinen, da er selbst diese nur benutzt. Floats
sind eher umständlich simulierte Dezimalzahlen, da
ein Computer diese Zahlenmenge nicht kennt, sondern
halt nur die natürlichen Zahlen.
Außerdem ist die Verwendung von Integern auch noch
speicherplatzsparend, da die Darstellungsweise wie
gesagt nicht so komliziert ist. Sollten Sie also später einmal größere Programme schreiben, bei denen
dann auf einmal die 37911 Bytes, die BASIC als Hauptspeicher frei hat ( siehe auch Einschaltmeldung), zu
knapp werden, dann können Sie häufig mit der gezielten Benutzung von Integern wieder ein paar Bytes " herausschinden" .
Wohlgemerkt ist die Benutzung von Integern nur dann
angebracht, wenn wirklich nur mit ganzen Zahlen gerechnet wird, bzw. wenn eine Integervariable für eine
Rechnung eine ganze Zahl darstellen soll. Hier sei
auch noch gesagt, daß bei Integerwerten mit Nachkommastellen diese grundsätzlich abgeschnitten werden.
Das heißt, das bei der Zuweisung " a%=5 .78" die Variable dann den Wert 5 enthält. Oder daß bei der Division 3/2(=1 .5) das Ergebnis 1 ausgegeben wird.
Wir werden trotz allem wahrscheinlich doch immer
Floats benutzen, weil es so einfacher zu schreiben
ist ( da wir ja kein Prozentzeichen anzuhängen brauchen) und es außerdem schwieriger ist das Ganze zu
verstehen, wenn z. B. in einer Formel verschiedene
Variablentypen vorkommen. Doch ist es grundsätlich
besser, Integers zu verwenden, wobei ich Ihnen freistelle, wie Sie dies handhaben möchten. Sie könnten
ja zum Beispiel auch die hier im Kurs behandelten
Programme einmal umschreiben, wobei Sie allerdings
sehr weit voraus denken müssen, um prüfen zu können, ob eine Variable nicht doch irgendwann einmal einen
Dezimalwert annimmt, wegen dem dann die ganze Rech- nung zunichte wird, da falsche Ergebnisse herauskommen, zumal der Computer sich bei solchen Operationen
ja nicht beschwert, sondern ganz einfach die Nachkommastellen abschneidet.
Ich hoffe, daß Sie bis jetzt meinen Gedankengängen
und vor allem denen des Computers folgen konnten und
möchte mich nun verabschieden bis nächsten Monat, wo
wir dann endlich zur Sache gehen werden, was das
Schreiben von Programmen angeht.
Hiermit möchte ich nun schließen und wünsche Ihnen
viel Erfolg beim experimentieren,
Ihr Uli Basters.
Basic-Kurs Teil 2
Lieber Leser. Nachdem wir uns das letzte Mal ja ausgiebig um die Variablen und den PRINT-Befehl gekümmert haben, möchten wir uns diesen Monat nun endlich
dem Programmeschreiben, also der wirklichen Programmerung, von BASIC befassen.
Letzte Ausgabe hatten wir unsere Befehle und Anweisungen ja immer direkt auf den Bildschrirm geschrieben, und der Computer hat sie dann auch immer, nachdem wir die Taste RETURN gedrückt hatten, sofort ausgeführt, insofern er nichts an der Syntax der Zeile
auszusetzen hatte. Nun müssen Sie allerdings zugeben, daß unsere kleinen PRINT-Anweisungen sich als relativ
umständlich und sinnlos erwiesen, zumal man, um einen
Text auf den Bildschirm zu drucken, ja mehr Schreibarbeit hatte, als wenn man ihn einfach " von Hand" auf den Bildschirm geschrieben hätte. Man hatte ja
noch zusätzlich den PRINT-Befehl zu schreiben und die
Anführungszeichen, die den Text einschlossen.
Nun, all dies hat natürlich einen Sinn, denn der
PRINT-Befehl ist, ebenso wie die meisten anderen BA-SIC- Befehle, nicht dafür geschaffen worden, direkt
Texte auszugeben, sondern um in Programmen zu arbeiten, wo die Textausgabe zur Kommentierung des Programms absolut unerläßlich ist, zumal dann ein völlig
ahnungsloser Benutzer auch dann mit dem Programm etwas anfangen kann, wenn er es sich zum ersten Mal
ansieht. Doch wie sag ichs meinem Computer? Wie machen wir denn unserem C64 klar, daß wir die eingegeben Zeile nicht jetzt, sondern irgendwann später ausgeführt haben wollen, und daß er sich diese Zeile für
jenen späteren Zeitpunkt merken soll? Nun, geben Sie
doch einfach einmal folgende Zeile ein :
10 print" Das ist ein Programm !"
Sie sehen, daß Sie nichts sehen. Denn sobald Sie die
RETURN-Taste drücken, druckt Ihnen Ihr 64 er nicht den
Text " Das ist ein Programm !" aus sondern springt mit
dem Cursor ( das ist das kleine hellblaue Viereck, das
immer so blinkt, und Ihnen Ihre Schreibposition angibt) einfach in die nächste Bildschirmzeile und war- tet nun wiederum auf eine Eingabe. Noch nicht mal
eine Fehlermeldung ist zu sehen. Eine Riesensauerei! ! !
Doch keine Panik ! Ihr C64 ist nicht etwa beleidigt, oder kaputt, sondern er hat sich soeben gerade eine
Programmzeile gemerkt. Doch was heißt das eigentlich?
Nun, wie Ihnen bestimmt aufgefallen ist, haben wir
vor unsre PRINT-Anweisung noch eine Zahl geschrieben.
Dies ist die sogenannte Zeilennummer. Ihr Computer
merkt sich Ihre Eingaben intern nämlich mit Nummern, die er nach ihrer Größe ordnet. Das heißt, daß Sie
mit dieser Zahl auch immer wieder auf eben jene Zeile
zurückgreifen können. Sie ist sozusagen das " Erkennungszeichen" einer Programmzeile. Was das genau bedeutet, möchte ich Ihnen mit einem kleinen Beispiel
noch ein wenig näher bringen. Geben Sie doch einmal
ein:
list
Sie sehen nun folgendes:
10 print"Das ist ein Programm !" ready.
Nach Eingabe des BASIC-Befehls LIST hat uns der C64 die eben eingegebene Programmzeile wieder aufgeLI-STet; so, wie wir sie eingegeben hatten, nämlich mit
ihrer Zeilennummer vorangestellt. Er hat sich diese
Zeile also gemerkt. Sie können gerne einmal probieren
ob es auch funktioniert wenn Sie den Bildschirm
gelöscht haben ( dies tun Sie mit der Tastenkombination SHIFT und CLR/ HOME), auch nun wird Ihnen der
Text noch haargenauso angezeigt, wie Sie ihn eingaben, es hat also nichts damit zu tun, daß unsere Zeile noch auf dem Bildschirm stand. Das ist auch gut
so, denn der C64 merkt sich solche Programmzeilen in
seinem Programmspeicher ( ebenso wie die Variablen) von wo er sie auch wieder auf dem Bildschirm anzeigen
kann, halt mit eben jenem Befehl LIST.
Auch für Zeilennummern müssen Sie bestimmte Regeln
einhalten, damit Ihnen keine Fehler angezeigt werden.
Hier eine Zusammenfassung dieser Regeln :
1 .) Sie können alle Zahlen von 0 bis 63999 für eine
Zeilennummer benutzen. Dabei sollten Sie jedoch
die Zeilennummern immer in 10 er-Schritten ( also
10,20,30,40, etc.) vergeben, warum dies von Vorteil ist, werde ich Ihnen später erklären.
2 .) Egal in welcher Reihenfolge Sie die Zeilen eingeben, der C64 ordnet diese immmer wieder neu nach
der Größe ihrer Zahlen ein. Sollten Sie also einmal folgende Zeilen in der hier dargestellten
Reihenfolge eingeben:
30 print"Zeile 30" 10 print"Zeile 10" 20 print"Zeile 20" 40 print"Zeile 40"
So wird Ihnen Ihr C64 nach der Eingabe von LIST
immer wieder folgendes Bild liefern :
10 print"Zeile 10" 20 print"Zeile 20" 30 print"Zeile 30" 40 print"Zeile 40"
3 .) Sollten Sie eine Zeile eingeben, die eine Zeilennummer hat, die schon im Speicher existiert, dann
wird die alte Zeile im Speicher durch die neue
ersetzt. Sollten Sie also bei obigem Programm ( so
können wir es jetzt nennen) die Zeile:
30 print" Aetsch! Das is jetzt anders."
eingeben, dann wird das Programm beim nächsten
Listen so aussehen :
10 print"Zeile 10" 20 print"Zeile 20" 30 print"Aetsch! Das is jetzt anders." 40 print"Zeile 40"
4 .) Sollten Sie eine Zeile eingeben, die nur aus einer Zeilennummer besteht OHNE darauffolgende Befehle, so wird die entspechende Zeile mit dieser
Nummer, sollte sie im Speicher stehen, gelöscht
werden. Würden Sie also:
30
eingeben, dann würde Zeile 30 aus unserem Programm oben gelöscht werden.
Jetzt möchte ich Ihnen die Syntax des LIST-Befehls
erst einmal noch etwas genauer erklären, bevor ich
weitergehe und Ihnen zeige, wie Sie unser kleines
Progrämmchen zum Ablauf bringen.
Sie können dem LIST-Befehl nämlich sogar noch spezifischer sagen, in welche Programmzeilen Sie einen
Einblick wünschen. Hierzu müssen Sie dem Befehlswort
LIST ganz einfach die Zeilenummer der Zeile, die Sie
sich ansehen wollen hinterherstellen. Der Befehl:
list 20
bewirkt also, daß Ihnen anstatt des ganzen Programms
nur die Zeile 20 angezeigt wird. Ich glaube jetzt
wird es Ihnen hoffentlich auch etwas deutlicher, warum eine Zeile eine Nummer braucht. Durch sie kann
man jede einzelne Zeile ansprechen wie man möchte, der Computer versteht also sofort, welche Zeile Sie
von ihm sehen wollen.
Doch die Anwendung von LIST geht noch weiter. Sie
können sich ebenso auch einen ganz bestimmten Bereich
aus Ihrem Programm ansehen, geben Sie etwa folgendes
ein:
list 20-30
so werden die Zeilen 20 und 30 auf dem Bildschirm
gelistet. Sie geben also einfach eine obere und eine
untere Grenze an, und LIST wird seine Arbeit auf diese Zeilengrenzen beschränken. Ebenso können Sie diese
Schranke nach oben und unten offen lassen. Dann wird
dementsprechend einfach von der ersten Zeile bis zu
der angegebenen Zeile, beziehungsweise von der angegebenen Zeile bis zur letzten Zeile gelistet. Probieren Sie doch einfach einmal folgendes mit unserem
kleinen Beispielprogramm im Speicher. Geben Sie ein:
list -30
Nun werden die Zeilen 10,20 und 30 gelistet, weil das
Programm ab Zeile 10 anfängt.
Bei dem Befehl:
list 20-
werden die Zeilen 20,30 und 40 gelistet. Der C64 fängt bei der von Ihnen angegebenen Zeile an und hört
erst am Ende des Programms auf.
Wie der LIST-Befehl funktioniert wissen Sie jetzt ja, klären wir also schnell noch die Frage, warum man im
Allgemeinen besser Zeilennummern in 10 er-Schritten
verteilt. Nun, dies liegt einfach darin begründet, daß Sie, wie jeder Mensch auch, nicht unfehlbar sind, und daß es Ihnen durchaus einmal passieren kann, daß
Sie, aufgrund eines Fehlers im Programm, noch eine
Zeile einfügen müssen. Würden Sie in 1 er-Schritten
die Programmzeilen eingeben, so müßten Sie erst einmal Platz schaffen, indem Sie alle der einzufügenden
Zeile folgenden Zeilen nochmals neu einzutippen hätten, da diese ja im Speicher stehen bleiben sollten, aber zwischen den Zeilen 33 und 34 kein Platz mehr
für eine weitere Zeile wäre. Deshalb benutzen Sie
besser 10 er Zahlen, so, daß Sie bequem zwischen die Zeilen 20 und 30 beispielsweise eine weitere Zeile, vielleicht mit der Zeilennummer 25, einfügen könnten.
Gewöhnen Sie sich diese Programmierweise also gleich
an, Sie werden sehen, es lohnt sich ganz bestimmt.
Doch widmen wir uns nun unserem Problem, unser Programm auch zum Ablaufen zu bringen. Auch hierfür gibt
es einen Befehl: den RUN-Befehl ( von engl. : to run = laufen) . Haben Sie unser kleines Programm noch im
Speicher? Gut. Dann geben Sie doch einmal ein:
run
Und nun, siehe da, werden unsere ersehnten PRINT-Zeilen endlich aktiv, denn Sie sehen nun folgendes
auf dem Bildschirm :
Zeile 10 Zeile 20 Aetsch! Das is jetzt anders. Zeile 40 ready.
Und nun sehen Sie auch den Vorteil des PRINT-Befehls.
Sie können nämlich so auf einfache Art und Weise lange, lange Texte eingeben, die dann dem Benutzer während des Ablaufs eines Programms wertvolle Meldungen
und Hinweise geben können.
Der RUN-Befehl kann übrigens ähnlich wie LIST angewandt werden. Sie können Ihm nämlich auch sagen, wo
genau er beginnen soll, ein Programm abzuarbeiten.
Nämlich indem Sie ihm, wie bei LIST, eine Zeilennummer nachstellen, ab der er beginnen wird das Programm
abzuarbeiten. Gäben Sie also :
run 30
ein, so würde Sie folgendes Bild auf dem Bildschirm
anstrahlen :
Aetsch! Das is jetzt anders. Zeile 40 ready.
Eines sollte noch gesagt sein: sollten sich Variablen im Speicher befinden, wenn Sie eine neue Programmzeile eingegeben haben, so werden diese nach dem
drücken der RETURN-Taste restlos gelöscht. Das liegt
daran, daß der 64 er zum Eingliedern der neuen Zeile
in die richtige Zahlenreihenfolge den gesamten Programmspeicher hinund herschieben muß und daß bei
dieser Schieberei sehr leicht der Inhalt einer Variablen zerstört werden kann. Deshalb werden alle Variablen vorher gelöscht, damit später kein Mist im Programmtext stehen kann, und falsche Variablenwerte zu
falschen Programmreaktionen führen können.
Ebenfalls aus letztem Grund heraus werden grundsätzlich vor der Ausführung eines RUN-Befehls alle Variablen vom Computer gelöscht, da so ebenfalls ungewollte Veränderungen der Variablen entstehen könnten.
Außerdem kann für die beiden Befehle LIST und RUN
gesagt werden, daß sie durch das Drücken der RUN/ STOP-Taste wieder angehalten werden können.
Das heißt also, wenn LIST Ihnen gerade ein Programm
auflisten sollte, und Sie sich einen Teil etwas genauer ansehen wollten, Sie dadurch den Vorgang des
Listens unterbrechen könnten.
Ebenso bei RUN. Möchten Sie aus irgendeinem Grund Ihr
Programm anhalten, vielleicht weil es nicht das tut, was Sie von Ihm wollen, dann können Sie es ebenfalls
auf diese Weise unterbrechen. Sollten Sie es dann
allerdings doch an der Stelle fortsetzen wollen, an
der Sie es angehalten haben, allerdings ohne den Inhalt aller Variablen zu zuerstören, dann können Sie
den Befehl CONT benutzen. Er hat haargenau selben
Effekt wie RUN, nur, daß er zum einen die Variablenwerte nicht vorher löscht, und zum anderen genau hinter dem Befehl weiterarbeitet, bei dem das Programm
vorher abgebrochen wurde, vorrausgesetzt es wurde
zwischendurch nicht verändert. Am besten zeige ich
Ihnen noch einen weiteren Befehl, damit Sie hier auch
ein wenig experimenieren können: der GOTO-Befehl.
Übersetzen wir GOTO aus dem Englischen, wissen wir
auch schon gleich, was wir mit diesem Befehl anfangen
können. GEHE ZU einer Zeilennummer und arbeite das
Programm von dort aus weiter ab. Hinter GOTO muß also
noch eine Zeilennummer folgen. Probieren wir also
wieder an unserem kleinen Progrämmchen etwas aus.
Geben Sie doch zusätzlich noch folgende Zeile ein:
50 goto 10
Starten Sie nun das Programm mit RUN. Sie sehen nun
immer wieder unseren Demotext auf dem Bildschirm
" runterlaufen", also etwa folgendes Bild :
... Zeile 40 Zeile 10 Zeile 20 Aetsch! Das ist jetzt anders. Zeile 40 Zeile 10
. . .
Verfolgen wir einmal unseren C64, wie er sein Programm abarbeitet. Zuerst werden die Zeilen 10-40 wie
gewohnt durchlaufen. Der Text in den PRINT-Zeilen
erscheint also auf dem Bildschirm. Anschließend
trifft der Computer in Zeile 50 auf den GOTO Befehl, der besagt, daß er bei Zeile 10 weiterarbeiten soll.
Er führt diesen Befehl aus, und beginnt wieder von
vorne bei 10 . Dies wiederholt sich nun bis ins Unendliche. Pausenlos wird der Text ausgedruckt, und unser
64 er würde dies Jahre lang machen, vorrausgestzt es
gäbe keinen Stromausfall. Er befindet sich in einer
sogenannten " Endlosschleife" eine Schleife, die immer
wieder durchlaufen wird, ohne daß Sie zu einem Ende
kommt. Eine Schleife ist also ein bestimmter Programmabschnitt, der mindestens zweimal durchlaufen
wird. Um nicht den ganzen Programmteil nochmals eingeben und somit das Programm unnötig verlängern zu
müssen verwendet man also den GOTO-Befehl. Nun kommt
der Auftritt für die RUN/ STOP-Taste. Drücken Sie sie
einmal. Es erscheint nun:
break in xx ready.
Der Computer meldet Ihnen also, daß Sie soeben das
laufende Programm in Zeile xx abgebrochen haben. Für
" xx" können alle Zeilennummern des Programms stehen, da es Zufall ist, in welcher Zeile Sie gerade abgebrochen haben. Auf alle Fälle sind Sie nun unserer Endlosschleife entkommen und können wieder an Ihrem
Programm weiterarbeiten. Sollten Sie allerdings wieder den Wunsch hegen, schöne Zeichenketten auf dem
Bildschirm " runterlaufen" zu sehen, dann können Sie
jetzt ganz einfach wieder mit CONT das Programm fortfahren lassen ( CONT von engl. : to continue = fortsetzen, fortfahren) .
Fassen wir doch einmal zusammen, wie weit wir schon
fortgeschritten sind. Wir können mittlerweile kleine
Programme schreiben, die etwas auf dem Bildschirm
ausgeben, wir können rechnen, Programme mit Hilfe von
LIST editieren und kennen auch RUN, um diese zum laufen zu bringen. Außerdem kennen wir uns mit den Namen
und Typen von Variablen aus. Nunja, auf den ersten
Blick erscheint dies ja sehr viel, doch direkt weltbewegende Programme können wir noch nicht so ganz
schreiben, da wir eigentlich nur einen einzigen Befehl kennengelernt haben, mit dem sich innerhalb von
Programmen etwas anfangen läßt, den PRINT-Befehl. Die
anderen sind mehr oder weniger ausschließlich außerhalb von Programmen, im sogenannten " Direktmodus" nützlich, obwohl sie ebenso in Programmen funktionie- ren würden. Wollen wir also nun unser Befehlsspektum
noch ein wenig mehr erweitern und wenden wir uns einem sehr mächtigen Befehl zu, mit dem schon etwas
mehr zu machen ist.
Erinnern wir uns doch einmal an unser Beispiel vom
letzten Monat mit der Coladose. Wir hatten mit Hilfe
von Variablen die Oberfläche einer Coladose berechnet. Diese Dose hatte eine Höhe von 11 .5 cm und einen
Deckelradius von 3 .25 cm. Mit Hilfe der Formel
o=2* r*π*( r+ h) sind wir dann zu dem Ergebnis 301 .2 qcm
gekommen. Bedenkt man nun, daß durch den Trend zum
Umweltschutz es heutzutage durchaus möglich sein
könnte, daß man ein anderes Material für Einwegdosen
erfinden wird, und daß man deshalb vielleicht ein
anderes Dosenformat wählen muß, so wäre unsere schöne
mühselige Rechnung nur noch Müll, da unbrauchbar. Man
müßte die ganze Prozedur nochmals mit den Werten der
neuen Dosen durchführen. Eine mehr oder wenig
umständliche Sache also. Doch wozu können wir jetzt
Programme schreiben, wir hatten ja gelernt, daß die
Formel für die Zylinderoberfläche, wie ich sie oben
schon aufgeführt hatte, ja allgemeingültig ist und somit mit allen nur erdenklichen Werten für r und h
einen richtigen Wert liefert. Im Prinzip könnte man
nun ein Programm schreiben, daß diese Formel benutzt, und würde dann hierfür die Variablen in einer vorangehenden Zeile mit den entspechenden Werten versorgen. Doch wir machen es uns noch komfortabler, wir
benutzen den INPUT-Befehl, der für Eingaben vom Benutzer aus sehr empfänglich ist ( im wahrsten Sinne
des Wortes, denn INPUT bedeutet nichts anderes als
" EINGABE") . Mit ihm wird es uns gestattet, eine Abfrage zu machen, auf die der Benutzer mit einer Eingabe antworten kann, und dies alles sogar mitten im
im Programm! ! !
Wir benötigen also Werte für Radius und Höhe. Wie
beim letzten Mal wollen wir hierfür die Variablennamen r und h wählen. Sehen wir uns nun doch einmal die
ersten Zeilen unseres Programms an :
10 print chr$(14) ;
20 print"[ CLR,4 SPACE] Zylinderoberflaechenberechnung"30 input"[2 DOWN] Radius " ; r 40 input" Hoehe " ; h
Da haben wir ja schon eine ganze Menge neue Anweisungen. Fangen wir einmal in Zeile 10 an. Sie sehen hier
einen PRINT-Befehl, doch was dieser Befehl ausdruckt, können Sie nicht wissen. Eine String-Variable ist das
nicht ( obwohl es fast so aussieht), ich kann Ihnen
allerdings versichern, daß es etwas ähnliches darstellt. Dies ist die CHR$- Funktion. ACHTUNG! Ich betone das Wort FUNKTION! Es handelt sich hierbei wohlgemerkt NICHT um einen Befehl, das dürfen Sie nie
verwechseln. Eine Funktion wird zwar ebenfalls durch
ein BASIC-Schlüsselwort dargestellt, doch sie ist
ohne einen verknüpfenden Befehl, oder eine Variablenzuweisung nicht ausführbar, da der Computer in diesem
Fall nicht spezifisch weiß, was er mit ihr anfangen
soll. Das heißt also, daß Sie Funktionen immer mit
PRINT ausgeben, oder einer Variablen zuweisen können.
Zum Beispiel so:
a$=chr$(65) print a$
Es gibt übrigens noch mehr Anwendungsmöglichkeiten
für Funktionen, doch werden wir hierzu später kommen, da Sie die entprechenden Befehle hierzu noch nicht
kennen.
Was bewirkt die CHR$- Funktion? Nun, CHR$, wird benutzt um einzelne Zeichen spezifiziert aufrufen zu
können. Jedes Zeichen auf Ihrer Tastatur besitzt einen eigenen Zahlencode. Geben Sie der CHR$- Funktion
nun diesen Zahlcode eines Zeichen in Klammern an, dann steht die ganze Funktion für eben dieses Zeichen. In unserem Beispiel von eben haben wir der Variable a$ den Zeichencode 65 zugeordnet. Anschließend
wurde die Variable a$, in der ja nun dieser Zeichencode als Buchstabe dargestellt war, auf dem Bildschirm ausgegeben. Dieses Zeichen, das zu dem Code 65 gehört, ist das kleine " a" . Somit ist unsere Variablendefinition gleich der Definition:
a$=" a"
mit der ja auch der Buchstabe " a" dem String a$ zugeordet wird. Ich hoffe Sie haben dies verstanden.
Somit hat der folgende PRINT-Befehl auch das " a" auf
dem Bildschirm ausgedruckt. Genauso hätten Sie auch
schreiben können:
print chr$(65)
womit Sie das selbe Ergebnis erzielt hätten, allerdings nicht mehr über den Umweg mit der Stringvariable. Hier sei auch noch gesagt, daß das Ergebnis der
CHR$- Funktion immer einer Stringvariablen zugeordnet
wird, nicht also einer Floatoder Integervariable, da diese Variablentypen ja keine Zeichen darstellen
können. Allerdings können Sie problemlos auch Anweisungen von dieser Art vergeben:
a=65 a$=chr$(a) Hier haben wir nicht den Zeichencode 65 in "a" ge- speichert, sondern einfach nur den Zahlwert 65 (bei "PRINT a" kriegen Sie wie erwartet "nur" die Zahl 65 auf den Bildschirm gedruckt). Sie dürfen also
Floats und Intergers benutzen, um den Zahlwert in
Klammern ( von CHR$) anzugeben, dies führt also zu dem
selben Ergebnis, CHR$ holt sich den Wert von a aus
dem Speicher und ordnet dann dem String a$ den Zeichencode des Zahlwerts von a zu. Auf der Rückseite
dieser Magic Disk finden Sie diesmal auch ein kleines Programm namens ASCII-Code. Es zeigt Ihnen alle
möglichen ASCII-Codes ( das sind eben jene Codes der
Zeichen) des C64 an.
Wollen wir in diesem Zusammenhang gerade noch die
Umkehrfunktion von CHR$ betrachten, die ASC-Funktion, mit der Sie sich beispielsweise den ASCII-Wert ( so
nenne ich ab jetzt diesen Zeichencode, ASCII ist ein
internationaler Standard, an den sich die meisten
Computerhersteller halten, die Zeichen haben also auf
den meisten Computern die selben Codes. Leider ist
dies beim C64 aus unerfindlichen Gründen nicht der
Fall, trozdem wird auch hier von ASCII gesprochen) eines Zeichens ausgeben lassen können. Hier geht alles genau umgekehrt, hier geben Sie ein Zeichen an, und es kommt ein Zahlwert heraus. Dies müssen Sie
also auch bei Variablenzuweisungen beachten. Die
ASC-Funktion sieht so aus:
print asc(" a")
Wie chr$, nur daß Sie jetzt das zu untersuchende Zeichen in Anführungsstrichen in die Klammer einsetzen
müssen. Die Anführungsstriche deshalb, weil Sie hier
auch Strings als sogenanntes Funktionsargument verwenden dürfen, diese dann allerdings OHNE Anführungsstriche. Also:
a$="a" print asc(a$)
hätte die selbe Wirkung wie die oben aufgezeigte Zeile. Sie können sich so also alle CHR$- Codes, bzw.
ASCII-Codes ausgeben lassen, und dann bei Bedarf verwenden. Auch ASC-Funktionswerte kann man Variablen
zuweisen :
a$="x" a=asc("x") a%=asc(a$)
Die beiden letzten Zeilen führen zum selben Ergebnis, nur daß der eine Wert in der Floatvariable " a" gespeichert ist und der andere in der Integervariablen
" a%" . Außerdem ist der Weg, mit dem die Ergebnise
erreicht werden jeweils ein anderer, doch das dürften
Sie mittlerweile ja kennen.
Doch wollen wir uns nun, nach unsrem langen langen
Ausflug zu den ASCII-Codes wieder unserer Zylinderberechnung widmen. Wir sind ja gerade dadurch auf dieses Thema gekommen. . .
In Zeile 10 stand der Befehl PRINT CHR$(14) . Es wurde also ein ASCII-Zeichen ausgegeben, mit dem Zeichencode 14 . Dieser Code steht für eine sogenannte
" Steuerfunktion" . Mit einer Steuerfunktion können Sie
ein Zeichen ausgeben, das nicht direkt als Buchstabe
auf dem Bildschirm sichtbar wird, sondern eher eine
" unsichtbare" Funktion ausübt, wie zum Beispiel den
Bildschirm zu löschen, den Cursor eine Zeile höher
oder tiefer rücken zu lassen, oder die Zeichenfarbe
zu verändern. Unser Code 14 bewirkt, daß der Zeichensatz von Großauf Kleinschrift umgeschaltet wird. Er hat also die selbe Wirkung wie das gleichzeitige
Drücken der SHIFTund der Commodoretaste. Dies ist
deshalb notwendig, damit beim späteren Ausdruck von
" Zylinderoberflächenberechnung" in Zeile 20, der
Großbuchstabe " Z" nicht etwa als Grafikzeichen ausgegeben wird, was leicht passieren kann, zumal die
Großschrift doch direkt nach dem Einschalten des
64 ers vorhanden ist.
Sicher ist Ihnen der Text in den eckigen Klammern
-[]- aufgefallen, dies ist kein Programmtext im
allgemeinen, hiermit habe ich ebenfalls angegeben, welche Steuerzeichen an dieser Stelle eingefügt werden müssen. Sie wissen ja, unsere Zeichen, die keine
sind, sondern etwas bestimmtes ausführen. Man kann
Sie nämlich auch direkt in die PRINT-Anweisung
einfügen, zumal das auch einfacher und platzsparender
ist. Ich tat dies bei CHR$(14) bewußt nicht, da Sie
so bei der Gelegenheit einmal die CHR$- und ASC-Funktion kennenlernen konnten, und weil außerdem dieses Steuerzeichen nicht als solches in einer PRINT-Anweisung darstellbar ist ( es gibt zwar schon einen
Weg, doch das wäre jetzt hier zuviel) . Doch wie sollen Sie denn überhaupt diese Steuerzeichen in die PRINT-Anweisung hereibringen? Die Lösung ist ebenso
einfach wie genial. Sie müssen lediglich, NACHDEM Sie
den auszugebenden Text mit einem Anführungszeichen
schon angekündigt haben, die entspechende Taste drükken, und schon wird unser Steuerzeichen mit einem
inversgedruckten Zeichen dargestellt. Von nun an wissen Sie, daß an dieser Stelle dann ein Steuerzeichen
gedruckt wird. Die Steuerzeichen können Sie ebenso
wie normale Buchstaben überall innerhalb der Anführungsstriche einfügen. Mit der Zeit werden Sie dann
auch lernen, diese an Ihren Reverszeichen zu erkennen.
Inverszeichen wurden deshalb gewählt, da man sie innerhalb einer PRINT-Klammer nicht verwenden kann, man
kann trotzdem aber inverse Texte ausgeben, indem man
einfach die Steuerzeichen für RVS ON und RVS OFF benutzt. Die Zeichen zwischen diesen Steuerzeichen werden dann auch invers gedruckt.
In unserem Fall müssten Sie also ein CLR ( CLEAR
( dtsch. : lösche)= SHIFT + CLR/ HOME-Taste) einfügen. Ich werde in Zukunft bei solchen Steuerzeichen
bestimmte Ausdrücke in eckigen Klammern angeben.
Damit Sie wissen welche Zeichen nun gemeint sind. Die Programme, die sich ja auf der Rückseite der Magic
Disk befinden, werden dann natürlich immer schon die
entspechenenden Steuerzeichen in Reversdarstellung
enthalten, da wir ja keine " geschweiften" Texte nachher auf dem Bildschirm haben wollen. Diese Ausdrücke, die ich verwenden werde, werde ich Ihnen dann im
nachfolgenden Text immer noch erläutern, damit Sie
wissen, was gemeint war.
Nachdem wir uns jetzt wohl zur Genüge in den ersten 2 Zeilen unseres Programms verrannt haben, wollen wir
uns nun endlich dem Befehl widmen, von dem ich anfangs gesprochen hatte. Sie werden ihn schon in den
Zeilen 30 und 40 bemerkt haben. Es ist der INPUT-Befehl. Übersetzen wir doch einmal:
INPUT = engl. EINGEBEN, EINGABE
Na wunderar, wir können also etwas eingeben. Und das
auch noch wahnsinnig komfortabel, denn Sie brauchen
lediglich dem INPUT-Befehl eine Variable zu geben, in
der er die Eingabe ablegen soll und schon weiß unser
Programm genauer, was sein Benutzer von ihm will.
Sehen wir uns die Syntax einmal genauer an:
30 INPUT" Radius " ; r
Ich muß hier noch anmerken, daß ich bei diesem Beispiel, die im Programm vorkommenden Steuerzeichen
weggelassen habe. Es ist dort von [2 DOWN] die Rede, womit Sie aufgefordert sind,2 mal die Taste " Cursor
runter" zu drücken.
Wie Sie an den Steuerzeichen und auch an den Anführungsstrichen erkennen können, kann man auch bei IN-PUT einen Text angeben, der vor Ausführung der eigentlichen Eingabe ausgegeben werden soll. Hinter
einem Semikolon ( oder Strichpunkt - ;) wird dann
noch der Name einer Variablen angehängt, in unserem
Fall " r" für den Radius. Probieren Sie doch einmal
obige Zeile als Programm aus.
Sie MÜSSEN übrigens unbedingt den INPUT-Befehl im
Programm verwenden, da es vom Direktmodus aus zu Fehlern kommen kann, da der INPUT-Befehl im Direktmodus
keinen Sinn hat. Deshalb haben die Programmierer von
BASIC 2 .0 sich gesagt, daß die Benutzung dieses Befehls im Direktmodus nicht erlaubt sein darf und des- halb mit einer Fehlermeldung quittiert wird.
Sie sehen, wenn Sie alles richtig eingegeben haben, nun folgendes auf dem Bildschirm :
Radius ?
und einem blinkenden Cursor hinter dem Fragezeichen.
Sie sind nun dazu aufgefordert einen Wert für den
Radius einzugeben. Tun Sie dies also. Geben Sie doch
beispielsweise einmal 3 .25 ein:
Radius ?3 .25
und drücken Sie die Return-Taste. Das Programm endet
nun, vorausgesetzt, Sie hatten auch wirklich nur diese eine Zeile im Speicher stehen. Geben Sie doch
jetzt einmal im Direktmodus:
print r
ein. Was sehen Sie? Es erscheint der Zahlwert 3 .25 auf dem Bildschirm! Genau Ihre Eingabe, die Sie soeben taten. Na ist ja entzückend - würde Kojak, lollilutschend, jetzt sagen. Merken Sie was INPUT tat? Es
hat Ihre Eingabe gleich einer Variablenwertzuweisung, der Variable " r" zugeordnet und in ihr gespeichert! Dies geht sogar noch weiter! Sie dürfen sogar
Strings und Integers benutzen, um Eingaben in Variablen ablegen zu können. Ein solches Programm wäre
also auch denkbar:
10 input" Wie heissen Sie bitte " ; n$20 input" Und wie alt sind Sie " ; a%30 print" Sie heissen " ; n$ ;" und sind " a%" Jahre alt."
Sie sehen, hier benutzen wir einen String n$( für
Name) und eine Integervariable a%( für Alter) . Den
Integer können wir bedenkenlos anwenden, da ja Alter
im allgemeinen mit ganzen Zahlen angegeben wird.
Vielleicht ist Ihnen allerdings etwas aufgefallen:
Obwohl wir KEIN Fragezeichen in unserem Text stehen
hatten, erschien doch eins auf dem Bildschirm. Wie
denn das? Nun, INPUT druckt grundsätzlich immer ein
Fragezeichen am Ende seines Textes aus, da ja nach
etwas gefragt wird, und somit dieses Fragezeichen
auch berechtigt ist. Es wird vielleicht Fälle geben, in denen es Sie stören wird, da es nicht in den Kontext der Frage passt, doch werden wir später einmal
behandeln, wie man es abschalten kann.
Im Übrigen brauchen Sie auch nicht unbedingt einen
Text mit INPUT auszugeben, Sie können dies auch unterdrücken, indem Sie die Anführungsstriche und das
Semikolon einfach weglassen und den Variablennamen
einfach anhängen. Also so beispielsweise:
10 input a$ 20 input a 30 input xx%
Ebenfalls ist es möglich, mehrere Eingaben gleichzeitig aufzunehmen. Ich finde diese Methode allerdings
sehr unbequem, und außerdem gefällt es mir getrennt
besser, doch möglich wäre auch dies:
10 input " Koordinaten ( X/ Y)" ; x, y
Sie können hier also gleich mehrere Werte abfragen, die allerdings mit einem Komma voneinander getrennt
sein sollten. Jetzt wissen Sie auch, wofür das Komma
reserviert ist, da wir ja gesagt hatten, daß das Dezimalkomma bei Floatvariablen immer einem Punkt entspricht. Die Eingabe müßte dann so aussehen:
Koordinaten ( X/ Y) ?22 .3,10
Den Variablen x und y wären dann folgende Werte zugeordnet worden:
x=22.3 y=10
Leider muß ich nun an dieser Stelle abbrechen, um
keinen Informationsstau bei Ihnen hervorzurufen. Versuchen Sie erst einmal die eben erkannten neuen Befehle kennenzulernen. Sie können sich ja auch einmal
das gesamte Zylinderberechnungsprogramm auf der Rückseite dieser Magic Disk 64 ansehen. Nächsten Monat werde ich es dann auf jeden Fall zu Ende kommentieren. Des weiteren wollen wir uns dann mit der Schleifenprogrammierung und den Entscheidungsbefehlen ( und
- operatoren) widmen.
Bis dahin wünsche ich Ihnen weiterhin ein allzeit
" Gut Hack",
Ihr Uli Basters G
BASIC-Kurs : "Von Adam und Eva..." (Teil 3)
Auf in die dritte Runde in unserem Basickurs. Diesen
Monat wollen wir endlich unser Zylinderberechnungsprogramm zu Ende abhandeln, um uns anschließend noch
ein paar kleine, nichtsdestotrotz ebenso wichtige
Befehle anzuschauen.
So. Nun also weiter. Nachdem Sie die Fülle an Informationen letzten Monats hoffentlich verarbeitet haben, möchten wir uns nun gleich frisch ans Werk machen und den Rest unseres Zylinderberechnungsprogramms abhandeln. Erinnern wir uns:
Wir hatten uns die ersten 40 Zeilen angeschaut und
dabei den INPUT-Befehl kennengelernt, sowie die CHR$- und die ASC-Funktion. Außerdem hatten wir uns noch
ein wenig mit den Steuercodes befaßt, und ich hoffe, daß Sie mit dem ASCII-Druck- Programm auf der Rückseite ebenfalls etwas anzufangen wußten, hier gab es
nämlich auch noch eine Menge weiterer Steuerfunktionen zu finden, die wir im einzelnen im Laufe des Kurses noch kennenlernen werden.
Doch nun weiter im Text, sprich im Listing ( so nennt
man die vom Computer geordnete Liste der einzelnen
Programmzeilen) unseres kleinen Programms, machen wir
weiter ab Zeile 50, also LIST 50-( Sie wissen doch
wohl hoffentlich noch, was dies bewirkt ? ! ?) :
50 o=2*r*π*(r+h) 60 print"[2 DOWN]Die Oberflaeche eines Zylinders mit" 70 print"der Hoehe"h"und dem Radius"r 80 print"betraegt";o 90 input"[2 DOWN]Noch eine Berechnung (J/N)";a$ 100 if a$="j"then run 110 end
Zeile 50 kennen wir ja noch von unseren Versuchen im
Direktmodus. Mit ihr können wir die Berechnung unseres Zylinders durchführen, und das allgemeingültig, denn wir können für Radius ( r) und Höhe ( h) beliebige
Werte angeben. Diese müssen halt nur vorher festgelegt werden. Wie Sie sich erinnern, hatten wir dies
in den Zeilen 30 und 40 erledigt, wo wir die zwei
INPUT-Befehle untergebracht hatten, die diese beiden
Variablen einlesen sollten. Also wird in dieser Zeile nun die eigentliche Berechnung durchgeführt, anschließend steht dann in der Variablen " o" die
Oberfläche des verlangten Zylinders. Bitte verwechseln Sie nie den Buchstaben o mit der Zahl 0 !
Die Zeilen 60-80 sind jetzt nur noch für die korrekte, beziehungsweise formatierte Ausgabe des Ergebnisses der Rechnung verantwortlich. Damit das alles
ein weing besser aussieht ( denn darauf sollte man als
Programmierer ebenfalls achten, daß die Nachrichten, die ein solches Programm ausgibt auch leichtverständlich und ansprechend lebendig sind), habe ich das
Ergebnis in einen kleinen Satz eingebunden. Zunächst
wird einmal Platz geschaffen, indem die Textausgabe 2 Zeilen tiefer geschoben wird ( das Steuerzeichen DOWN
dürften Sie ja noch aus der letzten Ausgabe kennen), jetzt haben wir das ganze schön abgesetzt von den
anderen Buchstaben auf dem Bildschirm plaziert. Nun
druckt Zeile 60 den Text " Die Oberflaeche eines Zylinders mit" aus. In der nächsten Zeile geht es dann
weiter mit " der Hoehe" und nun sehen Sie nach den
Anführungsstrichen den Buchstaben " h" eingefügt. Da
sich dieser außerhalb der " Gänsefüßchen" befindet, wird er auch nicht als Text, sondern, wie wir es bei vorherigen PRINT-Anweisungen ja schon gesehen haben, als Variablenname interpretiert. Deshalb wird jetzt
nicht ein " h" ausgedrucht sondern ganz einfach der
Wert der Variablen h. Ebenso geht es dann bei dem
anschliessenden Text, der direkt nach unserer Variablen wieder in Anführungszeichen folgt. Auch hier
wird am Ende dann der Wert der Variablen " r" ausgedruckt.
Interessant wird es dann wieder in Zeile 80, hier ist
eine weitere Funktion des PRINT-Befehls enthalten, die Ihnen vielleicht aufgefallen ist:
Nach dem Text " betraegt" folgt ein Semikolon ( oder
Strichpunkt) wie bei INPUT und anschließend der
Name der Variablen, die hier folgen soll (" o") . Ich
muß gleich zugeben, daß der Strichpunkt an dieser
Stelle eigentlich total überflüssig ist und daß man
ihn auch genausogut weglassen könnte, nur paßt er
gerade gut in den Stoff, weshalb ich Ihnen seine
Funktion nicht vorenthalten möchte.
Wie Ihnen vielleicht aufgefallen ist, arbeitet jeder
PRINT-Befehl so, daß er nachdem er einen Text ausgegeben hat in eine neue Zeile springt, wo der nächste
PRINT-Befehl dann wieder seine Arbeit fortseten kann.
Ersichtlich wird das in folgendem kleinen Programm:
10 PRINT"DAS IST IN EINER " 20 PRINT"ZEILE !!!"
Starten Sie es, so sehen Sie folgendes auf dem Bildschirm :
DAS IST IN EINER ZEILE !!!
Was zum ausgegebenen Text wohl total im Gegensatz
steht. Doch PRINT hat hier genau das getan, was er
sollte. Nach Zeile 10 hat er den Cursor an den Anfang
der nächsten Zeile gesetzt und dann den Text aus Zeile 20 ausgedruckt ( durch einen erneuten PRINT-Aufruf) .
Doch was hat das alles mit unserem Semikolon zu tun ?
Nun, das Semikolon am Ende eines PRINT-Befehls bewirkt, daß das eben beschriebene Springen in die
nächste Zeile unterdrückt wird. Ändern Sie doch einmal unser Programm folgendermaßen ab:
10 PRINT"DAS IST IN EINER "; 20 PRINT"ZEILE !!!"
Starten Sie es jetzt so sehen Sie:
DAS IST IN EINER ZEILE !!!
Womit diesmal tatsächlich alles " in einer Zeile ist" .
In unserem Zylinderberechnungsprogramm hat das eigentlich keinen Zweck, denn das, was nach dem Semikolon ausgedruckt wird, würde sowieso schon direkt folgen, da das Drucken der Variablen " o" ja noch zum
selben PRINT-Befehl gehört. Doch wäre durchaus auch
so etwas denkbar:
80 PRINT "betraegt"; 85 PRINT o
Würden Sie diese beiden Zeilen in unser Programm
einfügen, so kämen Sie ebenfalls zum selben Ergebnis.
Nun weiter in den folgenden Zeilen, von 90-110 . Hier
gibt es nämlich wieder etwas neues zu lernen: der
IF-THEN- Befehl. Ich liste Ihnen diese Zeilen hier
noch einmal auf, damit Sie sich das ein wenig genauer
ansehen können:
90 input"[2 DOWN]Noch eine Berechnung (J/N)";a$ 100 if a$="j"then run 110 end
Zunächst einmal Zeile 90 . Hier fragen wir, nachdem
wir die Augabe um 2 Zeilen nach unten geschoben haben, um dem ganzen einen besseren Eindruck zu verleihen zunächst einmal, ob der Benutzer noch eine weitere Zylinderberechnung verlangt. Das heißt, ob er den
Rechenvorgang eventuell wiederholen möchte oder
nicht.
Hier kann er, wie vom Text vorgeschlagen, mit J für
JA, oder mit N für NEIN antworten. Die Antwort, zu
der er sich entscheidet, wird dann in der String-Variablen " a$" abgespeichert.
Nun das neue: in Zeile 100 sehen wir die sogenannte
IF-THEN- Klammer. Übersetzen wir doch erst eimal wieder aus dem Englischen : WENN-DANN. Wie Sie vielleicht erraten, ist dieser Befehl dazu gedacht bestimmte Abrfragen auf ihren Wahrheitsgehalt zu prüfen, um anschliessend entsprechend im Programm zu
verzweigen. Ich kann gleich anmerken, daß dies wohl
einer der wichtigsten Befehle für Programme ist, da
Sie ohne ihn kaum komplexere Dinge schreiben könnten, als unsere einfache Zylinderberechnung. Hier benutze
ich ihn eigentlich nur, um das Programm ein klein
wenig komfortabler zu machen, und um außerdem diesen
äußerst wichtigen Befehl einzuführen. Was geschieht
nun in Zeile 100 ?
Ganz einfach :
1 .) Der IF-Befehl prüft, ob die ihm folgende Bedingung erfüllt ist, das heißt, ob in der Variablen
" a$" der Buchstabe " j" enthalten ist.
2 .) Sollte diese Bedingung " wahr" sein, so wird der
Computer ganau das ausführen, was hinter dem
THEN-Wort folgt. In unserem Fall würde er den
RUN-Befehl aufrufen, der unser kleines Programm
wieder von vorne ablaufen lassen würde. Aber
jetzt kommt der Clou:
3 .) Sollte die Bedingungen " unwahr" sein, oder ganz
einfach " falsch", dann wird der Teil hinter THEN
ignoriert und einfach in der Zeile hinter der
IF-THEN- Klammer weitergemacht. In unserem Fall
steht hier der Basic-Befehl END, den wir noch
nicht kennen, den ich Ihnen später jedoch genauer
erläutern werde. Erst einmal zu IF-THEN :
Sie sehen also, hier wurde ganz einwandfrei eine Entscheidung vom Computer getroffen. Aufgrund einer Eingabe des Benutzers wurde eine bestimmte Reaktion veranlasst. Wenn Sie " j" eingaben, dann startete das
Programm wieder von vorne, wie es ja auch sein sollte, wenn man " noch eine Berechnung" wünscht, andern- falls wurde das Programm beENDet ( nichts anderes tut
der END-Befehl, doch ist trotzdem noch mehr zu ihm zu
sagen) .
Um den IF-THEN- Befehl ( es ist nur ein Befehl, da
die beiden Teilworte alleine keinen Sinn ergeben und
vom Computer auch mit einem ERROR quittiert werden) zu benutzen brauchen wir also zum einen eine Bedingung, nach der unterschieden werden soll und zum anderen einen oder mehrere Befehle, die beim Zutreffen
der gestellten Bedingung ausgeführt werden sollen.
Als Bedingungen können Sie hier mit allen Variablen
" spielen" die unser Computer kennt, oder Sie können
auch einfach nur Argumente angeben, wobei dies nicht
unbedingt sinnvoll ist, da eine folgende Bedingung ja
immer wahr wäre, und man somit sich die Abfrage sparen könnte:
IF 3=3 THEN PRINT"3 ist gleich 3 ."
Dies allerdings nur einmal als kleines Beispiel, damit Sie auch verstehen, was mit " Bedingung" gemeint
ist. Weitaus sinnvoller als Abfrage wäre schon eher
so etwas:
IF A= B THEN PRINT" A und B sind gleich."
Hier könnten die beiden Variablen tatsächlich einmal
verschieden von einander und einmal gleich sein.
Bei den Bedingungen, die Sie angeben können, müssen
Sie, wie Ihnen vielleicht aufgefallen ist, immer einen sogenannten " Vergleichsoperator" angeben. Dies
ist ein Operator, mit dem wir dem Computer klar machen, in welcher Weise nun verglichen werden soll, denn man kann die einzelnen Vergleichsargumente auch
relativ aufeinander beziehen. So wären zum Beispiel
die folgenden Ausdrücke vollkommen identisch :
IF A>B THEN PRINT"A ist groesser B." IF B<A THEN PRINT"A ist groesser B."
Zumal ja automatisch mit der Bedingung, daß " A" kleiner als " B" ist, auch gesagt ist, daß " B" größer als" A" ist. Hier werden natürlich die Variablenwerte
verglichen. Wie wir ja gelernt haben müßte das bei
Strings ja dann in Gänsefüßchen stehen. Sie können
übrigens problemlos auch ganze Wörter vergleichen:
IF a$="BASIC" THEN PRINT "BASIC find ich auch super!"
Doch nun wieder zu den Vergleichsoperatoren. Hier
können Sie mehrere Arten verwenden, die ich Ihnen
hier einmal auflisten möchte:
a=b A gleich B a<>b A ungleich B (entweder größer oder kleiner) a>b A größer B a<b A kleiner B a>=b A größer oder gleich B a<=b A kleiner oder gleich B
Zu den beiden letzten Punkten sei noch zu sagen, daß
sie ebenso auch folgendermaßen lauten könnten :
a=>b A gleich oder größer B a=<b A gleich oder kleiner B
Hierbei bewirken beide Schreibarten dasselbe.
Es gibt übrigens noch 3 weitere Vergleichsoperatoren, die wir aber hier vorläufig übergehen wollen, da zu
deren Verständnis weitere Grundkenntnisse vorausgesetzt sein müssen. Nun noch zu END:
Wie bereits erwähnt sorgt dieser Befehl dafür, daß
ein Basicprogramm beENDet wird. Der Computer bricht
an dieser Stelle ganz einfach ab und meldet sich im
Direktmodus mit " READY." wieder zurück. Auch dieser
Befehl ist an der Stelle im Programm eigentlich ganz
überflüssig, denn sollte Ihr C64 irgendwann einmal am
Ende eines Listings, also in der letzten Zeile des
Programms, daß er zu diesem Zeitpunkt gerade abarbeitet angelangt sein, so wird er es sowieso beenden und
in den Direktmodus zurückspringen. Ich habe diesen
Befehl eigentlich auch nur deshalb benutzt, weil ich
ihn Ihnen halt vorstellen wollte. Ich hätte Ihn besser anders benutzt, dann wäre er sinnvoller gewesen.
Sie können ja die Zeilen 100 und 110 unseres Programms einmal folgendermaßen abändern:
100 IF a$="n" THEN END 110 RUN
Dies hat den selben Effekt, nur daß Sie nun den Sinn
des END-Befehls sehen. Hier ist es unbedingt nötig
das Programm abzubrechen, und da es dies nicht von
selbst tut, da es ja noch eine Zeile hat die es
ausführen könnte, müssen wir dieses Beenden sozusagen
" künstlich" erzwingen. . .
Wie Ihnen womöglich auffiel, hatte ich vorhin übrigens von mehreren Befehlen ( also Plural) gesprochen, die nach dem THEN ausgeführt werden können.
Doch wie? Hierzu kennt BASIC das Befehlstrennzeichen
" :" . Ja, ein ganz schlichter Doppelpunkt, mit ihm
können Sie dann 2 Befehle in einer Zeile voneinander
trennen, ohne einen SYNTAX ERROR zu erhalten, bei
IF-THEN sähe das so aus :
IF a$=" n" THEN PRINT" Tschuess dann, bis zum naechsten
Mal. . ." : END
Sie sehen, hier haben wir zunächst einen PRINTund
dann den END-Befehl, beide getrennt durch einen Doppelpunkt. Diesen Trick können Sie auch so in einer
normalen Zeile ( also in einer solchen, in der KEIN
IF-THEN steht) anwenden. Etwa so:
10 PRINT" Das ist eine Endlosschleife mit viel Gedrukke! ! !" ; : GOTO 10
Probieren Sie es, nun haben wir unsere Endlosschleife
vom letzten Mal in nur EINE Zeile gepackt, und sie
funktioniert genauso zuverlässig. Wie man sie jetzt
auch wieder " endlich" macht wissen Sie ja mittlerweile - einfach RUN/ STOP drücken.
Die einzige Grenze für Zeilen mit Doppelpunkten
stellt die maximale Länge einer BASIC-Programm- Zeile
dar. Grundsätzlich darf eine Programmzeile nämlich
nie mehr als 80 Zeichen lang sein ( also 2 Bildschirmzeilen) . Dies ist eine computerinterne Regel, die
etwas mit der Art und Weise zu tun hat, mit der eine
Zeile im Speicher des Computers abgespeichert wird.
Alles, was Sie mehr eingeben, wird radikal vom Compu- ter abgeschnitten, er akzeptiert also nur maximal 80 Zeichen.
Ich kann Ihnen übrigens gleich verraten, daß der Doppelpunkt auch seine Nachteile hat.
Vorteilhaft ist, daß der Computer Programme mit vielen Doppelpunkten, wo die einzelnen Befehle also in
lange Zeilen zusammengefasst sind, grundsätzlich
schneller abarbeitet, als die gleiche Befehlsfolge in
mehreren Zeilen. Dies hat ebenfalls etwas mit internen Vorgängen zu tun, nämlich ganz einfach damit, daß
der Computer einen Doppelpunkt schneller erkennt, als
eine neue Programmzeile, beziehungsweise ist er gezwungen, beim Abarbeiten einer jeden neuen Zeile ein
paar Arbeitsvorgänge mehr ablaufen zu lassen. Deshalb
also ein ( ganz, ganz) geringer Zeitgewinn bei der Benutzung des Doppelpunkts.
Ebenso vorteilhaft ist auch, daß durch die Benutzung
des Doppelpunkts Speicherplatz gespart wird. Die
Speicherung einer neuen Programmzeile kostet mehr
Platz im Hauptspeicher des C64 als ein einzelner Doppelpunkt.
Doch nun der große Nachteil, weshalb ich Ihnen auch
sehr von der Benutzung des Doppelpunkts außerhalb von
IF-THEN- Klammern abrate. Dadurch, daß alles so durcheinander über 2 Bildschirmzeilen verteilt steht, entsteht ein wahres Chaos auf dem Bildschirm, wenn
Sie Ihr Programm einmal listen sollten. Es wird durch
den Doppelpunkt sehr, sehr unübersichtlich, was eine
Tücke von BASIC ist, die einem als Anfänger häufig
Schwierigkeiten macht. Ich empfehle Ihnen also, den
Doppelpunkt nur dann zu benutzen, wenn nicht sehr
viel Unheil durch ihn im Gesamtbild des Listings auf
dem Bildschirm entsteht ( also nur, wenn alle durch
ihn getrennten Befehle noch in EINE Bildschirmzeile - das sind 40 Zeichen - passen) . Und in IF-THEN- Klammern, wo es manchmal unerläßlich ist, mehrere Befehle auszuführen, bevor BASIC dann in der IF-THEN
folgendenden Zeile mit seiner Arbeit fortfährt.
Hier gibt es übrigens auch eine Alternative mit der
Sie auch bei IF-THEN keine Probleme bekommen sollten, was die Formatierung des Programmtextes angeht, denn
nichtsdestotrotz wird eine " Doppelpunkt-IF- THEN-Zeile" ebenso unübersichtlich wie eine normale 80- Zeichen-Zeile. Hierbei hilft uns eine kleine Eigenart des THEN-Befehls. Sie könnten nämlich eine längere
Befehlsfolge ebensogut auch in mehreren Zeilen unterbringen, die Sie, von ihren Zahlennummern her gesehen, ein wenig vom Hauptprogramm absetzen, und diese
dann mit ihrer Zeilennummer DIREKT anspringen. Denkbar wäre folgendes :
10 INPUT"[CLR]WOLLEN SIE TEXT SEHEN (J/N) ";a$ 20 IF a$="J" THEN 200 30 PRINT"DANN NICHT...":END 40 : 200 PRINT"DAS IST IHR GEWUENSCHTER TEXT..." 210 PRINT"UND HIER NOCH EINE KLEINE ZUGABE AN" 220 PRINT"TEXT, DAMIT SIE SICH NICHT VERAEPPELT" 230 PRINT"FUEHLEN, UND DAMIT HIER AUCH NOCH MEHR" 240 PRINT"ZEILEN GEFUELLT WERDEN."
Zuerst haben wir in Zeile 10 die Abfrage, ob die Einsicht vom Benutzer in den Text überhaupt erwünscht
ist. Die Antwort, wieder ein J oder ein N, wird in
der Variablen a$ gespeichert. Dann folgt eine IF-THEN- Abfrage, ob die Anwort ein " J" war. Wenn nicht, dann wird der Text " DANN NICHT. . ." ausgedruckt und
das Programm wird beendet.
Sollte die Antwort allerdings tatsächlich " J" gewesen
sein, traf unsere Bedingung also zu, so springt der
Computer gleich weiter zu Zeile 200, wo er dann den
gewünschten Text ausdruckt, der hier getrennt in 5 eigenen Zeilen abgelegt wurde. Bestimmt ist Ihnen
aufgefallen, daß merkwürdigerweise nur die Zeilennummer unserer gewünschten Zeile hinter dem THEN folgt.
Dies ist eben jene Eigenart des THEN-Befehls, von der
ich eben sprach. Er interpretiert Zahlen, die direkt
nach ihm folgen grundsätzlich immer als eine Zeilennummer, auf die er springen soll. Er führt sozusagen
den Befehl GOTO 200( oder GOTO xxxx) aus. Ändern Sie
Zeile 20 doch einmal folgendermaßen um:
20 IF a$=" J" THEN GOTO 200
Sie werden feststellen, daß Sie hiermit genau dasselbe erreichen wie vorher, allerdings mit dem Unterschied, daß diese Zeile langsamer abgearbeitet wird, da der GOTO-Befehl ja noch erkannt werden muß, und
daß sie außerdem auch noch mehr Speicherplatz verbraucht. Die Kurzschreibweise ist also nur von Vorteil und sollte eigentlich immer verwandt werden.
Auf diese Weise können Sie übrigens auch Programmzeilen überspringen, etwa so:
10 INPUT"[CLR]WUENSCHEN SIE TEXT (J/N) ";a$ 20 IF a$="N" THEN 40 30 PRINT"HIER IST TEXT FUER SIE..." 35 END 40 PRINT"NIX TEXT!"
Die ersten 2 Zeilen sind ja mittlerweile ein " alter
Hut" für uns. In Zeile 20 sehen Sie, daß bei der Antwort " N" ganz einfach der Teil, der bei " J" gekommen
wäre ( bzw. auch bei jedem anderen Zeichen, das ungleich " N" gewesen wäre, wie auch in den Beispielen
zuvor, ich hatte es dort allerdings nie erwähnt, die
Zeilen 30 und 35 ausgeführt werden. Sie können es
gerne einmal ausprobieren und mit " Y" oder " Z" antworten. . .) übersprungen wird. Wenn nicht, dann wird
der folgende Teil ausgeführt. Von hier können Sie
entweder gleich mit END aufhören, oder Sie springen
dann von dort wieder mit GOTO hinter die Zeilen, die
bei " N" ausgeführt worden wären. Dies sähe dann so
aus:
10 INPUT"[CLR]WUENSCHEN SIE TEXT (J/N) ";a$ 20 IF a$="N" THEN 40 30 PRINT"HIER IST TEXT FUER SIE..." 35 GOTO 50 40 PRINT"NIX TEXT!" 50 END
Ich hoffe Ihnen nun klar und deutlichst die Benutzung
und vor allen Dingen den Sinn von IF-THEN dargelegt
zu haben und möchte mich nun einmal der übersichtlichen Programmierung zuwenden. In diesem Zusammenhang
wollen wir dann auch noch 2 neue Befehle kennenlernen.
Doch zunächst möchte ich schnell noch etwas nachholen. Ich habe nämlich - ich muß es gestehen - einen
äußerst wichtigen Befehl vergessen, als ich Ihnen
letzten Monat erläuterte, wie man Programme
schreibt: den NEW-Befehl.
Dieser Befehl braucht keinerlei Parameter, und ist
daher auch ganz schnell und einfach abgehandelt. Er
dient dazu, ein Programm aus dem Programmspeicher Ihres C64 wieder zu löschen. Dies ist insofern wichtig, da Sie ab jetzt wohl häufiger Programme schreiben werden, und Sie diese nun ganz einfach mit NEW
wieder löschen können, falls Sie ein neues eingeben
möchten, und nicht mehr immer gleich den ganzen Computer ausschalten müssen, beziehungsweise alle vorkommenden Zeilennummern eines Programms einzeln eintippen müssen, um diesen Effekt zu erzielen.
Außer den gesamten Programmspeicher zu löschen, löscht NEW auch alle sich zu diesem Zeitpunkt sich im
Speicher befindlichen Variablen! Wundern Sie sich
also nicht, wenn manche vorher von Ihnen definierte
Variablen plötzlich leer sind.
Den gleichen Effekt, nämlich daß alle Variablen im
Speicher gelöscht werden können Sie ebenso mit dem
Befehl CLR ( für CLEAR = löschen) erzielen. Mit dem
einzigen Unterschied zu NEW, daß Ihr geschriebenes
Programm noch im Speicher steht, die Variablen allerdings gelöscht sind. Dieser Befehl wird eigentlich
kaum benutzt, allerdings ist es gut, ihn zu kennen, da es auch hier und da mal Gelegenheiten geben wird, wo er ganz angebracht ist. Sie werden schon sehen. . .
Dies also zu NEW und CLR, die übrigens beide keine
Parameter brauchen - leider, da es manchmal ganz angebracht wäre, wenn man einfach nur einen bestimmten
Bereich eines Programms löschen könnte, doch leider
ist dies nicht möglich und wirklich nur so zu realisieren, indem man halt sämtliche Zeilennummern dieses
Bereichs durch einzelnes Eintippen löscht.
Wenden wir uns nun einmal dem übersichtlichen, der
formatierten Programmierung zu, wie ich es weiter
oben schon angekündigt hatte.
Vielleicht haben Sie sich unser kleines Textausgabeprogramm von vorhin einmal genauer angeschaut und
sicher sind Ihnen daran auch mindestens eine Sache, wenn nicht sogar 2, aufgefallen. Wie? Nein? Na dann
schauen Sie doch einfach nochmal rein:
10 INPUT"[CLR]WOLLEN SIE TEXT SEHEN (J/N) ";a$ 20 IF a$="J" THEN 200 30 PRINT"DANN NICHT...":END 40 : 200 PRINT"DAS IST IHR GEWUENSCHTER TEXT..." 210 PRINT"UND HIER NOCH EINE KLEINE ZUGABE AN" 220 PRINT"TEXT, DAMIT SIE SICH NICHT VERAEPPELT" 230 PRINT"FUEHLEN, UND DAMIT HIER AUCH NOCH MEHR" 240 PRINT"ZEILEN GEFUELLT WERDEN."
Na? Klingelt es bei Ihnen? Genau - die eine Sache
liegt ja wohl auf der Hand. Zeile 40 ist ja wohl total überflüssig! Nicht nur, daß sie niemals abgearbeitet wird, da das Programm ja vorher in Zeile 40 schon mit END beendet wurde, sie ist außerdem auch
von ihrem Aussehen etwas merkwürdig, zumal KEINE Anweisungen in ihr vorkommen, und sie einfach nur aus
einem Doppelpunkt besteht. Warum also überhaupt eine
solche Zeile? Na wie Sie sich schon denken können, da es hier ja um die Formatierung des Programmtextes
geht, hat das ganze etwas mit eben jenem zu tun.
Ich habe diese Zeile ganz einfach deshalb eingefügt, um die vorherige Abfrage und den anschließenden Text
ein wenig voneinander abzusetzen. Damit man, sollte
man sich dieses Listing zu einem späteren Zeitpunkt
nocheinmal ansehen, sofort erkennt, daß die beiden
Programmteile verschiedene Aufgaben haben und nicht
zusammengehören und hintereinander abgearbeitet werden. Zugegeben - bei einem solch kleinen Programm wie
diesem hätte ich diese Feststellung wahrscheinlich
auch so noch hingekriegt, doch stellen Sie sich einmal vor, Sie hätten ein etwas längeres Listing vor
sich mit ca.10000 Zeilen ( natürlich in 10 er Schritten gerechnet)- Sie müssen zugeben, daß es hier
nicht mehr ganz so einfach wäre das Ganze zu überschauen.
Benutzen Sie also, um einzelne Programmteile, sogenannte Module, optisch voneinander abzusetzen immer
eine oder mehr Doppelpunktzeilen, damit Sie sich später wieder in Ihrem eigenen Programm zurechtfinden.
" Wieso soll ich mich denn nicht mehr in meinem eigenen Programm zurechtfinden können, zumal ich es doch
selbst geschrieben habe?" werden Sie sich jetzt
vielleicht fragen, doch glauben Sie mir, denn ich
speche aus Erfahrung, wenn Sie nach einiger Zeit mal
wieder in ein altes Programm reinschauen, um es vielleicht zu verbessern, dann wissen Sie manchmal selbst
nicht mehr, was Sie da eigentlich bewirken wollten
und es passiert dann schnell, daß man dann einfach
die Lust verliert, an so einem Anweisungschaos weiterzuarbeiten. Das ist wohl auch eine der Hauptschwächen von BASIC, die dem Anfänger anfangs das Programmieren sehr erschwert. Also immer die einzelnen Module eines Programms gut sichtbar voneinander absetzen, das kostet zwar ein kleines bißchen Speicherplatz, aber es lohnt sich wirklich !
Übrigens: wir hatten zwar festgestellt, daß die Doppelpunktzeile 40 in unserem Programm nicht abgearbeitet wird, da dieses vorher ja mit END beendet wird, aber es sei hier auch noch gesagt, daß der Computer
sie auch ruhig hätte ausführen können - sie hätte
keine Fehlermeldung bewirkt, sondern wäre sozusagen
ganz einfach " übergangen" worden, obwohl dies nicht der richtige Ausdruck hierfür ist. Sie wird nämlich wie eine normale Programmzeile behandelt.
Der Grund, warum nichts passiert, wenn der Computer
eine solche Zeile durchläuft ist ganz einfach der, daß der Doppelpunkt, wie wir ja gelernt haben, als
Trennzeichen zweier Befehle dient. In unserer Zeile
trennt er ganz einfach den " Befehl" NICHTS von dem
" Befehl" NICHTS, wird also als gültiges Trennzeichen
erkannt; daß diesem gar kein Befehl folgt, steht auf
einem anderen Blatt. Der Computer " übersieht" das
sozusagen. Er erkennt nur, daß dann die Programmzeile
endet, und daß er die nächste abzuarbeiten hat, was
er auch prompt tut. Daß wir ihm soeben eine völlig
hirnund sinnlose Zeile vorgesetzt hatten ist ihm
egal, solange er nichts an dieser auszusetzen hatte, was ja nicht der Fall war. Sie könnten also ebenso
einzelne Funktionsmodule im Programmfluß voneinander
trennen:
10 input"Bitte geben Sie einen Text ein ";a$ 20 a$="Das ist Ihr Text : "+a$ 30 : 40 PRINT 50 PRINT a$
Sie sehen, in Zeile 10 wird ein Text in die Variable
a$ eingelesen, und in Zeile 20 wird vor diesen Text
noch der Prefix " Das ist Ihr Text :" gehängt. Die
Variablenzuweisung dürfte Ihnen ja bekannt sein, hier
wird a$ ganz einfach das zugeordnet, was auf der
rechten Seite steht. Hierbei gilt natürlich noch der
alte Inhalt der Variablen a$- genau also wie bei dem
Ausdruck I= I+1 . Sie müßten das noch von dem letzten
Kurs her kennen. . .
Hier sieht man übrigens auch sehr schön, wie man
Strings aneinanderhängen kann, nämlich ganz einfach, indem man sie wie Zahlen mit dem Pluszeichen addiert
( ACHTUNG! In umgekehrter Richtung, also mit Minus ist
nichts zu machen! Wie das geht kommt später. . .)
In Zeile 30 wird nun das Modul, das für die Vorbereitung des auszudruckenden Textes zuständig ist, mit
einem Doppelpunkt von einem zweiten Modul, nämlich
das, das den Text dann ausgibt, getrennt. Der Computer arbeitet also auch diese Zeile ab, sie hat allerdings keinerlei Einwirkung auf den Programmablauf
ansich, außer daß dieser vielleicht um wenige Mikrosekunden verlangsamt wird.
Vielleicht ist Ihnen in Zeile 40 auch das einsame
PRINT aufgefallen, das, ganz im Gegensatz zu unseren
PRINTs, keinen Text oder gar eine Variable hinter
sich stehen hat. Dieses PRINT, ohne Parameter also, tut nichts anderes, als den Cursor an den Anfang der
nächsten Zeile zu setzen. Hiermit haben wir also wieder ein absetzen der Ausgabe vom bisherigen Text erreicht. Genausogut hätte ich in Zeile 40 schreiben
können :
40 PRINT "[ DOWN]" ;
Also einfach einmal " Cursor runter", allerdings dürfen Sie hier das Semikolon ( ;) nicht vergessen, da
sonst 2( !) Zeilen freigelassen werden. Da PRINT ja
nach jeder Ausgabe den Cursor in die nächste Zeile
vorschiebt, und wir dies mit dem Semikolon unterbinden können. Hier sehen Sie auch warum PRINT alleine
einfach nur eine Zeile weitergeht - nachdem es den
Text ausdruckte, den es ja leider bei dieser alleinigen Anweisung nicht gibt, warum auch nichts ausgegeben wird, rückt es eine Zeile weiter. . .
Als letztes möchte ich jetzt noch den REM-Befehl
einführen. REM steht für REMark, was so viel heißt
wie " Anmerkung", womit schon wieder alles gesagt ist.
REM wird nämlich dazu benutzt, kleine Anmerkungen in
Programmen unterzubringen, die später dem Programmierer erklärend wieder Anzeigen sollen, was dieser an
bestimmten Stellen mit seinen Programmierkünsten bewirken wollte.
REM wird folgendermaßen angewandt :
10 REM DAS IST EIN KOMMENTAR
Hinter dem eigentlich Befehlswort REM folgt ganz einfach ein beliebiger Text, der Hinweise auf etwas geben kann. Hier können Sie grundsätzlich alle Zeichen
verwenden, die auf Ihrer Tastatur vorkommen, allerdings sollten Sie von den Grafikzeichen absehen, da
diese interne Probleme verursachen könnten. Im allgemeinen sollte man allerdings mit den Buchstaben und
Zahlen auskommen.
Was genau passiert jetzt bei REM im innern unseres
64 ers? Nun, sobald dieser erkannt hat, daß er hier
einen REM-Befehl vor sich hat, springt er sofort in
die nächste Programmzeile, um diese abzuarbeiten, und
ignoriert ganz einfach den Text der hinter REM kommt.
Somit kann dann natürlich auch keine Fehlermeldung
entstehen, von dem was da steht, zumal die meisten
Computersprachen mehr auf Englisch ansprechen ( wie
wir ja mittlerweile oft genug gemerkt haben) als auf
Deutsch, und somit unser C64 wohl nicht mehr als einen SYNTAX ERROR in solchen Fällen auf Lager hätte.
Versuchen Sie es doch einmal so :
10 DAS IST EIN KOMMENTAR
Sie werden sich denken können, was passiert. . .
Was jetzt noch erwähnenswert wäre, ist, daß bei REM
grundsätzlich ALLES, was in dieser Zeile noch folgt, übersprungen wird. Also auch Befehle, oder Anweisungen, die hier stehen könnten. Eine solche Zeile wäre
also ein fataler Fehler:
10 PRINT"ERST DAS.":REM AUSDRUCK 1:PRINT"DANN DAS."
Der Ausdruck, den Sie jetzt sähen, wäre folgender:
ERST DAS.
Die zweite PRINT-Anweisung, wäre übergangen worden, da grundsätzlich alles ignoriert wird, also auch die
PRINT-Anweisung, was hinter dem Befehlswort REM
steht. Dies sollten Sie sich einprägen !
Der Vorteil von REM liegt mittlerweile ja dann auch
auf der Hand. Mit diesem Befehl kann man seine Programme auf sehr einfache Art und Weise sehr übersichtlich gestalten. Natürlich gibt es auch Nachteile, nämlich wieder die selben, wie beim Doppelpunkt - REM verbraucht Speicherplatz und verlangsamt das Programm um wenige Mikrosekunden, doch ist es immer besser ein gut formatiertes Listing zu haben, als einen
Haufen Spaghetti-Code durch den man selbst nicht mehr
durchsteigt. Wen es wurmt, daß sein Programm dadurch
langsamer und Speicherintensiver wird, der kann ja, nachdem er eine Kopie von der kommentierten Version
angefertigt hat, die überflüssigen Zeilen löschen und
es in dieser endgültigen Version dann benutzen, so
hat man dann immer noch eine kommentierte Kopie, an
der man leicht wieder kleine Veränderungen machen
kann.
Hiermit möchte ich dann wieder schließen und mich bis April von Ihnen verabschieden, wo wir uns dann
noch zwei wichtige Befehle zur formatierten Programmierung ansehen werden, und anschließend endlich
die schon letzten Monat versprochenen Schleifen anschauen werden. Bis dahin Servus,
Ihr Uli Basters
BASIC-Kurs: "Von Adam und Eva..." (Teil 4)
Hiermit möchte ich Sie zum vierten Teil unseres Basickurses herzlichst begrüßen. Diesen Monat werden
wir uns noch ein wenig mit der formatierten Programmierung befassen und werden uns anschließend endlich
den lang versprochenen Schleifenbefehlen zuwenden.
Letzten Monat hatten Sie ja gelernt, wie man, mit
Hilfe von REM und sogenannten " Doppelpunktzeilen" ein
wenig Ordnung in einen Programmtext bringt. Eine
richtige " Programmierung" war das ja noch nicht, zumal die von uns eingefügten Zeilen und Kommentare ja
nichts mit dem eigentlichen Programmablauf zu tun
hatten, und wir sie genausogut auch hätten weglassen
können, wie ich zum Schluß andeutete.
Deshalb kommen wir heute zum GOSUB-Befehl, der in
zusammenhang mit dem RETURN-Befehl uns ungeheuerliche
Weiten zur platzsparenden, einfachen und formatierten
Programmierung öffnet.
GOSUB steht für GO to SUBroutine, was soviel heißt, wie GEHE zu UNTERprogramm, und ist in etwa vergleichbar mit GOTO. Hinter GOSUB wird ebenfalls eine Zeilennummer angegeben, zu der der Computer springen
soll. Bis hierhin tut GOSUB genau dasselbe, was auch
GOTO tut, nämlich ganz einfach zu einer bestimmten
Zeile im Programm springen. Die Programmzeilen, die
dort stehen und folgen werden ganz normal abgearbeitet. Doch nun kommt der Clou: nachdem diese Zeilen
abgearbeitet wurden, können Sie mit dem RETURN-Befehl
wieder an die Stelle im Programm zurückspringen, von
wo der GOSUB-Befehl in das Untersprogramm ( so nennt
sich das nämlich) eingesprungen ist. Dies hat den
Vorteil, daß Sie beliebige Programmsequenzen, die Sie
innerhalb eines Programms benötigen, beliebig oft
benutzen können, aber nur EINMAL schreiben müssen.
Der Computer merkt sich jedesmal die Stelle, von welcher Sie in das Unterprogramm eingesprungen sind, und
wird jedesmal auch wieder dorthin zurückkehren. In
der Praxis sieht das so aus:
5 REM ***************** 6 REM * hauptprogramm * 7 REM ***************** 8 : 10 GOSUB 200 20 PRINT"Hallo Leute..." 30 GOSUB 200 40 PRINT"Unn weils so schön war, grad nochmal..."; 50 GOSUB 200 60 END 90 : 195 REM ************ 196 REM * demotext * 197 REM ************ 198 : 200 PRINT 205 PRINT"Das ist ein Text, der hier zur Demon-" 210 PRINT"stration insgesamt 3 Mal ausgedruckt" 220 PRINT"wird." 230 PRINT 240 RETURN
Genau so sollte ein gut formatiertes Programm übrigens aussehen. Vor jedem Modul (= Programmabschnitt, das hatten wir letzten Monat ja schon einmal. . .) steht ein unübersehbarer Kommentar. Zuerst haben wir
das " HAUPTPROGAMM" . Der Programmteil also, der am
Anfang auch mit RUN gestartet wird, und der alle
benötigten Unterprogramme, so wie zum Beispiel das
Programm " DEMOTEXT", zu dem Zeitpunkt aufruft, zu dem
sie benötigt werden.
Schauen wir uns doch einmal unser Programm ein wenig
näher an. Gleich am Anfang, in Zeile 10, wird unser
kleines Unterprogramm schon beansprucht und aufgerufen. Dann wird in Zeile 20 der Text " Hallo Leute. . ." ausgegeben. Anschließend kommt wieder das Unterprogramm dran. Dann kommt etwas aus dem Hauptprogramm, nämlich der Text " Unn weils so schoen war, grad nochmal. . ." . Schließlich und endlich wird DEMOTEXT noch
ein letztes Mal aufgerufen und das Hauptprogramm mit
END beendet. Der Ausdruck, den Sie somit erhalten, sieht im Endeffekt dann so aus:
Das ist ein Text, der hier zur Demon- stration insgesamt 3 Mal ausgedruckt wird.
Hallo Leute. . .
Das ist ein Text, der hier zur Demon- stration insgesamt 3 Mal ausgedruckt wird.
Unn weils so schoen war, grad nochmal. . .
Das ist ein Text, der hier zur Demon- stration insgesamt 3 Mal ausgedruckt wird.
Sie sehen, obwohl Sie den Text, der hier, wie so oft
angezeigt," insgesamt 3 Mal ausgedruckt wird", nur
einmal eingegeben haben, erscheint er tatsächlich
drei Mal auf dem Bildschirm. Sie haben sich also ersteinmal ein wenig Tipparbeit gespart, und dann auch
noch Speicherplatz, da drei mal mehr Platz verbraucht worden wäre, hätten Sie jedesmal unseren Text nochmal
eingegeben. Außerdem sieht unser Programm so jetzt
schön sauber und ordentlich aus - Unterprogramm schön
vom Hauptprogramm getrennt. . .
Und es gibt da noch einen kleinen Vorteil: angenommen, Sie sind gerade dabei ein Programm zu schreiben, zu dem Sie ein bestimmtes Unterprogramm benötigen, das eine ganz bestimmte Aufgabe erfüllen soll. Welche
Aufgabe im Einzelnen, sei jetzt einmal dahingestellt.
Dieses Unterprogramm haben Sie vor längerer Zeit allerdings schon einmal in einem anderen Programm benutzt, und haben es dort noch voll funktionsfähig
drin stehen. Das einzigste, was Sie jetzt zu tun haben, ist das Unterprogramm aus Ihrem alten Programm
herauszuisolieren, und es dann in Ihr neues einzubinden. Also ein weiterer Vorteil von Unterprogrammen, da Sie sie jederzeit wiederverwenden können, können
Sie sich Ihre Programme sozusagen aus vielen kleinen
Modulen ( also Unterprogrammen)" zusammenbauen", wie
als wenn Sie mit Bauklötzen einen Turm konstruieren
würden.
Ich muß Ihnen allerdings gestehen, daß dies gar nicht
so einfach ist, wie es sich anhört, da man beim BA-SIC V2 .0 des C64 nicht so einfach riesige Programmabschnitte löschen kann, geschweige denn, daß man einzelne Module so einfach aneinander hängen könnte.
Doch nicht verzagen, in einer der nächsten Ausgaben, wird wahrscheinlich ein kleines Hilfsprogramm hierzu
erscheinen, daß diese Aufgaben bewältigen wird.
Wie oben schon erwähnt, kann man GOSUB auch zum " herumspringen" genauso wie GOTO verwenden, doch möchte
ich Ihnen DRINGENDST davon abraten. Denn wie ebenfalls schon gesagt, merkt sich der GOSUB-Befehl ( im
Gegensatz zu GOTO) eben jene Stelle, von wo aus er in
ein Unterprogramm eingesprungen ist. Da der Computer
allerdings nur einen begrenzten Speicherplatz für
solche Rücksprünge bereithält, kann es Ihnen somit
passieren, daß Ihr Programm irgendwann aus Speichermangel einen Fehler ausspuckt. Benutzen Sie also immer GOTO, wenn Sie " nur" springen möchten. Dies ist
auch ein kleiner Hinweis für Sie, falls Sie mal ein
Programm haben sollten, das nicht so laufen sollte, wie Sie es wünschen. Eine häufige Fehlerquelle ist nämlich auch die Tatsache, daß vergessen wurde, das
Unterprogramm mit RETURN abzuschließen. Sollte nämlich jetzt zufällig wieder der Programmteil folgen, von dem aus das Unterprogramm aufgerufen wurde, dann
wiederholt sich dieser Aufruf solange, bis der Computer abbrechen muß, da sein Merkspeicher " überläuft"( so nennt man das, wenn bei einer internen Operation
der Computer über die Speichergrenze hinaus einen
Zugriff machen muß) . Das soll jetzt natürlich NICHT
heißen, daß Sie ein Unterprogramm nicht wiederum von
einem weiteren Unterprogramm aus aufrufen könnten.
Natürlich geht das, Sie müssen nur jedes Unterprogramm immer wieder ornungsgemäß mit dem RETURN-Befehl
abschließen, um keinen Ärger zu bekommen. Theoretisch
könnten Sie sogar 24 Unterprogramme untereinander
verschachteln, doch werden Sie diese Grenze wohl nie
erreichen. . .
Wollen wir uns nun endlich den Scheifenbefehlen zuwenden. Zuerst einmal, was ist eine Schleife? Wie
Sie sich vielleicht erinnern, hatten wir, beim Abhandeln des GOTO-Befehls eine sogenannte " Endlosschleife" geschrieben. Deshalb Endloschleife, weil ein ganz bestimmter Programmteil immer und immer wieder abgearbeitet wurde, so, daß das Programm endlos lange
weitergelaufen wäre, hätten wir es nicht mit RUN/ STOP
angehalten. Hier nochmals ein solches Programm:
10 PRINT" Das ist eine Endlosschleife. . ." ;
20 GOTO 10
Hier wird der Text " Das ist eine Endlosschleife. . ." also immer wieder ausgegeben, da in Zeile 20 ja immer
wieder zu Zeile 10 verzweigt wird, womit sich unser
Programm also immer wieder selbst aufruft. Klarer
wird es, wenn Sie Zeile 20 wie folgt abändern:
10 PRINT" Das ist eine Endlosschleife. . ." ;
20 RUN
Jetzt startet sich das Programm also immer wieder
selbst, ohne daß es jemals zu einem Ende kommen würde.
Sie müssen allerdings zugeben, daß solche Endlosschleifen, so wie sie hier dargestellt sind zumindest, wenig Sinn ergeben. Es wäre doch viel besser, wenn man eine solche Schleife unter Kontrolle hätte, und sie endlich machen könnte, so also, daß sie nach
eine bestimmten Anzahl von Durchläufen beendet wird.
Zum Einen könnte man das, wenn wir uns auf unser bisheriges Wissen stützen, sehr gut mit der IF-THEN- Klammer lösen. Nämlich so:
5 i=0 10 i=i+1 20 PRINT"DAS IST EIN TEXT" 30 IF i<>5 THEN 10 40 END
Zuerst wird in Zeile 5 die Variable I auf 0 gesetzt.
Anschließend wird diese Laufvariable ( so wollen wir
es einmal nennen), ihres Zeichens eine Floatvariable, um eins erhöht. Dann drucken wir den Text " DAS IST
EIN TEXT" aus. In Zeile 30 vergleichen wir nun, ob I
den Wert 5 enthält. Wenn nicht, dann wird wieder zu
Zeile 10 gesprungen und der Vorgang des Um-Eins-
Erhöhens und des Ausdruckens wiederholt sich. Andernfalls wird das Programm beENDet. Sie sehen, daß diese
Schleife nur 5 Mal durchlaufen werden kann, da sich
nämlich bei jedem Durchlauf die Variable I um eins
erhöht, hat sie nach 5 Durchgängen den Wert 5 tatsächlich erreicht. Also wird die Schleife abgebrochen, und es geht in Zeile 40 weiter im Programm.
Hiermit hätten wir also eine Endlichschleife geschaffen, doch dies geht auch einfacher und übersichtlicher, denn BASIC stellt uns extra zur Schleifenprogrammierung zwei Befehle zur Verfügung, FOR und NEXT, die die FOR-NEXT- Schleife bilden.
FOR-NEXT arbeitet ähnlich, wie unsere IF-THEN- Schleife. Auch hier benötigen wir eine Laufvariable, nur, daß wir hier gleich in einem Zug angeben können, von welchem Wert zu welchem Wert gezählt werden soll.
Also haben wir hier die Zeilen 5 und 30 unseres ersten Schleifenprogramms in EINEM zusammengefaßt. Sehen Sie sich doch einfach einmal dieses kleine Programm an, das die selbe Arbeit verrichtet, wie unser
letztes Programm, allerdings mit Hilfe von FOR-NEXT:
10 FOR I=1 to 5 20 PRINT"DAS IST EIN TEXT" 30 NEXT
Das war alles! Auf den ersten Blick sieht das zwar
genauso lang aus, wie unser erstes Schleifenprogramm, doch der FOR-Befehl hat noch einige Eigenarten, die
ihn zum einen komfortabler machen, und zum anderen
ÜBERSICHTLICHER, was ja außerordentlich wichtig ist, wie wir festgestellt hatten. Nicht umsonst nämlich
hatte ich ein ganzes Kapitel der formatiertien Programmierung gewidmet!
Das Übersichtliche an FOR-NEXT ist, daß der gesamte
Schleifenrumpf, der Teil also, der immer wieder abgearbeitet werden soll, durch FOR und NEXT eingegrenzt wird. Sehen wir uns nun einmal an, was im Innern unsers Computers abläuft, wenn er eine solche
Schleife abarbeitet:
In Zeile 10 erkennt der 64 er erst einmal ( an FOR), daß hier gleich eine Schleife folgt. Direkt hinter
dem FOR-Befehl wird dann die Laufvariable mit einem
Grundwert " initialisiert", das heißt, daß ein bestimmter Wert als Ausgangswert für diese Variable
festgelegt wird. Diese Initialisierung entspricht
Zeile 5 unseres ersten Programms, hier wurde die Variable ' I' auf 0 gesetzt. Daß wir sie nicht mit 1 initialisierten, wie bei FOR, liegt einfach daran, daß sie anschließend, in Zeile 10, schon auf 1 gezählt wurde. Womit sie den selben Anfangswert hat, wie in unserem zweiten Programmbeispiel.
Wie gesagt haben wir nun die untere und die obere
Grenze festgelegt, innerhalb der der Computer zählen
soll. In unserem Beispiel ist das von 1 bis 5 .
In Zeile 20 geht' s jetzt weiter mit dem Schleifenrumpf, der hier nur diese eine Zeile, mit Nummer 20, lang ist. Natürlich könnten Sie hier auch mehrere
Zeilen stehen haben, Hauptsache ist, daß Sie diese
dann auch zwischen FOR und NEXT sozusagen " einklammern" . Unser Schleifenrumpf besteht also aus der Anweisung, den Text " DAS IST EIN TEXT" auszudrucken.
In Zeile 30 nun trifft der Computer auf die NEXT-Anweisung. Jetzt zählt er die Schleifenoder Laufvariable erst einmal um 1 hoch. Entsprechend also der
Zeile 10 unseres ersten Programms:
10 I= I+1
Anschließend prüft er, ob der Inhalt dieser Variable
mittlerweile größer ist, als der obere Grenzwert, ob
dieser also schon überschritten wurde. Ist dies der
Fall, so wird die Schleife beendet und der Computer
fährt in Programm fort. Ist die Laufvariable allerdings noch kleiner oder gleich dem Grenzwert, so
wird wieder an den Befehl im Programm verzweigt, der
nach der FOR-Anweisung kommt. Dies wiederholt sich
dann halt solange, bis der Grenzwert dann endlich
überschritten wurde. Ich möchte hier auch noch darauf
aufmerksam machen, daß die Laufvariable VOR dem Vergleich hochgezählt wird. Deshalb hat Sie nach dem
Aussprung aus der Schleife immer den Inhalt des oberen Grenzwertes plus 1 ! ! ! Dies zu wissen kann äußerst wichtig sein, da hier manchmal Fehler gemacht
werden:
FOR i=0 TO 3:PRINT"TEXT":NEXT
Diese Schleife zum Beispiel wird insgesamt 4( !) mal
durchlaufen, da von 0 nach 3 gezählt wird ( also 3 Ziffern plus die Null. . .) . Nicht also, wie man
fälschlicherweise annehmen könnte, nur 3 mal!
Hier sehen Sie übrigens auch, daß man FOR und NEXT
nicht unbedingt in eigene Programmzeilen schreiben
muß, es ist nämlich auch durchaus möglich sie in EI-NER Zeile zusammenzufassen, vorrausgesetzt, der
Schleifenrumpf ist nicht zu lang.
Grundsätzlich gilt: alle Befehle, Anweisungen und
Funktionen, die zwischen FOR und NEXT stehen bilden
alle gemeinsam den Schleifenrumpf, den Teil also, der
immer wieder von der Schleife durchlaufen wird, unabhängig davon, wie die einzelnen Befehle innerhalb
von Programmzeilen verteilt sind.
Doch kann man mit FOR noch viel mehr anfangen! Angenommen Sie wollten nicht immer um 1 erhöhen, sondern
immer um 2, weil Sie, aus welchen Gründen auch immer, alle 2 er Zahlen, oder alle geraden Zahlen, benutzen
möchten. Hierzu kann man die STEP-Anweisung benutzen, die an den FOR-Befehl angehängt wird, ohne diesen sie
nicht existieren kann, sprich nicht verwendbar ist.
Geben Sie doch einfach einmal folgendes ein:
FOR I=0 to 10 STEP 2:PRINT I:NEXT
Die Ausgabe dieser Schleife sieht so aus:
0 2 4 6 8 10
Eigentlich nichts neues mehr für uns. Hier wurde ganz
einfach von 0 bis 10 gezählt, allerdings in 2 er
Schritten, wie man an der Ausgabe erkennen kann - der
Inhalt von ' i' war immer um 2 erhöht. Auch hier
galt: erst als NACH einem Hochzählen um den Zählwert
( oder die sogenannte Schrittweite) der obere Grenzwert überschritten wurde, wurde die Schleife verlassen.
Es mag sein, daß dieses Ihnen noch nicht ganz einleuchtet, deshalb also ein weiteres Beispiel. Wir
hatten bis jetzt immer von einem kleineren Wert bis
zu einem größeren gezählt. Manchmal könnte es aber
auch ganz nützlich für uns sein, rückwärts zu zählen, beispielsweise von 5 bis 0 in 1 er-Schritten, oder gar
in halben Zahlen, also in 0 .5 er-Schritten. Das ist
absolut kein Problem mit STEP. Der Wert hinter diesem
Anweisungswort muß ganz einfach negativ sein, also
mit einem Minuszeichen (-) davor. Etwa so:
FOR I=5 to 0 STEP -1:PRINT I:NEXT
Hier haben wir dann eine " Rückwärtsschleife" . Sie
zählt rückwärts von 5 bis 0 . Auch hier gilt: erst
wenn der zweite Grenzwert, diesmal ist er allerdings
kleiner als der erste, UNTERSCHRITTEN wurde, wird die
Schleife verlassen. Diesmal also erst, wenn der Inhalt der Zählvariable kleiner ist, als der Grenzwert, zu dem gezählt werden soll. Dies ist ein kleiner Unterschied, der bei Schleifen mit negativen Zählwerten
auftritt, an den man sich jedoch leicht gewöhnt, da
er im Grunde ja ganz logisch ist, oder?
Das zum Thema Schleifen. Ich hoffe, Ihnen dieses Problem verständlich dargelegt zu haben. Nun möchte ich
mich, quasi zur Entspannung, einem etwas leichteren
Themen zuwenden, sozusagen ein paar kleine Häppchen
als " Hors d' oevre" vorschicken, auf das was nächsten
Monat auf sie zu kommt. . .
Beginnen wir mit einem kleinen Rechenoperator, den
ich Ihnen bei unserer Rechnerei am Anfang dieses Kurses verschwiegen habe. Es handelt sich hierbei um den
Exponentialoperator, der durch den ' Pfeil nach oben'('↑') ausgedrückt wird. Mit ihm können Sie die nte Potenz einer Zahl berechnen. Etwa 2 hoch 8, oder 5 zum Quadrat. Geschrieben wird das so:
PRINT 2↑8 PRINT 5↑2
Sie können diesem Operator natürlich genauso benutzen, wie die anderen Operatoren auch, also ebenfalls
auch bei Variablenzuweisungen benutzen.
Sollten Sie übrigens darauf bedacht sein, Ihre Programme so zu programmieren, daß sie mit einem Minimum
an Zeit ablaufen, dann gebe ich Ihnen den Tip, Ihre
Quadrat-Potenzen ( also die Potenzen, die die 2 als
Exponenten, oder als ' Hochzahl' haben) mit dem Multiplikationsoperator '*' auszudrücken. Dies rechnet der
64 er nämlich bedeutend schneller aus, als wenn Sie
den Potenz-Operator verwenden würden. Also anstatt:
PRINT X↑2 schreiben Sie besser:
PRINT X* X
Dieses führt zum selben Ergebnis, verbraucht allerdings bedeutend weniger Zeit. Sie selbst dürften das
vielleicht nicht direkt merken, da es der Computer
für uns normal Sterbliche immer noch sehr schnell berechnet, aber schreiben Sie doch vielleicht einfach
einmal eine Schleife, die eine solche Potenzoperation
vielleicht 1000 oder 2000 Mal durchführt, und stoppen
Sie dann doch mal die Sekunden, ich denke, daß Sie
einen Unterschied feststellen müßten. . .
Das nächste, was ich Ihnen nicht vorenthalten möchte, ist die " DEF-FN"- Anweisung. Mit dieser Anweisung können Sie ganze Funktionen in einem Ausdruck definieren, so daß sie diesen Ausdruck nur noch durch ein
kleines Namenskürzel aufrufen müssen. Angenommen, Sie
haben eine Formel, mit der Sie durch Eingabe einer
Unbekannten eine gewisse Größe berechnen können. Als
praktisches Beispiel will ich mich mal ein wenig an
der Kreisberechnung auslassen. Nehmen wir an, Sie
wollten ein Programm schreiben, das Ihnen den Kreisumfang sowie den Kreisinhalt berechnet. Die dazugehörigen Formeln lauten, wie wir wissen, wenn wir alle
schön in der Schule aufgepaßt haben:
Kreisumfang: 2rπ (= 2*r*π) Kreisinhalt: r↑2π (= r↑2*π)
Da wir hier in unserem Kurs leider keine Sonderzeichen haben, habe ich, um das Quadrat auszudrücken, wie unser C64 auch, den Exponentenpfeil (↑) benutzt.
Sie kennen Ihn ja mittlerweile. In Klammern sehen Sie
dann die endgültige Computerschreibweise ( da ja noch
die Multiplikations-Zeichen '*' eingefügt werden mußten.
Die Formel für den Kreisinhalt werden wir allerdings
gleich nochmal ein wenig abändern. Da wir ja die Quadrate etwas schneller berechnen wollen, heißt es
jetzt also: r* r*π( was ja dasselbe ist wie r↑2*π) .
Nun müssen diese beiden Funktionen nur noch mit
DEF FN in einem Namen definiert werden. Dies geschieht folgendermaßen:
10 def fnu(r)=2*r*π 20 def fni(r)=r*r*π
Mit DEF zeigen Sie dem Computer also an, daß Sie hier
eine Funktion definieren wollen. Dann geben Sie den
Namen der Funktion an, der sich immer aus dem FN-Prefix, einem oder zwei Buchstaben und dem '( R)'- Suffix zusammensetzt. Das Prefix ist bei jeder Definition gleich, der eigentliche Name der Funktion wird
durch die beiden Buchstaben in der Mitte bestimmt, bei denen Sie nach den selben Regeln arbeiten müssen
wie bei den Variablennamen. Diese Regeln hatte ich
Ihnen, als wir die Variablennamensgebung hatten, ja
schon einmal aufgezählt. Zum Suffix sei nur noch zu
sagen, daß hier in Klammern immer die Unbekannte stehen muß, die in der zu definierenden Funktionsgleichung ( oder Formel) eingesetzt werden soll.
Warum, werden Sie beim Aufruf erkennen. Ich möchte
hier jedoch erst einmal wieder ein weiteres Stück
unseres Programmes einfügen:
30 print chr$(14)chr$(8) 40 print"[CLS]Programm zur Berechnung von Kreisum- fang" 50 print"und -inhalt." 60 input"[2 DOWN]Radius ";r 70 u=fnu(r) 80 i=fni(r)
Die Zeilen 30-50 drucken die Titelzeile des Programms
aus. In Zeile 30 wird übrigens wieder mit CHR$(14) die Kleinschrift eingeschaltet und mit CHR$(8) die
Umschaltmöglichkeit durch Drücken der SHIFTund der
COMMODORE-Tasten blockiert. Wir hatten dies ja schon
einmal bei unserem Zylinderberechnungsprogramm. . .
In Zeile 60 fragt das Programm jetzt nach dem Radius, der nach Eingabe eines beliebigen Wertes in der Variablen ' r' gespeichert wird.
Jetzt folgt endlich unser langerwarteter Funktionsaufruf. Sie sehen, daß in Zeile 70 das Ergebnis der
Funktion erst einmal der Variablen ' u' zugeornet
wird. Der Aufruf ansich gestaltet sich höchst einfach
und schmerzlos. Sie schreiben ganz einfach wieder den
Prefix ' FN' gefolgt vom Funktionsnamen und dem Suf- fix, mit der unbekannten Variablen in runden Klammern
eingeschlossen - das wars schon. Jetzt müssen wir das
Ergebnis nur noch ausdrucken, und das geschieht folgendermaßen:
90 print" Der Kreisumfang ist:" u 100 print" Der Kreisinhalt ist:" i
Was ja hoffentlich keinerlei Erklärung bedarf. . .
Der Clou an den vordefinierten Funktionen ist also, daß man eine Unbekannte gleich in den Klammern am
Ende angeben kann. Sie hätten die Funktion ebenso
auch so aufrufen können:
print fnu(1 .5)
Hier haben wir den Wert der Funktion also gleich numerisch angegeben, nicht also in einer Variablen. Der
Vorteil von solchen Funktionsdefinitionen liegt auf
der Hand. Angenommen, Sie haben eine bestimmte Formel, die Sie in einem Programm wahnsinnig oft benutzen müssen. Mit DEF-FN können Sie diese also immer
abkürzen, und haben Ihre Funktion immer sofort parat.
Mit FN haben Sie also eine Art Variable für Formeln
( oder Funktionen), weshalb FN als ' normaler' Variablenname nicht zulässig ist. Sie können gerne einmal
versuchen der Variable ' fn' einen Wert zuzuweisen, doch wird Sie der C64 dann nur mit einem lapidaren
SYNTAX ERROR belohnen. . .
Außerdem sei noch hinzuzufügen, daß Sie eine Funktionsdefinition ausschließlich NUR innerhalb von Programmen durchführen können. Versuchen Sie dies im
Direktmodus, so quittiert Ihnen das der Computer mit
einem " ILLEGAL DIRECT ERROR", einem " UNERLAUBTEN DI-REKTANWEISUNGS FEHLER" also. Ebenso wie INPUT beispielsweise ist DEF außerhalb von Programmen unsinnig, weshalb dieser Fehler auftritt. Einmal definiert
allerdings, können Sie jede Funktion aus dem Direktmodus aus aufrufen - andersherum geht es also. . .
Beschäftigen wir uns nun noch ein wenig mit der benutzerfreundlichen Programmierung. Das heißt, daß wir
unsere Programme so schreiben wollen, daß sie auch
jeder Computeranfänger problemlos bedienen kann. Genauergesagt möchte ich Ihnen die komfortable Programmierung von sogenannten " Menüs" näherbringen. BASIC
stellt uns hierzu 2 äußerst nützliche und komfortable
Befehle zur Verfügung, die auch sehr gut noch für
weitere Aufgaben zu verwenden sind.
Als erstes will ich den Begiff " MENÜ" einmal klären.
Bei einem Menü handelt es sich um eine Zusammenfassung von Unterpunkten innerhalb eines Programms, die
der Benutzer einzeln aufrufen kann. Sie kennen dies
bestimmt schon von meinem kleinen ASCII-Druck- Programm namens " SHOWASC", das dem zweiten Teil dieses Kurses beigefügt war. Hier wurden Sie nämlich
gefragt, welche Funktion des Programms Sie wünschen.
Ich zeige Ihnen hier am besten einmal das Menü von
SHOWASC, damit Sie sich ein besseres Bild machen können:
----------------------------------------------------- ASCII-Tabellen-Druck. Written in 1988 by Uli Basters.
Bitte druecken Sie:
==================== F1 - Ausgabe der Liste auf Drucker F7 - Ausgabe der Liste auf Bildschirm E - fuer Programmende -----------------------------------------------------
Sie können hier also zwischen 3 sogenannten " Menüpunkten" wählen, die Sie durch das Drücken einer bestimmten Taste erreichen können. Kommen wir hier nun
zum ersten der beiden Befehle, die ich Ihnen vorstellen wollte: dem GET-Befehl.
Mit ihm können Sie einen Buchstaben von der Tastatur
einlesen, der dann - in einer Stringvariable gespeichert - jederzeit abgerufen werden kann. Hier ein
Auszug aus dem Programm des Menüs von oben ( ich habe
es aus Gründen der besseren Verständlichkeit ein wenig abgeändert. . .) :
... 25 print"Bitte druecken Sie: " 26 print"====================" 30 print" F1 - Ausgabe der Liste auf Drucker" 40 print" F7 - Ausgabe der Liste auf Bildschirm" 50 print" E - für Programmende" 60 get a$:if a$=""then 60
In den Zeilen 25-50 wird erst einmal der Text zu unserem Menü auf dem Bildschirm ausgegeben. Wie das
dann aussieht haben wir oben ja schon einmal gesehen.
In Zeile 60 haben wir jetzt unseren GET-Befehl. Wie
Sie sehen, steht ihm die String-Variable ' a$' nach.
Die Taste, die also auf der Tastatur gedrückt wird, wird im ASCII-Code in dieser Stringvariablen gespeichert. Hier könnte natürlich auch jede andere Stringvariable stehen, nicht aber eine Numerische, oder
eine Intgervariable.
Direkt anschließend, aber immer noch in Zeile 60, kommt ein IF-THEN- Vergleich. Es wird geprüft, ob der
Inhalt der Variablen a$="" ist. Sie werden sich vielleicht fragen, was diese 2 Hochkommas ausdrücken.
Nun, ganz einfach, schreiben Sie irgendwo in BASIC
für einen String, bei einer Zuweisung, oder wie hier
zum Vergleich, ein "" dann steht das für NICHTS, oder
auch KEIN STRING. Es wird also hier bei uns geprüft, ob ' a$' leer ist, oder ob ein String in ihr gespeichert ist. Dieser Vergleich ist notwendig, da der
Computer ja eine Taste in ' a$' gespeichert haben
könnte, obwohl Sie gar keine gedrückt haben. Das
hängt ganz einfach mit internen Vorgängen zusammen.
Mit GET fragen Sie nämlich grundsätzlich immer die
Tastatur ab, egal, ob jetzt eine Taste gedrückt ist, oder nicht - GET holt sich immer den aktuellen Tastaturstand in die ihm nachgestellte Stringvariable.
Sollte also beim Aufruf von GET keine Taste gedrückt
sein, so brauchen wir gar nicht erst weiterzumachen, sondern schicken den Computer gleich wieder auf GET.
Solange bis endlich eine Eingabe gebacht wurde. Wir
haben hier also praktisch eine Endlosschleife produziert, die erst dann beendet wird, wenn eine Taste gedrückt wird.
Jetzt können wir prüfen, welche Taste dies war. Dies
funktioniert ganz einfach über ein paar IF-THEN- Abfragen, siehe auch die folgenden Zeilen:
70 if a$="[F1]" then 300 80 if a$="[F7]" then 200 90 if a$="e" then end 100 goto 60
Wie die eckigen Klammern ja anzeigen, haben wir hierwieder 2 neue Sonderzeichen, die sehr leicht zu
erklären sind. Sie entstehen, wenn Sie innerhalb der
Gänsefüßchen die F1-( in Zeile 70) oder die F7- Taste
( in Zeile 80) drücken. Diese beiden Zeichen sind
übrigens gute Beispiele für die Sonderzeichen, denn
obwohl sie nicht sichtbar sind, wenn man sie ausdruckt, sind sie doch relativ wichtig, da man ohne
sie die Abfrage der F-Tasten nur schwer realisieren
könnte. Sie könnten hier übrigens ebenso schreiben:
70 if a$=chr$(133) then 300 80 if a$=chr$(136) then 200
Dies würde dasselbe bewirken, da die ASCII-Codes 133 und 136 ja den Tasten F1, und F7 entsprechen, die sie
nebenbei auch der ASCII-Tabelle im Bedienungshandbuch
des 64 ers, Anhang F, entnehmen können, oder Sie benutzen ganz einfach SHOWASC.
Es wird hier also nach Zeile 300 verzweigt, wenn der
Drucker die Tabelle drucken soll, oder zu Zeile 200, wenn sie auf dem Bildschirm dargestellt werden soll.
Anschließend kommt in Zeile 90 unseres Programms noch
der Vergleich, ob ' a$' nicht den Buchstaben ' e' beinhaltet. Ist dies der Fall, so wird das Programm mit
END beendet.
Interessant ist noch Zeile 100 . Hier wird wieder in
Zeile 60 zum GET-Befehl gesprungen, also zurück in
unsere Abfrageschleife. Dies ist notwendig, da ja
auch noch andere Tasten, als F1, F7 oder e, gedrückt
worden sein könnten - sei es aus Versehen, oder nur
weil der User das Programm einmal ärgern wollte. War
dies der Fall, so hat der Computer bis in Zeile 90 verglichen und festgestellt, daß keiner der 3 ASCII-Codes in ' a$' gespeichert ist. Jetzt würde er ja im
Programm ganz normal weitermachen. Da ich in ( der nun folgenden) Zeile 200 allerdings das Modul abgelegt
habe, das die Ausgabe auf den Bildschirm übernimmt, müssen wir ihn hier dann abgefangen, damit er nicht
unkontrolliert in eine Unterroutine reinläuft, was
eben durch jenen besagten Sprung in die Zeile 60 realisiert wird.
Der zweite Befehl, den ich Ihnen noch vorstellen
möchte, heißt ON, und wird in Verbindung mit GOTO und
GOSUB benutzt. Er ist sozusagen eine spezielle Version des IF-Befehls. Hinter ON folgt eine Formel, die
vom Computer errechnet wird. Dies ist im einfachsten
Fall eine numerische Variable. Dann kommt entweder
der GOTOoder der GOSUB-Befehl, gefolgt von einer
Liste mit Zeilennummern, die durch Kommata getrennt
werden. Praktisch sieht das etwa so aus:
20 on x goto 100,200,300,400,500
Jetzt wird geprüft, welcher Wert in ' x' enthalten
ist. Ist x=1, dann wird die erste Zeilennummer, die
in der Liste steht, angesprungen ( wie wenn sie ein
GOTO 100 ausführen würden) . Ist x=2 dann wird die 2 .
Zeilennummer angesprungen, bei x=3 die 3 . und so
fort. . .
Diese eine Zeile entspricht also den 5 IF-THEN- Zeilen:
10 if x=1 then 100 20 if x=2 then 200 30 if x=3 then 300 40 if x=4 then 400 50 if x=5 then 500
Sollte x gleich 0, beziehungsweise negativ, oder gar
größer als die angegebenen Glieder der Liste sein, so
wird ganz normal im Programm fortgefahren. Wollten
wir unser Programm von vorhin also umschreiben, so
müßte das folgendermaßen aussehen.
60 input"Menüpunkt ";x 70 on x goto 200,300,400 80 goto 60
Das sieht doch schon gleich viel kürzer aus! Allerdings darf man hier nicht vergessen, daß in Zeile 400 dann auch wirklich noch ein END-Befehl steht, da dieser ja in unserem alten Programm direkt in der IF-THEN- Abfrage kam.
Ich habe hier übrigens ganz bewußt den INPUT-Befehl
benutzt, da wir ja gelernt haben, daß man bei GET nur
Stringvariablen einlesen kann. Hierbei haben wir dann
im Endeffek keine Möglichkeit mit ON zu arbeiten, es sein denn man greift zu einem kleinen Trick:
die Ziffern der Zahlen sind nämlich im ASCII-Code
alle hintereinander angeordnet. Die 0 hat den Code
48, die 1 den Code 49 und so weiter, bis zur 9, die
den Code 57 belegt. Wird bei einer GET-Abfrage also
die 1 gedrückt, so enthält a$ den CHR$- Code 49 . Wenn
wir jetzt von dieser Zahl einfach den Wert 48 subtrahieren, so erhalten wir das Ergebnis 1, was ja genau
die Taste ist, die gedrückt wurde, nur haben wir
jetzt einen Zahlwert, mit dem ON etwas anfangen kann.
Das Programm hierzu müßte dann so aussehen:
60 get a$:if a$="" then 60 70 on asc(a$)-48 goto 200,300,400 80 goto 60
Hier haben Sie dann auch ein Beispiel, in dem wir
eine ganze Formel benutzen, die zuerst berechnet und
dann ausgewertet wird. Wir haben dabei die, uns mittlerweile schon altbekannte, ASC-Anweisung angewandt, um den CHR$- Code der in ' a$' gespeicherten Taste zu
erfahren.
Wie eingangs schon erwähnt, könnten Sie hier auch den
GOSUB-Befehl verwenden, nur müssen Sie dann Ihre Module auch mit RETURN wieder abschließen. Denkbar wäre
auch, daß man mit Buchstaben die Tasten abfrägt, wobei man alphabetisch vorgeht. Da der ASCII-Code des
Zeichens ' a' den Wert 65 hat, müßten Sie hier nur den
Wert 64 subtrahieren, um brauchbare Zahlwerte für ON
herauszubekommen.
Hiermit möchte ich nun für diesen Monat wieder einmal
schließen und mich bis Mai verabschieden. Wir werden
uns dann, wie ich diesmal schon angedeutet hatte, um
etwas höchst wichtiges kümmern, was unerläßlich ist, wenn man sich ein wenig mit der Grafikund Soundprogrammierung des C64 beschäftigen möchte. Ich rede von
dem sogenannten Binärsystem und dem Speicheraufbau
unseres kleinen Freundes. Mehr dann nächsten Monat.
Bis dann also, Ihr Uli Basters.
BASIC-Kurs: "Von Adam und Eva..." (Teil 5)
Herzlich Willkommen beim fünften Teil unseres Basickurses. Wie letzten Monat schon versprochen geht es
diesmal um das sogenannte Binärsystem und den Speicheraufbau unseres 64 ers. Dieses Thema hat eigentlich
mit BASIC im allgemeinen ganz und garnichts zu tun, doch ist es unerläßlich wenigstens einige Kenntnisse
davon zu haben, wenn man sich mit der Grafikund
Soundprogrammierung auf dem C64 beschäftigen möchte.
Zunächst einmal eine kleine Erläuterung zu Zahlen im
allgemeinen:
Wie Sie ja wissen benutzen wir Menschen ein Zahlensystem mit dessen Hilfe wir Maße, Gewichte, Geldsummen
oder ähnliches bequem ausdrücken können. Ich spreche
vom sogenannten " Dezimalsystem" . Indem wir uns der
Ziffern 0123456789 bedienen, können wir durch beliebiges kombinieren dieser Ziffern Zahlen von unendlicher Länge bilden. Ein Beispiel wäre da die Zahl
1989 . Sie gliedert sich in 4 Teile auf, die ich Ihnen
im Folgenden einmal grafisch darstellen möchte:
Die Buchstaben T,H,Z und E stehen für "Tausender", "Hunderter", "Zehner" und "Einer". Das heißt also, daß die Zahl 1989 in eine Zahl mit vier Kompo- nenten aufge- spaltet wird.
Mathematisch läßt sich das folgendermaßen ausdrücken:
1000*T + 100*H + 10*Z + 1*E = THZE (oder auch) 10↑3*T + 10↑2*H + 10↑1*Z + 10↑0*E = THZE
Oder in unserem Beispiel:
1000*1 + 100*9 + 10*8 + 1*9 = 10↑3*1 + 10↑2*9 + 10↑1*8 + 10↑0*9 = 1000 + 900 + 80 + 9 = 1989
Jeder Stelle der Zahl ist also eine Potenz von 10 zugeordnet (1=10↑0,10=10↑1,100=10↑2,1000=10↑3, usw. . .) . Daher auch der Name DEZIMALsystem -" decum" kommt aus dem lateinischen und heißt " zehn" .
Dieses Verfahren läßt sich natürlich auch bei größerstelligen Zahlen anwenden. Bei der Zahl 2313660 ist
die höchste Zehnerpotenz 10↑6 . Hierbei ist übrigens
noch anzumerken, daß die letzte Ziffer eine Null ist, bei der der ihr zugehörige Potenzfaktor ( hier 10↑0) sozusagen " wegmultipliziert" wird, denn 1*0=0, weshalb auch hier als Endsumme aller Produkte der Potenzen 2313660 herauskommt. Das scheint alles komplizierter als es ist - wichtig ist, daß Sie begriffen
haben, daß eine Dezimalziffer nur aus der Addition
von 10 er-Potenzen besteht.
Sie sehen auch, daß jedesmal nachdem wir die höchste
Ziffer einer Potenz erreicht haben, nämlich die 9, die nächste Zahl als ein Vielfaches der nächsthöheren
Potenz darstellen können. Haben Sie also die Zahl
neun erreicht, so findet ein sogenannter " Überlauf" statt, das heißt, daß die nun folgende Zahl eine
Stelle mehr bekommt, und ihre höchste 10 er Potenz mit der Ziffer 1 als Multiplikator versehen wird. Der
Nachfolger von 9 ist 10 wobei letztgenannte Zahl eine
zweistellige ist, erstere allerdings nur eine einstellige.
Ebenso kommen Überläufe vor, wenn wir von 19 auf 20 zählen. Hier wird der Zähler der nächsten Potenz um
eins erhöht. Auch von 29 auf 30 verhält es sich so, und so fort. Bei jedem Überlauf erhält also die niedrigere Potenz die Ziffer 0 in den Zähler, während
die höhere die nächst höhere Ziffer verpasst bekommt.
Beim Zählen von 99 auf 100 zum Beispiel geschieht
dies sogar gleich zweimal. Zum Einen erhalten die
" Einer"(10↑0) die Nullziffer und es findet ein Überlauf zu den " Zehnern"(10↑1) statt, zum Anderen bewirkt dieser wiedrum, daß die " Zehner" überlaufen und
somit den Zähler 0 erhalten, wobei die " Hunderter"(10↑2) um 1 erhöht werden und nun die Ziffer 1 dort
im Zähler steht.
Sehen Sie hier das Ganze ein wenig grafisch aufgemacht ( denn ein Bild sagt mehr als tausend Worte) :
Wir haben also gelernt, daß die 10 mit ihren Potenzen
die Basis unseres Zahlensystems liefert, da alle Dezimalzahlen als Summe von 10 er-Potenzen dargestellt
werden können. Sie werden jetzt fragen:
" Was hat das Ganze denn mit dem Binärsystem zu tun, darum geht es hier doch?"
Nun, das Binärsystem folgt nämlich ( fast) genau diesem Muster, mit dem einzigen Unterschied ( daher auch
die Einschränkung eben), daß wir hier nicht mit einer
Basis von 10 sondern mit der von 2 arbeiten. Auch
hier können Sie den Namen des Systems von ihr ableiten " Bi" steht für Zwei. Da wir ja nun alle 2 er-Potenzen verwenden, brauchen wir logischerweise auch
nur zwei Ziffern, mit denen wir unsere Binärzahlen
darstellen ( im Dezimalsystem hatten wir ja 10 davon - Sie sehen, es werden immer soviele Ziffern benötigt, wie die Basis angibt) . Dies sind ganz einfach die
Ziffern 0 und 1 . Demnach kann man also sagen, daß
eine Binärzahl so aussehen könnte:11001010 . Diese
hier zum Beispiel ist achtstellig. Das hat einen besonderen Grund, wie wir später erkennen werden.
Wie sich eine solche Zahl jetzt zusammensetzt ist
klar - wir müssen ganz einfach die Potenzen von 2 nebeneinander schreiben ( allerdings mit der niedrigsten ganz links und der höchsten ganz rechts) und die
Produkte der Binärziffern mit den ihnen zugehörigen
Potenzen miteinander addieren. Als Ergebnis erhalten
wir dann unsere Binärzahl in Dezimalschreibweise.
Führen wir dies doch einmal durch:
Sie sehen also: wir benutzen hier genau dasselbe
Prinzip wie beim Dezimalsystem, mit dem Unterschied, daß hier die Produkte der 2 er-Potenzen addiert werden.
Doch warum das alles? Wozu können wir das Binärsystem gebrauchen, und warum sind achtstellige Binärzahlen etwas Besonderes? Leider muß ich zur Beantwortung dieser Frage wiederum etwas weiter ausholen:
Im Prinzip kann man sagen - und das wird mir jeder, der sich mit Computern gut auskennt bestätigen:
" Computer sind dumm" .
Sie können nämlich ausschließlich nur zwischen
" STROM AN" und " STROM AUS" unterscheiden. Das heißt, daß sie nur erkennen können, ob auf einer ihrer vielen Leitungen ein elektrischer Strom fließt, oder
nicht. Was Computer jetzt allerdings so schlau macht, daß wir Ihnen Befehle eingeben können, die sie dann
ausführen können liegt einfach nur daran, daß sie
immens viele socher EIN/ AUS-Leitungen besitzen und
daß diese in richtiger Kombination bestimmte Wirkungen erzielen können. Ein recht einfaches Beispiel
wäre etwa folgendes:
Angenommen, ein Computer hätte vier Leitungen vor
sich, die er auf EIN oder AUS überprüfen könnte. Er
erkennt, daß Leitung 1 EINgeschaltet ( sprich:" auf
ihr fließt Strom), Leitung 2 AUSgeschaltet ( hier
fließt also KEIN Strom), Leitung 3 wieder EINgeschaltet und Leitung 4 ebenfalls wieder EINgeschaltet
sind. Daraus ergibt sich die Kombination:
EIN AUS EIN EIN
Nun weiß unser Computerchen zusätzlich noch, daß er, wenn diese Kombination eintreten sollte, beispielsweise die Hintergrundfarbe auf Dunkelgrau umschalten
soll. Diese Information ist irgendwo in seinem Aufbau
gespeichert.
Sie sehen also, so einfach ( oder kompliziert) ist es, einen Computer ganz elementar zu programmieren, das
heißt also ganz grundsätzlich, ohne irgendwelche
Hilfsmittel ihm einen Befehl zu erteilen, indem man
bestimmte Stromleitungen in ihm einoder ausschaltet. Kompliziert ist dies vielleicht deshalb, weil
man hierzu alle möglichen Kombinationen mit ihrer
Wirkung kennen muß. Das sind bei vier Leitungen zwar
" nur"16 verschiedene, aber es könnten ja beispielsweise auch viel mehr Leitungen zum Unterscheiden zur
Verfügung stehen.
Hm - Moment einmal, die Zahl 16 hatten wir doch heute
schon einmal! ! ! Genau -16 ist die vierte Potenz von
2( also 2↑4), der Wert der fünften Ziffer des
Binärsystems! Und genau das ist es, worauf ich hinaus möchte: die oben genannte EIN/ AUS-Kombination
könnte nämlich auch genausogut folgendermaßen aussehen ( wenn man anstelle von EIN die Ziffer 1 und anstelle von AUS die Ziffer 0 schreibt) :
EIN AUS EIN EIN 1 0 1 1
Und siehe da: da haben wir doch eine echte ( vorläufig vierstellige) Binärzahl! Ins Dezimalsystem umgerechnet lautet sie übrigens 11( elf) . Und tatsächlich
ist es auch so, daß wenn wir unserem C64 an einer
bestimmten Stelle in seinem Speicher die Zahl 11 angeben, er den Bildschirm in die Farbe Dunkelgrau umfärben wird." An einer bestimmten Stelle" hört sich
vielleicht etwas merkwürdig an, doch werden wir dies
jetzt noch klären.
Wollen wir uns nun mit dem Speicheraufbau unseres C64 befassen. Anschließend werden Sie feststellen, daß
das Wort " Stelle" absolut passend ist.
Wie Sie vielleicht einmal gehört haben, oder in Ihrem
C64 Bedienungshandbuch gelesen haben, verfügt Ihr
kleiner Freund über 64( sogenannte) Kilobytes ( Abkürzung : KB) Speicher ( bei denjenigen Lesern, die die
Funktionsweise des Binärsystems begriffen haben sollten, müßte eigentlich gerade eben ein Licht aufgegangen sein -64 ist die sechste Potenz von 2, also
2↑6) . Bestimmt konnten Sie bis jetzt absolut nichts
damit anfangen, weshalb wir jetzt erst einmal klären
wollen was ein Kilobyte, oder besser ein einzelnes
Byte ist. Zuerst einmal zum Byte:
Ein Byte ist die Zusammenfassung von acht( !) sogenannten Bits. Man kann also sagen:1 Byte =8 Bits.
Doch was, um alles in der Welt, ist jetzt wieder ein
Bit? Nun, ein Bit ist ganz einfach eine von jenen
vielen Leitungen, wie ich sie oben schon beschrieben
hatte, die einund ausschaltbar sind. Eine von diesen Leitungen, die ein Computer miteinander kombiniert, um den Befehl, den er ausführen soll zu ermitteln. Womit unsere Frage nach dem " Warum eine achtstellige Binärzahl" beantwortet wäre: da unser Bit
für eine stromführende Leitung steht, die entweder
EINoder AUSgeschaltet sein kann (1 oder 0), und
weil acht Bit einem Byte entsprechen, kann dieses
Byte mit Hilfe einer achtstelligen Binärzahl ausgedrückt werden. Man spricht hier von dem " Wert" eines Bytes. Von der Binärzahl also, die in diesem Byte
enthalten ist, oder anders gesagt: von den Bits, die
in diesem Byte " gesetzt"( Bit=1) oder " nicht gesetzt"( Bit=0) sind.
Würde man also sagen: dieses Byte hat den Wert 202, so würde man damit die Bitgruppe 11001010 meinen
( hier einmal die Werte unseres Beispiels von oben) .
Ein Kilobyte ist jetzt ganz einfach die Gesamtheit
von 1024 Bytes. Dies verhält sich etwa ähnlich wie
bei Gramm und Kilogramm. Ein Kilogramm sind 1000 Gramm, oder das 10↑3- fache von 1 . Bei Bytes rechnet
man mit einer Potenz von 2, da die Bytes ja auch auf
ein System aus 2 er-Potenzen aufgebaut sind, und somit
die Zahlen besser " harmonieren" . Doch dies ist jetzt
unwichtig, da Sie die Bedeutung dieser " Harmonie" erst verstehen müssen, wenn Sie einmal die Maschinensprache ( auch " Assembler genannt) lernen werden.
Des Weiteren sind ein Megabyte demnach also 1024 Kilobytes. Am Rande vielleicht eine kleine Umrechnungstabelle:
1 Megabyte =1024 Kilobytes =1024*1024 Bytes (1024*1024 sind übrigens 1048576, also " ein klein
wenig" mehr als eine Million. . .)
Jetzt wissen Sie also, daß wir insgesamt 64*1024*8(=524288) Leitungen in unserem C64 haben (64 KB
eben), die alle in verschiedenster Weise einoder
ausgeschaltet sein können. Zahlenmäßg gesehen ist das
ja eine ganz schöne Menge, in der Realität werden wir
allerdings nur eine Handvoll davon effektiv nutzen
können. Man kann etwa sagen, daß gute 99 Prozent dieser 64 Kilobytes nur zur Speicherung von Befehlen
benutzt wird. Das heißt also, daß sich der Computer
in diesen Bereichen die Befehle, die er irgendwann
einmal ausführen soll, einfach nur zwischenspeichert, damit er sie bei Bedarf dann gleich griffbereit hat, um sie abzuarbeiten. Doch dies fällt ebenfalls in den
Themenbereich der Maschinensprache, wo es sogar eine
sehr große Rolle spielt.
Diese 65536 Bytes (=64 KB), können jetzt alle einzeln
mit ihren Nummern angesprochen werden. Bildlich könnte man sich das etwa wie eine Straße vorstellen, in
der es 65536 Häuser gibt, mit ebenso vielen Hausnummern. Möchten Sie jetzt beispielsweise einen Brief an
das Haus mit der Nummer 53281 schicken, so müßten Sie
diesen an folgende Adresse schicken:
An Herrn Byte Speicherstraße 53281 64KB Commodore 64
Der Name des Adressaten und der adressierten Stadt
dient hier nur zur Untermalung, wichtig ist jedoch, daß Sie erkennen, daß Sie so einen " Brief" an das
Haus mit der Nummer 53281 schicken können. Der Inhalt
dieses Briefes könnte etwa folgendermaßen aussehen:
Sehr geehrter Herr Byte,
00001011 Herzlichst, Ihr Programmierer.
Auch diesmal nur ein kleines aufmunterndes Beispiel, um den Zweck des " Verschicken eines Briefes" aufzuzeigen. Tatsächlich sagt man sogar, daß man ein Byte
" adressiert", also seine " Adresse" angibt, und ihm
dann einen Wert zuweist. Mit unserem Brief hätten wir also dem Byte 53281 den Wert 00001011 zugewiesen, womit wir wieder beim Binärsystem wären. Der aufmerksame Leser hat bestimmt schon längst gemerkt, daß wir
hier die Binärzahl von vorhin auf dem Bildschirm stehen haben, nämlich die dezimale 11 . Diesmal allerdings achtstellig, da wir ja gelernt haben, daß man
das ganze Byte adressiert, und somit auch auf jeden
Fall 8 Bits verändert. Die höherwertigen 4 Bits beinhalten jetzt ganz einfach die Ziffer 0, womit ihre
Produkte mit ihren jeweiligen Potenzen auch zu 0 werden, weshalb sie auch nicht zu Gewicht schlagen.
Wollen wir nun endlich den BASIC-Befehl kennenlernen, mit dem wir " Briefe verschicken" können: der POKE-Befehl.
Die Syntax von POKE ist denkbar einfach: Sie müssen
hinter dem Befehlswort POKE ganz einfach nur noch die
Adresse des zu verändernden Bytes angeben und anschließend, durch ein Komma voneinander getrennt, den
Wert, der zugewiesen werden soll, allerdings in dezimaler Schreibweise. Daher also auch die vorangehende
langwierige Erklärung des Binärsystems, denn später
müssen Sie sich Ihre Bitkombinationen selbst zusammenrechenen können.
Um unser Adressierungsbeispiel gleich in die Realität
umzusetzen - hier ist der Brief an Herrn Byte, wie
wir ihn in BASIC schreiben mÜssten:
POKE 53281,11
Wir haben also der Speicherzelle ( das ist die deutsche Übersetzung für Byte)53281 den Dezimalwert 11 beziehungsweise den Binärwert 00001011 zugewiesen.
Probieren Sie es doch einmal aus, und beobachten Sie, was passiert. . . Na? Verblüfft? Eben genau DAS ist
eingetreten, was ich Ihnen vorhin beschrieben hatte:
der Hintergrund des Bildschirms Ihres C64 hat sich
vom üblichen Blau in ein tristes Dunkelgrau verfärbt.
Sie sehen also, man muß nur die richtigen STELLEN im
Speicher des 64 ers verändern, um gewisse Ergebnisse
zu erzielen.
Jetzt möchte ich Ihnen allerdings nicht verschweigen, daß es ebenso möglich ist, von einer Speicherzelle
einen Brief zu erhalten. Das heißt also, daß Sie als
Programmierer die Speichezelle dazu veranlassen können, ihren Inhalt ( oder ihren Wert) Ihnen zuzuschikken. Dies kann in BASIC mit der PEEK-Funktion realisiert werden. Die Syntax von PEEK ist ebenfalls sehr
einfach: Sie müssen nach dem Befehlswort PEEK nur
noch die gewünschte Byteadresse, in Klammern gesetzt, angeben, um den Inhalt dieses Bytes zu erhalten. Ich
möchte darauf aufmerksam machen, daß es sich hierbei
um eine FUNKTION handelt. Sie können PEEK also ohne
alles kaum effektiv nutzen, es solte nämlich schon
ein PRINT-Befehl, eine Variablenzuweisung, oder ein
Vergleich durch IF-THEN dabei stehen, um der Funktion
entsprechend einen Sinn zu geben. Eine Möglichkeit, sich den Inhalt einer Speicherzelle anzusehen, wäre
über PRINT gegeben. Versuchen Sie doch einmal folgendes:
PRINT PEEK(53281)
Jetzt sollten Sie eine Zahl auf dem Bildschirm stehen
haben. Sie gibt die Farbe des Hintergrundes an, da
das Byte 53281 ja für die Farbe des Bildschirms
zuständig ist, wie wir es vorhin gelernt hatten. Es
kann durchaus sein, daß Sie jetzt hier etwas anderes
als 11 auf dem Bildschirm stehen haben. Das hat etwas
mit der computerinternen Handhabung der Farben zu
tun, doch das wollen wir an späterer Stelle genauer
behandeln. Prinzipiell kann man jetzt also sagen, daß
Sie mit Hilfe von PEEK und POKE ein Byte zu verschiedenen Aktionen veranlassen können. Mit PEEK lassen
Sie sich von dem Byte einen Brief schicken, der seinen Wert beinhaltet und mit POKE können Sie das Spiel
umkehren und dem Byte einen Brief zuschicken, der den
Wert beinhaltet, den es annehmen soll. Wie wir gesehen haben, ist gerade letztere Funktion ja sehr nützlich, wenn wir verschiedene Dinge im Computer bewirken wollen, man muß nur wissen an welchen Stellen man
Änderunngen vornehmen muß, um einen gewissen Effekt
zu erzielen.
Womit wir wieder bei den Stellen wären. Ich möchte
Ihnen hier einmal eine kleine Übersicht aller Stellen
( Bytes, Speicherzellen, Hausnummern, Adressen, oder
wie Sie es auch immer nennen möchten) geben, wie Sie
im C64 vorkommen. Man kann diese 65536 Bytes nämlich
in gewissen Aufgabenbereichen zusammenfassen, um etwas Ordnung in die Tausenden von verschiedenen Zellen
zu bringen:
Ich habe hier den Speicher des C64 einmal mit Hilfe
eines Balkens, der in verschiedene Teilbereiche aufgespalten ist, dargestellt. Unten sehen Sie die Speicherzelle 0, und am oberen Rand haben wir das letzte
Byte, mit der Adresse 65535 . Sie werden jetzt fragen:" Warum 65535 wo wir doch die ganze Zeit von
65536 Bytes reden ?"- Nun, wir müssen hier wieder
berücksichtigen, daß das Byte mit der Adresse 0 ja
auch mitzählt, somit haben wir ( rein zahlenmäßig) dann 65535 Bytes plus ein 0- Byte, das macht
65535+1=65536 !
Ich möchte Ihnen hier dann gleich noch die Aufgaben
der verschiedenen Speicherbereiche erläutern, wie ich
sie im Bild schon angedeutet habee. Hierbei möchte
ich allerdings vorerst die Bytes von 0 bis 40960 übergehen, da Sie deren Funktionsweise besser verstehen können, wenn Sie die der Folgenden schon kennen.
Beginnen wir also bei 40960 bis 49152 . Hier steht das
sogenannte BASIC-ROM. Klären wir zunächst einmal, wofür ROM steht. Hierzu sollte ich vielleicht erwähnen, daß es zwei verschiedene Arten von Speicherzellen in Ihrem C64 gibt. Bestimmte Teilbereiche haben
also bestimmte Eigenschaften, die ein anderer wiederum nicht hat. Die zwei Arten, von denen hier gesprochen wird, nennt man RAM und ROM. RAM steht für " Random Access Memory" und ROM für " Read Only Memory" .
Übersetzen wir dies aus dem Englischen, so haben
wir:" Speicher für beliebigen Zugriff" und " Speicher, der nur gelesen werden kann." Dies heißt im
Klartext, daß RAM-Speicherzellen beschrieben UND gelesen werden können, im Gegensatz zu ROM-Adressen, die NUR gelesen werden. Sie können sich dies etwa mit
folgendem Bild verdeutlichen: die RAM-Adressen sind
schreibfreudige Mitbürger. Sie erhalten gerne Briefe, und beantworten diese auch, sollten sie dazu aufgefordert worden sein. ROM-Adressen hingegen sind eher
Kontaktscheu, sie ignorieren ihre Post, und werfen
sie, wie Sie es vielleicht auch manchmal bei Werbesendungen tun, ungelesen in den Mülleimer. Sie kennen
ihren Programmierer schon gut genug, weshalb sie auch nur dann an ihn ihren Inhalt senden, wenn dieser es
unbedingt verlangt. Außerdem sind ROM-Adressen sehr
konservative Individuen, sie haben nämlich auch gar
nicht vor, ihre Einstellung ( also ihren Wert) zu ändern und bleiben auch auf Immer und Ewig bei ihrem
voreingestellten Wert.
Doch jetzt einmal Spaß beiseite - der Grund, warum
man ROM und RAM schuf, war einfach der, daß man einen
Speicher benötigte, der auch ohne Stromzufuhr, also
im ausgeschalteten Zustand des Computers, in der Lage
ist, seine in ihm gespeicherten Informationen zu behalten. Da man sonst bei jedem neuen Einschalten eines Computers ein gewisses Grundprogramm jedesmal
wieder von Neuen hätte eingeben müssen, wobei natürlich die Frage aufkommt, wie man dies getan hätte, da
in einem leeren Computer ohne Programm auch nichts
getan werden kann, um Daten aufzunehmen, da dieser
immer ein Programm braucht, das ihm diese Daten einliest. Ebenso ist es bei BASIC. In dem vorhin angesprochenen Bereich des BASIC-ROMs sind die Grundprogramme gespeichert, die es uns ermöglichen, in BASIC
mit unserem 64 er zu kommunizieren. Alle Befehle, die wir bisher behandelt haben, ebenso wie diese, die
noch kommen werden, sind hier genauestens definiert, so daß der Computer immer genau weiß, was er zu tun
hat, wenn Sie ihn Beispielsweise mit der Buchstabenfolge PRINT konfrontieren.
ROM braucht also keinen Strom, um die in ihm gespeicherten Bits zu behalten. Sie können sich dies etwa
als eine Unmenge von Leitungen vorstellen, die fest
und unveränderlich sind. Und nicht, wie es beim RAM
der Fall ist, durch Schalter ein-, oder ausschaltbar
sind. ROM-Bits STEHEN ganz einfach schon auf EIN oder
AUS.
Der Vorteil am RAM ist ganz einfach, daß man seinen
Inhalt sozusagen " von Hand" verändern kann und wäre
dies nicht möglich, so könnte man beispielsweise die
Bildschirmfarbe auch gar nicht verändern. Dafür geht
diese dann allerdings auch verloren, wenn man die
Stromzufuhr unterbricht.
Doch machen wir nun wieder in unserer Speicherübersicht weiter. Es folgt nun der Bereich von 49152 bis
53248 . Hier ist freier RAM-Speicher, der vom Computer
nicht benutzt wird. Wir als Programmierer, können ihn
uns zwar zu Nutze machen, doch das ebenfalls erst, wenn Sie sich einmal mit Assembler befassen sollten.
Der folgende Speicherbereich ist der für uns BASIC-Programmierer wichtigste, weshalb ich anschließend
auch etwas genauer darauf eingehen werde. Der sogenannte I/ O-Bereich, oder Input/ Output-Bereich ( von
53248 bis 57344), enthält die Speicherzellen der verschiedenen Ein-/ Ausgabe-Bausteine ( Input/ Output = Eingabe/ Ausgabe) . Das sind jene Bausteine ( oder Computerchips) in unserem C64, die dafür verantwortlich
sind, daß zum Beispiel der Ton aus dem Lautsprecher
kommt, daß das Floppylaufwerk auch odrnungsgemäß seine Daten speichert, oder daß, wie oben schon gezeigt, der Bildschirm in dunkelgrauer Farbe dargestellt
wird. Wir wollen uns Speziell um zwei bestimmte Chips
aus diesem Bereich kümmern, sie tragen die Namen SID
und VIC.
SID steht für " Sound Interface Device" was etwa soviel heißt wie " Musikerzeuger"( nicht wörtlich übersetzt, doch das hier trifft die Aufgabe von SID auf
den Punkt genau) . Um ihn werden wir uns in einer der
nächsten Ausgaben noch kümmern.
VIC ist die Abkürzung für " Video Interface Controller" . Wie sein Name schon verrät ( Überwacher der Videoschnittstelle, oder frei nach J. R. R. Tolkien " Der
Herr der Videoschnittstelle"), ist er zuständig für
Bildschirmaufbau und Grafik innerhalb unseres Computers. Er wird auch unser Hauptthema sein, um das es
sich nächsten Monat drehen wird.
Nun wollen wir noch unsere Speichertabelle zu Ende
abhandeln. Da wäre zunächst einmal noch der Bereich
von 57344 bis zum Ende des Speichers ( also bis
65535) . Hier haben wir wieder einen ROM-Bereich vorliegen, diesmal allerdings das Betriebssystem-ROM.
Das Betriebssystem ist der wichtigste Teil eines Computers, da in ihm alle Unterprogramme enthalten sind, die zur Steuerung des Computers beim Einschalten und
während der Eingabe über die Tastatur unbedingt notwenig sind. Hier liegt das eigentliche Herzstück des
C64, ohne das er nur bedingt leben könnte. Wenn wir
das aus unserer Sicht als werdende BASIC-Programmierer betrachten, könnte er es sogar überhaupt nicht. Hier muß ich dann abermals auf die Maschinensprache verweisen, denn bei dieser ist es durchaus möglich, den C64 OHNE Betriebssystem zu benutzen, doch ist dies auch hier nur unter - relativgro-ß em Aufwand machbar. Auch werden Sie beim Erlernen
der Maschinensprache nicht umhin kommen, sich mit dem
Betriebssystem eingehender zu befassen, Sie werden es
nach einiger Zeit sogar sehr zu schätzen wissen.
Zum Abschluß noch die Speicherbereiche von 0 bis
40960, deren Funktionen Sie jetzt besser verstehen
werden:
Da wäre ja zuerst einmal der Bereich von 0 bis 1024 .
In diesem Bereich findet sich eine Ansammlung von
Bytes, die ausschließlich vom Betriebssystem und von
BASIC benutzt werden, um bestimmte Werte zwischenzuspeichern. Uns als BASIC-Programmierern bleiben die
meisten davon verschlossen, und wir können Sie nur in
bedingtem Maße für uns nutzen, doch auch dies zu einem späteren Zeitpunkt.
Dann käme als nächstes das VIDEO-RAM, oder der Bildschirmspeicher, von 1024 bis 2048 . Auf diesen Bereich
werden wir nächsten Monat auch noch genauer eingehen, da er, wie sich aufgrund des Namens vielleicht ja
schon vermuten läßt, etwas mit VIC zu tun hat. Hier
sei nur gesagt, daß in diesem Bereich die Zeichen, wie sie normalerweise immer auf dem Bildschirm stehen, in genau der Reihenfolge abgespeichert sind, wie
Sie sie auf diesem abgebildet sehen.
Als letztes hätten wir dann noch den Bereich von 2048 bis 40960 . Zugegebenermaßen wohl der größte Speicherbereich im 64 er. Hier werden in aller Regel die Programmzeilen, so wie Sie sie eingeben gespeichert.
Der LIST-Befehl tut also nichts anderes, als die
BASIC-Zeilen, die hier gespeichert sind, Ihnen auf
dem Bildschirm darzustellen.
In diesem Bereich finden übrigens gleichzeitig auch
alle Variablen Platz, die Sie in Ihren Programmen
verwenden.
Hiermit bin ich nun wieder am Ende der Folge angelangt und hoffe, Ihnen nicht zu sehr die Gehirnwindungen mit der Thematik des Speicheraufbaus und des
Binärssystems verknotet zu haben. Wie Sie ja merkten, hatten wir diesmal eigentlich kaum etwas mit BASIC
zu tun, wenn man einmal von PEEK und POKE absieht.
Doch glaube ich mit diesem Artikel bei Ihnen einen
Grundstein für das " wirkliche" Vertändnis von Computern gelegt zu haben, da Sie mit Hilfe der Informationen, die Sie hier und heute erlangt haben, sich
viele Phänomene der Informatik sehr einfach und verständlich verdeutlichen können.
Ich darf Ihnen nun noch ein fröhliches Gehirnentknoten wünschen und verabschiede mich bis nächsten Monat, wenn es dann heißt " Von nun an wirds aber bunt - die Grafikprogrammierung als solche", Ihr Uli Basters.
BASIC-Kurs : "Von Adam und Eva..." (Teil 6)
Herzlich Willkommen zum 6 . Teil unsers BASIC-Kurses.
Nachdem mich meine Mitredakteure letzen Monat wegen
Platzmangels aus meiner Sparte geschmissen haben, geht es nun wieder weiter im Text. Allerdings kann
ich Ihnen eine weitere kleine Enttäuschung nicht vorenthalten. Ich hatte Ihnen im Mai zwar versprochen, daß wir uns dieses Mal mit der Grafik beschäftigen
würden, doch möchte ich dies nun erst einmal aufschieben. Der Grund hierfür liegt darin, daß nach
diesem Kurs hier ein Grafikkurs geplant ist. Da habe
ich dann auch genügend Platz und Freiheit, Ihnen dieses Thema besser zu erläutern und näher zu bringen.
Gerade die Grafik ist beim C64 ein sehr brisantes
Thema, zumal BASIC die Grafikprogrammierung in keinster Weise unterstützt, wie man das von größeren Computern ( ich sage da ja nur " AMIGA" und " AmigaBasic") gewohnt ist. Doch ganau das wird dann Thema dieses
Kurses werden, weshalb ich Sie jetzt noch 3 Monate
vertrösten muß. Dann wird nämlich der Basickurs beendet sein.
Nun wollen wir aber einmal mit diesem sechsten Basickurs beginnen. Ich möchte Sie nun ein wenig in die
Soundprogrammierung des 64 ers einführen, die auch
nicht gerade ohne ist, und für die Sie die Informationen über das Binärsystem und den Speicheraufbau
des C64 vom letzten Mal genauso, wenn nicht sogar
noch mehr, benötigen.
Erinnern wir uns : mit der Soundprogrammierung hat
der SID, der Chip der Musik erzeugt, etwas zu tun.
Wir hatten ja gelernt, daß die Adressen mit denen man
ihn programmiert im sogenannten I/ O-Bereich ( INPUT-/ OUTPUToder EIN-/ AUSGABE-Bereich) liegen, der sich
von Adresse 53248 bis 57344 erstreckt." Puh!" werden
Sie sagen," Das sind ja mehr als 4000 Speicherzellen ! Wie soll man sich die denn alle merken !" Doch
keine Angst ich kann Sie beruhigen. Der SID belegt
lediglich 28 davon. Ebenso wie alle anderen Ein-/ Ausgabe-Bausteine ( es sind derer insgesamt vier, die
wir hier allerdings, außer dem SID, nicht behandeln
werden), die auch nicht mehr als 50 Bytes in diesem
Riesenbereich belegen. Doch Vorsicht. Sie können hier
zwar die meisten Adressen mit beliebigen Werten be- schreiben, doch ist es NICHT möglich die nicht benutzten Speicherzellen zu benutzen. Sollten Sie hier
einen Wert hineinschreiben, so wird gar nichts passieren, da die adressierte Speicherzelle nämlich physisch, also im Innern Ihres 64 ers, gar nicht existiert. Sie bekommen irgendwelche Werte beim Auslesen
mit PEEK geliefert, und beim Schreiben mit POKE wird
der zu schreibende Wert einfach, wie bei einer ROM-Speicherzelle, ignoriert.
Doch gehen wir nun einmal zu den Speicherzellen die
wir benutzen DÜRFEN. Die sogenannte Basisadresse des
SID liegt bei Adresse 54272 . Dies ist die erste Speicherzelle des SID. Sie ist deshalb so wichtig, weil
wir sie benutzen wollen, um sogenannte " Register" adressieren zu können. Ein Register ist eine Speicherzelle des SID ( oder eines anderen I/ O-Bausteins) die man mit Hilfe der Basisadresse und der Registernummer anspricht. Hierzu vielleicht ein Beispiel. Mit
dem Befehl:
POKE SI+24,15
setzt man die Lautstärke der erzeugten Töne auf" laut" . Hierbei steht die Variable SI für die Basisadresse des SID, wir haben ihr also vorher den Wert
54272 zugeordnet ! Das Register 24 des SID ist für
die Lautstärke verantwortlich. Schreibt man hier 0 hinein, so wird der Ton gänzlich abgeschaltet. Mit 15 schalten Sie volle Lautstärke ein. Natürlich können
Sie auch alle Werte zwischen 0 und 15 hier benutzen.
Diese sind dann eben je nach dem mehr, oder weniger
laut.
Nachdem Sie nun hoffentlich über die Bedeutung eines
Registers ausfgeklärt sind, möchte ich erst einmal zu
den Grundlagen übergehen. Wie Sie vielleicht wissen
verfügt Ihr 64 er über drei " Stimmen" . Das heißt er
kann 3 verschiedene Töne gleichzeitig gerenerieren.
Deshalb gibt man einer Stimme des SID auch den etwas
päßlicheren Namen " Tongenerator" . Diese sind aufgeteilt in Tongenerator 1,2 und 3 . Jeder dieser Generatoren arbeitet unabhängig von den anderen und kann
eigene Töne erzeugen ohne seine Kollegen damit zu
stören. Sie können jeden einzelnen von Ihnen mit einer bestimmten " Tonhöhe" und einem bestimmten " Klang" programmieren. Damit Sie dies ein wenig besser verstehen, schlage ich vor, daß wir einmal einen kleinen Ausflug in die Physik machen:
Wie Sie vielleicht wissen besteht ein Ton, so wie ihn
das menschliche Ohr hört, aus nichts anderem als einem extrem schnellen Schwingen der Luft. Auch bekannt
unter dem Namen " Schall" . Die Art dieses Tones, warum
sich Töne also voneinander unterscheiden können, wird
von zwei Komponenten bestimmt. Da wäre zum einen die
Wellenform und zum anderen die Frequenz. Die Wellenform gibt an, wie die Schwingungen verlaufen. Diese
lassen sich durch eine Grafiklinie darstellen, häufig
sogar durch eine mathematische Funktion. Ein Beispiel
wäre da sie Sinuskurve. Mit ihr lässt sich eine Sinuswelle erzeugen. Dies klingt dann etwa wie eine
Oboe. Ein weicher und " perfekter" Klang, da die Wellenform ja dem perfektesten geometrischen 2- dimensionalen Körper zugrunde liegt, dem Kreis.
Jedem der 3 Tongeneratoren Ihres C64 können Sie nun
eine eigene Wellenform einprogrammieren, die dann von
diesem erzeugt wird. Eine Sinuskurve kriegt der SID
zwar nicht ganz hin, doch reicht es immerhin zu einer
Dreieckskurve, die der Sinuskurve in Punkto Hochund
Tiefpunkten ja schon sehr ähnlich kommt. Sollten Sie
jetzt hier nur " Bahnhof, Abfahrt und Koffer geklaut"
verstehen, so möchte ich sie mit dem Folgenden
noch ein wenig mehr aufklären. Jede Wellenform kann
nämlich auch mit Hilfe eines Oszillators als Tonwelle
sichtbar gemacht werden. Aus der Schule kennen Sie
bestimmt noch diese Experimente, wo dann auf so einem
kleinen runden Bildschirm eine merkwürdige Kurve erschien, wenn der Lehrer irgend einen Ton von sich gab
( oder mit Hilfe eines Tongenerators erzeugte) .
Der C64 versteht es nun,4 veschiedene solcher Kurven
zu erzeugen, zwischen denen Sie dann auch wählen können, wenn Sie einem Tongenerator eine " persönliche" Note geben möchten. Diese sind die Dreieck-( ich hatte diese Kurve oben schon erwähnt), Rechteck-, und
Sägezahnkurve. Dann gibt es da noch eine Wellenform
die eher eine Sonderstellung einnimmt, die Rauschkurve. Man kann hier eigentlich nicht mehr von einer
Wellenform reden, da das Rauschen nicht nach einer
vorgegebenen Kurve erzeugt wird, sonden von verschiedenen Zufallswerten, die den Abstand zum 0- Wert angeben und einfach nur aneinandergereiht werden. So
entsteht ein Eindruck des Rauschens.
Die Rechteckskurve nimmt ebenfalls eine Sonderstellung ein, was ihre Programmierung betrifft. Dies werde ich ein weinig später erläutern.
Wie man nun dem SID klarmacht, welche der 4 Möglichkeiten man auf einer Stimme spielen möchte, werde ich
Ihnen gleich erklären. Zunächst einmal noch zu der
2 ten Komponente, mit der sie einen Ton beeinflussen
können, der Frequenz. Davon haben Sie sicher auch
schon einmal gehört. Je höher die Frequenz ist, desto
schneller wird die Luft zu Schwingungen angeregt. Es
kommen quasi mehr Dreiecksspitzen einer Dreieckkurve
( beispielsweise) in gleichen Zeitabständen an Ihrem
Ohr an, als bei einer niedrigeren Frequenz. Dadurch
werden die Hörnerven mehr gereizt und es entsteht im
Gehirn der Eindruck eines höheren Tones. Dies kann
bis zum Schmerz gehen, wenn der Ton besonders laut
und intensiv gespielt wird, wie etwa bei einer Sägezahnkurve, oder bei manchen Rechteckkurven ( mit laut
meine ich RICHTIG laut - wenn Sie auf einem Rockkonzert einmal nahe den Boxen standen als der Leadgittarist ein Solo von sich gab, dann wissen Sie was ich
meine) .
Diese Frequenzen kann man nun auch jedem Tongenerator
angeben, so daß dieser dann genau weiß, wie er den
Ton zu gestalten hat. Um beispielsweise den Kammerton
A zu spielen benötigen Sie eine Frequenz von 440 Hz
( Hertz) . Geben Sie diese dem Computer an, so wird er
Ihnen genau diesen Ton vordüdeln. Das hört sich doch
ganz einfach an ! Nun ja, ist es allerdings nicht
unbedingt. Denn Sie können dem SID nicht einfach die
Zahl 440 irgendwo hinschreiben. Dem stehen 2 Dinge im
Weg. Erstens einmal benötigt der SID auch noch weitere Angaben über einen Ton, bevor er richtig " loslegen" kann und zweitens gibt es mit der Frequenzangabe
auch noch einige kleine Probleme, die etwas mit der
Hardware des 64 ers zu tun haben.
Zunächst möchte ich Ihnen eine Übersicht aller SID-Register geben. Anschließend können wir dann richtig
anfangen. Ich muß noch hinzufügen, daß ich die Register 25-28 aus Platzgründen ausgelassen habe. Wir
werden uns mit diesen sowieso nicht befassen, da deren Funktion für uns kaum von Nutzen ist. Nur als
Assemblerroutinen wären diese Register effektiv von
Nutzen, und dann auch nur sehr, sehr selten. Nun aber
zu unsrer Tabelle :
Register Adresse Funktion ––––––––––––––––––––––––––––––––––––––––––––––––––––– 00 54272 Frequenz für Stimme 1 - LO 01 54273 Frequenz für Stimme 1 - HI 02 54274 Pulsbreite für Stimme 1 - LO 03 54275 Pulsbreite für Stimme 1 - HI 04 54276 Ton anschlagen und Wellenform für Stimme 1 05 54277 Hüllkurve ATTACK/DECAY Stimme 1 06 54278 Hüllkurve SUSTAIN/RELEASE Stimme 1 07 54279 Frequenz für Stimme 2 - LO 08 54280 Frequenz für Stimme 2 - HI 09 54281 Pulsbreite für Stimme 2 - LO 10 54282 Pulsbreite für Stimme 2 - HI 11 54283 Ton anschlagen und Wellenform für Stimme 2 12 54284 Hüllkurve ATTACK/DECAY Stimme 2 13 54285 Hüllkurve SUSTAIN/RELEASE Stimme 2 14 54286 Frequenz für Stimme 3 - LO 15 54287 Frequenz für Stimme 3 - HI 16 54288 Pulsbreite für Stimme 3 - LO 17 54289 Pulsbreite für Stimme 3 - HI Register Adresse Funktion ––––––––––––––––––––––––––––––––––––––––––––––––––––– 18 54290 Ton anschlagen und Wellenform für Stimme 3 19 54291 Hüllkurve ATTACK/DECAY Stimme 3 20 54292 Hüllkurve SUSTAIN/RELEASE Stimme 3 21 54293 Filter-Grenzfrequenz LO 22 54294 Filter-Grenzfrequenz HI 23 54295 Resonanz und Filterschalter 24 54296 Filtermodus und Lautstärke
Doch nun frisch ans Werk. Wie Sie ja gesehen haben
gibt es hier jeweils 7 Register für jede Stimme. Als
aufmerksamer Leser sind Ihnen hierbei bestimmt für
Stimme 1 die Register 00,01 und 04 aufgefallen. Mit
diesen Registern nämlich können wir unsere Töne
beeinflussen, so wie wir das bisher gelernt haben. In
Register 00 und 01 wird die Frequenz des Tons für
Stimme 1 angegeben und in Register 04 die Wellenform.
Wollen wir nun das Problem lösen, wie wir eine Frequenz, in Hertz gemessen, in diese beiden Register
eingeben. Ich hatte ja schon angedeutet, daß dies
nicht so einfach sein wird.
Ich hole hierzu einmal ein wenig weiter aus. Vielleicht haben Sie ja schon einmal gehört, daß der C64 mit einer bestimmten Taktfequenz " getaktet" ist, so
wie das bei jedem Computer der Fall ist. Ein Mikroprozesor und überhaupt alle logischen Bausteine in
einem Computer brauchen so etwas ganz einfach, damit
die Arbeiten im Computer geregelt und gleichmäßig
ablaufen. Als Herzstück dient hierzu ein Quarzbaustein, der eine bestimmte Taktfrequenz vorgibt. Alle
Bausteine greifen sich nun den Takt von diesem Quarz
ab und modulieren ihn meistens auf eine eigene Frequenz, mit der sie besser arbeiten können. Der Mikroprozessor in Ihrem C64 arbeitet zum Beispiel mit einer Taktfrequenz von 985 .2484 KHz. Dies ist genau der
18 Teil der Systemtaktfrequenz, die vom Quarz
herrührt. Diese beträgt demnach 17734472 Hz. Also
knapp 17 .7 MHz. Der SID benutzt nun ebenfalls diese
Frequenz. Um nun aus internen Gründen des Aufbaus des
SID auf den richtigen Wert zu kommen, mit dem dieser
dann die echte Tonfrequenz spielt muß man vorher noch
eine kleine Umrechnung vornehmen. Diese folgt der
folgenden Formel :
WERT= Tonfrequenz *2'24/ Taktfrequenz
Möchten Sie also den Kammerton A, mit 440 Hz, spielen, so müssen Sie erst den SID-Wert hierfür berechnen. Dies sieht dann so aus :
440Hz * 2'24 / 17734472 = 416.25
Lassen wir nun noch die Stellen hinter dem Komma wegfallen, so erhalten wir den Wert 416 . Genau diesen
Wert müssen Sie jetzt an den SID übergeben, damit
dieser einen 440 Hz-Ton erzeugt. Hierbei haben wir
allerdings ebenfalls noch ein kleines Problem zu
bewältigen. Wie Sie sich errinnern können wir mit dem
POKE-Befehl lediglich ein Byte verändern, also 8 Bit.
Die größte Zahl, die Sie mit dem POKE-Befehl also
übergeben können ist die Zahl 255(2↑8 Bits -1), die
nun folgende Zahl, die 256 also, hat jetzt schon 9 Bits, da ja ein Überlauf stattfand. Ich zeige Ihnen
das einmal in Form von (16 stelligen) Binärzahlen:
dezimal binär 255 0000 0000 1111 1111 256 0000 0001 0000 0000
Nun ist aber die Zahl 416 größer als 255, somit müssen wir zu einem kleinen Trick greifen um sie zu
übermitteln. Wir schreiben sie einfach mit 16 Bit, da
eine 16- Bit-Zahl maximal den Wert 65535 aufnehmen
kann, was für unsere Zwecke vollkommen reicht. Dies
sieht dann so aus:
416 (dez.) = 0000 0001 1010 0000 (bin.)
Diese 16- Bit spalten wir jetzt ganz einfach in zwei
8- Bit-Zahlen auf. Die Eine nennen wir " höherwertiges
Byte", die Andere " niederwertiges Byte" einer 16- Bit-Zahl. Das sähe dann für 416 etwa folgendermaßen
aus :
416=0000000110100000 Höherwertiges Byte ( die ersten 8 Bits von links) :
0000 0001 = 256 (dez.) Niederwertiges Byte (die nächsten 8 Bits von links) :
10100000=160
Und siehe da, schon hätten wir unsere Zahl in zwei
Bytes zerlegt, die wir nun einzeln, mit Hilfe des
POKE-Befehls, an den SID übergeben können. Dieser
setzt sie dann intern wieder zusammen und erzeugt
dann die Frequenz 440 Hz !
Für diese beiden Frequenzbytes der Stimme 1 sind nun
die Register 00 und 01 zuständig. Oben in der Registertabelle waren deren Funktionen beschrieben mit
" Frequenz für Stimme 1- LO" und " Frequenz für Stimme
1- HI" . Das " LO" und " HI" steht hierbei für " LOw
significant byte" und für " HIgh significant byte" oder höherund niederwertiges Byte. Sie müssen also
den LO-Wert von 416, also 160, in Register 00 POKEn
und den HI-Wert 1 in Register 01 . Dies sieht als
kleines Programm geschreiben dann so aus :
10 SI=54272:REM BASISADRESSE SID 20 POKE SI+0,160 30 POKE SI+1,1
Und schon wäre der Kammerton A programmiert. Um dasselbe bei Stimme 2 tun zu können, müssen Sie die Register 07 und 08 benutzen, bei Stimme 3 Register 14 und 15 .
So, die Frequenz wäre gesetzt, aber hören können Sie
jetzt noch nichts. Wir müssen zuerst ja noch die Wellenform angeben. Nehmen wir hierzu doch einfach einmal eine Dreieckskurve. Was ist nun zu tun, um dies
dem SID klarzumachen ? Hierzu benötigen wir für Stimme 1 das Register 04( analog für Stimme 2 und 3, die
Register 11 und 18) . Dieses Register vereint mehrere
Funktionen in einem. Die einzelnen Bits in diesem
Register haben verschiedene Aufgaben, die erfüllt
werden, wenn man das entspechende Bit auf 1 setzt.
Ich möchte Ihnen die Bitbelegung hier einmal anhand
einer Grafik darstellen :
Die Bits 1,2 und 3 sind für uns unwichtig. Sie aktivieren zu komplexe Funktionen, als daß sie hier in
den Kurs passen würden. Für uns sind eher die Bits
4-7 und Bit 0 wichtig. Wie Sie sehen steht jedes dieser Bits ( außer dem 0 .) für eine bestimmte Wellenform. Wir möchten nun eine Dreieckskurve spielen.
Also setzen wir einfach Bit 4 . Die anderen bleiben
unberührt und haben somit den Wert 0 . Unser Byte sähe
Binär geschrieben dann so aus :
00010000
Das enstpricht der dezimalen Zahl 16( der Wert des 4 .
Bits) . Sollten Sie diese Zahl jetzt in Register 04 schreiben, so wird allerdings immer noch nichts zu
hören sein. Der SID benötigt nämlich noch 2 weitere
Angaben. Zum Einen müssen wir noch die Lautstärke der
vom SID gespielten Musik setzen und zum anderen
braucht dieser auch noch eine sogenannte " Hüllkurve", die etwas über den Verlauf des gespielten Tons angibt. Kommen wir jedoch erst einmal zur Lautstärke.
Diese schalten Sie am besten auf volle Lautstärke.
Wir hatten dies ja oben schon einmal. Sie müssen ein- fach den Wert 15( Maximalwert) in das Lautstärkeregister 24 schreiben. Also :
POKE SI+24,15
So. Nun machen wir uns einmal an die Hüllkurve heran.
Physikalisch haben wir den Ton ja nun schon festgelegt. Wir können jetzt allerdings noch seinen
Lautstärkeverlauf, WÄHREND er gespielt wird bestimmen, eben mit Hilfe der oben genannten Hüllkurve.
Diese besteht aus 4 Phasen. Diese heißen " Attack-"," Decay-", Sustain-" und " Releasephase" und werden in
der eben angezeigten Reihenfolge vom SID durchgegangen. Wozu nun das ganze ?
Wie Sie ja vielleicht wissen ist nicht jeder Ton, der
die gleiche Frequenz hat, allerdings von 2 verschiedenen Instrumenten gespielt wird, vom Klang her
gleich. Eine Oboe zum Beispiel hört sich " weicher" an
als ein Glockenspiel, obwohl die Wellenformen einander sehr ähnlich sind. Das Glockenspiel wird " härter" gespielt als die Oboe. Das heißt, daß beim Anschlagen
einer Metalleiste des Glockenspiels der Ton die meisten Schwingungen erzeugt und somit am lautesten klingt. Im Gegensatz zur Oboe, bei der die hindurchgeblasene Luft erst einmal einen Ton erzeugen und
quasi " in Schwingung" gebracht werden muß. Ein anderes Beispiel wäre eine Klaviersaite. Schlagen Sie
eine Taste auf der Klaviatur an, so wird der Ton anfangs am lautesten sein und nach und nach abklingen.
Dies kann manchmal bis zu 50 Sekunden dauern, wobei
die Oboe kaum mehr als 0 .5 Sekunden braucht. Sie sehen also, daß ein Ton einen sogenannten Lautstärkeverlauf bestitzt. Genau diesen Verlauf beschreibt
eben die Hüllkurve. Wie Sie in der obigen SID-Tabelle
sahen sind die Hüllkurvenregister für den ersten Tongenerator die Register 05 und 06 . In ihnen werden die
Werte für die 4 Hüllkurvenphasen gespeichert. Da wir
4 Werte haben, allerdings nur 2 Register, wird dies
so gehandhabt, daß jedes Register in zwei 4- Bit-Bereiche aufgeteilt wird. So, daß die vier " höherwertigen" Bits eine, und die vier " niederwertigen" Bits
eine andere Phase darstellen. Diese sind folgendermaßen verteilt :
Register Bits 4-7 (HI) Bits 0-3 (LO) –––––––––––––––––––––––––––––––––––––––– 05 Attack Decay 06 Sustain Release
Somit sind Werte von 0-15 für jede Phase möglich
(2↑4-1) . Wollen wir nun klären, welche Aufgaben die
einzelnen Phasen haben :
1.) Die Attackphase:
Mit ihr kann die Zeit angegeben werden, in der ein
Ton von Lautstärke 0 auf die in Register 24 angegebene Lautstärke ansteigt, wobei bei dem Wert 0 diese am
schnellsten, und beim Wert 15 am langsamsten erreicht
wird. Hier eine Tabelle mit den genauen Werten :
WERT ZEIT (in Sekunden) ‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾ 0 0.002 1 0.008 2 0.016 3 0.024 4 0.038 5 0.056 6 0.068 7 0.080 8 0.100 9 0.250 10 0.500 11 0.800 12 1.000 13 3.000 14 5.000 15 8.000
2.) Die Decayphase :
Diese Phase gibt an, in welcher Zeit der soeben in
der Attackphase erreichte Wert der Lautstärke, auf
den Lautstärkewert absinkt, der als Sustainwert angegeben wird.
3.) Sustain-spanne :
Hier wird ein Wert zwischen 0 und 15 angegeben, der
die Endlautstärke nach ablauf der Decay-Phase angibt.
4.) Releasephase :
Wird ein Ton abgeschaltet ( dazu kommen wir gleich
noch) dann wird unverzüglich die Releasephase eingeleitet. Sie gibt an in welcher Zeit der Ton von der
Sustainlautstärke wieder auf 0 absinkt.
Die Zeitwerte für die Decayund Releasephase können
Sie der folgenden Tabelle entnehmen :
WERT ZEIT (in Sekunden) ‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾ 0 0.008 1 0.024 2 0.048 3 0.072 4 0.114 5 0.168 6 0.204 7 0.240 8 0.300 9 0.750 10 1.500 11 2.400 12 3.000 13 9.000 14 15.000 15 24.000
Angenommen, wir wollten ein Glockenspiel mit dem SID
simulieren, dann bräuchten wir einen Ton der schnell
auf voller Lautstärke steht und dann auch relativ
schnell wieder abklingt. Wählen wir also folgende
Werte für die einzelnen Phasen :
Attack - 00 Decay - 07 Sustain - 09 Release - 01
Die 2 Bytes für die Hüllkuve müßten dann folgendermaßen aussehen :
1.) 0000 0111 A=0 S=7 2.) 1001 0001 S=9 R=1
Nun müssen Sie diese Bytes also nur noch ins dezimale
System umrechnen und in die Register 05 und 06 poken.
Die Werte wären demnach 7 und 145 . Zugegebenermaßen
ist dies eine ein wenig mühselige Arbeit, wenn man
nicht gerade über einen Taschenrechner verfügt, der
das Binärsystem beherrscht. Deshalb kann das auch ein
wenig einfacher gehandhabt werden. Denn ebenso, wie
man HIund LO-Bytes bilden kann, lassen sich auch
" HIund LO-Halb- Bytes" bilden. Diese heißen dann
" Nibble" . Nun müssen Sie nur noch nach einem bestimmten Schema die verschiedenen Werte miteinander zu
multiplizieren ( der Umgekehrte Weg der Zerlegung in
LOund HI-Byte) . Nämlich nach der Formel :
HI-Nibble *16+ LO-Nibble
In unserem Fall hätten wir dann folgende Berechnungen
durchzuführen :
Attackund Decay-Byte :0*16+7=7 Sustainund Release-Byte :9*16+1=145
Und schon wären wir am Ziel. Nun gilt es nur noch die
Werte im SID zu setzen, also :
POKE SI+5,7 POKE SI+6,145
Das wäre geschafft ! Doch - oh Enttäuschung - es
kommt immer noch nichts aus dem Lautsprecher ! ! ! Keine Panik, das ist ganz normal so, denn wir haben noch
eine weitere Operation durchzuführen. Der SID weiß
jetzt zwar welche Frequenz er zu spielen hat, was für
eine Wellenform er unserem Ton geben soll, und welchen Klangverlauf dieser haben soll, damit er aber
nun endlich die Hüllkurve abspielt, muß man ihm auch
noch mitteilen, wann er dies zu tun hat. Wir müssen
ihm also quasi ein " Startzeichen" geben, daß er die
Attackphase einleiten darf. Dies geschieht mit Hilfe des 0 . Bits aus Register 04( ich hatte es vorhin
schon einmal erwähnt, siehe auch Grafik) . Erst wenn
dieses Bit gesetzt wird, beginnt er nämlich die Attackphase einzuleiten. Wir müssen somit also zu dem
Wellenform-Wert 16 für die Dreieckskurve auch noch
eine 1 addieren, damit dies der Fall ist (1 ist die
Wertigkeit des 0 . Bits) . Schreiben Sie also nun folgenden Befehl :
POKE SI+4,17
Nun kommt er endlich aus dem Lautsprecher, unser lang
erwarteter Ton. Lange hat es gedauert, doch schließlich und endlich haben wir es doch noch geschafft!
Wie Sie jetzt allerdings schnell merken werden, hört
er gar nicht mehr auf zu spielen, sondern brummt munter weiter. Das war allerdings gar nicht der Effekt, den wir erzielen wollten. Der Ton sollte doch eigentlich wieder in der Releasephase abklingen ! Der Grund
hierfür liegt darin, daß die Releasephase noch gar
nicht eingeleitet wurde ! Dies geschieht nämlich
erst, wenn das 0 . Bit in Register 04 wieder auf 0 gesetzt wird. Bitte, probieren Sie - diesmal kommt also nur 16 in dieses Register, da wir ja die
Dreieckswellenform ja noch beibehalten möchten, also :
POKE SI+4,16
Und schon hört der Krach auf. Dies ist ein Punkt den
Sie beim Soundprogrammieren genauestens beachten
sollten. Die Zeit, in der der Ton auf der Sustain-Lautstärke gehalten wird, bestimmen Sie als Programmierer, nicht der SID. Sie müssen ihn erst " von Hand" wieder abschalten. Praktisch läßt sich das etwa mit
einer Verzögerungsschleife realisieren.
Sie programmieren einfach eine Schleife, in der der
Computer zwar mit dem Abarbeiten der Schleife
beschäftigt ist, jedoch nichts tut. Es fehlt ganz
einfach der Schleifenrumpf. Hier ein Beispiel :
FOR I=1 TO 100 : NEXT
Sie sehen, die Schleife zählt ganz still und heimlich
bis 100 . Effektiv tut der Computer jedoch nichts. So
können wir das Programm mit Scheinberechnungen quasi" anhalten", damit der SID auch genug Zeit hat, die
ersten 3 Phasen auch durchzuspielen. Am besten sehen
Sie sich einmal das Programm " MINISOUNDDEMO" auf der
Rückseite der MagicDisk einmal an. Hier habe ich alle
notwendigen Befehle noch einmal zusammengerafft, damit Sie auch ein kleines praktisches Beispiel haben.
Nun will ich Ihnen noch erklären welch eine Besonderheit die Rechteckskurve auf sich hat, und wofür die
Register 02 und 03 benutzt werden. In diesen beiden
Registern können Sie nämlich die Pulsbreite der Rechteckskurve für Stimme 1 angeben. Wie Sie oben in der
Wellenformgrafik gesehen haben, wird der Abstand, der
zwischen den beiden Punkten liegt, an dem die Rechteckskurve von ihrem Tiefstpunkt zu ihrem Höchstpunkt
" springt" in der sogenannten " Pulsbreite" angegeben.
Sie können in diesen beiden Registern also ganz einfach den Abstand dieser beiden Rechtecksseiten angeben. Dadurch können Sie den Klang der Rechteckskurve
noch einmal drastisch verändern. Mit niedrigen Pulsbreiten gespielt hört sich diese Welle sehr " krächzend" an, fast schon wie ein " Sägezahn" . Je größer die Abstände werden, desto weicher und voller wird
der Klang. Hier liegt es an Ihnen, die einzelnen
Zustände einmal durchzuprobieren. Es sei nur noch
gesagt, daß hier mit einem 12- Bit-Wert gearbeitet
wird. Das heißt, daß die Bits 4-7 von Register 03 KEINE Auswirkung auf die Pulsbreite haben. Der maximale Pulsbreitenwert liegt somit bei 2↑12-1, also
4095 . Probieren Sie einfach einmal ein wenig herum, denn, wie heißt es so schön :" Nur die Übung macht
den Meister." Wie Sie dies handhaben, sollten Sie ja
mittlerweile wissen, ich hatte Ihnen die Problematik
von HI-LO- Byte oben ja schon erklärt. Sie müssen
hier nur darauf achten, daß Sie im Register 04 auch
die Rechteckwellenform einschalten, und daß das HI-Nibble ( Bits 4-7) der Pulsbreite immer 0 ist.
Im übrigen sei noch erwähnt, daß Sie alle hier genannten Vorgänge mit Registern usw. natürlich ebenfalls an den Stimmen 2 und 3 durchführen können. Sie
müssen nur in der Registertabelle nach dem entspechenden Äquivalent des Registers für die entspechende
Stimme suchen. Sie werden merken, daß diese alle in
der gleichen Reihenfolge für die einzelnen Stimmen angeordnet sind. Im übrigen sind die meisten Register
des SID nicht auslesbar ( bis auf die der 3 . Stimme) .
Es passiert also dasselbe, wie wenn Sie auf eine der
oben erwähnten I/ O-Adressen zugreifen. . .
Ich möchte mich nun bis nächsten Monat wieder verabschieden, wenn wir uns dann ein wenig mit der Datenspeicherung und der Peripherie des 64 ers beschäftigen
werden. Sie werden dann auch gleich noch den noch
fehlenden Befehlssatz von BASIC 2 .0 kennenlernen.
Ich bedanke mich nun für Ihre Aufmerksamkeit und wünsche ein fröhliches SID-Gedüdels, bis in einem Monat,
Ihr Uli Basters. BASIC-Kurs:"Von Adam und Eva" (Teil 7) --------------------------------------
Hallöchen da draußen ! Weiter gehts in unserem Basickurs. Nachdem wir nun auch
schon ein bißchen Musik machen können
mit unserem 64 er, wollen wir uns in diesem Monat einmal um die Dateiverwaltung
und die Programmierung der Floppy kümmern. Gleichzeitig lernen Sie dann auch
noch etwas über das Ansteuern eines
Druckers, da diese beiden Themen nämlich
sehr nahe beieinander liegen und die
Programmierung von BASIC aus sogar
( fast) gleich ist. Man braucht halt nur
noch ein paar Backgroundinformationen zu
den einzelnen Geräten. Begeben wir uns
nun also in die Außenwelt unseres C64 in
die Welt der Peripherie. . .
Beginnen wir mit der Floppy. Die Befehle
LOAD und SAVE brauche ich Ihnen ja
bestimmt nicht mehr zu erklären. Wenn
Sie die nicht kennen würden, würden Sie ja diesen Kurs gar nicht lesen können.
Zu LOAD bleibt nur zu sagen, daß es 2 Arten gibt, diesen Befehl zu benutzen:
Die eine Möglichkeit kennen Sie bestimmt. Nachdem Sie ein BASIC-Programm
mit dem Befehl SAVE" PROGRAMM",8 gespeichert hatten, konnten Sie es immer
wieder mit LOAD" PROGRAMM",8 in den
Basicspeicher Ihres 64 ers laden. Wie
ich schon im 5 . Teil dieses Kurses
erwähnte, ist das der Bereich von 2048 bis 40960 . Ein BASIC-Programm wird also
immer an die Adresse 2048 und folgende
geladen. Wenn Sie allerdings einmal ein
Maschinenprogramm haben, das an eine
andere Speicheradresse geladen werden
soll, so müssen Sie LOAD folgendermaßen
benutzen :
LOAD"PROGRAMM",8,1
Wir haben also an das ",8" noch ein ",1" angehängt. Dieser Appendix teilt LOAD
mit, daß nun an eine absolute Adresse geladen wird. Das heißt, an eine Adresse
die in dem File schon angegeben wird.
Dies kann von Nutzen sein, wenn wir zum
Beispiel Grafikdaten an eine bestimmte
Adresse im Speicher laden wollen. Ich
werde in dem diesem Kurs anschließenden
Grafikkurs hierauf noch einmal näher
eingehen.
Im übrigen gibt es auch noch einen weiteren Befehl, der mit LOAD nahe verwandt
ist. Ich spreche von dem VERIFY-Befehl.
Diesen benutzen Sie ebenso wie LOAD, nämlich:
VERIFY"PROGRAMM",8
Dieser ist nur in Verbindung von BASIC-Programmen sinnvoll, daher auch kein
",1" am Ende.
VERIFY macht nun nichts anderes als ein
Programm auf der Diskette mit dem sich
im Speicher befindlichen BASIC-Programm
zu vergleichen. Sie können hiermit also
prüfen, ob auf der Diskette eine andere Version des Programms vorliegt. Sollte
das der Fall sein, so meldet sich VERIFY
mit " VERIFY ERROR ?" zurück.
Andernfalls schreibt es einfach nur ein
" OK" auf den Bildschirm. Das Programm im
Speicher, ebenso wie das auf der Diskette, bleiben jedoch komplett erhalten.
Es wird somit also NICHTS an den Programmen verändert!
So. Nach diesem kleinen " Vorgeplänkel" wollen wir uns nun um die " seriösen" Anwendungen in BASIC zusammen mit der
Floppy kümmern. Es besteht nämlich auch
die Möglichkeit, Daten, wie zum Beispiel
Variablen, DIREKT in ein File zu schreiben und sie hieraus wieder auszulesen.
Dies ist sehr sinnvoll, wenn man eine
Anwendung schreiben möchte, die irgendwelche Werte zwischenspeichern soll, oder wenn Sie bei einem Spiel die Highscoreliste der Nachwelt erhalten möchten.
Damit wir dieses Problem jedoch richtig angehen können, muß ich erst etwas weiter ausholen und Sie einmal über die
Ein-/ Ausgabe in BASIC aufklären.
Alle Geräte, die an Ihrem 64 er hängen, haben, wie Sie vielleicht wissen, eigene
Gerätenummern. Die Floppy zum Beipsiel
die 8, wie man das am LOAD-Befehl sehen
kann. Das ",8" gibt ihm nämlich an, daß
er von der Floppy laden soll. Wollten
Sie von der Datasette laden ( heutzutage
nur noch von wenigen benutzt), so müßten
Sie dies mit einem ",1" kenntlich machen
( also LOAD" PROGRAMM",1) . Hier einmal eine Liste aller möglichen Gerätenummern:
Nummer Gerät
0 Tastatur 1 Datasette 2 RS232 - Serielle Schnittstele am User- Port für Datenfernübertragung (DFÜ) 3 Bildschirm 4 Drucker 1 5 Drucker 2 (am Drucker selbst einstell- bar) 8 Diskettenlaufwerk 0 (normal) 9,10,11 Weitere Diskettenlaufwerke
Der C64 ist nun so ausgelegt, daß man
ihm zuerst einmal sagen muß, mit welchem
der oben erwähnten Geräte man arbeiten
möchte. Dies geschieht in BASIC mit dem
OPEN-Befehl. OPEN ist englisch und heißt
" Öffne" . Es heißt nämlich auch, man
" öffnet" einen sogenannten Filekanal für
ein Gerät.
Damit man nun mit mehreren Geräten
gleichzeitig arbeiten kann, ohne hierbei
jedesmal den Kanal wieder neu öffnen zu
müssen, kann man jeden Filekanal mit einer eigenen Nummer zwischen 1 und 127 versehen, die dann quasi als Kennung
dient, wenn man auf einen Kanal zugreift. Tun Sie dies, so weiß unser C64 gleich, mit welchem Gerät er zu kommunizieren hat und handhabt dies dann auch
entspechend, da alle Geräte ja in einer
besonderen Art und Weise " bedient" sein wollen. Diese Filenummern muß man also
ebenfalls dem OPEN-Befehl mit auf den
Weg geben, damit er die Gerätenummer
auch der richtigen ( Erkennungs-) Filenummer zuordnet. Bei einem Drucker zum
Beispiel ( mit der Geräteadresse 4) sähe
das dann etwa folgendermaßen aus:
OPEN 1,4
Schon hätten wir einen Filekanal für den
Drucker eröffnet, an den wir nun Daten
senden könnten. Hierzu wird dann eine
kleine Abwandlung unseres mittlerweile
altbekannten PRINT-Befehls benutzt - der
PRINT#- Befehl. Das Doppelkreuz (#) hier
ist sehr wichtig, da BASIC sonst die
beiden Befehle ja nicht auseinanderhalten könnte - PRINT ohne "#" gibt ja
ausschließlich auf den Bilschirm aus.
Daß PRINT " drucke" heißt, wissen Sie
mittlerweile ja auch schon. Das
Doppelkreuz ist eine im englischen
allgemein bekannte Abkürzung für" Nummer" . Die komlette Übersetzung von
PRINT# wäre demnach also " Drucke auf
Nummer" . Diese Nummer wird nun
anschließend angegeben und stellt die
oben erwähnte Filenummer dar. Um nun
also Daten an den Drucker zu senden
müßten wir, nachdem wir den oben
erwähnten OPEN-Befehl durchgeführt
haben, folgendes schreiben:
PRINT#1," Das ist eine Datenausgabe"
Hier haben wir einmal eine Zeichenkette, wie auch bei PRINT durch Gänsefüßchen
eingeklammert, ausgegeben. Ebenso können
Sie hier jedoch auch mit Variablen arbeiten, etwa so:
PRINT#1,a$ PRINT#1,x PRINT#1,z%
Beim Zugriff auf die Floppy ist diese
Vorgehenweise nun genau dieselbe. Wir müssen zuerst einen Kanal öffnen und
können anschließend mit PRINT# Daten
übergeben. Allerdings müssen wir hier
wieder ein wenig unterscheiden, denn die
Floppy kann nämlich in zwei Richtungen
bedient werden; zum einen " Daten
schreiben", hierzu benutzt man dann
PRINT#, und zum anderen " Daten Lesen" .
Da brauchen wir dann einen neuen Befehl, doch hierzu später. Zuerst einmal müssen
wir einen Filekanal für die Floppy öffnen. Dies ist leider nicht mehr ganz so
einfach wie beim Drucker ( daher auch zuerst das Beispiel mit selbigem), denn
der OPEN-Befehl verlangt für die Floppy
mehr Parameter als nur Fileund Gerätenummer. Da wäre nämlich zunächst einmal
noch die sogenannte " Sekundäradresse" und dann noch ein entsprechender Filename, damit das Laufwerk auch weiß, mit
welchem File wir arbeiten wollen.
Kommen wir zunächst einmal zur Sekundäradresse. Diese gibt an, auf welche Art
und Weise wir Daten verarbeiten möchten.
Sie wird in Form einen Zahl angegeben
und bezeichnet damit vorher vereinbarte
Funktionen. Die Floppy akzeptiert insgesamt 16 Sekundäradressen, die folgende
Funktionen belegen:
Sekundäradresse Funktion
0 Daten Lesen (LOAD) 1 Daten Schreiben (SAVE) 2-14 Daten Lesen ODER schreiben 15 Sek.adresse für Befehlskanal
Für uns sind im Augenblick nur die Nummern von 2 bis 14 wichtig, die anderen
werde ich Ihnen später erklären.
Zuerst muß ich Sie noch ein wenig über
die verschiedenen Filearten der Floppy
auflären. Es gibt derer fünf, von denen
wir allerdings nur 2 benutzen werden.
Jede der verschiedenen Arten wird in der
Fileliste einer Diskette, dem sogenannten Directory ( LOAD"$",8), mit einem
kleinen Kürzel versehen, so daß man er- kennt, welche Fileart man vor sich hat.
Programme haben zum Beispiel immer das
Kürzel " PRG" . Das kennen Sie ja bestimmt
aus vielen Directories. Hier nun eine
Liste aller weiteren Filearten:
1 .) PRG - PRoGramm. Diese Fileart ist
eigens für Programme reserviet. Die
Datenbytes, die an die Floppy gesandt werden, werden in sequentieller
Reihenfolge, also ein Byte nach dem
anderen, gespeichert. Das PRG-Kürzel
gibt an, daß man das Programm mit
LOAD in den Speicher des 64 ers
laden kann. Alle Programme, die Sie
mit SAVE abspeichern, erhalten
ebenfalls dieses Filekürzel zur
Erkennung.
2 .) SEQ - SEQuenz. Diese Fileart wird
genauso wie PRG gehandhabt. Die
Daten folgen also Byte für Byte auf
der Diskette, mit dem einzigen
Unterschied, daß Sie diese Daten
NICHT mit LOAD laden können. Es ist quasi ein Erkennungszeichen für
Datenfiles von Programmen, aus denen
auf diese Files zugegriffen wird.
3 .) REL - RELatives File. Relative Files
sind Files, in denen bestimmte
Datenblöcke, sogenannte " Records", gespeichert sind. Duch Angabe einer
Recordnummer wird NUR dieser Record
geladen, und nicht das ganze File.
Reltive Files werden auch " Files mit
Wahlfreiem Zugriff genannt" und sind
sehr häufig bei Dateiverwaltungsprogrammen zu finden, da durch
diese Fileart schnell auf einen
bestimmten Datensatz zugegriffen
werden kann, ohne gleich die ganze
Datei zu durchforsten. Leider ist
sie nicht sehr einfach in BASIC zu
Programmieren, weshalb wir sie an
dieser Stelle auch nicht behandeln
werden.
4 .) DEL - DELeted. Files mit diesem
Kürzel sehen Sie in der Regel NIE, da diese Fileart lediglich für floppyinterne Anwendungen reserviert
ist. Sie gibt an, daß ihr File
gelöscht wurde, daß also die von ihm
belegten Datenblöcke auf der
Diskette wieder benutzt werden
können.
5 .) USR - USeR File. Der Aufbau ist
derselbe wie bei PRG und SEQ. USR
gibt lediglich an, daß das hierin
gespeicherte Programm NUR von der
Floppy ausführbar ist, also für uns
uninteressant.
Wir wollen uns hier nur mit den ersten
beiden Arten beschäftigen. Zunächst
einmal die SEQuenz-Dateien. Wie Sie oben
ja schon lesen konnten ist diese Fileart
für Daten im Allgemeinen reserviert. Daß
wir das mit den Filearten zuerst noch
klären mußten ist deshalb wichtig, da
diese Angabe beim OPEN-Befehl ebenfalls
mitangegeben werden muß. Dies geschieht
zusammen mit dem Filenamen. Hier einmal
ein Beispiel, damit Sie wissen wie das öffnen eines Kanals für die Floppy
aussieht:
OPEN 1,8,2,"HIGHSCORE,S,W"
Dabei ist:
1 - die Filenummer 8 - die Geräteadresse (Floppy) 2 - die Sekundäradresse HIGHSCORE - der eigentliche Filename S - die Fileart W - die Betriebsart
Sie sehen also, zuerst kommen die uns
bisher schon bekannten Parameter dran, also Filenummer und Geräteadresse.
Anschließend, mit einem Komma vom Rest
getrennt, folgt die Sekundäradresse, in
unserem Beispiel die 2 . Sie könnten natürlich auch alle anderen Nummern von 2 bis 14 benutzen, dies wäre kein Unterschied. Jetzt jedoch zum Filenamen - nachdem Sie auch diesen mit einem Komma
vom Rest abgehoben haben folgt, in
Gänsefüßchen gesetzt, der eigentliche Filename. Wie Sie jedoch sehen, werden
zusammen mit dem Filenamen noch 2 weitere Parameter übergeben. Da wäre zum
einen die Fileart, markiert durch den
Buchstaben " S" und zum anderen die
Betriebsart, hier in unserem Beispiel
durch den Buchstaben " W" dargestellt.
Beide Parameter werden wieder mit
Kommata vom Filenamen abgetrennt, wobei
allerdings zu beachten ist, daß beide
sich zusammen mit dem eigentlichen
Filenamen in dem Filename-String
befinden, so daß die Parameter NAME, FILEund BETRIEBSART" alle in EIN
Gänsefüßchenpaar gefaßt sind.
Wie Sie vielleicht schon erraten haben, bezeichet das " S" die Fileart SEQenz.
Wir haben hier also ein sequentielles
File geöffnet. Bei einem Programmfile
hätten wir hier ein " P" einsetzen
müssen. Nun zur Betriebsartkennung. Der
Buchstabe " W" im Beispiel oben steht für
" Write", zu Deutsch " Schreibe" . Der
Kanal wurde also zum Schreiben geöffnet.
Die Floppy erwartet nun, daß Daten an
sie gesandt werden, die sie dann auf die
Diskette in das angegebene File
schreibt. Für uns heißt das nun, daß wir
mit Hile von PRINT# jetzt Daten auf den
Kanal 1 schicken können und diese auf
Diskette gespeichert werden. Senden wir
doch einfach einmal etwas an die Floppy:
na$="Fritz Meier" sc=100000 PRINT#1,"Highscoreliste" PRINT#1,pl$ PRINT#1,sc
Hier haben wir nun den Highscore von
Fritz Meier abgespeichert, der sich
auf 100000 Punkte beläuft, indem wir
die verschiedenen Werte erst einmal in
Variablen definierten und anschließend
nacheinander ( sequentiell !) an die
Floppy gesendet haben. Sie hätten
natürlich die Daten auch dirket
schreiben können, wobei der String na$
in Gänsefüßchen hätte stehen müssen und
die Zahl ohne, so wie das bei dem String
" HIGHSCRORELISTE" zu sehen ist. Wichtig
ist, daß Sie jedes einzelne Datum mit
einem EINZIGEN PRINT#- Befehl senden, und
nicht etwa von Kommata getrennt - wie
man das vielleicht nach der
Parametertrennung bei OPEN denken
könnte. Diese Kommatrennung ist zwar
auch möglich, doch bewirkt Sie hier
etwas anderes, wozu ich später kommen
werde. Außerdem könnten Sie mit Kommatrennung später die Daten nicht mehr so
einfach einlesen, doch hierzu ebenfalls
später mehr.
Unsere Daten wären jetzt also an die
Floppy geschickt und somit gespeichert.
Den Filekanal brauchen wir jetzt nicht
mehr. Deshalb müssen wir ihn zuerst noch
wieder schließen, bevor wir fortfahren.
Dies ist sehr sehr wichtig, da wir somit
nicht nur den Computer entlasten, weil
der sich jetzt auch nicht mehr den Kanal
" merken" muß, der mit der Floppy zu tun hat, sondern durch ein Schließen des
Kanals veranlassen wir gleichzeitig auch
die Floppy das File komplett und richtig
auf der Diskette anzulegen. Das heißt, daß sie jetzt auch den Eintrag in der
Fileliste der Diskette machen und diesem
Eintrag auch die entspechenden Daten
zuweisen kann. Das Schließen eines Kanals wird in BASIC mit dem Befehl CLOSE
durchgeführt. Als Parameter benötigt
CLOSE lediglich die Filenummer, in
unserem Fall also die 1 :
CLOSE 1
Nun haben wir also das File komplett
angelegt. Schauen Sie doch einfach
einmal ins Directory - hier sehen Sie
nun ein weiteres File, das etwa so aussieht:
1" HIGHSCORE" SEQ
Der CLOSE-Befehl muß übrigens ebenfalls beim Drucker, wie auch bei allen Geräten
bei denen Sie vorher einen Filekanal mit
OPEN öffneten, angewandt werden. Ich
hatte dies vorhin nur nicht erwähnt, da
es mir zunächst einmal um die Funktion
von OPEN ging.
Um die Fortsetzung dieses Kurses zu lesen, wählen Sie bitte den zweiten Teil
des Basic-Kurses an.
Jetzt wollen wir aber einmal versuchen, unsere gespeicherten Daten wieder einzulesen. Dies geschieht in etwa nach dem
selben Schema. Zuerst müssen wir einen
Kanal öffnen:
OPEN 1,8,2,"HIGHSCORE,S,R"
Wie Sie sehen, sieht dieser OPEN-Befehl
fast genauso aus wie der obige. Ich habe
hier also dieselben Parameter benutzt, bis auf den Kennungsbuchstaben der
Betriebsart. Hier haben wir jetzt ein
" R" was einen weiteren Modus umschreibt, nämlich " Read" für " Lese" .
Wir haben also wieder ein sequentielles
File geöffnet mit der Filenummer 1, der
Geräteadresse 8, der Sekundäradresse 2 und dem Namen " HIGHSCORE", diesmal
allerdings zum Lesen, denn wir wollen ja
unsere gespeicherten Daten wieder
zurückholen. Dies geschieht mit einem
neuen Befehl, einer kleinen Abwandlung
von INPUT, dem INPUT#- Befehl. Wie Sie sehen ist auch hier einfach nur ein
Doppelkreuz angehängt worden. Die
Eingabe ist nun ja denkbar einfach. Wir
müssen nach INPUT# nur noch die
Filenummer unseres Kanal angeben und
anschließend, durch Komma getrennt, die
Variable, der das einzulesende Datum
zugewiesen werden soll, also:
INPUT#1,x$ INPUT#1,na$ INPUT#1,sc
In " X$" hätten wir nun den String
" Highscoreliste" gespeichert und in
" NA$" den vorhin gepeicherten Namen
" Fritz Meier" . In " SC" steht jetzt
100000, die Punktzahl von Fritz Meier.
Sie können diese Daten nun also wieder
weiterverarbeiten. Übrigens sollte ich
hier vielleicht erwähnen, daß der
INPUT#- Befehl, ebenso wie INPUT, NICHT
im Direktmodus anwendbar ist. Sie können
ihn also ausschließlich NUR in Programmen anwenden. Auch sollten Sie
den dazugehörigen OPEN-Befehl in diesem
Programm aufführen, und nicht etwa im
Direktmodus das File öffnen und
anschließend ein Programm mit den obigen
INPUT#- Anweisungen starten, da RUN
leider die Merktabellen, die sich der
64 er intern über alle geöffneten
Filenummern anlegt, wieder löscht. Die
Floppy bekommt jedoch davon nichts mit, so daß für sie der Kanal noch offen ist, für den Computer ist er allerdings
geschlossen. Sie können sich vielleicht
vorstellen, was für ein Chaos hierbei
entstehen könnte. . . In solchen Fällen
hift es dann immer, einmal kurz die
Diskette aus dem Laufwerk zu holen, da
die Floppy dann den Kanal ebenfalls
( zumindest intern) schließt. Die Daten
können dabei allerdings verloren
gehen.
Nachdem wir nun unsere Daten wieder
eingelesen haben, müssen wir den Lesekanal natürlich wieder mit CLOSE
schließen, also:
CLOSE 1
Nun sollten sie mit SEQ-Files ja bestens
umgehen können, was laden und speichern
zumindest angehen. Die Floppy kennt
jetzt allerdings noch eine weitere
Betriebsart. Außer " Read" und " Write" gibt es nämlich auch noch " Append" . Das
ist englisch und heißt soviel wie
" hinzuoder anfügen" . Mit diesem Modus
können Sie also an eine schon früher
erstellte Datei weitere Daten anhängen.
Angenommen, Sie wollten vielleicht einen
weiteren Highscore abspeichern, dann
bräuchten Sie nur einen Floppykanal in
der Betriebsart " Append" zu öffnen. Für
" Append" kennt die Floppy das " A"- Kürzel, also:
OPEN 1,8,2,"HIGHSCORE,S,A"
Jetzt können Sie mit Hilfe von PRINT# weitere Daten an das alte File anhängen, nach " Fritz Meier" und 100000 könnten
wir nun also auch z. B." Heinz Müller" und 99999 an die Floppy schicken. Bei
einem erneuten Einlesen der Datei müßten
wir dann noch einmal gesondert alle
Daten von vorne bis hinten auslesen.
Kommen wir nun zur Fileart PRG. Wie ich
oben ja schon erwähnte, ist diese
Fileart nur für Programme reserviert.
Trotzdem kann man sie von BASIC aus
ansprechen und auch Daten in PRG-Files
speichern. Dies wird ebenso gehandhabt
wie mit SEQ, da PRG-Files, physisch
gesehen, also im Aufbau auf der
Diskette, ebenso angelegt werden, wie
SEQ-Files. Der Zugriff auf ein PRG-File
ist somit haargenau derselbe, mit dem
einzigen Unterschied, daß jetzt an den
Filenamen angehängt nicht mehr ein " S" als Parameter für die Fileart, sondern
ein " P" für PRG steht. Der OPEN-Befehl für ein PRG-File sähe also folgendermaßen aus:
OPEN 1,8,2,"DATEI,P,R" zum Lesen, oder OPEN 1,8,2,"DATEI,P,W" zum Schreiben.
Ansonsten können Sie ebenso verfahen als
hätten Sie ein SEQ-File geöffnet. Eines
gibt es allerdings schon noch hierzu zu
sagen. Der OPEN-Befehl hat für PRG-Files
nämlich noch zwei kleine Sonderheiten
eingebaut. Bei den Sekundäradressen
hatte ich ja schon einmal angegeben, daß
die Adressen 0 und 1 jeweils eine Sonderstellung einnehmen.
Diese lassen sich jetzt sehr einfach
erklären, nachdem wir uns mit der
Materie der Betriebsart eines Files
schon ein wenig beschäftigt haben. Mit
der Sekundäradresse 0 können Sie der
Floppy nämlich schon gleich angeben, daß
Sie ein READ-File ( also ein File aus dem
Sie lesen) öffnen möchten.
Gleichzeitig geht diese dann auch davon aus, daß es sich hierbei um ein PRG-File
handelt, Sie können damit also die
Angabe der Fileund Betriebsart im
Filenamen wegfallen lassen. Etwa ähnlich
verhält es sich mit der Sekundäradresse
1 . Sie gibt an, daß Sie Daten schreiben
möchten, ebenfalls in ein PRG-File.
Somit ergeben sich dann also folgende
Vereinfachungen des OPEN-Befehls für
PRG-Files:
OPEN 1,8,0,"DATEI" zum Lesen, und OPEN 1,8,1,"DATEI" zum Schreiben.
Wenn Sie allerdings ein PRG-File öffnen, um beispielsweise ein richtiges
BASIC-Programm daraus auszulesen, aus
welchen Gründen auch immer, so werden
Sie mit INPUT# nicht viel Glück haben.
INPUT# verläßt sich nämlich darauf, daß
Sie vorher alle Ihre Daten mit PRINT# eingegeben haben, wobei Sie für jedes
Datenelement einen eigenen PRINT#- Befehl
benutzten. PRINT# arbeitet nämlich eben- so wie PRINT, wenn man keinen weiteren
Parameter hinter dem Befehl angibt. Es
macht einen sogenannten " Wagenrücklauf
mit Zeilenvorschub" . Oder auch " Carriage
Return" genannt. In der Praxis wird bei
diesem Wagenrücklauf nichts anderes
getan, als daß der Cursor lediglich eine
Zeile tiefer, in die erste Spalte dieser Zeile befördert wird, und daß eine
weitere Ausgabe auf dem Bildschirm an
dieser Stelle dann ausgeführt wird.
Der Wagenrücklauf hat auch einen eigenen ASCII-Code ( er ist eines der
Steuerzeichen, die eine besondere
Funktion erfüllen, wie ich bei den
ASCII-Zeichen erwähnte), die 13 nämlich.
Mit einem PRINT CHR$(13) erzwingen Sie
also einen solchen Wagenrücklauf.
Probieren Sie das doch einfach einmal
mit folgendem Programm aus:
10 PRINT"DAS IST ZEILE 1";CHR$(13) 20 PRINT"DAS IST ZEILE 2"
Sie sehen, zwischen den beiden Zeilen
ist nun eine Leerzeile, was ja ohne
CHR$(13) nicht wäre. Der PRINT#- Befehl
sendet nun ebenfalls ein CHR$(13) an die
Floppy, nachdem er seine Daten
übertragen hat. Beispielsweise die
einzelnen ASCII-Code- Bytes der
Buchstaben einer String-Variable. INPUT# erkennt nun an diesem Wagenrücklauf, daß
hier das Ende des Strings erreicht ist
und beendet seine Eingabe. Alle Zeichen, die vor dem Carriage Return kamen werden
nun der Variablen zugeordnet, die am
Ende von INPUT# steht, jedoch ohne
dabei das CHR$(13) mit anzuhängen. Es
dient also lediglich als Trennmarke, nicht aber als Datenelement. Das hat
aber auch einen entscheidenden Nachteil - sollten Sie einmal in die
Verlegenheit kommen, einen Wagenrücklauf
mitabzuspeichern, oder sollten Sie nicht
wissen, ob der Wagenrücklauf überhaupt
in einem File ( z. B. ein PRG-File mit
einem BASIC-Programm) existiert, so sollten Sie die Alternative zu INPUT# benutzen, den Befehl GET# . Wie Sie sehen
haben wir auch hier ein Doppelkreuz, das
für Filenummer steht, das Befehlswort
selbst kann man etwa mit " Hole" übersetzen. Der 64 er soll sich also ein
Byte von dem Kanal mit der Filenummer, die hinter dem "#" angegeben wird, holen. Dies geschieht wie bei INPUT#, namlich folgendermaßen:
GET#1, A$
Hiermit hätten wir der Variablen " A$" jetzt ein Byte vom Filekanal 1 zugewiesen. Dieses können wir jetzt weiterverarbeiten. Entweder Sie geben es
gleich mit PRINT aus, etwa so:
PRINT A$ ;
Oder Sie schauen sich an, ob wir hier
überhaupt ein druckbares ASCII-Zeichen
vorliegen haben, oder ob es sich hierbei nicht doch um ein Sonderzeichen handelt, indem Sie sich einfach den ASCII-Code
des Bytes ausgeben lassen. Etwa so:
A=ASC(A$) IF A=13 THEN PRINT "DAS IST EIN CARRIAGE RETURN." IF A=19 THEN PRINT "DAS IST DAS 'HOME'-ZEICHEN."
oder einfach :
PRINT ASC( A$)
Allerdings gibt es hier noch ein kleines
Problem. Da wir ja ein sequentielles
File auslesen und bei diesem ein Byte
nach dem anderen folgt, wird mit ziemlicher Sicherheit auch irgendwann einmal
das letzte Byte über den Kanal gewandert
kommen und anschließend ist dann nix
mehr los mit Bytes auslesen. Trotzdem
aber holt sich GET# immer noch
irgendwelche nicht existenten Bytes vom Kanal und übergibt diese an unser
Programm, was ja nun nicht unbedingt
sein soll. Hier hilft dann eine
Sondervariable des 64 ers. Ich spreche
von der Statusvariablen " ST" . Diesen
Variablennamen dürfen Sie in Ihren
Programmen übrigens NIE benutzen, da
diese Variable halt für den eben
genannten Zweck reserviert ist. BASIC
stellt in dieser Variablen nämlich immer
den sogenannten Status des Diskettenkanals bereit. Wie Sie sehen ist " ST" ja eine numerische Variable, also
liefert sie einen Zahlenwert zurück.
Sollten Sie nun bei einer Abfrage von
ST einmal feststellen, daß Sie den Wert
64 beinhaltet, so sind Sie am Ende eines
Diskettenfiles angelangt.
Bei allen anderen Zahlen ist dies nicht der Fall. Das Durchlesen eines Files sähe also so aus:
10 OPEN 1,8,0,"PROGRAMM" 20 GET#1,A$ 30 PRINT A$ 40 IF ST<>64 THEN 100 50 CLOSE 1
" ST" dürfen Sie natürlich auch benutzen, wenn Sie mit INPUT# auslesen. Dies wäre
sogar nur sinnvoll und wünschenswert, wenn Sie flexibel arbeiten möchten.
Aus Platzmagel muß ich nun leider die
heutige Folge dieses Kurses abschließen.
Nächsten Monat werden wir dann mit einem
neuen Hauptprogramm hier in der MD
aufwarten können, durch das ich wieder
mehr Platz haben werde ihnen die Sprache
BASIC näherzubringen. Ich werde nächsten
Monat dann das Thema Floppy noch beenden und Sie über die noch fehlenden
Befehle von BASIC V2 .0 aufklären. Dann
müßten wir eigentlich mit allem durch
sein, und Sie sollten das Grundzeug zu
einem guten BASIC-Programmierer besitzen. Doch noch sind wir nicht ganz so
weit, deshalb verabschiede ich mich jetzt bis nächsten Monat, Ihr
Uli Basters. Basickurs:"Von Adam und Eva..."(Teil 8) ---------------------------------------
Willkommen zum 8 . Teil unseres Basickurses. Ich werde Ihnen heute noch ein
klein Wenig über die Floppy erzählen und
die etwas kleineren Befehle und Funktionen von BASIC 2 .0 erwähnen.
Wie Sie sich vielleicht erinnern hatten
wir letzten Monat etwas über Sequenzund Programmfiles gehört. Hierbei lernten wir die Befehle OPEN, CLOSE, PRINT#, INPUT# und GET# kennen. Zum Schluß
erklärte ich Ihnen noch die Bedeutung
der Statusvariablen ST.
Es gibt jetzt noch ein paar Dinge über
ST zu sagen, die ich Ihnen letzte Woche
verschwiegen hatte. Wie ich ja damals
schon erwähnte, kann man durch den Wert
64 in ST feststellen, daß man am Ende
eines Files angelangt ist, doch ST ist
noch für 3 weitere Zwecke zu gebrauchen.
Hier eine kleine Übersicht:
Wert Bedeutung
-------------- 64 Fileende erreicht 66 Über das Fileende herausgelesen 1 Fehler beim Schreiben 128 Floppy nicht angschlossen
Die 64 kennen wir ja. Sobald wir das
letzte Byte gelesen hatten, stand diese
Zahl in ST. Sollten wir jetzt, aus welchem Grund auch immer, noch ein weiteres
Byte auslesen wollen, so werden wir ein
falsches, da nichtexistentes Datenbyte
zurückerhalten. Nach diesem Lesevorgang
meldet ST den Wert 66, was heißt, das
wir versucht haben, ein Byte aus einem
mittlerweile schon bis zum Ende gelesenen File auszulesen. Sollte also einmal
ein solcher Fehler auftreten, so werden
Sie wissen, woran es liegt.
Als nächstes gibt es da noch die 1 als
Wert für ST. Sollten Sie diesen Wert
einmal zurückbekommen, so bedeutet das, daß beim Schreiben in eine Write-Datei
ein Fehler aufgetreten ist.
Zum Beispiel, wenn die Diskette voll ist.
Das wäre dann ein " DISK FULL"- Error. In
In diesem Fall ist es dann sinnvoll, den
Fehlerkanal der Floppy abzufragen, was
ich Ihnen gleich noch erklären werde.
Zunächst noch zu dem 4 . Fall für ST, der
Wert 128 . Er gibt an, daß die Floppy, die angesprochen werden sollte, nicht
angeschlossen beziehungsweise ausgeschaltet ist. Doch gibt es da noch ein
kleines Problem. Sollte nämlich ein solcher Fehler einmal auftreten, so wird
der 64 er das momentan laufende Programm
sofort abbrechen und einen " DEVICE NOT - PRESENT"- Error auf dem Bildschirm ausgeben. Das ist ja nicht unbedingt im Sinne
eines komfortablen Programms, außerdem
erhalten wir somit noch nicht einmal die
Gelegenheit, uns einmal den Inhalt von
ST anzuschauen, da der C64 hier schneller reagiert und VOR einer eventuellen
Abfrage abbricht. Doch es gibt eine Möglichkeit, diesen kleinen Nachteil zu umgehen. Wie wir ja im 5 . Teil gelernt
haben, kann man mit dem POKE-Befehl Bytes im Speicher unseres C64 verändern.
Damals hatte ich den Bereich von Speicherzelle 0 bis 1024 als wenig interessant für uns erklärt, da dort hauptsächlich Speicherzellen untergebracht sind, die für interne Arbeiten im 64 er reserviert sind. Doch hier und da bieten sich
in diesem Speicherbereich schon noch ein
paar sinnvolle Anwendungen. In unserem
Beispiel wäre da die Speicherzelle 768 .
Ändert man nämlich den Inhalt dieser
Speicherzelle in den Wert 61 um, so wird
jegliche Ausgabe von Fehlermeldungen
ganz einfach unterdrückt. Dies ist in
unserem Fall ganz interessant, zumal wir
die Meldung von " DEVICE NOT PRESENT" ja
gar nicht gebrauchen können.
Wir können diese Abfrage ja auch selbst über ST vornehmen. Nachdem wir dies dann
jedoch taten, sollten wir unsere Fehlermeldungsausgabesperre jedoch wieder zurücknehmen, da ja auch noch ganz andere Fehler auftreten könnten, zum Beispiel
ein " SYNTAX ERROR" . Das Programm würde
in diesem Fall versuchen weiterzuarbeiten und das könnte verheerende Folgen
haben. Rückgängig machen wir unsere
Sperre mit dem Befehl " POKE768,139" .
Jetzt ist wieder alles beim Alten und
Fehler brechen das Programm wieder wie
gewohnt ab und drucken ihren entsprechenden Text dann auch aus. Hier noch
ein kleines Beispiel zur Abfrage, ob die
Floppy angeschlossen ist:
10 POKE 768,61 :REM FEHLER SPERREN 20 OPEN 1,8,15 :REM FLOPPY ANSPRECHEN 30 CLOSE 1 :REM KANAL WIEDER ZU 40 POKE 768,139:REM FEHLER ZULASSEN 50 IF ST=128 THEN PRINT "FLOPPY IST NICH T ANGESCHLOSSEN !"
Nun möchte ich Ihnen noch ein wenig den
Sinn und die Bedeutung des Befehlskanals
der Floppy näherbringen. Letzten Monat
hatte ich Ihnen ja schon erzählt, daß
dieser Kanal eine Sonderstellung einnimmt, weshalb er auch eine eigene Sekundäradresse, nämlich die 15, besitzt
( siehe auch Tabelle von letztem Monat) .
Über jenen Befehlskanal kann man nun
kleine Befehle an die Floppy senden, die
diese zu bestimmten Operationen veranlaßt, wie zum Beispiel das Löschen eines
Files, oder das Formatieren einer Disk.
Letzteres möchte ich hier einmal anhand
eines Beispiels erläutern. Wie Sie ja
vielleicht wissen, muß man eine Diskette, bevor man sie mit Daten beschreiben
kann," formatieren", das heißt, man gibt
der Floppy den Befehl die Diskette quasi
zu " ordnen", da sich die Magnetspuren
auf ihr, wenn sie ganz frisch als Leerdiskette aus der Fabrik kommt, noch in
einem undefinierten Zustand befinden.
Man muß sie durch das " Formatieren" also
in einen definierten Zustand bringen, so
daß Daten auf sie geschrieben werden
können. Dies ist von Computer zu Computer verschieden, der C64 beziehungsweise die Diskettenlaufwerke desselben, benutzen ein eigenes Format, MS-DOS- Rechner, sei das ein XT oder AT benutzen
wiederum ein anderes, weshalb eine Diskette für jeden Rechnertyp eigens formatiert werden muß.
Bei der C64- Floppy ( normalerweise die
1541, es gibt jedoch auch noch andere, zum Beispiel die 1571, die auch für den
C128 benutzbar ist) geschieht dies durch
den Befehlskanal. Hierzu müssen wir diesen erst einmal öffnen. Zu diesem Zweck
brauchen wir natürlich erst eine Filenummer, dann die Geräteadresse ( in unserem Fall die 8- jedoch können Sie durch
die Geräteadressen von 9-11 auch andere Zusatzlaufwerke ansprechen) und
schließlich und endlich die Sekundäradresse, die für den Befehlskanal immer15 ist. Filenamen oder ähnlichs brauchen
wir zunächst einmal nicht, also öffnen
wir den Kanal mit:
OPEN 1,8,15
Nun, da er geöffnet ist, können wir über
diesen Kanal eine Vielzahl von Befehlen, mit Hilfe von PRINT#, an die Floppy
schicken, die diese dann ausführen wird, wobei wir uns dann nicht mehr darum kümmern müssen. Ich hatte ja angedeutet, daß ich dies anhand eines Format-Befehls
einmal demonstrieren wollte. Beim Formatieren ist noch zu beachten, daß wir der
Floppy einen Diskettennamen und ein
2 stelliges Identifikationskürzel mit auf
den Weg geben. Diese sogenannte " ID" ist
quasi ein Erkennungszeichen für die
Floppy, damit sie verschiedene Disketten
voneinander unterscheiden kann. Der Diskettenname an sich darf maximal 16 Zeichen lang sein, beide Parameter werden, ähnlich wie bei OPEN durch ein Komma getrennt, an die Floppy übergeben. Hier
also einmal ein PRINT#- Befehl, der die
Floppy eine Diskette formatieren läßt, mit dem Namen " NEUE DISKETTE" und der
ID-Kennung " MD" :
PRINT#1,"N:NEUE DISKETTE,MD"
Unter der Vorraussetzung, daß wir den
Befehlskanal vorher mit der Filenummer 1 geöffnet hatten und daß Sie auch eine
Diskette eingelegt hatten, beginnt nun
die Floppy, die Diskette zu formatieren.
Doch VORSICHT, vergewissern Sie sich, daß Sie auf jeden Fall eine Diskette
eingelegt haben, die KEINE, beziehungsweise, für Sie UNBRAUCHBARE Daten
enthält ! ! ! Jegliche Art von Daten auf
dieser Diskette wird nämlich mit dem
Format-Befehl UNWIDERRUFLICH gelöscht!
Nicht also, daß Sie sich versehentlich
diese Ausgabe der MD löschen, wir übernehmen für eine solche Fehlbehandlung
keine Haftung und auch keine Garantie!
Wenn Sie sichergehen möchten, daß eine
Ihrer Disketten nicht durch einen zufälligen Irrtum gelöscht wird, so kleben
Sie doch einfach einen kleinen Schreibschutzstreifen auf die Schreibschutzkerbe dieser Diskette. Dann wird nämlich
bei einem vermeindlichen Format-Befehl
abgebrochen. Diese Kerbe finden Sie, wenn Sie die Diskette von vorne betrachten, an der rechten Seite, ich meine den
etwa 7-8 mm langen und 4 mm breiten viereckigen Einschnitt.
Sollte nun mit der eingelegten Diskette
alles in Ordnung und der Schreibschutz
an ihr auch nicht vorhanden sein, so
werden Sie feststellen, daß die Floppy
nun läuft und munter diese Diskette
formatiert. Gleichzeitig blinkt auch
noch der Cursor bei unserem 64 er, wenn
Sie obigen PRINT#- Befehl im Direktmodus
eingaben. Für uns heißt das, daß die
Floppy nun eigenständig arbeitet und wir
mit dem 64 er weiterarbeiten können, ohne
uns an dem Formatiervorgang zu stören.
Dies ist jedoch nur so lange der Fall, bis wir einen weiteren Befehl an die
Floppy senden, dann wartet der 64 er
nämlich intern auf ein " OK" von der
Floppy, daß diese mit dem Formatiervorgang fertig ist. Dann erst schickt er
den nächsten Befehl nach. Da der CLOSE-Befehl ebenfalls die Aufmersamkeit der
Floppy beansprucht ist dies bei ihm genauso der Fall. Schließen wir also den
Befehlskanal jetzt wieder mit " CLOSE 1", so müssen wir warten, bis das Formatieren beendet ist. Im Programm ist das
eigentlich ganz brauchbar, da es sonst
vielleicht ein paar Probleme geben könnte mit der Koordinierung der Operationen
von Floppy und Rechner.
Ihnen ist bestimmt oben in dem PRINT#- Befehl aufgefallen, daß ich vor den Diskettennamen und der ID noch den Prefix
" N:" gesetzt hatte. Das war das Erkennungszeichen für die Floppy, daß es sich bei diesem Befehl um einen Formatbefehl
handelt. Das " N" steht nämlich für
" NEW", was soviel bedeutet, wie " NEUanlegen der Diskette" . Logisch, die übersetzung, nicht wahr? Auf diese Weise
können auch noch andere Befehlskürzel an
die Floppy gesandt werden, die dann auch
andere Aufgaben erfüllen. Jeder Befehlsbuchstabe wird grundsätzlich mit einem
Doppelpunkt (" :") von den Parameterangaben getrennt. Im Folgenden möchte ich
Ihnen noch die 3 wichtigsten, da für uns
als Basicprogrammierer am sinnvollsten, Floppybefehle erklären.
Der Scratch-Befehl "S" :
Mit dem " S"- Befehl können Sie die Floppy
dazu veranlassen ein oder mehrere Files
auf der eingelegten Diskette zu löschen.
" Scratch" heißt nämlich soviel wie
" kratzen", und somit geht es hier um das
sinnbildliche " wegkratzen" eines Files
von der Oberfläche der Diskette.
Der Scratchbefehl wird folgendermaßen
benutzt :
PRINT#1,"S:FILENAME1,FILENAME2,FILENAME3 ,...,FILENAME n"
Sie können also beliebig viele Filenamen
anhängen, jeweils durch Kommata getrennt, die dann gelöscht werden. Das
Ganze steht natürlich wieder in Anführungsstrichen, da dies der PRINT#- Befehl
ja so verlangt. Möchten Sie nur EIN File
löschen so gehen Sie analog vor, lassen
Sie jedoch das Komma am Ende des Filenamens weg und schließen Sie den Befehl
gleich mit einem Gänsefüßchen ab.
Der Rename-Befehl "R" :
Mit diesem Befehl können Sie ein schon
vorhandenes File auf der Diskette mit
einem neuen Namen versehen." Rename" bedeutet nämlich nichts anderes als " umbenennen" .
Dies funktioniert folgendermaßen:
PRINT#1,"R:NEUER NAME=ALTER NAME"
Sie geben nach dem " R:"- Prefix also einfach den Namen an, den das File von nun
an haben soll. Anschließend geben Sie
mit Hilfe eines "="- Zeichens an, daß das
File mit dem nun folgenden Namen umbenannt werden soll.
Der COPY-Befehl "C" :
Mit diesem Befehl können Sie 2 oder mehrere SEQuentielle Files auf der Diskette
zu EINEM File, von ebenfalls sequentieller Art, zusammenkopieren. Dies geschieht so:
PRINT#1,"C:NEUER NAME=ALT1,ALT2,ALT3,... ,ALT n"
Sie geben also einfach den neuen Filenamen an, den die zusammenkopierten Files
haben sollen und schreiben, nachdem Sie
ein "=" eingefügt haben, die Files die
zusammenkommen, durch Kommata getrennt
hintereinander auf. In dem neuen File
werden dann die alten Files in der von
Ihnen vorgegebenen Reihenfolge stehen.
Soviel zu den einzelnen Befehlen. Nun
möchte ich Ihnen noch etwas über den
Fehlerkanal erzählen. Wie ich oben schon
erwähnt hatte, kann die Statusvariable
ST ja auch den Wert 1 annehmen. Das
heißt, daß ein Fehler beim Schreiben
aufgetreten ist. Ich hatte da ja schon
angedeutet, daß man anschließend einmal
den sogenannten " Fehlerkanal" auslesen
sollte, um festzustellen, welcher Fehler
im Einzelnen aufgetreten ist. Dieser
Fehlerkanal wird ebenfalls über den Befehlskanal der Floppy angesprochen. Fehlermeldungen sind übrigens die einzigen
Daten, die man vom Befehlskanal LESEN kann, ansonsten wird nur dorthin GE-SCHRIEBEN. Aus diesem Grund weiß die
Floppy direkt, daß sie, falls gelesen
wird, die aktuelle Fehlermeldung senden
soll. Diese besteht aus insgesamt 4 Teilen und sieht etwa folgendermaßen aus:
FNR,NAME,SPUR,SEKTOR
Die Abkürzungen bedeuten :
FNR : Dies ist die Fehlernummer. Je- der Floppyfehler hat eine be- stimmte Nummer, mit der man ihn identifizieren kann. Eine Auf- listung dieser Fehler, ihrer Nummern und ihrer Bedeutung, finden Sie im Anhang des Floppyhandbuchs. NAME : Dies ist eine kleine Kurzbe- schreibung des Fehlers. Wenn Sie zum Beispiel auf eine schon randvolle Diskette (0 BLOCKS FREE) zu schreiben versuchen, so kommt hier die Meldung "DISK FULL" von der Floppy. TRACK : Die Tracknummer, auf der der Fehler auftrat. Was ein Track ist, paßt nicht unbedingt in den Rahmen dieses Kurses und soll an anderer Stelle genauer erklärt werden. SEKTOR : Die Sektornummer des Tracks auf dem der Fehler auftrat. Auch dies gehört nicht hier hinein, weshalb wir es ebenfalls aus- lassen werden.
Wie Sie sehen, haben wir hier drei numerische Werte ( FNR, TRACK, SEKTOR) und einen Stringwert ( NAME) . Um nun die Fehlermeldung auszulesen, müssen wir
zunächst wie gewohnt, den Befehlskanal
mit OPEN öffnen. Anschlißend müssen die
einzelnen Parameter mit INPUT# ganz einfach ausgelesen werden, dies geschieht
denkbar einfach, nämlich mit Hilfe
dreier numerischer und einer $- variable.
INPUT#1, NR,NA$,SP,SE
Nun können wir die eben geholte Fehlermeldung ausdrucken :
PRINT NR;NA$;SP;SE
Sollten Sie zum Beispiel versucht haben, ein File zu laden, daß auf der Diskette
gar nicht existiert, so haben Sie nun
folgendes auf dem Bildschirm stehen:
62 FILE NOT FOUND 0 0
Wir sollten übrigens auch nicht vergessen, den Fehlerkanal wieder zu schließen. Hier noch einmal das komplette Programm, das Sie übrigens auch auf der
Rückseite dieser Ausgabe der MAGIC DISK
64 finden werden ( unter dem Namen " FEH-LERKANAL") :
10 OPEN 1,8,15 20 INPUT#1,NR,NA$,SP,SE 30 CLOSE 1 40 PRINT NR;NA$;SP;SE
Wenn übrigens gar kein Fehler vorliegt
( rote LED der Floppy blinkt NICHT) dann
werden Sie folgende Meldung erhalten:
0 OK 00
Als Nächstes möchte ich Ihnen noch einen
kleinen Befehl zeigen, der ebenfalls
etwas mit der Datenausgabe zu tun hat.
Er wird hauptsächlich in Zusammenhang
mit einem Drucker benutzt, kann aber
auch für andere Geräte angewandt werden.
Ich spreche von dem sogenannten CMD-Befehl. Mit CMD können Sie alle Ausgaben, die sonst auf den Bildschirm gemacht werden, auf einen logischen Filekanal leiten, den Sie vorher natürlich
mit OPEN geöffnet hatten.
Angenommen, Sie wollten ein Programm auf
dem Drucker ausgeben, dann müßten Sie
lediglich folgendes eingeben :
OPEN 1,4:CMD 1 LIST
Wir öffnen hier also einen Filekanal mit
der Filenummer 1 und der Geräteadresse 4 für den Drucker. Anschlißend geben wir
dem C64 bekannt, daß alle Ausgaben von
nun an auf den Kanal mit der Nummer 1 umgelenkt werden sollen. Wenn Sie nun
LIST eingeben dann erscheint Ihr Programmlisting nicht auf dem Bildschirm, sondern es wird ohne Umwege gleich an
den Drucker geschickt. Auf diese Weise
können Sie beispielsweise in Programmen, die irgendwelche Tabellen auf dem Bildschirm ausdrucken, ganz einfach diesen
Tabellendruck auch auf den Drucker umleiten, indem Sie nämlich VOR der Druckroutine für den Bildschirm einen CMD-Befehl einschieben.
Man könnte dies vielleicht sogar mit
einer IF-THEN- Abfrage lösen, wobei zuerst der Benutzer nach dem Ausgabegerät
gefragt wird und anschließend entschieden wird, ob ein CMD ausgeführt werden
soll oder nicht.
Eine andere Anwendungsweise wäre vielleicht die Möglichkeit, ein Programm in
Form von ASCII-Zeichen in einem File zu
speichern, um es, zum Beispiel mit Hilfe
eines Terminalprogramms, in eine Mailbox
zu schicken. In diesem Fall müßten Sie
nur ein sequentielles File zum Schreiben
öffnen, mit CMD die Ausgabe auf dieses
File umleiten und das Programm dann
LISTen.
Eines wäre jedoch noch zu beachten. Damit Sie nämlich wieder aus dem CMD-Befehl herauskommen, um dann die Ausgabe
wieder auf den Bildschirm zu leiten, müssen Sie einen einfachen PRINT#- Befehl
nachschieben, ohne Parameter, etwa so:
PRINT#1
Wobei hier anstelle der "1" auch jede
andere Zahl stehen könnte, je nachdem, welche Filenummer Sie vorher beim OPEN-Befehl benutzt hatten, auf dessen geöff- neten Kanal Sie dann die Ausgabe umleiteten.
Anschließend sollte man den Kanal auch
noch schließen, also:
CLOSE 1 : REM ( je nach Filenummer)
Damit hätten wir das Thema Peripherie
abgeschlossen. Ich muß Ihnen nun noch
etwas über Variablen erzählen. Wie wir
diese handhaben und vor allem, wie wir
deren Namen wählen, hatten wir ja schon
im 1 . und 2 . Teil dieses Kurses geklärt.
Es gibt allerdings noch eine weitere Art
Variablen zu benutzen, nämlich durch die
Definition von sogenannten Variablenfeldern. Dies klingt vielleicht etwas
merkwürdig, doch werden Sie gleich verstehen, was damit geimeint ist.
Ein Feld, oder eine Fläche, hat ja, wie
Sie vielleicht aus dem Geometrieunterricht noch wissen, zwei Ausdehnungen.
Zum einen die Länge und zum anderen die
Breite. Man sagt auch " ein Feld hat zwei
Dimensionen" . Es ist also ein Objekt der
Zweiten Dimension. Ebenso gibt es eine
Erste Dimension, die alle Strecken beinhaltet. Diese haben nur eine einzige
Ausdehnung, nämlich die Länge.
Diesen Begriff der Dimension kann man
nun auch auf Variablen übertragen. Es
gibt nämlich in BASIC die Möglichkeit, mehrere Variablen mit dem gleichen Namen
anzulegen, die alle jedoch voneinander
unterschieden werden, indem man ihnen
einen sogenannten Index gibt. Das heißt, daß jeder Variable eine bestimmte Zahl
nachgestellt wird, die eine ganz bestimmte Variable darstellt. Anwendungsgebiete gibt es hierfür wie Sand am
Meer. Angenommen, Sie möchten ein Programm schreiben, daß alle Adressen Ihrer
Bekannten und Verwandten speichert. Gehen wir einmal davon aus, daß dies maximal 100 bis 200 an der Zahl sind. Möchten Sie nun alle diese Namen in " norma- len" Variablen speichern, so würden Sie
jedesmal einen neuen Variablennamen heraussuchen müssen, damit BASIC diese
voneinander unterscheiden kann. Stellen
Sie sich einmal das Chaos vor, daß Sie
dann in einem Programm hätten.200 Variablen, von denen Sie nicht mehr genau
wissen was zu wem gehört. Wenn man davon
ausgeht, daß Sie vielleicht zu jedem
Namen auch noch Straße, Hausnummer, Wohnort und Telefonnummer speichern wollen, dann müßte Herr Müller aus der
Bahnhofstaße 37 in 8000 München und
der Telefonnummer 089/12345678 etwa in
folgenden Variablen verteilt werden :
AX$="Herr Mueller" FR$="Bahnhofstraße" KL=37 OG=8000 TA$="Muenchen" XD$="089/12345678"
Sie sehen also, wir haben hier wahllos
verteilte Variablen vor uns, die nichts
über ihren Inhalt aussagen, da jeder nur
erdenkliche Variablenname genutzt werden
muß. Stellen Sie sich doch nur die meterlangen Listings von IF-Abfragen vor, die man machen müßte, um eine ganz bestimmte Adresse herauszufinden. Außerdem
wüßte man noch nicht einmal welche Variablen zu einer Adresse gehören. Deshalb gibt es die Feldvariablen. Sie sollen hier eine Abhilfe schaffen. Auf diese Art und Weise können nämlich beispielsweise alle Namen in einem Variablennamen zusammengeafßt werden, oder
alle Straßennamen, oder alle Städtenamen. . .
Doch wie wirds gemacht? Dazu wollen wir
jetzt kommen. Zuerst müssen wir eine
Variable " dimensionieren" . Im Klartext
heißt das, daß wir einen Namen für
das Variablenfeld und die maximale Anzahl der in ihm zu speichernden Daten, festlegen müssen.
In unserem Fall einer Adressverwaltung
nehmen wir ( beispielsweise) den Variablennamen NA$ für " Name" . Die Dimensionierung wird mit einem eigenen BASIC-Befehl durchgeführt, dem DIM-Befehl. Bei
diesem wird zuerst der Name des Variablenfeldes angegeben und anschließend
seine maximale Ausdehnung. Wir wollen
also 200 Stringvariablen im Feld NA$ speichern. Deshald also diese Anweisung:
DIM NA$(200)
Schon wäre unser Feld dimensioniert. Wir
haben hier ein eindimensionales Feld vor
uns, dem DIM-Befehl wird zuerst der
Feldname und dann die maximale Anzahl
aller Datenelemente, in Klammern gesetzt, nachgestellt. In dem Feld NA$ können wir nun also 200 Variablen unterbringen.
Um jetzt ein einzelnes dieser 200 Datenelemente adressieren zu können, müssen
wir seine Indexnummer, ebenfalls in Klammern gesetzt, einfach dem Feldnamen
nachstellen. Diese Datenelemente eines
Feldes werden übrigens genauso gehandhabt, wie die Variablenart in der sie
dimensioniert wurden. Wir haben hier
einen Stringvariablennamen angegeben, also haben wir auch 200 Stringvariablen
vordefiniert. Demnach sind auch die Zuweisungen ausgelegt. Wie bei Strings
auch geben Sie den obigen " Variablennamen" an und weisen ihm mit Hilfe des
"="- Zeichens eine Zeichenkette zu. Etwa
so:
NA$(0)=" HERR MUELLER"
Hier haben wir dem 0 . Datenelement den
String " Herr Mueller" zugewiesen. Sie
erinnern sich ja : der Computer fängt
immer bei 0 an zu zählen, dementsprechend ist das 0 . Datenelement der erste
Eintrag in unserem Datenfeld. Doch wir
müssen hier keineswegs einer numerischen
Reihenfolge der Variablenzuweisung vor- gehen. Vielmehr können Sie ebenfalls
auch Zuweisungen von Werten bei numerisch größeren Variablen vornehmen. Sie
haben hierbei also freie Hand. Wie wärs, wenn wir " Herrn Schultze" im 134 . Datenelement unterbrächten, kein Problem:
NA$(134)=" SCHULTZE"
Doch die eigentliche Stärke der Feldvariablen liegt nicht darin, daß man sie
in einem Namen zusammenfassen kann, sondern vielmehr, daß man mit Hilfe einer
Schleife gezielt ein Feld nach einem
bestimmten Datensatz durchsuchen kann, ohne dabei großen Programmieraufwand
leisten zu müssen. Angenommen wir wollten Herrn Schultze in unserem Datenfeld
wiederfinden, dann wäre folgendes Programm schnell und einfach geschrieben:
100 FOR I=0 TO 200 110 IF NA$(I)="HERR SCHULTZE" THEN 130 120 NEXT 130 PRINT"HERR SCHULTZE STEHT IM DATENS ATZ NR.";I
Wenn wir nun die anderen Daten ebenfalls
so anlegen, daß wir 200 Datenelemente
darin speichern können und den einzelnen Feldelementen mit dem Index 134 ebenfalls die zu Herrn Schultze gehörigen Daten zuordnen, so können wir ganz
einfach mit Hilfe der Variablen I auf
alle Datenelemente der Adresse von ihm
zugreifen, etwa so:
200 PRINT NA$(I) :REM NAME 210 PRINT SR$(I) :REM STRASSE 220 PRINT NR(I) :REM HAUSNUMMER 230 PRINT PL(I),OR$(I) :REM PLZ UND ORT 240 PRINT TE$(I) :REM TELEFONNUMMER
Und schon wäre die gesamte Adresse von
Herrn Schultze ausgedruckt, da wir ja
vorher die einzelnen Elemente ebenfalls
den Feldelementen mit der Nummer 134 zuweisen wollten. So einfach ist es dann
beispielsweise einen bestimmten Datensatz zu finden. Auch beim Abspeichern
haben wir keine Probleme, wir brauchen
lediglich eine Schleife zu programmieren, die alle Datenelemente des Feldes
von 0 bis 200 in ein WRITE-File
schreibt.
Wie Sie sahen, hatten wir ein eindimensionales Feld dimensioniert. Es hatte
also nur EINE Ausdehnung. Man kann dies
jedoch beliebig erweitern. Wie wäre es
denn mit einem zwei-, drei-, oder gar
vierdimensionalen Feld? Bitte:
DIM A$(1000,10) DIM B%(10,3) DIM C(5,5,5)
Mit diesen Dimensionierungen haben wir
nun also veranlaßt, daß beispielsweise
ein Feld mit dem Namen A$ für 1000 Datenelemente dimensioniert wurde, von denen
jedes einzelne wiederum 10 weitere Datennelemente aufnehmen kann. Diese können Sie dann folgendermaßen ansprechen:
PRINT A$(523,3)
Hier hätten wir das 3 . Datenelement des
523 . Hauptelements von A$ ausgedruckt, dies kann man in beliebig vielen Dimensionen weiterführen, soweit diese sinnvoll sind. Eines sollte ich jedoch noch
sagen: bei einer Dimensionierung von
Variablen reserviert der C64 für jede
einzelne Variable einen bestimmten Speicherbereich. Bei FLOAT-Variablen ist
dies besonders Speicherintensiv. Pro
Variable gehen nämlich 5 Bytes flöten, die nicht mehr für andere Variablen benutzt werden können. Hierbei ist es
übrigens egal, ob diese Variable nun
einen Inhalt hat oder nicht. Man muß
sich also immer ausrechnen, wieviel
Speicherplatz so ein Feld einnimmt, um
nicht in Speichermangel zu kommen, denn
dann bricht der 64 er unweigerlich mit
einem " ? OUT OF MEMORY ERROR" ab. Wollten Sie beispiel ein 6- dimensionales
Feld mit jeweils 4 Datenelementen dimensionieren, so könnten Sie mit dem Speicherplatz knapp werden:
DIM A(3,3,3,3,3,3)
Wenn Sie sich wundern, warum hier immer
3 anstatt 4 steht, wie ich ja eben sagte, so denken Sie bitte daran, daß das
0 . Datenelement ebenfalls mitzählt, also
0,1,2,3= vier Elemente. Oben bei A$ hätte ich auch schreiben sollen, daß wir
dort anstatt 1000 sogar 1001 Elemente, mit 11 anstatt 10 Unterelementen dimensioniert haben, doch habe ich dies zum
besseren Verständnis zu jenem Zeitpunkt
weggelassen.
Wir hätten hier also 4*4*4*4*4*4=4↑6 Variablen dimensioniert, für die alle 5 Bytes Speicherplatz reserviert werden, also 4↑6*5 Bytes oder 4096*5 Bytes =20480 Bytes, das entspricht etwa 2/3 des
gesamten Basicspeichers (38911 Bytes) .
Es ist also keineswegs egal, wieviele
Elemente Sie dimensionieren. Suchen Sie
ein Optimum heraus. Bei Stringund Integervariablen ist der Speicherplatzverbrauch etwas geringer.
Probieren Sie doch einfach einmal aus, wie viel Platz Sie haben.
Kommen wir nun noch zu drei weiteren
kleinen Befehlen, die ich ihnen noch
erklären muß. Da wäre zunächst einmal
der DEF FN-Befehl. Dies ist eigentlich
nichts weiter als eine kleine Programmierhilfe, die man zwar nicht unbedingt
braucht, die jedoch ganz nützlich sein
kann, wenn man strukturiert programmieren möchte. FN ist quasi ein Variablenkürzel für eine vorher definierte
Funktion. Sie müssen an dieses Kürzel
nur noch einen FLOAT-Variablennamen
anhängen ( also einen Variablennamen OHNE
"%" oder "$") . Auf diese Weise können
Sie häufig benutzte Funktionen, zum Beispiel komplexere Rechenformeln vordefinieren, die Sie dann durch einen simplen
und kurzen Aufruf komplett durchrechenen
können. Dies ist rechenzeitund speicherplatzsparend.
Doch hier die Praxis. Zunächst wollen
wir erst einmal eine Funktion vordefinieren, hierzu benutzt man das DEF-Statement:
DEF FNAX(X)=(10/X)*SIN(X)+201
Hier haben wir der FunktioN AX die Formel (10/ X)* SIN( X)+201 zugeordnet. Das
" X" in Klammern der Definition muß immer
mit angehängt werden. Möchten Sie nun
einmal das Ergebnis der Formel ausgedruckt haben, wenn Sie für X beispielsweise den Wert 7 einsetzen, so müssen
Sie dies folgendermaßen tun:
PRINT FNAX(7)
Schon erhalten Sie ein Ergebnis. Die
Möglichkeit eine Funktion zu definieren
eignet sich gut für Kurvendiskussionsprogramme, da Sie bei einer Funktionsberechnung natürlich auch Variablen verwenden können. So zum Beispiel die Lauf- variable einer Schleife, die eine Wertetabelle ausdruckt.
Als Nächstes hätten wir da den WAIT Befehl. Mit ihm können wir den 64 er darauf
warten lassen, daß eine Speicherzelle
einen anderen Wert annimmt. Als Beispiel
nehme ich hierzu einmal die Speicherzelle 198, aus dem oben schon genannten
Speicherbereich für interne Aufgaben
unseres Computers. In dieser Spicherzelle wird nämlich vom Betriebssystem zwischengespeichert, wieviele Tasten schon
vom Benutzer gedrückt wurden, ohne daß
das dazugehörige Zeichen ausgedruckt
wurde. Wenn Sie sich im Direktmodus befinden steht hier nie mehr als der Wert
1 drin, da der 64 er die Tastendrücke
schneller druckt, als Sie sie tippen
können. Doch während eines laufenden
Programms kann diese Zahl auch schon
einmal bis zu 10 ansteigen. Deshalb wollen wir vor der Abfrage dieser Speicherzelle besser eine 0 hineinPOKEn.
Ich möchte Ihnen nämlich nun zeigen, wie
man ganz einfach ein Programm zum Anhalten bringt, so, daß es auf einen
Tastendruck wartet. Hier ein Beispiel:
10 POKE 198,0:WAIT 198,1:POKE 198,0
Hier löschen wir zuerst einmal jeglichen
Inhalt der eben genannten Speicherzelle, um sicherzugehen, daß hier auch wirklich
nichts drinsteht. Mit dem folgenden
WAIT-Befehl warten wir auf das Ereignis, daß eine Taste gedrückt wird, daß also
eine 1 vom Betriebssystem in die Speicherzelle 198 geschrieben wird. Ist dies
der Fall, so fährt der 64 er mit dem Programm fort, wo wir dann gleich noch einmal die Zelle 198 löschen, damit das
eben eingegebene Zeichen nicht doch noch
einmal irgendwann eingelesen werden kann
und irgendwelche, nicht gewollte, Funktionen im Programm verursacht.
Als drittes noch kurz der SYS-Befehl.
Dieser Befehl ist für BASIC-Programmier
eigentlich wenig wichtig. Mit ihm kann
man den 64 er dazu veranlassen die BASIC-Ebene zu verlassen und ein Maschinenprogramm an einer bestimmten Speicheradresse auszuführen. Der Befehl " SYS 49152" zum Beispiel, startet ein Assemblerprogramm, das in Speicherzelle 49152 beginnt. Wenn Sie übrigens mehr über Assembler bzw. Maschinensprache wissen
möchten, so möchte ich an dieser Stelle
darauf hinweisen, daß wir, die Redaktion
der MAGIC DISK 64, planen, etwa Anfang
nächsten Jahres einen Assemblerkurs auf
einer eigenen Diskette quasi als Sonderausgabe, herauszubringen. Wenn es soweit sein wird, werden wir Sie dann auch
auf jeden Fall noch rechtzeitig informieren. Der Kurs wird übrigens ebenfalls
von mir sein, falls Sie also meine Erklärungen für einsichtlich und einfach
halten, so wird diese Diskette ein Muß
für alle angehenden Assemblerprogrammie- rer unter Ihnen sein.
Der letzte Teil des Basickurses sollte
dies sein. Aber das Basic V2 .0 beinhaltet noch ein paar weitere Befehle. Diese
sind besonders bei der Programmierung
der Grafik wichtig, weswegen sie eigentlich im sich anschließenden Grafikkurs
abgehandelt werden sollten.
Da aber zu befürchten ist, daß die eigentliche Beschreibung und Erklärung
dieser Befehle im Rahmen eines Grafikkurses zu kurz gerät, haben wir uns entschlossen, diese letzten Befehle in
einem weiteren, nun aber endgültig letzten Basickursteil abzuhandeln.
Diesen neunten Teil finden Sie in der
Oktoberausgabe der Magic Disk. Im
November werden wir dann aber voll in
die Grafikprogrammierung einsteigen.
Ihr Uli Basters
ASICKurs: "Von Adam und Eva..."(Teil 9)
Hallihallo, da sind wir wieder. Entgegen
allen Gerüchten, die ich das letzte Mal
aufgestellt habe, ist der Basickurs
jetzt doch noch einen Teil länger. Wir
haben uns dazu entschlossen, daß es doch
besser ist, wenn dieser Kurs hier komplett abgeschlossen ist, so daß es keiner langwierigen Erklärungen mehr benötigt, wenn wir uns ab nächten Monat an
die Grafik machen werden.
Heute kommen nun noch die ultimativ
letzten Basicbefehle an die Reihe, mit
denen sich auch noch einiges anfangen
läßt. . .
1.) Die Stringfunktionen :
Wie diese Überschrift schon verrät, bietet uns BASIC V2 .0 eine Fülle von Funktionen, mit denen wir auf einfachste Art
und Weise Stringvariablen verändern und manipulieren können. Was kann man darunter verstehen? Nun, vielleicht ist Ihnen ja schon im letzten Teil aufgefallen, daß ich dort ein sequentielles File
mit dem Befehl :
OPEN 1,8,2,NA$+",S,W"
zum Schreiben geöffnet hatte. Vielleicht
haben Sie sich gefragt, was dieses "+"- Zeichen bewirken soll. Nunja, wie wir
dann ja feststellten, diente es dazu, die beiden Stringketten ( zum einen der
String in NA$ und zum anderen das
", S, W") miteinander zu verknüpfen. Stünde beispielsweise der String " FILENAME" in NA$, so hieße das für den OPEN-Befehl, daß er hier die Gesamtzeichenkette " FILENAME, S, W" vor sich hat. Der
notwendige Appendix ist somit direkt an
den veränderbaren oder variablen Text in
NA$ angehängt worden. Genau dies ist
auch als Variablenzuweisung möglich, wie
es das folgende Programm demonstriert :
10 A$="STRINGS KOENNEN " 20 B$="MIT '+' VERKETTET " 30 C$=A$+B$+"WERDEN!" Nach Ablauf des Programms haben wir nun also in A$ den Text "STRINGS KOENNEN ", in B$ den Text "MIT ↑+↑ VERKETTET " und in C$ "STRINGS KOENNEN MIT '+' VERKET- TET WERDEN!" stehen.
Umgekehrt, beim Zerlegen eines Strings, verhält sich dies allerdings etwas
schwieriger. Sie können hier leider
nicht mit dem Minuszeichen ("-") arbeiten. Dazu haben wir allerdings die
Stringfunktionen LEFT$, RIGHT$ und MID$ zur Verfügung, die sogar noch viel besser arbeiten, als es mit "-" möglich
wäre. Mit Ihnen kann man nämlich einen
String gezielt in Stücke zerhacken, ohne
dabei großen Aufwand zu haben.
Zum einen wäre da LEFT$ . Mit dieser
Funktion können wir einen Teil aus einer Stringvariablen isolieren, der von LINKS
nach RECHTS reicht. Hierzu übergeben wir
LEFT$ ganz einfach den zu bearbeitenden
String und, durch ein Komma voneinander
getrennt, die Anzahl der zu übernehmenden Buchstaben an. Dies geschieht etwa
folgendermaßen :
A$="BASIC IST TOLL" PRINT LEFT$(A$,5)
Nach dieser Befehlssequenz sollten Sie
dann nur die 5 Buchstaben " BASIC" auf
dem Bildschirm stehen haben. Es wurden
also die ersten 5 Buchstaben aus dem
String A$ herausisoliert.
Ebenso verhält es sich nun mit RIGHT$, nur daß nun die Buchstaben von RECHTS
nach LINKS isoliert werden, wobei sie
ihre Reihenfolge jedoch beibehalten, nicht also rückwärts geschrieben sind !
Hier ein Beispiel :
A$="BASIC IST TOLL" PRINT RIGHT$(A$,4)"
Nun erhalten Sie also die 4 letzten
Buchtaben des Strings A$, den Text
" TOLL" .
Wem das noch nicht genügt, der kann auf
MID$ zurückgreifen. MID$ stellt quasi
eine Mischung aus LEFT$( von " Links") und RIGHT$( von " Rechts") dar. Sie können hiermit, wie der Befehl schon sagt, eine Zeichenkette " aus der Mitte" eines
Strings herausisolieren. Hierbei müssen
wir, wie bei den beiden Verwandten von
MID$ auch, erst einmal den zu Untersuchenden Stringnamen angeben, gefolgt von
der Nummer des Buchstabens, von dem an
wir die folgenden Buchstaben übernehmen
möchten, und der Anzahl der Buchstaben, die übernommen werden sollen; alle Parameter jeweils durch Kommata getrennt.
Den Text " IST" aus unserem Beispielstring " BASIC IST TOLL" können wir also folgendermaßen isolieren :
A$="BASIC IST TOLL" PRINT MID$(A$,7,3)
Hier werden also ab dem 7 . Buchstaben
des Strings A$,3 Buchstaben herausisoliert: das Wort " IST" .
Jetzt werden Sie sicher sagen," Na schön
und gut, doch wofür kann man denn so
etwas brauchen ?" Zugegeben, viele Anwendungen finden die Stringfunktionen
vielleicht nicht, doch kann ich Ihnen
ein höchst wichtiges Problem aufzeigen, das geradezu " wie geschaffen" für unser
Thema ist : die Eingaberoutine eines
Textadvetures zum Beispiel.
Wenn Sie diese Art von Spielen kennen, so werden Sie sicher wissen, daß die
Eingaben an das Programm meist mit Hilfe
einer Kommandozeile abgewickelt werden, über die die einzelnen Befehle an das Programm gehen. Sie wissen sicher auch, daß solche Befehle in aller Regel aus
Verben und Objekten bestehen, wie zum
Beispiel " NIMM BUCH" . Hier haben wir
also ein Verb, das angibt WAS getan werden soll und ein Objekt MIT DEM wir etwas tun wollen. Nun gilt es also diesen
Kommandostring in seine einzelnen Unterworte aufzusplitten, damit wir keine
Probleme bei der Erkennung der Worte
bekommen. Wir müssen also in unserem
String nach Leerzeichen suchen, die die
Worte ja voneinander trennen, und bis zu
dieser Stelle ein Wort isolieren. Damit
unser Beispiel nicht komplizierter wird, als es in diesem Rahmen sein soll, setzen wir einmal vorraus, daß nur 2 Worte
in der Eingabe vorkommen, daß also der
Anfang eines Strings, bis zum Leerzeichen, ein Wort bildet, und alles, was
danach folgt, ein weiteres. Erschwerend
kommt noch hinzu, daß wir ja nicht wissen WIE LANG der gesamte Eingabestring
ist. Doch dieses Problem können wir mit Hilfe einer weiteren Stringfunktion lösen, der LEN-Funktion. Diese funktioniert denkbar einfach, wir müssen nämlich lediglich den Namen des zu untersuchenden Strings, in Klammern gesetzt, nach dem Befehlswort LEN angeben. Etwa
so:
10 A$="OEFFNE TRUHE" 20 A=LEN(A$)
Danach steht in A der Wert 12, denn soviele Buchstaben enthält die Variable
A$ . Nun können wir uns um die Analyse
des Strings kümmern. Zunächst einmal
eine Schleife, mit deren Hilfe wir feststellen wollen, an welcher Stelle in
unserem String sich das Leerzeichen befindet. Hierzu bedienen wir uns dann
MID$ . Er holt sich jeweils nur EINEN
Buchstaben aus unserem String, damit wir
prüfen können welches Zeichen wir vor
uns haben :
30 FOR I=1 TO A 40 X$=MID$(A$,I,1) :REM NUR EIN ZEICHEN 50 IF X$<>" "THEN NEXT
Die Schleife holt sich hier also nur
solange Zeichen aus dem String, wie diese ungleich dem Leerzeichen ("") sind.
Ist dies nicht mehr der Fall, so sind
wir an dem Punkt angelangt, wo die Worte
getrennt werden. In der Laufvariable I
ist nun die Stelle des Leerzeichens in
unserem String gespeichert. Wir brauchen
uns die einzelnen Komponenten nur noch
mit Hilfe von LEFT$ und RIGHT$ in eigenen Variablen zuweisen. Hierbei ist noch
zu beachten, daß wir beim ersten Wort
auch das Leerzeichen am Ende mitbekommen
würden, würden wir I so benutzen. Da
dies jedoch nur behindernd ist brauchen
wir also lediglich alle Buchstaben bis
I-1 herauszuisolieren. Bei dem zweiten
Wort müssen wir dann auch erst noch berechnen, wieviele Stellen wir von Rechts
gebrauchen können, das tun wir mit Hilfe der Formel A-I. Das ganze sieht dann
folgendermaßen aus :
60 W1$=LEFT$(A$,I-1) 70 W2$=RIGHT$(A$,A-I) 80 PRINT"DAS ERSTE WORT IST : ";W1$ 90 PRINT"DAS ZWEITE WORT IST : ";W2$
Wir haben also nun ein kleines Anwendungsbeispiel für die bisherigen Stringfunktionen durchgeführt. Nebenbei haben
wir da dann auch noch LEN kennengelernt. BASIC kennt aber noch 4 weitere
Stringfunktionen. Zwei davon kennen wir
bereits, CHR$ und ASC, weshalb ich nicht
mehr auf diese eingehen werde, doch es
gibt noch zwei weitere.
Zum einen wäre da STR$ . STR$ liefert
ganz einfach den String einer numerischen Variablen, so wie sie mit PRINT
ausgedruckt worden wäre. So können Sie
zum Beispiel auf einfache Art und Weise
eine INTEGERoder FLOAT-Variable einer
Stringvariablen zuweisen, wobei der String dann halt die ASCII-Werte der
einzelnen Ziffern enthält. Zum Rechnen
können Sie diesen String natürlich nicht
mehr verwenden, jedoch kann diese Funktion manchmal ganz von nutzen sein. Hier
einmal ein Beispiel :
A=1989 X$=STR$(A):REM IDENTISCH MIT 'X$="1989"'
Hiermit hätten wir also der Stringvariablen X$ den String "1989" zugewiesen und
können diesen nun weiterverarbeiten.
Beispielsweise gibt es da eine Formel
zur Berechnung des Wochentages anhand
des reinen Datums die mit Parametern wie
" Jahrhundert" oder " Jahrzehnt" arbeitet.
Hierzu bietet es sich dann an mit LEFT$ und RIGHT$ eben jene Parameter zu isolieren und mit der nun folgenden Stringfunktion wieder in eine Zahl zurückzuwandeln.
Die Funktion von der ich rede heißt VAL und tut genau das umgekehrte wie STR$ .
Angenommen, wir hätten das Jahrhundert
aus "1989" mittlerweile herausisoliert
und fein säuberlich in der Variablen JH$ gespeichert. Dann könnten wir den String
"19" mit folgendem Befehl ganz einfach
zur Zahl 19 machen:
JH= VAL( JH$)
Das wars schon. Sie können nun wie gewohnt mit JH rechnen, denn dort haben
wir nun tatsächlich den numerischen Wert
19 stehen, und nicht etwa die Zeichenkette "19" .
Soviel zum Thema Stringfunktionen, machen wir nun weiter mit den ominösen
Befehlen, die eigentlich erst im Grafikkurs gekommen wären, ich werde Sie Ihnen
hier jedoch anhand eines anderen Beispiels erläutern:
2.) Datenhandling im Programm :
Bestimmt haben Sie schon einmal ein Basicprogramm aus einer Zeitschrift abgetippt, die NICHT über den Vorteil der
Magic Disk 64 verfügte, daß die Programme zum Heft alle auf einer Diskette mitgeliefert werden. Dabei mußten Sie mit
ziemlicher Sicherheit ( denn dies kommt
häufig vor) auch lange Kolonnen von Zeilen abtippen, in denen am Anfang das
Befehlswort DATA stand, gefolgt von vielen Zahlen, alle durch Kommata voneinander getrennt. Wie dieser Befehl schon
sagt, werden hier DAT( A) enwerte abgelegt. Auf ein Programm selbst hat er
eigentlich wenig Einfluß - er wird ganz
einfach von BASIC überlesen. Nur in Zusammenhang mit einem weiteren Basicbefehl hat DATA überhaupt einen Sinn, ich
spreche von dem READ-Befehl. Im übrigen
könnte dieser ohne DATA auch wenig anrichten, die beiden hängen also fest
zusammen und voneinander ab. READ ist( wie immer) englisch und heißt " LESE" .
Wir können den Computer also hiermit
anweisen ein Datenelement zu LESEN - und
woher nimmt er sich dieses Datenelement? Natürlich von einem DATA-Statement! READ liest nun also das erste Datenelement hinter der ersten DATA-Anweisung im Programm in eine Variable
ein, die wir ihm schlicht und einfach
nachstellen.
Ich gebe zu, daß es langsam vielleicht
etwas langweilig erscheint immer wieder
das Beispiel eines Textadventures durchzukauen, doch paßt dieses Beispiel hier
genau hin und erklärt hoffentlich eindeutig, wozu READ und DATA notwendig
sind.
Also angenommen, Sie wollten ein Textadventure schreiben, das mehrere Verben
und mehrere Objekte ( wie das ja, schon
oben beschrieben, zu JEDEM Textadventure
gehört) verstehen soll. Zuerst haben wir
einmal die Eingabe vom Spieler in seine
Einzelteile zerlegt und in W1$ das Verb und in W2$ das Objekt gespeichert. Nun
geht es darum zuerst einmal das eingegebene Verb zu analysieren und mit dem
Programmwortschatz zu vergleichen. Hierzu benutzen wir ein Variablenfeld ( Sie
erinnern sich an das letzte Mal. . .) in
dem alle Verben gespeichert werden sollen. Damit das bei einem Programm, das
vielleicht 100 Verben verstehen soll
nicht in Arbeit ausartet, wollen wir die
einzelnen Verbdaten mit Hilfe einer
Schleife den Variablen zuordnen. Hierzu
legen wir alle Verben in DATA-Zeilen ab
und lesen sie, eins nach dem anderen, ein und weisen sie somit einer Variablen
in unserem Feld zu. READ liest also immer das nächste Element aus einem DATA-Statement aus, solange bis es nichts
mehr zu lesen gibt. Das sollten Sie wissen, damit READ nicht zuviele Daten einzulesen versucht. Hier einmal ein Beispiel, bei dem ich 7 Verben in dem Variablenfeld VE$( X) speichern möchte. Wie
die Schleife schon zeigt, werden hier auch nur 7 Datenelemente gelesen,(6 Elemente plus das 0 . Element) .
10 DIM VE$(6) 20 FOR I=0 TO 6:READ VE$(I):NEXT 30 DATA NIMM,GIB,OEFFNE,SCHLIESSE,SCHLAG E,DRUECKE,RUFE
Somit hätten wir uns also das mühsehlige
Auflisten von Variablenzuweisungen gespart. Sie müssen doch zugeben, daß folgendes etwas umständlicher wäre :
10 VE$(0)="NIMM" 20 VE$(1)="GIB" 30 VE$(2)="OEFFNE" 40 VE$(3)="SCHLIESSE" und so fort...
Doch nicht genug, in DATA-Statements
kann man nicht nur Strings ablegen, sondern auch INTEGERoder FLOAT-Werte und
das dann noch bunt gemischt:
100 DATA 100,3.14,HALLO,2.689,BASIC,12
Alles worauf wir dann beim Lesen achten
müssen, ist, daß die einzelnen Elemente
auch den entsprchenden Variablentypen
zugeordnet werden. Es ist Ihnen ja mit
Sicherheit klar, daß wir nicht einfach
so einen Text einer INTEGER-Variablen
zuweisen können oder ähnliches.
Allerdings gibt es noch zwei Besonderheiten, die man in Zusammenhang mit DATA
erwähnen muß. Sie werden nämlich ganz
schöne Probleme bekommen, sollten Sie
einmal versuchen, ein Komma (",") in Ihren Strings zu verwenden, die bei DATA
abgelegt sind. Wie wir wissen dient das
Komma ja zur Trennung der einzelnen Elemente, was für den Computer heißt, daß
wir ihm da zwei einzelne Elemente, anstatt nur einem gegeben haben. Machen
Sie also niemals folgenden Fehler:
100 DATA HALLO,IHR!
Hier haben wir nämlich die beiden
Strings " HALLO" und " IHR" abgelegt, anstatt dem eigentlich gewollten Text " HAL-LO, IHR!" In diesem Fall müssen wir den
abzulegenden String dann ganz einfach in
Anführungszeichen setzen, damit er richtig erkannt wird, also :
100 DATA "HALLO,IHR!"
Und schon bekommen wir auch das, was wir
wollen. Es bleibt noch zu erwähnen, daß
dies derselbe Fall bei dem Doppelpunkt
(" :") und bei Leerzeichen ("") der Fall
ist. Sollten Sie also einmal in einem
Stringelement ein Komma, einen Doppelpunkt oder ein Leerzeichen enthalten
haben, so müssen Sie dieses Element UN-BEDINGT in Gänsefüßchen setzen. Bei
Strings, wo dies nicht zutrifft können
Sie sie auch weglassen ( müssen aber
nicht) .
Das zweite, was noch zu sagen wäre, ist,
daß man manche Datenelemente auch abkürzen kann. Das spart zum einen Speicherplatz und zum anderen läuft das Programm
dann später auch schneller ab. Wenn man
nach einem Komma, das ja zur Trennung
der einzelnen Datenelemente dient, ein
weiteres Komma nachstellt, also praktisch KEIN Datenelement angibt, so interpretiert unser 64 er diesen Datensatz
als den Wert 0 . Hier ein kleines Beispiel:
100 DATA 200,,,10,,,
Diese Zeile entspicht haargenau dem folgenden Ausdruck und bewirkt auch genau
dasselbe:
100 DATA 200,0,0,10,0,0,0
Der Unterschied ist, daß wir weniger
Tipparbeit hatten und somit Speicherplatz gespart haben, UND daß die erste
DATA-Zeile auch noch schneller abgear- beitet werden kann - mit einem Wort, nur
Vorteile.
Als Nächstes sollte ich vielleicht noch
erwähnen, daß READ grundsätzlich immer
das ERSTE Datenelement aus dem ERSTEN
DATA-Statement zuerst liest. Es ist dabei egal, WO sie Ihre DATAs im Programm
unterbringen, READ liest rigoros alles
durch, solange bis es keine Daten mehr
finden kann. Hierauf sollten Sie immer
achten, denn sonst kann es zu einem " OUT
OF DATA ERROR" kommen. Sie sollten auch
wissen, daß READ sich quasi " merkt" bis
zu welchem Datenelement es schon gelesen
hat. Dieser Merkspeicher ändert sich
solange nicht, bis Sie das Programm wieder mit RUN starten. Es wird hierbei
also der Merkspeicher wieder auf das
allererste Datenelement zurückgesetzt, so daß Sie die Daten wieder von vorne
lesen können.
Für diese Funktion gibt es übrigens sogar einen eigenen BASIC-Befehl. Er heißt RESTORE, was soviel heißt wie " zurücksetzen" . Er tut haargenau dasselbe was
auch unter anderem bei RUN passiert
( nämlich das Zurücksetzen des DATA-Merkspeichers), nur daß Sie ihn mitten
im Programm aufrufen können, ohne hierbei das Ganze von vorne starten zu müssen. RESTORE braucht übrigens keine Parameter.
3.) Die kleinen, aber feinen, Sonder- funktionen.
Im letzten Abschnitt dieses Artikels
möchte ich mich noch ein wenig um ein
paar kleine Sonderfunktionen kümmern, die BASIC so bietet. Diese kann man
nicht einfach unter einem Überbegriff
zusammenfassen, denn jede Funktion erledigt jeweils eine in sich abgeschlossene
Aufgabe. Fangen wir einmal mit einer der
Wichtigsten dieser Funktionen an, der
RND-Funktion :
RND steht für RaNDom, was soviel heißt
wie Zufall. Mit dieser Funktion können
wir uns Zufallszahlen liefern lassen, wie sie in einer Fülle von Spielprogrammen ihre Verwendung finden. Erst einmal
zur Arbeitsweise von RND. Mit dem Ausdruck RND( X) liefert Ihnen der C64 einen
Zufallswert zwischn 0 und eins, wobei
der Wert von X keine Rolle spielt ( X ist
eine Variable) . Da man aber meist wenig
mit solchen Dezimalbrüchen zwischen 0
und 1 anfangen kann, gibt es auch eine
besondere Formel, mit denen man sich
auch ganze Zahlen ( also OHNE Kommastellen) in einem vordefinierten Wertebereich abrufen kann. Diese Formel lautet
folgendermaßen:
ZU= INT( RND(1)* Y)+ X
Wobei X für die untere, und Y für die
obere Zahlengrenze steht. Wollten wir
also ein kleines Lottoprogramm schreiben, a la "6 aus 49", so müßte unser
Ausdruck folgendermaßen lauten :
ZU=INT(RND(1)*49)+1
Ich habe hier einmal die Werte von X und
Y schon direkt eingesetzt. Natürlich
könnten Sie auch unsere allgemeine Formel benutzen und vorher in X und Y bestimmte Werte festlegen.
Es sei jedoch noch zu erwähnen, daß die
Zufallszahlen, die RND liefert nicht unbedingt " zufällig" sind. Der 64 er ist
eben ein Computer und bei diesen geht
alles immer korrekt und logisch zu. Die
Zufallszahlen, die RND liefert werden
deshalb immer auch nach einem bestimmten
Schema berechnet, so daß es Ihnen gut
passieren kann, daß Sie, wenn Sie den
Rechner gerade frisch eingeschaltet haben immer dieselben Zufallszahlen erhalten. Probieren Sie das doch einmal aus.
Lassen Sie sich einmal ein paar Zufallszahlen, direkt nach dem Einschalten des
64 ers ausgeben, schalten Sie dann wieder
AUS und EIN, und rufen Sie wieder mit
RND ein paar Zahlen ab. Sie werden feststellen, daß diese haargenau dieselben
sind, die wir vorher auch hatten. Das
kann höchst negative Auswirkungen auf
ein Spiel haben, zumal Sie bei dem Lottobeispiel von oben immer dieselben Ziehungen hätten.
Um dieses Problem zu umgehen gibt es
einen kleinen Trick. Der 64 er verwaltet
nämlich auch eine kleine interne Uhr.
Diese Uhr benutzt zwei vordefinierte
Variablen, ähnlich wie bei ST. Diese
Variablennamen dürfen Sie nie für eigene
Zwecke benutzen, da sie vom System vordefinierte Werte enthalten. Zum einen
wäre da die interne Uhr TI$ . TI$ ist
eine Stringvariable, wie man zweifellos
erkennen kann. In ihr steht eine immer
abrufbereite, interne Uhr zur Verfügung.
Wenn Sie also PRINT TI$ eingeben, so
wird der C64 Ihnen die Zeit, seitdem Sie
ihren Rechner eingeschaltet haben anzeigen, in dem Format HHMMSS, wobei HH für
Stunde steht, MM für Minute und SS für
Sekunde. Möchten Sie diese Uhr nun auf
einen eigenen Wert setzen, weil Sie zum
Beispiel die aktuelle Tageszeit in einem
Programm verwenden wollen, so kann man
dies mit einer einfachen Variablendefinition bewerkstelligen. Angenommen es
ist 10 Uhr 42 und 15 Sekunden, dann
reicht folgende Definition vollkommen
aus:
TI$="104215"
Anschließed steht diese Zeit in der internen Uhr gespeichert, die die Sekunden
von diesem Zeitpunkt an mitzählt.
Die zweite Variable, die etwas mit der
Uhr zu tun hat, und die wir auch benötigen, um mit RND " richtige" Zufallszahlen
zu erhalten, heißt TI. Wie Sie sehen
eine numerische Variable. TI wird nun
alle 1/60- Sekunde vom C64 hochgezählt.
Das wiederholt sich solange bis Sie TI$ wieder neu setzen. TI selbst können Sie
nicht verändern. Man kann diese Variable
gut in Programmen benutzt werden, die
ziemlich genau arbeiten sollen, jedoch
sei gesagt, daß BASIC wahrscheinlich zu
langsam ist, als daß solche Veränderungen von BASIC schnell genug festgestellt
werden könnten. Sie können ja einmal ein
bißchen mit TI herumexperimentieren. . .
Es sei ebenfalls noch erwähnt, daß die
interne Uhr TI$ sehr, sehr, ungenau ist.
Es ist gut möglich, daß sie innerhalb von 24 Stunden um eine halbe Stunde ( !) von der wirklichen Zeit abweichen kann.
Auch wenn Sie irgendwelche Operationen
mit Ihrem Diskettenlaufwerk machen, kann
die Uhr gebremst werden. Bei Diskettenoperationen wird sie nämlich gänzlich
abgeschaltet, so daß die Zeit, in der
die Floppy tätig war erst gar nicht
gezählt wurde. Solche Abweichungen können sich sehr schnell summieren, so daß
die Uhr am Ende total falsch geht. Also
Vorsicht bei der Benutzung von TI$ . . .
(" richtige" Uhren kann man eigntlich nur
in Assembler programmieren, doch ich
glaube, daß wir auch schon einmal auf
einer Magic Disk dieses Problem eingehender Behandelt haben)
Nun noch zu der Sache mit den Zufallszahlen. TI spielt dabei eine große Rolle. Um praktisch die internen Zufallszahlen " zu mischen" benutzt man nämlich
einfach folgenden Ausdruck:
X= RND(- TI)
Was wir hier als Ergebnis in X erhalten
kann ignoriert werden. Wichtig ist, daß
wir nun die Zufallszahlen durcheinandergeworfen haben, so daß wir ab jetzt sehr
gut mit unserer Allgemeinformel Zufallswerte abrufen können, die jetzt auch
verschieden voneinander sind.
In unserer allgemeinen Formel für Zufallszahlen zwischen X und Y ist Ihnen
bestimmt der merkwürdige Ausdruck INT
aufgefallen. INT stellt ebenfalls eine
besondere Funktion dar, dieser Befehl
schneidet nämlich ganz einfach bei einer
Dezimalzahl den Nachkommastellen ab. Das
heißt, daß beispielsweise die Zahl
2 .54873 zu einer einfachen 2 reduziert
wird. Die mit INT erhaltenen Zahlen sind
also immer gleich oder kleiner als die
Ursprungszahl. Bei negativen Zahlen bedeutet das, das immer auf die nächst kleinere Zahl abgeschnitten wird, demnach ist INT(-2 .54873) gleich -3, weil
-3 ja kleiner ist als -2 !
Ansonsten hätten wir da noch FRE( X) .
FRE( X) gibt einem den noch verfügbaren
Basicspeicher an, wobei es egal ist, welchen Wert X enthält. Allerdings ist
diese Funktion etwas fehlerhaft. Es ist
quasi unter C64- Kennern ein alter Fehler, der schon von Anfang an im Betriebssystem enthalten war, und meines
Wissens niemals geändert wurde. Es benötigt nämlich einer besonderen Formel, um
den tatsächlichen freien Speicherplatz
zu ermitteln. Geben Sie nämlich nur
FRE(0) ein, so wird Ihnen Ihr 64 er eine
negative Zahl ausspucken, mit der wir im
Endeffekt ja garnichts richtig anfangen
können. Um die wahre Anzahl der freien
Bytes zu erhalten, müssen Sie mit der
folgenden Formel arbeiten :
PRINT 65538+FRE(0)
Nun haben Sie den richtigen Wert.
Damit sind wir nun endgültig am Ende
unseres Basickurses angelangt. Ich verabschiede mich zunächst von Ihnen und
hoffe, Ihnen die Programmierung Ihres
C64 einigermaßen verständlich veranschaulicht zu haben.
Ihr Uli Basters