ST-Ecke: Bilder kopieren leicht gemacht

So manche ST-Besitzer, besonders diejenigen unter Ihnen, die sich viel mit Grafik beschäftigen, sind bestimmt schon einmal auf die Idee gekommen, ein paar Ausschnitte auf dem Bildschirm zu kopieren. Nichts ist einfacher als das, denn GEM liefert uns dafür ja eine geeignete Routine, was eine GRECT-Struktur oder ein FDB ist wird im folgenden untersucht.

Ich habe die ST-Ecke dieses Monats der VDI-Routine vro_cpyfm() und deren Anhängsel gewidmet. Als erstes schauen wir uns die Routine mit ihren Parametern an (siehe Abb. 1):

Was ist ein FDB? Ein FDB ist ein sogenannter Form Definition Block, der die Art des Grafikspeichers beschreibt, aus dem oder in den der Ausschnitt kopiert werden soll. Die Bildspeicherorganisation des Atari ST ist je nach Auflösung unterschiedlich. Dabei sind folgende Kriterien vorhanden, die die Bildschirmspeicherarten unterscheiden:

a) Breite (in Pixeln)
b) Breite (in Worten - 16 Bit)
c) Höhe (in Pixeln)
d) Anzahl der Farbebenen (Bitbreite der Anzahl der Farben)

An einem Beispiel veranschaulicht: In der Monochrom-Auflösung besitzt der ST 640 (a) auf 400 (c) Punkte in 2 Farben. Um zwei Farben darzustellen, braucht man nur ein Bit, also hat die monochrome Auflösung nur eine Farbebene (Plane). Die Anzahl der 16 Bit-Worte, die in eine Zeile passen, beträgt 40. Die mittlere Auflösung hat 640 (a) auf 200 (c) Punkte in 4 (2 Planes) Farben und eine sich daraus ergebende Wortanzahl von 40. Die niedrigste Auflösung hat bei einer Anzahl von 16 (4 Planes) die meisten Farben, aber nur 320 (a) auf 200 (c) Punkte, dies entspricht einer Breite von 20 Worten. Demnach kann man an diesen Parametern sehr gut die Art (Form) des Bildspeichers beschreiben. Hier nochmal eine Übersicht der Werte:

vro_cpyfm(vdi_handle, modus, punkte, ausgang, ziel);

int vdi_handle; Kennungsnummer des VDI für die Applikation

int modus; Bitverknüpfung zwischen Ausgang und Ziel, siehe unten

int punkte[8]; Feld, das die Koordinaten von Ausgang und Ziel enthält, dabei werden die einzelnen Elemente folgendermaßen besetzt:

punkte[0]: X-Koordinate des Ausgangsbildbereiches
punkte[1]: Y-Koordinate des Ausgangsbildbereiches
punkte[2]: Breite des Ausgangsbildbereichs
punkte[3]: Höhe des Ausgangsbildbereiches
punkte[4]: X-Koordinate des kopierten Ausschnitts
punkte[5]: Y-Koordinate des kopierten Ausschnitts
punkte[6]: Breite des kopierten Ausschnitts
punkte[7]: Höhe des kopierten Ausschnittes

FDB ausgang,ziel: Form Definition Block - Struktur, die die Art des Ausschnittes kennzeichnet. In manchen Compilern wird diese Struktur auch MFDB (Memory Form Definition Block) genannt.

Abb. 1: Parameter der vro_cpyfm-Routine

Auflösung Breite (Pixel) Breite (Worte) Höhe Planes
monochrom 640 40 400 1
farb, mittel 640 40 200 2
farb, gering 320 20 200 4

Das einzige, was noch fehlt, ist die Adresse dieses Bildschirmbereichs. Nachdem wir diese verschiedenen Kriterien betrachtet haben, wollen wir uns den FDB anschauen, dessen Struktur hier noch einmal dargestellt ist (siehe Abb. 2).

Für uns sind nur die mit den Pfeilen gekennzeichneten Einträge interessant, da die anderen reserviert und damit vorbestimmt sind. Die mit den Pfeilen gekennzeichneten Einträge entsprechen den oben besprochenen Kriterien. Nun ein letztes Mal zur Verdeutlichung die FDBs der Bildschirmspeicher bei verschiedenen Auflösungen, wobei die Adressen natürlich nicht eingetragen sind:

