Este ejemplo muestra como colocar la hora del sistema en el centro de la pantalla.
Se utiliza para ello la lectura de la hora del sistema con el servicio: 2CH de la interrupción 21h
Para esto se utilizará una cadena -arreglo- con el formato HH:MM:SS:CC, la cual se sustituirá cada valor
obtenido como la hora, los minutos, los segundos y las centésimas, los cuales se sustituirán en sus respectivas
letras HH, para la hora, MM para los minutos, etc. Al término de llenar la cadena con los minutos, segundos y centésimas
se imprimirá en la pantalla, repitiendo el proceso hasta que oprimamos la tecla ESC.
Para obtener la hora del sistema se obtendrá con:
INT 21h / AH=2Ch - Leer la hora del sistema;
return: CH = hour. CL = minute. DH = second. DL = 1/100 seconds.
Así que obtendremos como podemos ver la hora en CH
, esto hora tendrá dos dígitos 01 hasta 24 por ejemplo.
Entonces lo que se tiene que hacer es poner las decenas -si hay- en la primera posición -si no hay pondrá cero- y las unidades en la segunda.
esto lo hacemos con la instrucción AAM
esta instrucción pasa las decenas a AH
y las unidades a AL
.
Solo sustituimos los valores respectivos en la posición de arreglo.
Por ejemplo, si la hora obtenida es la 1:35 P.M. al obtener la hora nos devolverá:
CX | DX | ||
---|---|---|---|
CH | CL | DH | DL |
0D | 35 | 00 | 2F |
Así, obtendremos 0D -hexadecimal- ósea 13 decimal, con AAM
, obtendremos en AH
las decenas -ósea 1- y en AL
las unidades -ósea 3-.
Ahora, pondremos en la cadena su equivalente en el código ASCII, del 1 es 31h del 3 es 33h, aquí aplicamos un truco,
ya que si observamos el valor de 0 es 30h, el de 1 es 31h, etcétera, es decir, sumamos 30h al número que queremos para obtener su código ASCII correspondiente.
Así que a AH
sumamos 30h con la instrucción ADD ah,30h
y lo mismo con AL ADD AL,30H
También podemos hacerlo en un solo paso con ADD AX,3030h
Ahora resta guardar en la cadena -recuerde que es un arreglo en ensamblador en realidad- el valor en su posición.
mov Hora[0],ah
; Aquí las decenas
mov Hora[1],al
; Aquí las unidades
Repetimos la misma acción para los minutos, segundos y las centésimas e imprimes la cadena.
quedando como:
13:53:00:02
Finalmente repetimos hasta que sea la tecla de salida, para ello leemos una tecla con el servicio 1 de la int 16h, para que no se detenga si no hay tecla.
Sacamos la tecla del buffer con el servicio 0 de la Int 16h.
Finalmente verificamos que sea el código de la letra S o 83h y si es así terminamos sino repetimos todo nuevamente.
; Univesidad Autonoma de Guerrero ; Facultad de Ingenieria ; Programacion del Microprocesador 8086 ; Escrito por: Ruben Rodriguez Camargo ; ------------------------------------- org 100h mov ah,9 mov dx,offset car int 21h inicio: ;Leemos la hora mov ah,2ch int 21h ;DH, hora xor ax,ax ;Limpiamos mov al, ch ;Pasamos decenas ah, unidades a al AAM add ah, 48 add al, 48 mov hora[0],ah ;Guardamos en el arreglo mov hora[1],al ;HH:... -> 12:... etc. ;Minutos Mov al,cl AAM add ah, 48 add al, 48 mov hora[3],ah mov hora[4],al ;Segundos Mov al,dh AAM add ah, 48 add al, 48 mov hora[6],ah mov hora[7],al ;Centésimas Mov al,dl AAM add ah, 48 add al, 48 mov hora[9],ah mov hora[10],al Cursor: mov ah,2 ;Ubicamos el cursor mov dh, ren mov dl, col int 10h Imprimir: mov ah,9 ;Imprimimos mov dx,offset hora ;HH:MM:SS:CC int 21h ;Salir con S mayuscula 83 mov ah,01h ;Hay tecla? int 16h jnz prefin ;Si hay jmp inicio ;Si no repetimos prefin: ; vaciamos la tecla del buffer mov ah,0 int 16h ;Verificamos que sea la S cmp al,83 jz fin ;Si es S salimos jmp inicio ;Si no iniciamos otra lectura... fin: int 20h ;Salimos ret col db 35 ren db 12 Hora db "HH:MM:SS:CC$" Car db "Oprime S para salir. $"
En este ejemplo se propone obtener una cadena de hasta 10 caracteres en la pantalla.
La lectura se hace carácter x carácter y antes de alcanzar la longitud -10 caracteres- podemos dar enter para indicar que ya terminamos.SI
se controla que este entre 0 y el número a leer máximo, es decir, la longitud de la cadena.
AL
un código 0h, y en AH
, el código ASCII de la tecla.
Por eso en estos casos verificamos el contenido del registro AH
.
AL
tienen un 0 y en AH
el código ASCII de la tecla- que sea un carácter valido. En el caso de los números 0,1,2,3,4,5,6,7,8 y 9; para números positivos
El signo - para los negativos y el punto para los reales.; Univesidad Autonoma de Guerrero ; Facultad de Ingenieria ; Programacion del Microprocesador 8086 ; Escrito por: Ruben Rodriguez Camargo ; ------------------------------------- org 100h ;leer cadena mov si,0 inicio: mov ah,0 int 16h cmp al,13 ;Verificamos si es enter 13 jz imp cmp al,8 ;BackSpace o retroceso 8 jnz sigue dec si mov cad[si],"$" ;Leer cursor mov ah,3 int 10h dec dl ;Una columna menos en cursor tambien ;mover cursor mov ah,2 int 10h mov ah,9 mov al," " mov cx,1 mov bl,15 int 10h jmp inicio sigue: mov ah,9 ;Imprimir caracter mov cx,1 ;Veces mov bl,15 ;Color int 10h ;Leer cursor mov ah,3 int 10h ;mover cursor mov ah,2 inc dl ;Incrementamos columna int 10h ;Mostrar el caracter leido mov cad[si],al mov cad[si+1],"$" cmp si,10 ;Numero de caracteres jz imp inc si jmp inicio imp: ;Leer cursor mov ah,3 int 10h ;mover cursor mov ah,2 inc dh mov dl,0 int 10h mov ah,9 mov dx,offset cad int 21h fin: int 20h ret Cad db 10 dup(32)
; Univesidad Autonoma de Guerrero ; Facultad de Ingenieria ; Programacion del Microprocesador 8086 ; Escrito por: Ruben Rodriguez Camargo ; ------------------------------------- GotoXY MACRO x, y PUSH AX PUSH BX PUSH DX ;Poner cursor mov ah,2 mov dh, y ;Ren mov dl, x ;Col mov bh,0 int 10h POP DX POP BX POP AX ENDM impC MACRO CAR,No PUSH AX PUSH BX PUSH CX PUSH DX ;Quedara asi: [0123456789] ;Poner corchete izq mov ah,9 mov al,CAR mov bh,0 mov bl,00011111b mov cx,No int 10h mov ah,3 int 10h mov ah,2 add dl,No int 10h POP DX POP CX POP BX POP AX ENDM Imp MACRO Cad Push ax Push dx mov ah,9 mov dx,offset Cad int 21h Pop dx Pop ax ENDM org 100h mov ah,0 mov al,03h int 10h GotoXY Col, Ren ;Imprimir texto Imp text ;Quedara asi: [0123456789] ;Poner corchete izq IMPC 91,1 ImpC " ",10 ImpC "]",1 GotoXY 14, Ren mov ah,0 mov al,0 ;Usaremos al como contador... mov si,0 inicio: mov ah,3 int 10h ;leer caracter mov ah,0 int 16h cmp al,8 jz Retro ;Si es enter Salir. cmp al,13 jz fin cmp al,0 jz inicio jmp Imprime Retro: cmp si,0 jz inicio dec si ;Decrementamos el indice mov al," " mov cad[si],"$" ;Ponemoss fin de cadena $ ;Leemos cursor mov ah,3 int 10h dec dl ;Una columna menos el ;mover cursor ;cursor tambien mov ah,2 int 10h ImpC Al,1 ;e imprimimos un espacio ;como esta macro mueve el mov ah,3 ;cursor una posición ;lo regresamos mov ah,3 int 10h dec dl ;Una columna menos el ;mover cursor ;cursor otra verz mov ah,2 int 10h jmp inicio Imprime: cmp si,10 jz inicio impC AL,1 Guarda: ; Almacenamos la letra en el arreglo mov cad[si],al mov cad[si+1],"$" inc si jmp inicio Fin: GotoXY 10,10 Imp Text2 Imp Cad mov ah,0 int 16h INT 20H ret Long db 10 Ren db 5 Col db 5 Cad db 20 dup(32),"$" Text db "Nombre : $" Text2 db "La Cadena es $"
; Univesidad Autonoma de Guerrero ; Facultad de Ingenieria ; Programacion del Microprocesador 8086 ; Escrito por: Ruben Rodriguez Camargo ; ------------------------------------- GotoXY MACRO x, y PUSH AX PUSH BX PUSH DX ;Poner cursor mov ah,2 mov dh, y ;Ren mov dl, x ;Col mov bh,0 int 10h POP DX POP BX POP AX ENDM impC MACRO CAR,No PUSH AX PUSH BX PUSH CX PUSH DX ;Quedara asi: [0123456789] ;Poner corchete izq mov ah,9 mov al,CAR mov bh,0 mov bl,00011111b mov cx,No int 10h mov ah,3 int 10h mov ah,2 add dx,No int 10h POP DX POP CX POP BX POP AX ENDM iCC MACRO Cad,Color PUSH AX PUSH BX PUSH CX PUSH DX PUSH SI mov SI,0 ini_icc: ;Quedara asi: [0123456789] ;Poner corchete izq mov ah,9 mov al,CAD[si] cmp al,0 jz fin_icc mov bh,0 mov bl,00011111b mov cx,1 int 10h mov ah,3 int 10h mov ah,2 add dl,1 int 10h inc si jmp ini_icc fin_icc: pop si POP DX POP CX POP BX POP AX ENDM iCC2 MACRO Cad,Color PUSH AX PUSH BX PUSH CX PUSH DX PUSH SI mov SI,0 ini_icc2: ;Quedara asi: [0123456789] ;Poner corchete izq mov ah,9 mov al,CAD[si] cmp al,0 jz fin_icc2 mov bh,0 mov bl,00011111b mov cx,1 int 10h mov ah,3 int 10h mov ah,2 add dl,1 int 10h inc si jmp ini_icc2 fin_icc2: pop si POP DX POP CX POP BX POP AX ENDM Imp MACRO Cad Push ax Push dx mov ah,9 mov dx,offset Cad int 21h Pop dx Pop ax ENDM LeeCad MACRO Cad,Long push si push ax push bx push cx push dx mov ah,0 mov al,0 ;Usaremos al como contador... mov si,0 inicio: mov ah,3 int 10h ;leer caracter mov ah,0 int 16h cmp al,8 jz Retro ;Si es enter Salir. cmp al,13 jz fin ;Si es flechas ; cmp ah,4Bh ;Es Flecha Izq? jz FlechaI cmp ah,4Dh ;Es flecha Der? jz FlechaD jmp Imprime FlechaI: cmp si,0 ;Si es 0 jz inicio ;No hace nada dec si ;Sino decrementa ;Leemos cursor mov ah,3 int 10h dec dl ;Una columna menos el ;mover cursor ;cursor tambien mov ah,2 int 10h Jmp inicio FlechaD: cmp Cad[si],"$" ;Comparamos con el final jz inicio ;si se alcanza inicio inc si ;Sino decrementa ;Leemos cursor mov ah,3 int 10h inc dl ;Una columna menos el ;mover cursor ;cursor tambien mov ah,2 int 10h jmp inicio Retro: cmp si,0 ;Si es 0 jz inicio ;Regresar dec si ;Decrementamos el indice mov al," " mov cad[si],"$" ;Ponemoss fin de cadena $ ;Leemos cursor mov ah,3 int 10h dec dl ;Una columna menos el ;mover cursor ;cursor tambien mov ah,2 int 10h ImpC Al,1 ;e imprimimos un espacio ;como esta macro mueve el mov ah,3 ;cursor una posición ;lo regresamos mov ah,3 int 10h dec dl ;Una columna menos el ;mover cursor ;cursor otra verz mov ah,2 int 10h jmp Inicio ;Inicio Imprime: cmp si,Long ;Si se alcanza limite jz inicio ;ir a inicio impC AL,1 Guarda: ; Almacenamos la letra en el arreglo mov cad[si],al ;Poner fin de cadena mov cad[si+1],"$" ;al final inc si jmp inicio ;ir inicio Fin: Pop dx pop cx pop bx pop ax pop si ENDM LeeNum MACRO Num, Long push si push ax push bx push cx push dx mov ah,0 mov al,0 ;Usaremos al como contador... mov si,0 inicio1: mov ah,3 int 10h ;leer carácter mov ah,0 int 16h cmp al,8 jz Retro1 ;Si es enter Salir. cmp al,13 jz fin1 ;Si es flechas ; cmp ah,4Bh ;Es Flecha Izq? jz FlechaI1 cmp ah,4Dh ;Es flecha Der? jz FlechaD1 ;Caracter Valido? cmp al,46 jne Car1 jmp Imprime1 Car1: cmp al,57 ;No Valido jg Inicio1 cmp al,46 jl inicio1 ;No valido cmp al, 47 ; / je inicio1 jmp imprime1 ;Car Valido FlechaI1: cmp si,0 ;Si es 0 jz inicio1 ;No hace nada dec si ;Sino decrementa ;Leemos cursor mov ah,3 int 10h dec dl ;Una columna menos el ;mover cursor ;cursor tambien mov ah,2 int 10h Jmp inicio1 FlechaD1: cmp Cad[si],"$" ;Comparamos con el final jz inicio1 ;si se alcanza inicio inc si ;Sino decrementa ;Leemos cursor mov ah,3 int 10h inc dl ;Una columna menos el ;mover cursor ;cursor tambien mov ah,2 int 10h jmp inicio1 Retro1: cmp si,0 ;Si es 0 jz inicio1 ;Regresar dec si ;Decrementamos el indice mov al," " mov cad[si],"$" ;Ponemoss fin de cadena $ ;Leemos cursor mov ah,3 int 10h dec dl ;Una columna menos el ;mover cursor ;cursor tambien mov ah,2 int 10h ImpC Al,1 ;e imprimimos un espacio ;como esta macro mueve el mov ah,3 ;cursor una posición ;lo regresamos mov ah,3 int 10h dec dl ;Una columna menos el ;mover cursor ;cursor otra verz mov ah,2 int 10h jmp Inicio1 ;Inicio Imprime1: cmp si,Long ;Si se alcanza limite jz inicio1 ;ir a inicio impC AL,1 Guarda1: ; Almacenamos la letra en el arreglo mov cad[si],al ;Poner fin de cadena mov cad[si+1],"$" ;al final inc si jmp inicio1 ;ir inicio Fin1: Pop dx pop cx pop bx pop ax pop si ENDM org 100h mov ah,0 mov al,03h int 10h GotoXY 5, 5 ;Imprimir texto Imp textC ;Quedara asi: [0123456789] ;Poner corchete izq IMPC 91,1 ImpC " ",15 ImpC "]",1 GotoXY 5, 6 ;Imprimir texto Imp text ;Quedara asi: [0123456789] ;Poner corchete izq IMPC 91,1 ImpC " ",7 ImpC "]",1 mov ax,15 ;Ponemos el valor AAM ;Que se leera add ax,03030h mov AyudaC[20],ah mov AyudaC[21],al GotoXY 0,24 iCC AyudaC,00011111b GotoXY 14, 5 LeeCad Cad,5 GotoXY 10,10 Imp TextC2 Imp Cad mov ax,7 ;Ponemos el valor AAM ;Que se leera add ax,03030h mov Ayudan[21],ah mov Ayudan[22],al GotoXY 0,24 iCC2 AyudaN,00011111b GotoXY 14, 6 LeeNum Cad,5 GotoXY 10,11 Imp Text2 Imp Cad mov ah,0 int 16h INT 20H ret Cad db 20 dup(32),"$" Text db "N",163,"mero : $" Text2 db "N",163,"mero es $" Ayudan db "Escriba n",163,"mero hasta XX, Mueva el cursor con ",27,26," finalice con Enter.",0h TextC db "Nombre : $" TextC2 db "La Cadena es $" AyudaC db "Escriba texto hasta XX, Mueva el cursor con ",27,26," finalice con Enter.",0h
Hay que mencionar que al integrar las macros tal como están puede causar conflictos ya que estas se insertan en realidad en donde se hace el llamado de la macro.
Por esa razón, el utilizar etiquetas -que son fijas- causa conflictos. Por lo tanto, si utiliza macros procure no utilizar etiquetas para los saltos.
En el tercer ejemplo notará, que para solucionar se crearon 2 macros para imprimir el carácter a color con etiquetas diferentes. Toca a usted el realizar los cambios para evitar errores.
Por último todos los problemas fueron resueltos utilizando el emulador 8086 y realizados para entornos de 16 bits.
Ejemplo de un carácter que se mueve por la pantalla hasta tocar los bordes de la pantalla y cambia de dirección.
Lo que debemos hacer es hacer un ciclo infinito y que salga cuando se oprima una tecla. Para eso está el servicio 0 de la int 16h, pero recuerda sacar la tecla del buffer con el servicio 1 de la misma interrupción.
Una vez realizado esto es colocar el cursor en una posición x, y, una dirección de desplazamiento –en mi caso lo controlo con la variable incx e incy– con un valor cero que indica que no hay incremento y 1 que si lo hay.
Al llegar a un límite, por ejemplo el eje X -columnas- tiene 2, 0 y 79. Al llegar a 0 cambia de dirección y ahora incrementa X, por lo tanto pongo la variable incx en 1, para que se incremente al llegar a 79, pongo el valor de incremento en 0, lo que hace ahora es decrementar.
Al cambiar de dirección incluí una opción interesante. Se obtiene un número aleatorio -usando para esto el servicio 2ch de la interrupción 21h, ósea obtener la hora, y utilizo las centésimas para el número aleatorio.
aleat PROC near PUSH BX PUSH CX PUSH DX mov ah,02Ch int 21h ;Generamos un numero aleatorio entre 1 y 99 ;Si es 0 inc 0 muy raro 1% ;Si es 1...29 inc 1 ocasional 29% ;si es 30..79 inc 2 frecuente 50% ;si es 80..99 inc 3 Raro 20% cmp dl,0 jz cero_1 cmp dl,30 jbe uno_1 cmp dl,79 jbe dos_1 mov al,3 jmp re_1 cero_1: mov al,0 jmp re_1 uno_1: mov al,1 jmp re_1 dos_1: mov al,2 re_1: POP DX POP CX POP BX ret aleat endp
De esta forma, divido las 99 posibles valores en 0, para 0, 1..29 para un valor de 1, 30 a 79 para un valor de 2 y 80a 99 para un valor de 3.
De esta forma 1% corresponde al cero, 29$ al 1, 50% al valor 2 y un 20% para el valor 3. Esto hace un comportamiento más o menos normal.
Como puede verse en el código del procedimiento, aleat
no restauro el registro AX
esto es así a propósito para poner en AL
el valor aleatorio entre 0 a 3.
Al Devolver la llamada con:
AX
y solo la variable -en este caso- mx
que es la variable que utilizo para el incremento o decremento del desplazamiento del -en este caso_, eje X. Lo mismo para el eje Y. Esto lo hacemos cada que llegamos a un limite tanto en el eje X como en el Y.
Antes de poner el cursor que rebota, guardo en la pila los valores del cursor, de esta forma pongo el cursor a mover y antes de regresar a hacer otro ciclo, restauro el cursor, y pongo ahora un espacio, en el mismo lugar del cursor.
Esto tiene como efecto que se vea como si el cursor fuera avanzando por la pantalla.
Finalmente oculte el cursor al empezar el screensaver ocultando el cursor con el servicio 1 de la interrupción 10h. Al salir restauramos el cursor.
Unos toques para entrar y otros para salir como hacer un ClearScreen -CLS- para limpiar la pantalla. etc.
Para probarlo se compiló y se utilizó DOSBox, para ejecutarlo y verlo a toda su velocidad. Para hacer esto montamos la unidad con Mount C: <Directorio en C>
Sin embargo al ejecutarlo va tan rápido que no se ve el efecto deseado, afortunadamente podemos reducir la velocidad de ejecución, oprimiendo ctrl+f11 y ctrl+f12 para reducir y aumentar los ciclos por reloj, y ctrl+f7 y ctrl+f8 para reducir los frames.
En mi caso obtuve una velocidad satisfactoria al reducir a 1 el ciclo por reloj y 0 el frameskip. Pero es tu caso debes probar hasta obtener el resultado dependiendo de la velocidad de tu PC.
; Univesidad Autonoma de Guerrero ; Facultad de Ingenieria ; Programacion del Microprocesador 8086 ; Escrito por: Ruben Rodriguez Camargo ; ------------------------------------- Titulo Macro ; Iniciamos moviendo el cursor mov ah,2 mov dh,0 mov dl,20 ;Columna 20,0 int 10h lea dx, tit1 mov ah, 9 int 21h ; output string at ds:dx ; moviendo el cursor mov ah,2 mov dh,1 mov dl,15 ;Columna 15,1 int 10h lea dx, tit2 mov ah, 9 int 21h ; output string at ds:dx Titulo endm data segment ; Area de datos Tit1 db "Universidad Aut",162,"noma de Guerrero",10,13,"$" Tit2 db "Programa para mover un caracter por la pantalla","$" pkey db "presione una tecla...$" autor db "Realizado por Rub",163,"n Rodr",161,"guez Camargo.","$" x db 0 y db 0 mx db 0 my db 0 incx db 0 ;0=no incy db 1 ;1=si color db 61 col_n db 7 ends stack segment dw 128 dup(0) ends code segment start: ; Asigna de datos mov ax, data mov ds, ax mov es, ax mov color, 7 call cls Titulo ; moviendo el cursor mov ah,2 mov dh,2 mov dl,25 ;Columna 15,1 int 10h lea dx, pkey mov ah, 9 int 21h ; output string at ds:dx ; Esperar una tecla.... mov ah, 1 int 21h ;Hacemos un CLS y ponemos la pantalla ;al centro. mov color,61 call cls ;ok ahora ponemos el cursor en el centro. ;Iniciamos las variables ;x para las columnas y Y para los renglones mov x,40 mov y,12 ; moviendo el cursor mov ah,2 mov dh,y ;Renglon 12 mov dl,x ;Columna 40,12 mov bh,0 int 10h ;mov ah,9 ;Lo eliminamos porque ;mov al,176 ;no se guardara su posicion ;mov bl,87 ;mov bh,0 ;mov cx,1 ;int 10h ;Ocultamos el cursor para que no se vea solo el caracter. mov ah,1 mov ch,32 int 10h ;Repetimos hasta que lleguemos a 0 ;Vamoa a iniciar con mov hacia la izq. mov mx,1 ;Avance en x mov my,1 ;AVance en Y inicia: ;-> esta es una etiqueta ;Si Dec entonces restamos el my o my mov al,incx cmp al,1 ;Comparamos si es hacia arriba ;Esto pone la bandera zf=1 si ;es asi ;Asi que buscamos que brinco dar jb NegX ;Salta si al, menor que 1 mov al,x add al,mx mov x,al jmp CompY NegX: mov al,x sub al,mx mov x,al CompY: ;Comparamos ahora en Y mov al,incy cmp al,1 jae NegY ;Salta si al, es mayor o igual mov al,y add al,my mov y,al jmp imprime NegY: mov al,y sub al,my mov y,al ;Incrementamos mov Y Imprime: ; moviendo el cursor mov ah,2 mov dh,y ;Renglon 12 mov dl,x ;Columna 40,12 mov bh,0 push ax push bx push cx push dx int 10h mov ah,9 mov al,176 mov bl,87 mov bh,0 mov cx,1 int 10h ;Verifica si es 0 para cambiar de direccion LiInfX: mov al,x cmp al,0 jnz LimInfY ;Si es cero, invertimos el movimiento mov incx,1 push ax call aleat mov mx,al pop ax LimInfY: mov al,y cmp al,0 jnz LimSupX mov incY,0 ;Aleatorio push ax call aleat mov my,al pop ax LimSupX: mov al,x cmp al,79 jbe LimSupY ;Si es menor mov incx,0 ;Aleatorio push ax call aleat mov mx,al pop ax LimSupY: mov al,y cmp al,24 jnz SalidaKey mov incy,1 ;Aleatorio push ax call aleat mov my,al pop ax SalidaKey: ;Leemos una tecla si hay Fun1h int 16h mov ah,01 int 16h jnz fin ;Restauramos el cursor y ponemos ' ' es su lugar pop dx pop cx pop bx pop ax mov ah,9 mov al," " mov bl,61 ;Mismo color de fondo mov bh,0 mov cx,1 int 10h jmp inicia fin: ; Esperar una tecla.... mov color,7 call cls Titulo ; moviendo el cursor mov ah,2 mov dh,2 mov dl,20 ;Columna 15,1 int 10h lea dx, autor mov ah, 9 int 21h ; output string at ds:dx ;Mostramos el cursor porque lo ocultamos mov ah,1 mov ch,6 mov cl,7 int 10h mov ah, 1 int 21h mov ax, 4c00h ; exit to operating system. int 21h ends aleat PROC near PUSH BX PUSH CX PUSH DX mov ah,02Ch int 21h ;Generamos un numero aleatorio entre 1 y 99 ;Si es 0 inc 0 muy raro 1% ;Si es 1...29 inc 1 ocasional 29% ;si es 30..79 inc 2 frecuente 50% ;si es 80..99 inc 3 Raro 20% cmp dl,0 jz cero_1 cmp dl,30 jbe uno_1 cmp dl,79 jbe dos_1 mov al,3 jmp re_1 cero_1: mov al,0 jmp re_1 uno_1: mov al,1 jmp re_1 dos_1: mov al,2 re_1: POP DX POP CX POP BX ret aleat endp cls Proc near push dx push cx push bx push ax mov ah,06 mov al, 25 mov bh,color mov ch,0 mov cl,0 mov dh,24 mov dl,79 int 10h pop ax pop bx pop cx pop dx ret cls endp end start ; set entry point and stop the assembler.
Algo que note es que al revisar que llegue comparo en algunos con cero o 79, es decir, con el valor máximo o mínimo que puede tener como coordenadas el cursor, en lugar de verificar que sea menor o igual o mayor o igual, según sea el caso, esto provoca que en ocasiones pueda verse que se pierde el cursor y tarde en aparecer por que se sale del límite. pero esto se realizó así para fines didácticos y corregir eso ya les toca a ustedes. Saludos.
El manejo del sonido tiene su base en el clip 8253 y/o 8454. ver apuntes UANL para consultar más sobre la teoría.
El problema principal radica en el manejo de control del tiempo, cada autor que he encontrado, realiza una forma para detener el tiempo suficiente para que la nota toque correctamente.
algunos realizan una rutina de retardo que solo consume tiempo con el fin de acercarse a los microsegundos que debe tocarse una nota, de igual manera con las pausas.
Entre nota y nota debe haber una pausa. Pero la velocidad de cada máquina hace que el problema de tocar alguna nota sea más complicado el manejo de los tiempos que él hace que toque la nota correcta.
Ya que el tocar alguna nota musical se traduce a simples matemáticas.
Así pues, utilizo un ejemplo de la referencia citada y lo modifique para hacer que toque la nota en la frecuencia correcta.
Con el DOSBox podemos reducir la velocidad de ejecución del programa, porque aun el método usado para detener el tiempo. no funciona. Así que vamos a utilizar este pequeño truco.
Al tocar una nota la divido en entre 1193180 y el resultado es la frecuencia de la nota, al tocar una nota imprimo en pantalla cual nota es.
Aquí se puede utilizar el colocar o dibujar en pantalla el efecto que queremos que se produzca al tocarse la nota, según el instrumento.
Cada instrumento tiene una frecuencia para su nota. Yo en el ejemplo pondré para piano.
Entre una estrofa y otra, pongo una pausa e imprimo un guion '-' para separar.
Así pues, el resultado se ve como en la imagen final.
.model tiny org 100h .code call nSol ;F Call nLa ;G Call nSi ;A call nSol ;F call pausa Call nSol ;F Call nLa ;G Call nSi ;A Call nSol ;F call pausa Call nSi ;A Call nDo6 ;b6, Call nRe6 ;C6 call pausa Call nSi Call nDo6 Call nRe6 call pausa Call nRe6 ;C6 Call nMi6 ;D Call nRe6 ;C Call nDo6 ;B6 Call nSi Call nSol call pausa Call nRe6 Call nMi6 Call nRe6 Call nDo6 Call nSi Call nSol call pausa Call nLa Call nRe Call nSol call pausa Call nLa Call nRe Call nSol ret pausa proc MOV AH,9 MOV DX,offset tPausa int 21h call demora ret endp demora proc dem: loop dem ret endp nDo proc MOV AH,9 MOV DX,offset tDo int 21h MOV AL,10110110b ; contador 2, modo 3, operaci?n 11b, datos binarios OUT 43h,AL ; programar contador 2 MOV AX,4561 ; 1.193.180 / 261 Hz (nota Do) = 4561 JMP SHORT $+2 OUT 42h,AL MOV AL,AH JMP SHORT $+2 OUT 42h,AL ; frecuencia programada JMP SHORT $+2 IN AL,61h OR AL,00000011b JMP SHORT $+2 OUT 61h,AL ; altavoz sonando MOV CX,0 ;demora: LOOP demora ; esperar un cierto tiempo por el peor m?todo call demora IN AL,61h AND AL,11111100b JMP SHORT $+2 OUT 61h,AL ; altavoz callado ret endp nDoS proc MOV AL,10110110b ; contador 2, modo 3, operaci?n 11b, datos binarios OUT 43h,AL ; programar contador 2 MOV AX,4307 ; 1.193.180 / 277 Hz (nota Do#) = 4307 JMP SHORT $+2 OUT 42h,AL MOV AL,AH JMP SHORT $+2 OUT 42h,AL ; frecuencia programada JMP SHORT $+2 IN AL,61h OR AL,00000011b JMP SHORT $+2 OUT 61h,AL ; altavoz sonando MOV CX,0 ;demora: LOOP demora ; esperar un cierto tiempo por el peor m?todo call demora IN AL,61h AND AL,11111100b JMP SHORT $+2 OUT 61h,AL ; altavoz callado ret endp nDo6 proc MOV AH,9 MOV DX,offset tDo6 int 21h MOV AL,10110110b ; contador 2, modo 3, operaci?n 11b, datos binarios OUT 43h,AL ; programar contador 2 MOV AX,1140 ; 1.193.180 / 1046 Hz (nota Do6) = 1140 JMP SHORT $+2 OUT 42h,AL MOV AL,AH JMP SHORT $+2 OUT 42h,AL ; frecuencia programada JMP SHORT $+2 IN AL,61h OR AL,00000011b JMP SHORT $+2 OUT 61h,AL ; altavoz sonando MOV CX,0 ;demora: LOOP demora ; esperar un cierto tiempo por el peor m?todo call demora IN AL,61h AND AL,11111100b JMP SHORT $+2 OUT 61h,AL ; altavoz callado ret endp nRe proc MOV AH,9 MOV DX,offset tRe int 21h MOV AL,10110110b ; contador 2, modo 3, operaci?n 11b, datos binarios OUT 43h,AL ; programar contador 2 MOV AX,4072 ; 1.193.180 / 293 Hz (nota Re) = 4072 JMP SHORT $+2 OUT 42h,AL MOV AL,AH JMP SHORT $+2 OUT 42h,AL ; frecuencia programada JMP SHORT $+2 IN AL,61h OR AL,00000011b JMP SHORT $+2 OUT 61h,AL ; altavoz sonando MOV CX,0 ;demora: LOOP demora ; esperar un cierto tiempo por el peor m?todo call demora IN AL,61h AND AL,11111100b JMP SHORT $+2 OUT 61h,AL ; altavoz callado ret endp nReS proc MOV AL,10110110b ; contador 2, modo 3, operaci?n 11b, datos binarios OUT 43h,AL ; programar contador 2 MOV AX,3836 ; 1.193.180 / 311 Hz (nota Re#) = 3836 JMP SHORT $+2 OUT 42h,AL MOV AL,AH JMP SHORT $+2 OUT 42h,AL ; frecuencia programada JMP SHORT $+2 IN AL,61h OR AL,00000011b JMP SHORT $+2 OUT 61h,AL ; altavoz sonando MOV CX,0 ;demora: LOOP demora ; esperar un cierto tiempo por el peor m?todo call demora IN AL,61h AND AL,11111100b JMP SHORT $+2 OUT 61h,AL ; altavoz callado ret endp nRe5 proc MOV AH,9 MOV DX,offset tRe5 int 21h MOV AL,10110110b ; contador 2, modo 3, operaci?n 11b, datos binarios OUT 43h,AL ; programar contador 2 MOV AX,2032 ; 1.193.180 / 587 Hz (nota Re5) = 2032 JMP SHORT $+2 OUT 42h,AL MOV AL,AH JMP SHORT $+2 OUT 42h,AL ; frecuencia programada JMP SHORT $+2 IN AL,61h OR AL,00000011b JMP SHORT $+2 OUT 61h,AL ; altavoz sonando MOV CX,0 ;demora: LOOP demora ; esperar un cierto tiempo por el peor m?todo call demora IN AL,61h AND AL,11111100b JMP SHORT $+2 OUT 61h,AL ; altavoz callado ret endp nRe6 proc MOV AH,9 MOV DX,offset tRe6 int 21h MOV AL,10110110b ; contador 2, modo 3, operaci?n 11b, datos binarios OUT 43h,AL ; programar contador 2 MOV AX,1016 ; 1.193.180 / 1174 Hz (nota Re#) = 1016 JMP SHORT $+2 OUT 42h,AL MOV AL,AH JMP SHORT $+2 OUT 42h,AL ; frecuencia programada JMP SHORT $+2 IN AL,61h OR AL,00000011b JMP SHORT $+2 OUT 61h,AL ; altavoz sonando MOV CX,0 ;demora: LOOP demora ; esperar un cierto tiempo por el peor m?todo call demora IN AL,61h AND AL,11111100b JMP SHORT $+2 OUT 61h,AL ; altavoz callado ret endp nMi proc MOV AL,10110110b ; contador 2, modo 3, operaci?n 11b, datos binarios OUT 43h,AL ; programar contador 2 MOV AX,3626 ; 1.193.180 / 329 Hz (nota Mi) = 3626 JMP SHORT $+2 OUT 42h,AL MOV AL,AH JMP SHORT $+2 OUT 42h,AL ; frecuencia programada JMP SHORT $+2 IN AL,61h OR AL,00000011b JMP SHORT $+2 OUT 61h,AL ; altavoz sonando MOV CX,0 ;demora: LOOP demora ; esperar un cierto tiempo por el peor m?todo call demora IN AL,61h AND AL,11111100b JMP SHORT $+2 OUT 61h,AL ; altavoz callado ret endp nMi6 proc MOV AH,9 MOV DX,offset tMi int 21h MOV AL,10110110b ; contador 2, modo 3, operaci?n 11b, datos binarios OUT 43h,AL ; programar contador 2 MOV AX,905 ; 1.193.180 / 1318 Hz (nota Mi6) = 905 JMP SHORT $+2 OUT 42h,AL MOV AL,AH JMP SHORT $+2 OUT 42h,AL ; frecuencia programada JMP SHORT $+2 IN AL,61h OR AL,00000011b JMP SHORT $+2 OUT 61h,AL ; altavoz sonando MOV CX,0 ;demora: LOOP demora ; esperar un cierto tiempo por el peor m?todo call demora IN AL,61h AND AL,11111100b JMP SHORT $+2 OUT 61h,AL ; altavoz callado ret endp nFa proc MOV AH,9 MOV DX,offset tFa int 21h MOV AL,10110110b ; contador 2, modo 3, operaci?n 11b, datos binarios OUT 43h,AL ; programar contador 2 MOV AX,3626 ; 1.193.180 / 349 Hz (nota Fa) = 3418 JMP SHORT $+2 OUT 42h,AL MOV AL,AH JMP SHORT $+2 OUT 42h,AL ; frecuencia programada JMP SHORT $+2 IN AL,61h OR AL,00000011b JMP SHORT $+2 OUT 61h,AL ; altavoz sonando MOV CX,0 ;demora: LOOP demora ; esperar un cierto tiempo por el peor m?todo call demora IN AL,61h AND AL,11111100b JMP SHORT $+2 OUT 61h,AL ; altavoz callado ret endp nSol proc MOV AH,9 MOV DX,offset tSol int 21h MOV AL,10110110b ; contador 2, modo 3, operaci?n 11b, datos binarios OUT 43h,AL ; programar contador 2 MOV AX,3043 ; 1.193.180 / 392 Hz (nota Sol) = 30431 JMP SHORT $+2 OUT 42h,AL MOV AL,AH JMP SHORT $+2 OUT 42h,AL ; frecuencia programada JMP SHORT $+2 IN AL,61h OR AL,00000011b JMP SHORT $+2 OUT 61h,AL ; altavoz sonando MOV CX,0 ;demora: LOOP demora ; esperar un cierto tiempo por el peor m?todo call demora IN AL,61h AND AL,11111100b JMP SHORT $+2 OUT 61h,AL ret endp nLa proc MOV AH,9 MOV DX,offset tLa int 21h MOV AL,10110110b ; contador 2, modo 3, operaci?n 11b, datos binarios OUT 43h,AL ; programar contador 2 MOV AX,2711 ; 1.193.180 / 440 Hz (nota LA) = 2711 JMP SHORT $+2 OUT 42h,AL MOV AL,AH JMP SHORT $+2 OUT 42h,AL ; frecuencia programada JMP SHORT $+2 IN AL,61h OR AL,00000011b JMP SHORT $+2 OUT 61h,AL ; altavoz sonando MOV CX,0 ;demora: LOOP demora ; esperar un cierto tiempo por el peor m?todo call demora IN AL,61h AND AL,11111100b JMP SHORT $+2 OUT 61h,AL ret endp nSi proc MOV AH,9 MOV DX,offset tSi int 21h MOV AL,10110110b ; contador 2, modo 3, operaci?n 11b, datos binarios OUT 43h,AL ; programar contador 2 MOV AX,2420 ; 1.193.180 / 493 Hz (nota SI) = 2420 JMP SHORT $+2 OUT 42h,AL MOV AL,AH JMP SHORT $+2 OUT 42h,AL ; frecuencia programada JMP SHORT $+2 IN AL,61h OR AL,00000011b JMP SHORT $+2 OUT 61h,AL ; altavoz sonando MOV CX,0 ;demora: LOOP demora ; esperar un cierto tiempo por el peor m?todo call demora IN AL,61h AND AL,11111100b JMP SHORT $+2 OUT 61h,AL ; altavoz callado ret endp .data tDo db " Do $" tRe db " Re $" tMi db " Mi $" tFa db " Fa $" tSol db " Sol $" tLa db " La $" tSi db " Si $" tDo6 db " Do6 $" tRe6 db " Re6 $" tMi6 db " Mi6 $" tRe5 db " Re5 $" tPausa db "-$" end
Colocando pixeles por la pantalla es lo que se hace en ensamblador con el servicio 0ch de la interrupción 10h
Para dibujar una línea, podemos utilizar la teoría de la línea recta y conociendo el desplazamiento en X o Y, podemos decidir cómo dibujar la línea y que eje utilizar para conociendo -por ejemplo, el eje X, calcular en qué posición debe ir en Y.
De esta manera dibujando pixel x pixel podemos dibujar la línea. Quizá un poco complicado, pero así lo debe hacer cualquier lenguaje de programación de alto nivel, desde luego tomando en cuenta más factores.
Para hacer un dibujo, es otro problema que resulta menos complicado y quizá más interesante.
Vamos a dibujar un insecto, que será el principio de todos los juegos, no quiero decir que todos los hacen así, sino que este es mi método para dibujar una imagen. Tanto que em BMP y otros formatos hacen casi lo mismo. este insecto se podrá dibujar, después volver a dibujar la imagen 2, y luego borrar. Repetir esto según se quiera.
Seleccionamos una imagen a copiar -si tienes mucha imaginación o te gusta diseñar, puedes empezar directamente a dibujar- y utilizando una hoja cuadriculada, iremos pintando con color, los cuadros conforme a la imagen.
Para hacerlo más sencillo utilizare una matriz de 16 x (lo que me dé la imagen)
Como no soy muy bueno dibujando -modestia parte pero si dibujo bien- o quizá un tanto flojo -o práctico, depende el punto de vista 🌝-, utilizaré una herramienta como Excel u hoja de cálculo.
Ahí, pinto cada color de celda y hago 2 imágenes, la 2a con ligeros cambios para simular movimiento.
Puede ver a la izquierda una imagen y a la derecha otra con pequeños cambios en las patas para simular el movimiento.
Ahora
lo que hacemos es colocar el color que corresponde a la cada pixel -celda o cuadro del cuaderno, según tu herramienta de trabajo elegida-
Ahora debes construir el código, que tendrá el arreglo, por ejemplo DB 0,6,6,0,0,15,0,0,15,0,0,6,6,0
Que corresponde a la 2a línea, y así sucesivamente hasta terminar.
Yo me ayude de Excel y en la celda S, construí una fórmula que me construyera el código en ensamblador, para no hacerlo en forma manual y evitar cometer errores..
Ahora solo copio y pego dicho código en ensamblador.
Lo siguiente es solo construir una rutina que ubique el pixel y tome el color que se va a pintar, pixel x pixel.
Tome en cuenta que aquí será un arreglo con las 16x24 renglones = 384, cada 16 debemos pasar al siguiente renglón en la pantalla. hasta llegar a los 23 renglones o los 384 valores.
El índice del arreglo utilice el registro Si y a partir de la dirección del arreglo + desplazamiento, obtengo el color.
; Univesidad Autonoma de Guerrero ; Facultad de Ingenieria ; Programacion del Microprocesador 8086 ; Escrito por: Ruben Rodriguez Camargo ; ------------------------------------- data segment Tit1 db "Universidad Aut",162,"noma de Guerrero",10,13,"$" Tit2 db "Programa para dibujar un insecto en la pantalla",10,13,"$" pkey db "presione una tecla...$" autor db "Realizado por Rub",163,"n Rodr",161,"guez Camargo.","$" cuca DB 0,6,0,0,0,0,0,0,0,0,0,0,0,0,6,0, ;Color 0=Negro, 6=Cafe DB 0,0,6,6,0,0,15,0,0,15,0,0,6,6,0,0, ;15=Blanco DB 0,0,0,0,6,6,6,6,6,6,6,6,0,0,0,0, DB 0,0,0,0,0,0,8,6,6,8,0,0,0,0,0,0, DB 0,0,0,0,0,0,8,6,6,8,0,0,0,0,0,0, DB 0,15,15,0,0,0,8,6,6,8,0,0,0,15,0,0, DB 15,0,0,15,0,0,8,6,6,8,0,0,15,0,15,0, ;8=gris, DB 0,0,0,0,15,8,0,6,6,0,8,15,0,0,0,0, DB 0,15,15,0,8,6,12,6,6,12,6,8,0,0,15,0, DB 15,0,0,8,6,6,12,6,6,12,6,6,8,15,0,15, DB 0,0,0,8,6,6,12,6,6,12,6,6,8,0,0,0, DB 0,0,0,8,6,6,12,6,6,12,6,6,8,0,0,0, DB 0,0,0,8,6,6,12,6,6,12,6,6,8,0,0,0, DB 0,0,0,8,6,6,12,6,6,12,6,6,8,0,0,0, DB 0,0,0,8,6,6,12,6,6,12,6,6,8,15,15,0, ;12=rojo DB 0,15,15,15,8,6,12,6,6,12,6,8,15,0,0,15, DB 15,0,0,0,0,8,6,6,6,6,8,0,,0,0,0, DB 0,0,0,15,15,15,8,6,8,8,15,15,15,,0,0, DB 0,0,15,0,0,0,8,6,8,0,0,0,0,15,0,0, DB 0,0,0,0,0,0,0,8,8,0,0,0,0,0,0,0, DB 0,0,0,0,0,0,0,8,8,0,0,0,0,0,0,0, DB 0,0,0,0,0,0,0,8,8,0,0,0,0,0,0,0, DB 0,0,0,0,0,0,0,8,8,0,0,0,0,0,0,0, Cuca2 DB 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 DB 0,0,6,6,0,0,10,0,0,10,0,0,6,6,0,0, DB 0,6,0,0,6,6,6,6,6,6,6,6,0,0,6,0, DB 0,0,0,0,0,0,8,6,6,8,0,0,0,0,0,0, DB 0,15,0,0,0,0,8,6,6,8,0,0,0,0,15,0, DB 0,0,15,0,0,0,8,6,6,8,0,0,0,15,0,0, DB 15,0,0,15,0,0,8,6,6,8,0,0,15,0,0,0, DB 0,15,0,0,15,8,0,6,6,0,8,15,0,0,0,15, DB 0,0,15,0,8,6,12,6,6,12,6,8,0,0,15,0, DB 0,0,0,8,6,6,12,6,6,12,6,6,8,15,0,0, DB 0,0,0,8,6,6,12,6,6,12,6,6,8,0,0,0, DB 0,0,0,8,6,6,12,6,6,12,6,6,8,0,0,0, DB 0,0,0,8,6,6,12,6,6,12,6,6,8,0,0,0, DB 15,0,0,8,6,6,12,6,6,12,6,6,8,0,15,15, DB 0,15,0,8,6,6,12,6,6,12,6,6,8,15,0,0, DB 0,0,15,15,8,6,12,6,6,12,6,8,15,0,0,0, DB 0,0,0,0,0,8,6,6,6,6,8,0,0,0,0,0, DB 0,0,15,15,15,15,8,6,8,8,15,15,15,15,0,0, DB 0,0,0,0,0,0,8,6,8,0,0,0,0,0,0,0, DB 0,0,0,0,0,0,0,8,8,0,0,0,0,0,0,0, DB 0,0,0,0,0,0,8,8,0,0,0,0,0,0,0,0, DB 0,0,0,0,0,0,0,8,8,0,0,0,0,0,0,0, DB 0,0,0,0,0,0,8,8,0,0,0,0,0,0,0,0 r dw 10 ;Renglon=10 C dw 10 X dw 10 ;En Columna 10, 0-320 y dw 10 ; renglon 10, 0-200 Color db 7 ;Fondo negro letra blanca. ends stack segment dw 128 dup(0) ends code segment start: Titulo Macro ; Iniciamos moviendo el cursor mov ah,2 mov dh,0 mov dl,20 ;Columna 20,0 int 10h lea dx, tit1 mov ah, 9 int 21h ; output string at ds:dx ; moviendo el cursor mov ah,2 mov dh,1 mov dl,15 ;Columna 15,1 int 10h lea dx, tit2 mov ah, 9 int 21h ; Imprime Escuela Titulo endm ; Asigna segmentos a los registros: mov ax, data mov ds, ax mov es, ax Call Cls ; Limpiamos la pantalla. Titulo ; Imprimie los titulos lea dx, pkey mov ah, 9 int 21h ; Imprimir Presiona una tecla... ; wait for any key.... mov ah, 1 int 21h ; Espera la tecla ;modo grafico mov ah,0h mov al,13h int 10h ;320x200 ;Colocamos las coordenadas a dibujar mov x,10 mov y,10 lea bx, cuca Call Dib Mov x,30 mov y,10 lea bx, cuca2 call Dib fin: lea dx, pkey mov ah, 9 int 21h ; Imprime Presiona una tecla mov ah, 1 ; Espera una tecla int 21h ;restauramos modo grafico mov ah,0h mov al,3h int 10h Titulo ; moviendo el cursor mov ah,2 mov dh,2 mov dl,20 ; Columna 15,1 int 10h lea dx, autor mov ah, 9 int 21h ;Mostramos el cursor porque lo ocultamos mov ah,1 mov ch,6 mov cl,7 int 10h mov ax, 4c00h ; Salir a SO int 21h ; Procedimiento para dibujar la cucaracha ; Requiere colocar en X y Y la posicion a dibujar ; en bx, la direccion de la imagen a dibujar.. Dib Proc push si push ax push bx push cx push dx mov si,0 mov c,0 mov ax,y mov r,ax @inicio: ;dibujamos la cucaracha ;lea bx, cuca xor cx,cx mov ah,0ch mov al,[bx + si] mov cx,c add cx,x mov dx,r int 10h inc si ;llegamos al final cmp si, 368 ;Es el tamaño del arreglo, 16 col x 23 Reng=368 jz @fin ;llegamos a la columna? Sig Renglon mov ax,si mov dl,16 ;Numero de columnas 16 idiv dl cmp ah,0 jnz @otr inc r mov c,0 @otr: inc c jmp @inicio @fin: pop dx pop cx pop bx pop ax pop si ret Dib endp ;Requiere poner en color ;el color del fondo a limpiar. cls Proc near push dx push cx push bx push ax mov ah,06 mov al, 25 mov bh,color mov ch,0 mov cl,0 mov dh,24 mov dl,79 int 10h pop ax pop bx pop cx pop dx ret cls endp ends end start ; set entry point and stop the assembler.
Una vez obtenido esto, se me ocurrió combinar el programa screensaver y en lugar de colocar un carácter, modificarlo para que en modo gráfico pintara la primera, imagen, luego la segunda, luego limpiara, pasara a la siguiente coordenada y repitiera esto hasta que presionemos una tecla.
El resultado se muestra a continuación. No pongo el código pero con gusto se lo enviare a los que me lo soliciten.
Escribe algún comentario.
Tel. 74 7131 1223
Email: ruben_@yahoo.com