Tips und Tricks für Programmierer

Trickreicher Bildschirmschoner

Viele Anwenderprogramme, wie beispielsweise »Tempus«, verfügen über einen Bildschirmschoner. Drückt der Anwender eine bestimmte Zeit keine Taste oder bewegt nicht die Maus, so schaltet das Programm automatisch den Bildschirm ab, um die Bildröhre des Monitors zu schonen. Erst wenn der Anwender wieder aktiv wird, schaltet sich der Bildschirm wieder ein.

Um einen solchen Bildschirmschoner in eigene Programme einzubinden, benötigen Sie nur drei Schritte. Zunächst stellen Sie fest, wie lange der Anwender bereits untätig ist. Dazu gibt es verschiedene Arten: Sie verwenden die »evnt_multi«-Funktion und messen die verstrichene Zeit über den Timer-Event, Sie bedienen sich des 200 Hz-Zählers in den Systemvariablen oder Sie klinken den Bildschirmschoner in den VBI-Queue ein. Nachdem feststeht, daß der Bildschirm abzuschalten ist, warten Sie mittels des »VSYNC«-GFA-Basic-Befehls bzw. der XBIOS-Funktion 37, bis der Rasterstrahl den Bildschirm fertig aufgebaut hat. Anschließend schalten Sie die Monitorsynchronisation auf das externe Signal um. Der Trick: Da normalerweise kein Gerät dieses externe Signal liefert, bleibt der Bildschirm einfach schwarz. Der Schalter zwischen internem und externem Signal befindet sich im Speicherwort $ff820a, Bit 0. Ist das Bit gelöscht, so verwendet der Shifter das interne Signal, bei gesetztem Bit das externe.

Wird der Anwender wieder aktiv, schalten Sie wieder auf das interne Signal um, und der Bildschirm erwacht wieder zum Leben. (Christhoph Andre/ba)

' 1)    Abschalten des Monitorbildes:
Vsync ! nicht weglassen ! !
' wenn VSYNC fehlt,wird der Bildschirm
' unsynchronisiert abgeschaltet,
'   was sich nach dem Wiedereinschalten in
'   einem verzerrten Bild wiederspiegelt!!!
Spoke &HFF820A,Peek(&HFF820A) Or 1 
' Abschalten des Bildschirms durch Setzen von 
' Bit 0 in &HFF820A (Videoshifters) auf 1 
' (= externe Synchronisation)
' 2) Wiedereinschalten des Monitorbildes
Spoke &HFF820A,Peek(&HFF820A) And Not 1 
' ^ Externe Synchronisation abschalten

Laute Töne mit dem STE

Durch einen Intialisierungsfehler des Rainbow TOS 1.6 im STE passiert es öfters, daß die Lautstärke des Monitorlautsprechers sehr gering ist. Das kleine Programm »MICROWIRE« für Megamax Modula-2 löst dieses Problem, indem es die entsprechende Hardware neu initialisiert. Anders als die ST-Baureihe verfügen STE und der TT über ein internes Microwire-Interface, über das Sie den erweiterten Soundchip ansprechen. Dieser gibt einerseits digitalen Sound und andererseits die Töne des alten Yamaha-Soundchips aus. Unsere Initialisierung setzt u. a. das Mischflag, so daß die Signale des alten Soundchips mit denen des neuen gemischt werden.

(Meinolf Schneider/ba)

MODULE Microwire;

(*----------------------------------------------------------------------------
 * System-Version: MOS 3.5
 *----------------------------------------------------------------------------
 * Version       : 1.0
 *----------------------------------------------------------------------------
 * Text-Version  : V#00000
 *----------------------------------------------------------------------------
 * Modul-Holder  : Meinolf Schneider
 *----------------------------------------------------------------------------
 * Copyright May 1990 by Digital Art Meinolf Schneider
 *----------------------------------------------------------------------------
 * MS  : Meinolf Schneider
 *----------------------------------------------------------------------------
 * Datum    Autor Version Bemerkung (Arbeitsbericht)
 *----------------------------------------------------------------------------
 * 27.05.90 MS    1.0     Grundversion
 *----------------------------------------------------------------------------
 * Modul-Beschreibung:
 *
 * Residentes Programm zur Programmierung des Microwire-Interfaces des
 * Atari STE. Hiermit wird der Fehler im Rainbow-TOS 1.6 korrigiert. Das
 * Programm kann in den Autoordner kopiert werden.
 *
 * ACHTUNG beim Linken: Keine Prelink Modul notwendig (z.B. M2Init) !
 *----------------------------------------------------------------------------
 *) (*$S-,M-,N+,L-,C-*)