FDB hoch =
{ 0L, 640, 400, 40, 0, 1, 0, 0, 0};

FDB mittel =
{ 0L, 640, 200, 40, 0, 2, 0, 0, 0};

FDB niedrig =
{ 0L, 320, 200, 20, 0, 4, 0, 0, 0};

Beachten Sie bitte das ’L’ hinter der Null, das die Null als Langwort kennzeichnet. Natürlich können Sie sich einen Block in beliebiger Größe definieren. Dies ist besonders sinnvoll, wenn Sie Ausschnitte aus dem Bildschirm in den Speicher kopieren wollen. Man definiert sich einen Speicherbereich in der Größe des Ausschnittes, allerdings mit gleicher Anzahl der Planes wie des Bildschirm-FDBs. Wollen Sie einen Ausschnitt von der Größe 133 x 120 an der Stelle X=10 und Y=40 in der mittleren Grafikstufe aus dem Bildschirm an die Stelle X = 300 und Y = 50 kopieren, müssen zwei FDBs erstellt werden. Wenn Sie die oben angesprochene VDI-Routine vro_cpyfm() benutzen, so entfällt die Arbeit den FDB des Bildschirms anzulegen, denn wenn Sie in die Adresse des FDBs eine 0 schreiben, wird diese automatisch vom VDI durch die aktuelle Adresse des Bildschirms ersetzt. Nicht nur das -sogar alle anderen Parameter, wie die Anzahl der Planes, etc. werden automatisch gesetzt. Wir müssen uns also in diesem Fall nicht um die FDBs kümmern, außer daß wir die Adresse auf Null setzen. Jetzt fehlt uns noch die Möglichkeit, die Koordinaten des Ausschnittes anzugeben - dies geschieht in dem Punkte-Feld, wobei das Feld für unser Beispiel folgendermaßen gesetzt wird (siehe Abb. 3).

long fd_addr;   /* < - Adresse */
int fd_w;       /*  < - Breite in Pixel */
int fd_h;       /* < - Höhe in Pixel */
int fd_wdwidth; /*  < - Breite in Worten */
int fd_stand;   /*  Standardformat 1 = Ja 0 = Nein */

int fd_nplanes; /*  < - Anzahl der Planes */
int fd_r1;      /* reserviert 0 */
int fd_r2;      /*  reserviert 0 */
int fd_r3;      /*  reserviert 0 */

Abb. 2: FDB-Struktur

Vorausgesetzt Sie haben VDI schon vorher initialisiert, rufen Sie die Routine folgendermaßen auf:

vro_cpyfm(vdi_handle, 3, punkte, ausgang, ziel );

wobei die beiden FDBs ’ausgang’ und ’ziel’ heißen, und der MODUS, um den wir uns am Ende noch genauer kümmern werden, auf 'Ersetzen’ eingestellt ist. Nun wollen wir uns dem interessanteren Beispiel, dem Speichern eines Ausschnittes im Speicher des Rechners zuwenden. Dabei bleiben der Ausgangs-FDB wie auch die ersten vier Feldelemente des Feldes ,,punkte[]“ wie im vorherigen Beispiel bestehen. Den zweiten FDB definieren wir uns genauso groß wie der Ausschnitt ist. Das bedeutet, daß die folgenden Einträge des Ziel-FDBs folgendermaßen aussehen müssen:

    ziel.fd_w = 133;
    ziel.fd_h = 120;
punkte[0] = 10;             /*  X-Koordinate Ausgang */
punkte[1] = 40;             /*  Y-Koordinate Ausgang */
punkte[2] = punkte[6] = 133; /* Breite */
punkte[3] = punkte[7] = 120; /* Höhe */
punkte[4] = 300;            /*  X-Koordinate Ziel */
punkte[5] = 50;             /*  Y-Koordinate Ziel */

Abb. 3

Die Wortbreite müssen wir uns errechnen, wobei ein angefangenes Wort (die Breite läßt sich in den wenigsten Fällen glatt durch sechzehn teilen) natürlich mitzählt:

ziel.fd_wdwidth = (ziel.fd_w)/16 +((ziel.fd_w)%16 != 0);

Die Elemente fd_stand und fd_nplanes werden mit den gleichen Werten versehen, wie sie auch im Aus-gangs-FDB vorhanden sind. In unserem Beispiel:

    ziel.fd_stand = 0;
    ziel.fd_nplanes = 2;

