Red de conocimiento informático - Conocimiento sistemático - Programación de animación musical en lenguaje ensamblador (urgente)

Programación de animación musical en lenguaje ensamblador (urgente)

Había un circuito integrado utilizado específicamente para la sincronización en las primeras series de PC, modelo 8253/8254. Tiene tres canales, el primer canal se usa para controlar el funcionamiento normal del reloj del sistema; el segundo canal se usa para actualizar la memoria, estos dos canales no tienen nada que ver con los temas que estamos comentando ahora; El tercer canal es el más interesante, está conectado al altavoz mediante un conjunto de circuitos.

La Figura 4-1 muestra el circuito de sonido completo en una PC. El terminal G del canal del temporizador 3 está conectado al bit 0 del puerto 61H. Si el bit 0 del puerto 61H se establece en 1, se iniciará el canal del temporizador 3. En este momento, se emitirá un conjunto de señales. Terminal OUT. La frecuencia de la señal se puede utilizar Control de programa; si el bit 0 del puerto 61H es 0, el temporizador se apaga y el terminal OUT será constante 1

Este circuito se utiliza aquí. como un "interruptor controlable". Si el bit 0 del puerto 61H es, el bit 1 se establece en 1, lo que equivale a encender tanto el temporizador como el interruptor. En este momento, la señal de sonido generada por el temporizador será. enviado al amplificador para presionar el altavoz para que emita sonido; si el bit bit0 se establece en 0, el temporizador se apaga y esto Cuando el terminal OUT es 1, si el estado del bit1 cambia continuamente en este momento, el sonido También se puede escuchar desde el altavoz. Este es el método que usamos en el Capítulo 2. Si el bit1 se establece en 0, el interruptor se apaga, incluso si no se puede escuchar ningún sonido incluso cuando el temporizador está encendido.

Esto se puede verificar a través de DEBUG: ingrese DEBUG, escriba "O61 3" después de "-" y escuchará un sonido continuo desde el altavoz. (Experimento bajo DOS puro)

Salida "03" al puerto 61H, lo que equivale a encender el temporizador y el interruptor. En este momento, habrá un sonido continuo. La frecuencia de este sonido es. aproximadamente 896 Hz, que es lo mismo que acabamos de hacer. La frecuencia del pitido que se escucha al encender es la misma.

Lo interesante es que una vez emitido el sonido, no se detendrá y no interfiere con las operaciones del usuario.

La única forma de detener este sonido es ingresar a DEBUG y escribir el comando "O61 0 (también puede ser 1 o 2)". La razón de este fenómeno es que el funcionamiento del temporizador no requiere la participación directa de la CPU. La CPU solo necesita configurar el estado de funcionamiento y el valor de frecuencia para el tiempo y encender el temporizador. trabajar de forma independiente y la CPU puede hacerlo algo más. Esta característica es muy útil, es un requisito previo para realizar "música de fondo".

Entonces, ¿cómo cambiar la frecuencia del sonido? Tenga en cuenta que el canal 3 del temporizador también tiene un terminal de entrada CLK. Este terminal introduce una señal fija con una frecuencia de 1193181,6 Hz. La señal de salida tiene la siguiente relación con esta señal:

-------------------------------- ------------------------------------------------

F(SALIDA)=F(CLK)/N

-------------------------- ------ -------------------------------------------- ------ -

Donde N es un dato de 16 bits, su valor puede ser establecido por el programa. El método es muy simple: divida estos datos de 16 bits en 8 bits altos y bajos, primero envíe los 8 bits bajos al puerto 42H y luego envíe los 8 bits altos al puerto 42H y la frecuencia de la señal de salida. cambiará. Podemos probar:

C:\ASM\>DEBUG[Enter]

-O61 3[Enter]

-O42 0[Enter]

p>

-O42 3[Enter]

Establezca el nuevo valor N en 300H, y el F (OUT) correspondiente es 1193191.6/300H=1553Hz. La voz inmediatamente se volvió más estridente.