CONST (* GEMDOS functions *)
      SuperOn   =         $20;
      SuperOff  =         $20;
      PTerm0    =         $00;

BEGIN
  ASSEMBLER

  ; Titletext ausgeben:
  lea           Title(PC),A0

  clr.w         D0
 !NextTitleChar
  move.b        0(A0,D0.W),D2
  beq           TitleED

  movem.l       A0/D0,-(A7)
  move.w        D2,-(A7)
  move.w        #2,-(A7)
  move.w        #3,-(A7)
  trap          #13
  addq.w        #6,A7
  movem.l       (A7)+,A0/D0
  addq.w        #1,D0
  bra           NextTitleChar
 !TitleED


  ; Mittels Bus-Error Microwire-Interface erkennen:
  clr.l         -(A7)
  move.w        #SuperOn,-(A7)
  trap          #1
  addq.l        #6,A7

  move.w        SR,D2
  ori.w         #$0700,SR                 ; Interrupts abschalten
  lea           $FF8900,A2
  move.l        $8,A1                     ; Bus-Error-Vektor retten
  pea           BusErr(PC)
  move.l        (A7)+,$8                  ; und eigenen setzen
  tst.b         (A2)
  bra           NoBusErrThere
 !BusErr
  lea           14(A7),A7                 ; war wohl nix...
  bra.w         Goon
 !NoBusErrThere
  move.w        #$07FF,$24(A2)
  move.w        #10011101000%,D1          ; Master Volume 0 dB
  bsr.s         MicrowireWrite
  move.w        #10101010011%,D1          ; Left Volume 0 dB
  bsr.s         MicrowireWrite
  move.w        #10100010100%,D1          ; Right Volume 0 dB
  bsr.s         MicrowireWrite
  move.w        #10010001100%,D1          ; Treble -6 dB
  bsr.s         MicrowireWrite
  move.w        #10001000110%,D1          ; Bass  0 dB
  bsr.s         MicrowireWrite
  move.w        #10000000001%,D1          ; MIX GI
  bsr.s         MicrowireWrite
  bra           Goon

 !MicrowireWrite
  cmpi.w        #$07FF,$24(A2)
  bne.s         MicrowireWrite
  move.w        D1,$22(A2)
  rts

 !Goon
  move.l        A1,$8
  move.w        D2,SR                   ; Interrupts wieder freigeben

  move.l        D0,-(A7)
  move.w        #SuperOff,-(A7)
  trap          #1
  addq.l        #6,A7

  ; Programm beenden
  move.w        #PTerm0,-(A7)
  trap          #1


 !Title
  dc.b          15c, 14c
  asc           '– MICROWIRE-CORRECTION Ω May 1990 by Meinolf Schneider'
  dc.b          15c, 14c, 0c
  END
END Microwire.

Von Computer zu Computer

Animationen, Bilder und Sound vom Amiga oder Texte vom Macintosh - die Übertragung von Daten zwischen Computern ist wegen der Formatinkompatibilität des Diskettenmediums oft nicht zu lösen. Doch es gibt einen einfachen Trick, der Übertragungen zwischen beliebigen Computern erlaubt: die Nullmodem-Verbindung. Dabei verbinden Sie beide Computerdirekt über die serielle Schnittstelle, an die Sie auch Modems anschließen. Einen Anschlußplan finden Sie in Bild 1. Nur drei Leitungen sind dabei relevant: Die Datensende-, Datenempfangs- und Masseleitung. Sende- und Empfangsleitung müssen Sie dabei überkreuzen, so daß die Sendeleitung des einen Rechners die Empfangsleitung des anderen ist.

Zum Übertragen der Daten verwenden Sie auf beiden Seiten ein Terminalprogramm. Stellen Sie die Baudrate auf 9600-oder soweit möglich 19200. Schalten Sie beidseitig auf 8 Datenbits, 1 Stopbit und kein Handshake. Das geeignetste Übertragungsprotokoll ist Zmodem. Verfügen Sie nicht über Zmodem, so empfehle ich Ymodem oder Xmodem.