Den zweiten Teil des punkte[]-Feldes belegen wir folgendermaßen: Die Breite und Flöhe übernehmen wir vom Ausgangsbiock, aber wir setzen die Koordinaten auf X = Y=0. Sie müssen sich also vorstellen, wir haben uns im Speicher einen Bildspeicher genau in der Größe eines Blocks erstellt, in den wir nun unseren genau passenden Ausschnitt hineinkopieren, also an die Koordinate (0,0). Es wäre natürlich auch möglich, einen kleineren Ausschnitt an eine andere Koordinate zu kopieren, aber dies paßt nicht zu unserem Beispiel. Also besetzen wir das punkte[]-Feld folgendermaßen (siehe Abb. 4).

    punkte[0] = 10;                     /* X-Koordinate Ausgang */
    punkte[1] = 40;                     /* Y-Koordinate Ausgang */
    punkte[2] = punkte[6] = 133;        /* Breite */
    punkte[3] = punkte[7] = 120;        /* Höhe */
    punkte[4] = 0;                      /* X-Koordinate Ziel */
    punkte[5] = 0;                      /* Y-Koordinate Ziel */

Abb. 4

Bevor wir jetzt zum eigentlichen Kopieren kommen, muß noch errechnet werden, wie groß der Speicherbedarf des Blocks sein darf. Dies ist ganz einfach:

bytes = Anzahl der Worte pro Zeile * 2 * Höhe * Anzahl des Planes;

ziel.fd_addr = Malloc(bytes);

Jetzt können Sie kopieren! Aber was ist nun schon wieder der Modus, den wir bisher immer auf 3 gesetzt haben? Dieser gibt die Verknüpfung zwischen zu kopierendem Ausschnitt (Ausgang) und Hintergrund (Ziel) an. Der Verknüpfungsmodus kann mit vier Bits eingestellt werden, wobei dann jedes Bit einer Verknüpfungsart entspricht und bei mehreren gesetzten Bits diese Verknüpfungen dann miteinander UND-verknüpft werden:

A bedeutet Ausgangspixel
~ A bedeutet Ausgangspixel (invertiert)
Z bedeutet Zielpixel (alter Bildpunkt)
~Z bedeutet Zielpixel (invertiert)
| ODER-VERKNÜPFUNG
& UND-Verknüpfung
^EXOR-Verknüpfung

Bit 0: Ergebnis = A & Z
Bit 1: Ergebnis = A & — Z
Bit 2: Ergebnis = ~A & Z
Bit 3: Ergebnis = ~(A | Z)

Ein Modus von 12 würde die Bitkombination 1100 und damit folgende End-Verknüpfung bedeuten: (siehe Abb. 5)

Ergebnis = Bit3-Verknüpfung ! Bit4-Verknüpfung
Ergebnis = ~(A | Z) | ~A & Z 
         = ~A & ~Z | ~A & Z 
         = ~A & (~Z | Z)
         = ~A & 1 
         = ~A

Abb.5

Ein zweites Beispiel mit Modus 7: (Abb. 6)

Ergebnis = A & Z | ~A & Z | A & ~Z 
         = Z & (A | ~A) | A & ~Z 
         = Z & 1 | A & ~Z 
         = Z | A & ~Z 
         = Z | A & (Z | ~Z)
         = Z | A & 1 
         = Z | A

Abb. 6

Anmerkung:
Die Umwandlungen sind mit Hilfe der Boolschen Algebra vollzogen worden. Zusammengefaßt in einer Tabelle sieht es folgendermaßen aus: (siehe Abb. 7)

Modus Verknüpfung Anmerkung
0 E = 0 Löschen des Zielblocks (s. Anmerkung d)
1 E = A & Z
2 E = A & ~Z
3 E = A Ersetzen des Ziels durch Ausgang
4 E = ~A & Z
5 E = Z dann kann man es auch sein lassen
6 E = A Z Pixel setzen, wenn A u. Z verschieden
7 E = A Z | transparent, Ziel scheint durch
8 E = ~(A | Z) wie 7, nur invertiert
9 E = ~ (A ^ Z) wie 6, nur invertiert
10 E = ~ Z Invertieren des Zielblocks (s. Anmerkung d)
11 E = A ~Z
12 E = ~A Ersetzen, mit invertierendem Ausgang
13 E = ~A | Z invertiert, transparent
14 E = ~(A & Z)
15 E = 1 Füllen (s. Anmerkung d)