Hay que explicar una cosa: el temporizador tiene múltiples estados de funcionamiento y no todos los estados de funcionamiento pueden producir sonido, por lo que cuando queremos producir sonido a través del temporizador, primero debemos "inicializar" el temporizador, establecer en el correcto estado de funcionamiento. Inicializar el temporizador no es complicado, simplemente envíe los datos 0B6H al puerto 43H.

La forma binaria de estos datos es 10110110. Algunos libros llaman a este número un "BYTE mágico".

Con los conocimientos introducidos anteriormente, podemos programar el temporizador para que emita sonidos a una frecuencia determinada. El programa PROG6 puede hacer que el altavoz produzca un sonido de 1000Hz

--------------------------------- - --------------

0A3E:0100 MOV AL,B6; el registro AL está cargado con el código de configuración de inicialización del temporizador

0A3E:0102 OUT 43 ,AL Envía el código de configuración al puerto 43H para la inicialización

0A3E:0104 MOV AX,04A9;1193181.6Hz/1000=1193hz =04A9 El registro hexadecimal AX está configurado en el valor N

<; p>0A3E: 0107 OUT 42,AL; Envía el valor N al puerto 42H en dos partes porque es de 8 bits

0A3E:0109 MOV AL,AH

0A3E:010B OUT 42,AL

p>

0A3E:010D IN AL,61; Obtener el estado actual del puerto 61H

0A3E:010F PUSH AXE; >

0A3E:0110 OR AL,03; 0111

0A3E:0112 OUT 61,AL; encender el temporizador y el interruptor electrónico

0A3E:0114 MOV AH,01; AH = 01h Retorno: AL = carácter leído esperando entrada

; el carácter se repite en la salida estándar (eco)

0A3E:0116 INT 21

0A3E: 0118 POP AX ;restaurar 61H

0A3E :0119 OUT 61,AL

0A3E:011B RET

0A3E:011C

Tenemos Analizamos cómo emitir un sonido de una determinada frecuencia a través del canal 3 del temporizador, en esta sección aprenderemos cómo cronometrarlo con precisión para resolver el problema de la reproducción de música.

El circuito de temporización del PC tiene tres canales, el canal 3 se utiliza para la generación de sonido y el canal 1 se utiliza para controlar el reloj interno del sistema. Todo el mundo sabe muy bien que se puede utilizar el comando "TIME" de DOS para observar y modificar un reloj dentro del sistema. La razón por la que este reloj puede seguir funcionando depende principalmente del canal 1 del temporizador.

El canal 1 funciona de la misma manera que el canal 3, pero cuando se inicia el sistema, está configurado para enviar una señal con una frecuencia fija de 18,2 Hz. Esta señal se envía directamente al "controlador de interrupción". " en el sistema. Cada "Hz" genera una interrupción de hardware, que generalmente se denomina "IRQ0" y el número de interrupción correspondiente es 08H. En otras palabras, cuando la computadora se inicia, nuestra máquina parece muy tranquila, pero en realidad la CPU está muy ocupada. Bajo el control del temporizador, se ejecuta una interrupción No. 08H cada 55 milisegundos. El trabajo principal de esta interrupción es contar continuamente.

Hay un espacio de almacenamiento de cuatro bytes en "0040H:006CH" en la memoria dedicado a guardar el valor de conteo. Cada vez que la CPU ejecuta una interrupción 08H, el valor de conteo de cuatro bytes se incrementa en 1. No es difícil. Se calcula que cada vez que el valor del conteo aumenta en 1091, pasa exactamente 1 minuto, y cada vez que aumenta en 65454, pasa exactamente 1 hora. La razón por la cual el reloj interno del sistema puede mantener la hora exacta depende de la interrupción 08H y del valor de conteo de cuatro bytes.

Por lo tanto, si queremos una sincronización precisa, debemos confiar en el valor del conteo del reloj

;---Un programa que puede emitir con precisión un sonido de 1000 Hz con una duración de sonido de 5 segundos------- - -------

PORTB equ 61H

segmento de código

asume cs:code,ds:code

org 100h

proceso principal cerca de

mov al,10110110b ; inicializar el temporizador

fuera 43h,al

mov ax,4a9h ; El valor es 04A9H

fuera 42h,al