Um digitale Sounds vom oder zum Amiga zu übertragen, müssen Sie die Samples noch konvertieren. Der Amiga speichert ein 8-Bit-Sample im Bereich von -128 bis 127 ($80-$7f), der ST speichert sein 6-Bit-Samples im Bereich von 0-63 ($0-$3f). Um Amiga-Sounds für den ST auf 6-Bit zu konvertieren, verwenden Sie die Formel

6bit = (8bit+128)/4

Um ein 6-Bit-Sample des STs für den Amiga zu konvertieren, verwenden Sie die Formel

8bit = (6bit*4)-128 

(ba)

Fragen und Antworten zu GFA-Basic (teils ab Version 3.0)

Wie kann ich feststellen, welche bzw. wieviele Laufwerke angeschlossen sind ?

Sie nutzen einfach die vom Betriebssystem zur Verfügung gestellte »BIOS 10« Funktion. Das folgende Listing testet in der FOR-NEXT-Schleife die 16 möglichen Laufwerke. Ist das gesuchte Laufwerk vorhanden, schreibt es die Laufwerkskennung in den String ‚I$'.

FOR i%=0 TO 15
    IF BTST(BIOS(10),i%)
        I$=I$+CHR$(ADD(65,i%))+":"
    ENDIF 
NEXT i%
PRINT I$

Ich habe ein Programm geschrieben, in dem ich die Befehle EVERY und AFTER benutze. Im Interpreter läuft alles nach Wunsch. Doch nach dem Compilieren werden diese Befehle nicht korrekt abgearbeitet. Was mache ich falsch?

Zunächst sollten Sie darauf achten, daß im Compiler die Option I+ (Interrupts erlaubt) aktiviert ist. Um die Abfrage auf EVERY und AFTER zu geben, muß in der Hauptschleife des Listings die Anweisung $U stehen, da nur die Anweisung $U auf einen Interrupt testet.

**Wie kann ich die »toten« Nullen hinter dem Dezimalpunkt einer Zahl sichtbar machen? Zum Beispiel möchte ich per Computer die DM-Beträge 5.30 und 1.10 addieren. Statt 6.40 bekomme ich als Ausgabe 6.4.

Mit dem folgenden Listing hängen Sie beliebig viele Nullen nach der letzten Stelle hinter einem Dezimalpunkt an. Beim Aufruf der Funktion „format$« geben Sie als ersten Parameter die Zahl an. Der zweite Parameter legt fest, bis zur wievielten Stelle die Nullen angefügt werden.**