Abb. 7

Sie sehen also, daß es vielfältige Möglichkeiten gibt, Ausgang und Ziel zu verknüpfen.

Bevor ich Ihnen noch einige Tips gebe, wie Sie die Kopierroutinen optimal einsetzen können, möchte ich noch einmal auf das Beispiel-Programm ein-gehen: (siehe Listing 1)

Es handelt sich um ein kleines Programm, das es ermöglicht, Teile aus dem Bildschirm auszuschneiden und mehrmals auf dem Bildschirm zu kopieren. Um besser erkennen zu können, welche Werte was bedeuten, werden die Koordinaten zunächst in eine GRECT-Structur gebracht. Dadurch sind alle vier Koordinaten eines Ausschnittes in einer Variable zusammengefaßt.

Durch die Routine grect_to_array() werden die Werte der GRECT-Struktur wieder in ein Feld kopiert. Auf das Benutzen einer Dialogbox wurde übrigens verzichtet, da für diesen Zweck auch eine ALERT-Box 'mißbraucht’ werden kann, und man damit einiges an Speicherplatz spart. Übrigens ist dieses Programm ganz lustig, wenn man es als Accessory ausführt, da man dann im DESKTOP ein wenig kopieren kann...

Hier nun ein paar Hinweise zum optimalen Einsatz der VDI-Kopierroutine:

a) Versuchen Sie soweit es geht, Koordinaten zu wählen, die auf eine Wortgrenze (X = 16, 32, 48...) fallen. Dadurch muß das Bild nicht noch erst intern bitweise verschoben werden, was sehr zeitintensiv ist, vor allem, wenn Sie Texte mit dem VDI ausgeben!

b) Vermeiden Sie Modi, in denen die Zielfläche erst noch gelesen werden muß. Wenn Sie auf solche Verknüpfungen verzichten, können Sie Zeiten von bis zu 50 % einsparen.

c) Vermeiden Sie unterschiedliche Verschiebungen einer Wortgrenze in Ausgang und Ziel, beispielsweise eine X-Koordinate von 4 im Ausgang und 9 im Ziel. Dadurch muß das Ausgangsbild erst um 5 Pixel verschoben werden.

d) Das Füllen, Löschen und Invertieren geht mit der Routine v_bar() schneller.

Die Routine vrt_cpyfm() unterscheidet sich um eine wesentliche Kleinigkeit von der Routine vro_cpyfm(). Mit vro_cpyfm() ist es nicht möglich, ein Monochrombild in eine Farbauflösung zu kopieren. Dies gelingt aber mit vrt_cpyfm(). Dabei können Sie noch zusätzlich angeben, welche Farbe ein gesetzter Punkt und ein ungesetzter Punkt haben soll. Folgende Parameter ergeben sich: (siehe Abb. 8).

vrt_cpyfm(vdi_handle, modus, punkte, ausgang, ziel, farben);

Die Parameter sind bis auf das Feld farben[] schon oben erklärt:

int farben[2]; /* farbe[0] = Farbe der gesetzten Punkte /
/
farbe[1] = Farbe der ungesetzten Punkte */

Abb. 8

Mit diesen Angaben können Bildschirmausschnitt kopiert und abgespeichert werden. Wenn Sie die Bilder auf der Diskette abspeichern, so denken Sie daran auch den FDB mit abzuspeichern.

#include <osbind.h>

#define ARROW   0       /* Gemdefinierungen für die Maus */
#define M OFF   256
#define M_ON    257

#define BUFLEN 33000    /* Länge des Buffers zum Abspeichern */
#define ERSETZEN 3      /* Modi für das Schreiben in das Bild */
#define EXODIEREN 6 
#define ODIEREN 7

#define END 3           /* Die Knöpfe der Auswahlbox */
#define PASTE 2 
#define CUT 1

typedef struct grect    /* Bildkoordinaten-Struktur */
{
int g_x;
int g_y;
int g_w;
int g_h;
} GRECT;

typedef struct fdbstr       /* Form-Definition-Block-Struktur */
{
    long    fd_addr;        /* Adresse der Bilddaten */
    int     fd_w;           /* Breite des Bildes */
    int     fd_h;           /* Höhe des Bildes */
    int     fd_wdwidth;     /* Breite in Worten */
    int     fd_stand;       /* reserviert immer */
    int     fd_nplanes;     /* Anzahl der Farbebenen->Planes */
    int     fd_r1;          /* reserviert */
    int     fd_r2;          /* reserviert */
    int     fd_r3;          /* reserviert */
} FDB;

