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 bits0A3E: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 p>
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 p>
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 p>
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