mov al,ah

fuera 42h,al

en al,PORT_B; en el dispositivo de sincronización y la puerta AND

o al,3

salida PORT_B,al

;------------- - -La siguiente es la parte de sincronización--------------

mov ah,0; Seleccione la función 0 de la interrupción 1AH

int 1ah. ; Llame a la interrupción 1AH para obtener el conteo del reloj actual

add dx,91; agregue 91---5 segundos al conteo del reloj actual

mov bx,dx; valor cuando expira el temporizador

retraso: int 1ah; llame a la interrupción 1AH dos veces para obtener el valor del conteo del reloj

cmp dx,bx se ha alcanzado el valor del conteo al final de el cronómetro?

jne retraso; si no se alcanza, regrese a DELAY para continuar

;----------------------- - ----------------------------

en al,PORT_B Terminación del temporizador, cierre del temporizador y puerta AND<; /p>

y al,0fch ;1111 1100

salida PORT_B,al

int 20h fin del programa

final principal

fin del código

Material de referencia: Explicación práctica del lenguaje ensamblador de PC/editado por Li Chunsheng.

segmento de datos

freq dw 196,220

dw 262,262,262,262,262,220,196

dw 262,262,262,262,294,262,220,262

dw 4,294,294 ,294,294,262,220

dw 294,294,294,294,330,294,330,392

dw 440,440,392,440,392,330

dw 294,294,330,294,262,220,196,220

dw 262, 262.262.262.262.220

dw 262.196.220

dw 440,440,392,440,524,440

dw 392,330,294,262,220,196,220

dw 262,262,262,262,294,262

dw 262,330,392

dw 44 0,440,440,440,52 4,440

dw 392,392,392,440,392,330,294

dw 262,262,262,262,294

dw 330,330,294

dw 262,262,262,262,524,440

dw 392,392,392,440,392,330,392

d w 440.524.524.440.392

dw 392,330,392

dw 440,440,440,440,524,440

dw 392,392,392,440,392,330,294

dw 262,262,262,262,392

dw 330 ,330,294

dw 262,262,262,262,294,330

dw 392,392,330,392,330,392

dw 440

dw 9,9,196,660,294,294,262

dw 262

,-1

tiempo dw 400,400

dw 400,200,400,400,800,400,400

dw 400,200,400,200,200,800,400,400

dw 400,200,4 800.400.400

dw 400,200,400,200,200,800,400,400

dw 400,800,400,800,400,400

dw 400,200,200,400,400,800,400,400

dw 400,200, 400.400.800.800

dw 160 0.800.800

dw 400.800.400.800.400.400

dw 400,400,400,400,800,400,400

dw 400,800,400,800,400,200

dw 2400,400,400

dw 400,800,400,800,400,4 00 p>

dw 400.800.200.200.800.400.400

dw 400,800,400,800,800

dw 2400,400,400

dw 400,800,400,800,400,400

dw 400,800,200,200,800,400,400

800.400.800.400.200

dw 2400, 24 00,400,400

dw 400,800,400,800,400,400

p>

dw 400,800,400,800,400,400

dw 3200

dw 800,400,400 ,400.400.400.400

dw4000

<

p> los datos terminan

segmento de código

asume cs:code,ds:data

proceso principal hasta

inicio:mov ax, datos

mov ds,ax

mov si,frecuencia de compensación

mov di,tiempo de compensación

l1: mov cx,[si ]

cmp cx,-1

salgo

mov bx,[di]

llama a gensound

agregar si,2

agregar di,2

jmp l1

salir:mov ax,4c00h

int 21h

endp principal

proceso gensound cerca

push dx

mov al,0b6h

salida 43h,al

mov dx,08h

mov ax,3208h

div cx

salida 42h,al

mov al,ah

salida 42h,al

en al,61h

mov ah,al

o al,3

out 61h,al

l2: push dx

push ax

mov dx,8h

mov ax,0f05h

s1: sub hacha,1

sbb dx,0

jnz s1

pop ax

pop dx

dec bx

jnz l2

mov al,ah

out 61h, al

pop dx

ret

gensound endp

el código termina

fin inicio