;*************************************** ;* Eine Uhr mittels Coprozessor * ;* berechnen und grafisch darstellen * ;* 2010 H.V.Viehof * ;* * ;* 31.01.2010 Bugfix: * ;* Abschattung des Sekundenzeigers * ;* durch die Loeschroutine des Minuten * ;* -zeigers unterbunden * ;*************************************** ;___________________________________ ; ; Stapelsegment : ;___________________________________ stack segment stack word 'stack' dw 26 dup (?) ; eine Graphikanwendung braucht mehr Stapel als ein Textanwendung stack ends ; das ist eben so... CODE SEGMENT WORD PUBLIC 'CODE' ASSUME CS:CODE, DS:data, SS:stack, ES:variablen ;----------------------------------- ; TextA Prozedur - Erzeugt ein Textfenster ; dh = oberer Rand ; di = linker Rand ; si = offset von Text im Speicher ; bl = farbe ; Zeilenende = 0a, Textende = 0 ;----------------------------------- TextA PROC ; Text auf dem Graphikschirm mov cx, 1 ; arbeitet mittels zwei Schleifen and di, 0ff ; di = Textposition vom linken Rand, dh = Pos. vom Oberrand L5: xor dl, dl ; dl loeschen und or dx, di ; mit dem Wert aus di fuellen, aber dh erhalten, deshalb or L3: ds: lodsb ; zeichen holen cmp al, 0 ; 0 beendet die Textausgabe jz >E1 ; Ende Textdarstellung cmp al, 0a ; oa ist Ende der dargestellten Zeile jnz L1 ; dann muss die Zeile heraufgezaehlt werden inc dh ; exakt hier, jmp L5 ; die Anfangsposition links gibts bei L5 L1: push dx ; dx zwischenspeichern, es enthält Zeile und Spalte xor bh, bh ; bh loeschen mov ah, 2 ; cursor setzen int 010 ; Video (VGA) Interrupt mov ah, 9 ; ein Zeichen auf Grafikbildschirm ausgeben int 010 ; s.o. pop dx ; dx mit den Positionen zurueckholen inc dl ; ein Zeichen weiter rechts ruecken jmp L3 ; das abholen und weiter ... E1: ret TextA ENDP ;---------------------------------------------------------- ; DrawAngle Prozedur zeichnet Skalenstriche und Zeiger ;---------------------------------------------------------- DrawAngle PROC ; Sinus und Cosinus in einer Prozedur entro: fninit ; Coprozessor initialisieren fild es: w ein ; Wert aus Speicherstelle laden fdiv ds: d korr ; durch Korrekturwert teilen (idR 180 fuer 1 Grad Aufloesung) fldpi ; und mit PI fmul ; multiplizieren = Grad zu Rad umwandeln fsincos ; jetzt kann man den Sinus (ST1) / Cosinus (ST0) bilden fimul es: w radius ; mit radius multiplizieren frndint ; auf ganze Zahl runden fistp es: w aus ; (ST0) in den Speicher schreiben fimul es: w radius ; mit radius multiplizieren frndint ; auf ganze Zahl runden fistp es: w aus2 ; (ST1) in den Speicher schreiben mov dx, 240 ; vert. Bildschirmzentrum sub dx, es: w aus mov cx, 320 ; horiz. Bildschirmzentrum sub cx, es: w aus2 mov al, es: b color ; Punkt in Farbe mov ah, 0C ; al = Farbe int 010 ; cx = x pos und dx = y pos dec es: w radius ; der Radius wird verkleinert mov ax, es: w minrad ; Minimum fuer Radius cmp es: w radius, ax jnz entro ret DrawAngle ENDP ; Haydi! start: mov ax, seg data ; das ist der erste Infotext mov ds, ax mov dx, offset Info mov ah, 9 int 021 mov ah, 1 ; Text gelesen? weiter nach Tastendruck int 021 ;---------------------------------------------------------- ; In Videomodus 640 * 480 mit 16 Farben wechseln ;---------------------------------------------------------- mov ax, 012 ; 012h ist genau der richtige Modus int 010 ; die Funktion 0 des Videointerupts ;---------------------------------------------------------- ; Skalen zeichnen, die Winkelschritte werden berechnet ; und an den Positionen Skalenstriche gesetzt ;---------------------------------------------------------- mov ax, seg ein ; Segmente setzen ist praktisch Alltagsgeschaeft mov es, ax mov ax, seg data mov ds, ax ; Ganze Stundenskala mov es: w ein, 2880 ; der Kreis hat 360 Grad = 2880 Schritte: Start mov es: b color, 05 ; Farbe setzen D1: mov es: w radius, 239 ; der Radius ist der Aeussere Punkt mov es: w minrad, 210 ; und minrad der innere call DrawAngle ; zeichnen sub es: w ein, 240 ; und nach 240 Schritten = 30 Grad jnz D1 ; der naechste Skalenstrich ; Minutenskala - selber Algorythmus wie fuer die Stunden mov es: w ein, 2880 ;mov es: b color, 05 ; auskommentiert, denn: hat sich noch nicht geaendert D2: mov es: w radius, 239 mov es: w minrad, 230 call DrawAngle sub es: w ein, 48 jnz D2 ;---------------------------------------------------------- ; Textdarstellung ;---------------------------------------------------------- mov dh, 0 ; Positionen laden mov di, 1 ; Anfang der dargestellten Zeile mov ax, seg message ; ds auf datensegment I umstellen mov ds, ax mov si, offset message ; Anfang des Textes mov bl, 5 ; violett call TextA ; Anzeigen des Textfensters ;---------------------------------------------------------- ; Zeit holen und Zeigerdarstellung ;---------------------------------------------------------- GetT: mov ah, 02c int 021 ; Abfrage der Uhr cmp es: b sekunde, dh ; Sekunde (alt) = Sekunde (neu)? jz GetT ; wenn ja, nochmal Abfragen mov es: b stunde, ch ; Stunden speichern mov es: b minute, cl ; Minuten mov es: b sekunde, dh ; Sekunden mov al, es: b sekunde ; zuerst den alten Sekundenzeiger loeschen cmp al, 0 ; hier muss der Wert der alten Sekunde errechnet werden jnz >S1 ; Null darf es Prozessbedingt nicht sein mov al, 60 ; dann wird 60 benutzt S1: dec al ; akt. Sek. - 1 = alte Sekunde mov ah, 0 ; ah loeschen fuer Multiplikation mov bl, 48 ; alte Sekunde x Schrittwinkel = alte Zeigerposition mul bl ; berechnen... mov es: w ein, 2880 ; der Kreis hat 360 Grad: StartWinkel sub es: w ein, ax ; diese Subtraktion ist noetig damit der Zeiger im Uhrzeigersinn laeuft mov es: w radius, 200 ; der Sek. Zeiger soll relativ lang sein mov es: b color, 0 ; schwarz um den alten Zeiger zu loeschen mov es: w minrad, 0 ; runter bis zur Zeigerachse call DrawAngle mov al, es: b sekunde ; aktuellen Zeiger zeichnen - aehnlich wie oben mov ah, 0 mov bl, 48 mul bl mov es: w ein, 2880 ; sub es: w ein, ax mov es: w radius, 200 mov es: b color, 5 mov es: w minrad, 0 call DrawAngle ; Minuten - das ist wieder sehr aehnlich wie oben mov al, es: b minute ; alten Minutenzeiger loeschen cmp al, 0 ; der Wert darf nicht Null sein jnz >S2 ; al > 0: keine Korrektur erforderlich mov al, 60 ; sonst al auf 60 setzen S2: dec al ; aktuelle Minute - 1 = alte Minute cmp al, es: b sekunde ; ist das derselbe Wert wie fuer akt. Sekunde? jz noClear ; dann die Loeschroutine ueberspringen mov ah, 0 ; ah loeschen, wir operieren mit kleineren Werten mov bl, 48 ; 48 Winkelschritte = 6 Grad mul bl ; deshalb Minutenwert x 48 mov es: w ein, 2880 ; Zeiger berechnen: Vollkreis - Minutenposition = sub es: w ein, ax ; Zeigerposition mov es: w radius, 170 ; Zeigerlaenge mov es: b color, 0 ; schwarz um den 'alten' Zeiger zu uebermalen mov es: w minrad, 0 ; die Zeiger fangen am Mittelpunkt an (koennte man natuerlich aendern) call DrawAngle ; Zeichnen! noClear: mov al, es: b minute ; neuen Zeiger zeichnen mov ah, 0 mov bl, 48 mul bl mov es: w ein, 2880 sub es: w ein, ax mov es: w radius, 170 mov es: b color, 5 mov es: w minrad, 0 call DrawAngle ; Stunden - bei den Stunden werden Winkelschritte der Minuten mitberuecksichtig mov ax, es: w oldposs ; dort befindet sich die alte Position des Stundenzeigers mov es: w ein, ax ; das vereinfacht das loeschen mov es: w radius, 150 mov es: b color, 0 mov es: w minrad, 0 call DrawAngle mov al, es: b stunde ; neuen Zeiger zeichnen mov ah, 0 mov bl, 240 ; Multiplikation mit Winkelschritten mul bl mov es: w ein, 2880 ; der Kreis hat 360 Grad bzw. 2880 Winkelschritte sub es: w ein, ax ; erstmal den Wert fuer volle Stunden subtrahieren mov al, es: b minute ; die akt. Minuten verbessern die Zeigerposition mov ah, 0 mov bl, 4 ; Stundenzeigerdrehung: 4 Winkelschritte pro Minute mul bl ; das wird hier berechnet sub es: w ein, ax ; diese geringe Bewegung wird beruecksichtigt mov ax, es: w ein ; endlich: Winkel des Stundenzeigers ist berechnet mov es: w oldposs, ax ; der wird in oldposs gespeichert mov es: w radius, 150 ; und nun als Zeiger dargestellt mov es: b color, 5 mov es: w minrad, 0 call DrawAngle ;---------------------------------------------------------- ; Auf Eingabe eines Zeichens warten, ; Videomodus zurückschalten und Programm beenden ;---------------------------------------------------------- mov ah, 1 ; praktisch 'im Vorbeigehen' int 016 ; auf 'gedrueckte Taste' pruefen jnz >W1 ; wenn nein, neue Uhrzeit jmp GetT W1: mov ax, 3 ; die Funktion 0 des Videointerupts int 010 mov ah, 04C ; geplantes Ende int 021 CODE ENDS ;___________________________________ ; ; Datensegment I: Text, feste Faktoren ;___________________________________ data segment public word 'daten' korr dd 1440.0 ; würde eine Genauigkeit in Grad ausreichen müsste hier 180.0 stehen message db "use any Key to quit!",0a db "2010 ",0 Info db "*********************************************",0a,0d db "* Berechnet und Zeichnet eine Analog Uhr *",0a,0d db "* Kurzbeschreibung: beliebige Taste = Start *",0a,0d db "* 2010 *",0a,0d db "*********************************************",0a,0d,024 data ends ;___________________________________ ; ; Datensegment II: 'echte' Variablen ;___________________________________ variablen segment public word 'daten' radius dw ? ; Radius ein dw ? ; letztlich alles Hilfsspeicherstellen, Eingabewert aus dw ? ; Ausgabewert 1 aus2 dw ? ; Ausgabewert 2 oldposs dw ? ; alte Stundenzeigerposition stunde db ? ; akt. Stunde minute db ? ; akt. Minute sekunde db ? ; akt. Sekunde color db ? ; Hilfsspeicher fuer Anzeigenfarbe minrad dw ? ; unteres Limit: Radius variablen ends END start