a$=@formats(5.5,2)
'
FUNCTION format$(a,b%)
    LOCAL a$,pos% 
    a$=STR$(a)+STRING$(SUCC(b%),"0”) 
    pos%=INSTR(a$,".")
    RETURN LEFT$ (a$,pos%)+LEFT$(RIGHTS(a$, SUB(LEN (a$),pos%))+"00",b%) 
ENDFUNC

Ich möchte wissen, ob ein bestimmter Ordner unter einem bestimmten Pfad existiert. Wie gehe ich vor?

Benutzen Sie dazu das folgende Listing. Der Funktion »exist_folder« übergeben Sie den gewünschten Pfad mit Ordner. Erhalten Sie das Ergebnis -33 zurück, so existiert der Ordner unter dem Pfad nicht. Eine 0 signalisiert, daß der Ordner vorhanden ist.

PRINT @exist_folder("F:\GFA_TUT.LST")
'
DEFFN
exist_folder(ordnerS)=GEMDOS(78,L:V:ordner$, -1)

Wie kann ich einer schon formatierten und beschriebenen Diskette nachträglich einen Diskettennamen geben?

Mit dem folgenden Listing ist dies Problem einfach gelöst. Es übergibt der Procedure »set_label« den neue Diskettennamen. Diese testet vor dem Schreiben, ob die Diskette bereits einen Namen besitzt.

CHDIR "\"
CHDRIVE 1                                       ! Laufwerk A:
CHDIR "\"
@set_label("TEST_3.LST")
@get_label(label$)
PRINT label$
PROCEDURE get_label(VAR dname$)
  LOCAL e%
  ~FSETDTA(BASEPAGE+128)                        ! DTA setzen
  e%=FSFIRST("*.*",8)                           ! nur DISKNAME lesen
  dname$=CHAR{BASEPAGE+158}                     ! D_NAME lesen
  IF e%=-33                                     ! wenn kein DISKNAME auf Disk
    dname$=""                                   ! dname$ auf Leerstring setzen
  ENDIF
RETURN
PROCEDURE set_label(label$)
  LOCAL test$,e%
  @get_label(test$)                             ! auf DISKNAME testen
  IF test$=""                                   ! wenn DISKNAME nicht da
    label$=label$+CHR$(0)                       ! dem Namen Nullbyte anhängen
    e%=GEMDOS(60,L:VARPTR(label$),0)            ! Datei anlegen
    IF e%>0                                     ! wenn Datei angelegt
      ~GEMDOS(62,e%)                            ! Datei schließen
      ~GEMDOS(67,L:V:label$,1,8)                ! Datei in DISKNAMEN umbennen
    ENDIF
  ELSE                                          ! wenn DISKNAME vorhanden
    ALERT 3,"  Es befindet sich  |  schon ein DISKNAME|  auf der Diskette",1,"  OK  ",e%
    END
  ENDIF
RETURN

Was bewirkt der CURVE-Befehl?

Der Befehl CURVE stellt Bézierkurven dar. Dem Befehl folgen vier xy-Koordinaten.

Leider vermisse ich im GFA-Basic Befehle, mit denen ich nur die linken oder nur die rechten Leerzeichen eines Strings entfernen kann. Ich stelle mir dies ähnlich dem Befehl TRIM$ vor.

Das folgende Listing stellt Ihnen dazu zwei Prozeduren zur Verfügung. Sie müssen beim Aufruf den String angeben, aus dem Sie die Leerzeichen entfernen wollen. Das erste Listing entfernt die linken Leerzeichen in einem String, das zweite die rechten.

ltrim$="   TOS  "
@ltrim(ltrim$)
PRINT "*";ltrim$;"*"
'
PROCEDURE ltrim(VAR ltrim$)
  LOCAL i%,pos%
  FOR i%=1 TO LEN(ltrim$)
    IF MID$(ltrim$,i%,1)=" "
      INC pos%
    ELSE
      i%=LEN(ltrim$)
    ENDIF
  NEXT i%
  ltrim$=RIGHT$(ltrim$,SUB(LEN(ltrim$),pos%))
RETURN

rtrim$="   TOS  "
@rtrim(rtrim$)
PRINT "*";rtrim$;"*"
'
PROCEDURE rtrim(VAR rtrim$)
  LOCAL i%,pos%
  pos%=LEN(rtrim$)
  FOR i%=LEN(rtrim$) DOWNTO 1
    IF MID$(rtrim$,i%,1)=" "
      DEC pos%
    ELSE
      i%=1
    ENDIF
  NEXT i%
  rtrim$=LEFT$(rtrim$,pos%)
RETURN

Wie stelle ich Text am besten im Blocksatz dar?

Der folgenden Prozedur übergeben Sie die maximale Zeilenbreite und den Text.

text$="Blocksatz in GFA-Basic für TOS"
@block(40,text$)
PRINT text$
PROCEDURE block(breit%,VAR text$)
  '
  ' breit%=max. breite des blocksatzes
  ' text$=zu setzender text
  '
  ' Lars 19.02.1990
  '
  LOCAL pos%,ueber%
  pos%=1
  ueber%=breit%-LEN(text$)
  WHILE ueber%>0
    pos%=INSTR(text$," ",pos%)
    IF pos%=0
      pos%=1
      pos%=INSTR(text$," ",pos%)
    ENDIF
    text$=LEFT$(text$,pos%)+" "+RIGHT$(text$,LEN(text$)-pos%)
    ADD pos%,2
    DEC ueber%
  WEND
RETURN

Ich möchte ein Programm entwickeln, mit dem ich Daten auf die Diskette schreibe. Immer wenn die Diskette schreibgeschützt ist, kommt eine TOS-Fehlermeldung. Da in diesem Falle mein Programm eingreifen soll, möchte ich die Fehlermeldung unterdrücken. Wie kann ich dieses Problem am einfachsten lösen?

Das folgende Listing demonstriert das Vorgehen. Es biegt den Critical Error Handler ($404) auf die Maschinenroutine im »INLINE« um. Nun können Sie mit dem Befehl »ON ERROR...« auf Ihre eigene Prozedur verzweigen.

Vergessen Sie nicht, am Schluß Ihres Programmes die Prozedur »alerts_on« anzuspringen, um die TOS-Fehlermeldungen wieder zu aktivieren.

ON ERROR GOSUB error_proc
@alerts_off
SAVE "a:\test"                ! um Fehler zu simulieren eine
' FILESELECT "B:\*.*","",x$   ! schreibgeschütze Diskette in A: einlegen
@alerts_on
'
PROCEDURE alerts_off
  INLINE noalert%,8
  {noalert%}=&H4CAF0001       ! eigentlicher Maschinencode : movem.w   $4(a7),d0
  {noalert%+4}=&H44E75        !                              rts
  IF {BASEPAGE+256}<>noalert% ! Um Alertbox nur einmal auszuschalten
    {BASEPAGE+256}=LPEEK(1028)! alten Wert von CEH merken
    SLPOKE 1028,noalert%      ! neue Routine installieren
  ENDIF
RETURN
'
PROCEDURE alerts_on
  IF BYTE{BASEPAGE+256}=0     ! Alertbox nur anschalten, wenn sie ausgeschlatet ist
    SLPOKE 1028,{BASEPAGE+256}! alte Adresse restaurieren
    {BASEPAGE+256}=-1         ! Einschaltung kennzeichnen
  ENDIF
RETURN
'
PROCEDURE error_proc
  ' eigene Fehlermeldung
  ALERT 3,"Eigene Fehlermeldung| ",1," Aha ",x%
  RESUME NEXT
RETURN

Wie kann ich feststellen, ob mein Programm gerade im Interpreter abläuft oder als Compilat gestartet wurde?

Die einzeilige Funktion

DEFFN comp(x%)=PEEK(BASEPAGE+256)=96

stellt dies fest. Liefert sie als Rückgabewert TRUE (-1), so läuft das Listing im Interpreter. Ist der Rückgabewert FALSE (0), läuft das Programm als Compilat.

Wie kann ich das auftretende Dauerklingeln bei meinen Alertboxen unterdrücken? Und wie kommt das überhaupt zustande?

Sobald eine Alertbox unmittelbar nach einem Mausklick aufgerufen wird, bekommt das Betriebssystem das Loslassen des Mausbuttons nicht mit. Um dieses zu verhindern, legen Sie vor dem Befehl »ALERT...« eine »REPEAT...UNTIL«-Schleife, die auf das Loslassen des Mausknopfs wartet.

REPEAT
UNTIL MOUSEK
ALERT 1," Kein Dauerklingeln !  ",1," Aha ",wahl%

Ich habe ein Programm geschrieben, daß mir zu Beginn eine ALERT-Box zeigen soll. Im Interpreter funktioniert alles ohne Mängel. Compiliere ich das Listing und kopiere es als erstes Programm in meinen AUTO-Ordner des Bootlaufwerks, wird die ALERT-Box einfach nicht angezeigt und das Programm wird ohne Fehlermeldung beendet. Starte ich das Programm jedoch hinterher, habe ich keinen Funktionsfehler.

Dieser »Fehler« liegt nicht an Ihrem Programm. Das Problem liegt in der Reihenfolge der Installation des ATARI ST. Zunächst wird das TOS (XBIOS, BIOS, usw.) installiert. Danach startet das System die Programme, die sich im AUTO-Ordner befinden. Zu diesem Zeitpunkt ist das GEM, das die Ausgabe der ALERT-Box steuert, noch nicht vorhanden. Es wird erst der Abarbeitung der AUTO-Ordner-Programme initialisiert. Zum Schluß werden dann noch die Accessories geladen. Fazit: Ohne systemeingreifende Tricks ist der Zugriff von AUTO-Ordner-Programmen auf das GEM nicht möglich. Im Archiv »Tips&Tricks für Programmierer« finden Sie dazu ein kleines Programm namens »GEMBOOT«, das dieses Problem löst. Kopieren Sie es in den AUTO-Ordner. Die zweite Datei »GEMBOOT.INF« kopieren Sie ins Wurzelverzeichnis. Es enthält als Inhalt den Namen der Datei, die beim Start nachgeladen werden soll.

Hille für GFA-Basic

Ab dieser Ausgabe bieten wir unseren Lesern einen weiteren Service: Haben Sie Fragen bzw. Probleme mit GFA-Basic, schreiben Sie uns. Wir leiten Ihre Fragen weiter an einen Experten in Sachen GFA-Basic und werden die interessantesten Problemlösungen veröffentlichen.

Bitte schicken Sie Ihre Fragen an:

ICP Verlag
Redaktion TOS
Stichwort: GFA-Basic
Wendelsteinstr. 3
8011 Vaterstetten



Links

Copyright-Bestimmungen: siehe Über diese Seite
Classic Computer Magazines
[ Join Now | Ring Hub | Random | << Prev | Next >> ]