GRECT ausgang1 = (0,0,0,0); /* Koordinaten des Ausschnitts tf
GRECT ziel = (0,0,0,0);     /* Koordinaten der Kopie */
FDB bildschirm  = ( 0x0L,640,400,40,0,1,0,0,0); /* Ausgangs-RDB */
FDB block1  = (0x01,400,400,25,0,1,0,0,0);  /* Ziel-FDB */

GRECT *ausg;                /* Zeiger auf Ausgangsblockstruktur */
char *buffer1;              /* Zeiger auf Bildbereich */
FDB *blocker;               /* Zeiger auf FDB */

            /* Vdi-Variablen */

int vdi_handle;
int contr1[12], intin[128], intout[128], ptsin[128], ptsout[128]; 
extern int gl_apid; 
int work_in[11]; 
int work_out[57];

int planes; /* Anzahl des Planes */
int mode;   /* Kopi#rmodus */

main()
{

    int exit_obj= PASTE;

    appl_init();    /* Applikation initialisieren */
    open_vwork();   /* VDI-Workstation initia1isieren */

    graf_mouse(ARROW, 01 ); /* Pfeil als Maus einschalten */

    block1.fd_addr = (long)buffer1; /* Bild-Speicheradresse «/

    ausg=&ausgang1;         /* Zeiger auf Variablenzeiger */
    blocker=&block1;        /* dito */

    ausgang.g_w=ausg->g_w;  /* Breite in Struktur setzen »/ ausgang.g_h=ausg->g_h;  /* Höhe setzen */
    ausgang.g_x=x;          /* Ausgangskoordinaten setzen */
    ausgang.g_y=y;
    ausg->g_x=0;            /* Im Ausgangsfeld (fast)immer 0 */
    ausg->g_y=0;            /* dito */

    grect_to_array(ausg,punkte);    /* Umwandlung von GRECT->Feld */
    grect_to_array(&ausgang,&punkte[4]); /* dito in zweiten Teil vom Feld */

    /* Raster-Kopieren Speicher -> Bildschirm */

    vro_cpyfm(vdi_handle,ERSETZEN,punkte,blocker,&bildschirm) ;

    graf_mouse(M_ON,01);    /* Maus, laß dich sehen ! */
}

do_cut() /* Ermitteln der Koordinaten des Ausschnitts und Ausschneiden */
{
    int x, y, breite, hoehe, dummy;

    /* Warten bis die Maustaste gedrückt ist */ 
    evnt_button(1,1,1,&x,&y,&dummy,&dummy);

    /* GUMMIBAND-BOX mit x,y-Kordinaten zeichnen */ 
    /* und die gewünschte Ausschnittsgröße ermitteln */ 
    graf_rubberbox(x,y,1,1, &breite,&hoehe);

    cut(x,y,breite,hoehe,1); /* Ausschnitt ausschneiden */
}

cut(x,y, w,h, f1) /* Ausschnitt in anderen Speicherbereich kopieren */ 
unsigned int x,y,w,h; /* Koordinaten */
{
    register int yh; 
    int punkte[8];

    graf_mouse(M_OFF, 01) /* Maus, aus! */

        ausg=&ausgang1; /* Zeiger auf Variable zeigen 1assen */ 
        blocker=&block1;

    /* Pufferspeicher löschen */
    for (yh=0; yh<BUFLEN; buffer1[yh++]=0);

    ausg->g_x=x;    /* Koordinaten setzen */
    ausg->g_y=y;
    ziel.g_w=ausg->g_w=w;
    ziel.g_h=ausg->g_h=h;
    ziel.g_x=0; /* Ist immer 0 */
    ziel.g_y=0;

    blocker->fd_wdwidth= ((w/16)+1); /* Breite in Worten errechnen */ 
    blocker->fd_w = w; eic
    blocker->fd_h = h;
    blocker->fd_addr = (long)buffer1;/* Speicheradresse setzen */

    grect_to_array(ausg,punkte);    /* Umwandlung von GRECT->F«ld */
    grect_to_array(&ziel,&punkte[4]); /* dito in zweiten Teil vom Feld */

    /* Raster-Kopieren Bildschirm->Speicher */

    vro_cpyfm(vdi_handle,ERSETZEN,punkte,&bildschirm,blocker);

    ausg&=ausgang1; 
    blocker=&block1;

    buffer1=(char*)(Mal1oc((1ong)BUFLEN)); /* Speicher reservieren */ 
    if (buffer1==(char*)0)                  /* Nicht genug vorhanden */
    {
        form_alert (1, "[1][Nicht genug Speicher vorhanden!][ OK ]");
        v_c1svwk();                         /* Workstation schließen */
        appl_exit();                        /* Applikation beenden */
        gemdos(0);                          /* Programm beenden */
    }
    while(exit_obj!=END)                    /* Bis die Taste END gedrückt ist */
    {
        wind_update(1); /* eigene Bildschirnausgabe- kein REDRAW */
        wind_update(3); /* eigene Maussteuerung ohne Menübegrenzung */

        planes=4>>Getrez(); /* Auflösung und Planes bestimmen */
        block1.fd_nplanes=bildschirm.fd_nplanes=planes; /* einschreiben */

        /* Auswahl der Funktion, die Box wurde als‘ ALERT-Box gewühlt */

        exit_obj=form_alert(0,"[1][Wählen Sie bitte aus][Schere|K1eber|Ende]");

        switch(exit_obj)    /* Welche Taste war’s wohl ? */
        {
            case PASTE:     /* Einfügen */
                do_paste(); /* los geht’s */
                break;

            case CUT:
                do_cut();   /* Ausschneiden */
                break;      /* ab geht’s */
        }
        wind_update(2); /* Mäuschen darf wieder von GEM geführt werden */
        wind update(0); /* Auch die Bildschirmausgabe geben wir zurück */
    }
    Mfree(buffer 1);    /* Speicherbereich freigeben */
    v_clsvwk(vdi_hand!e); /* VDI—Workstation schließen */ 
    appl_exit();        /* Applikation  beenden */
}   /* Auf Wiedersehen, bis zum nächsten Mal */

do_paste() /* Routine, um Einfüge-Koordinate her auszufinden*/
{           /* und dann zu Kopieren */
    int retx,rety,mx,my,w,h;

    mode=ERSETZEN;  /* kann nach Belieben geändert werden */

    /* Warten bis die Maustaste gedrückt worden ist */ 
    evnt_button(1,1,1,fcnix,&my,&retx,&retx);

    /* Box in der richtigen Größe verschieben */ 
    graf_dragbox (ausg->g_w, ausg->g_h, mx, my, 0,0,640, 400, &retx,&rety);

    paste(retx,rety,w,h,mode); /* Laßt es uns kopieren */
}

paste(x,y,w,h,modus) /* Kopierroutine */
unsigned int x,y,w,h,modus; /* Kordinaten und Einfügemodus */
{
    GRECT ausgang; /* Koordinaten-Struktur */ 
    int punkte[0];

    graf_mouse(M_OFF,01); /* Maus beim Kopieren ausschalten */

    graf_mouse(M_ON,01); /* Maus darf wieder erscheinen */
}

/* Umwandlungsroutine: von GRECT in FELD schreiben */ 
grect_to_array(rechteck,array);
GRECT *rechteck;
int *array;
{
    *arriy++ = rechteck->g_x; 
    *array++ = rechteck->g_y;
    *array++ = rechteck->g_x + rechteck->g_w - 1;
    *array++ = rechteck->g_y + rechteck->g_h - 1;
}

open_vwork() /* Initialisieren der VDI-Workstation */ 
{
    int i;

    for (i=0; i<10; work_in[i++]); 
    work_in[10]=2;
    v_opnvwk(work_in, &vdi_handle, work_out);
}

Der Fehlerteufel geht um

Leider haben sich im Listing 'Interrupts in Megamax C’ einige Fehler in Abb. 6 eingeschlichen. Die neunte Zeile muß folgendermaßen lauten:

static void_timavec()

Der Xbtimer-Aufruf in der vorletzten Zeile lautet:

Xbtimer (TIMER_A,TIMACTRL, TIMADAT,_timavec);

Abb. 6 ersetzt im Hauptlisting Zeile 23...44. Falls Sie die kleinen Unstimmigkeiten nicht schon selbst entdeckt haben, so hoffen wir, daß es nun funktioniert.


Links

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