Current location - Music Encyclopedia - QQ Music - Assembly language music animation programming (urgent)
Assembly language music animation programming (urgent)

There was an integrated circuit specifically used for timing in the early PC series, model 8253/8254. It has three channels, the first channel is used to control the normal operation of the system clock; the second channel is used for memory refresh; these two channels have nothing to do with the issues we are discussing now. The third channel is the most interesting, it is connected to the speaker through a set of circuits.

Figure 4-1 shows the complete sound circuit in the PC. The G terminal of timer channel 3 is connected to the bit0 bit of port 61H. If the bit0 bit of port 61H is set to 1, then timer channel 3 will be started. At this time, a set of signals will be output from the OUT terminal. The frequency of the signal can be used Program control; if the bit 0 of the 61H port is 0, the timer is turned off and the OUT terminal will be constant 1

This circuit is used here as a "controllable switch". If the bit 0 of the 61H port is , bit1 bit is set to 1, which is equivalent to turning on both the timer and the switch. At this time, the sound signal generated by the timer will be sent to the amplifier to push the speaker to make sound; if the bit0 bit is set to 0, the timer is turned off, and this When the OUT terminal is 1, if the state of bit1 is continuously changed at this time, the sound can also be heard from the speaker. This is the method we used in Chapter 2; if the bit1 bit is set to 0, the switch is turned off, even if No sound can be heard even when the timer is turned on.

This can be verified through DEBUG: enter DEBUG, type "O61 3" after "-", and you will hear a continuous sound from the speaker. (Experiment under pure DOS)

Output "03" to the 61H port, which is equivalent to turning on the timer and switch. At this time, there will be a continuous sound. The frequency of this sound is about 896Hz, which is the same as what we just The frequency of the beep heard when turning on is the same.

The interesting thing is that once the sound is emitted, it will not stop and does not interfere with any user operations.

The only way to stop this sound is to enter DEBUG and type the command "O61 0 (can also be 1 or 2)". The reason for this phenomenon is that the work of the timer does not require the direct participation of the CPU. The CPU only needs to set the working status and frequency value for the time and turn on the timer. At this time, the timer will work independently and the CPU can do it. Something else. This feature is very useful, it is the prerequisite for realizing "background music".

So how to change the frequency of sound? Please note that channel 3 of the timer also has an input terminal CLK. This terminal inputs a fixed signal with a frequency of 1193181.6Hz. The output signal has the following relationship with this signal:

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

F(OUT)=F(CLK)/N

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

Where N is a 16-bit data, its value can be set by the program. The method is very simple: divide this 16-bit data into high and low 8-bits, first send the low 8 bits to the 42H port, and then send the high 8 bits to the 42H port, and the frequency of the output signal will change. We can try:

C:\ASM\gt;DEBUG[Enter]

-O61 3[Enter]

-O42 0[Enter]

-O42 3[Enter]

Set the new N value to 300H, and the corresponding F (OUT) is 1193191.6/300H=1553Hz. The voice immediately became shriller.

One thing must be explained, the timer has multiple working states, and not every working state can produce sound, so when we want to produce sound through the timer, we should first "initialize" the timer, Establish it in the correct working order. Initializing the timer is not complicated, just output data 0B6H to port 43H. The binary form of this data is 10110110. Some books call this number a "magic BYTE".

With the knowledge introduced above, we can program the timer to emit sounds at a given frequency. The program PROG6 can make the speaker produce 1000Hz sound

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

0A3E: 0100 MOV AL, B6; AL register loads timer initialization setting code

0A3E: 0102 OUT 43 , AL; Output the setting code to the 43H port for initialization

0A3E: 0104 MOV AX, 04A9; 1193181.6Hz/1000=1193hz =04A9 hexadecimal AX register sets the N value

0A3E: 0107 OUT 42, AL; Output the N value to the 42H port in two parts because it is 8 bits

0A3E: 0109 MOV AL, AH

0A3E: 010B OUT 42, AL

p>

0A3E: 010D IN AL, 61; Get the current status of port 61H

0A3E: 010F PUSH AX; Push into the stack

0A3E: 0110 OR AL, 03; 0111

0A3E: 0112 OUT 61, AL; turn on the timer and electronic switch

0A3E: 0114 MOV AH, 01; AH = 01h Return: AL = character read waiting for input

; character is echoed to standard output (echo)

0A3E: 0116 INT 21

0A3E: 0118 POP AX; recovery 61H

0A3E :0119 OUT 61, AL

0A3E:011B RET

0A3E:011C

We have discussed how to make a sound of a determined frequency through channel 3 of the timer , in this section we are going to learn how to accurately time things so that we can solve the problem of playing music.

The timing circuit in the PC has three channels, channel 3 is used for sound generation, and channel 1 is used to control the internal clock of the system. Everyone knows very well that you can use the "TIME" command of DOS to observe and modify a clock inside the system. The reason why this clock can continue to run mainly depends on channel 1 of the timer.

Channel 1 works in the same way as channel 3, but when the system is started, it is set to send a signal with a fixed frequency of 18.2Hz. This signal is sent directly to the "interrupt controller" in the system. Each "Hz" generates a hardware interrupt, which is generally called "IRQ0", and the corresponding interrupt number is 08H. In other words, when the computer starts up, our machine looks very calm, but in fact the CPU is very busy. Under the control of the timer, an interrupt No. 08H is executed every 55 milliseconds. The main job of this interrupt is to count continuously.

There is a four-byte storage space at "0040H:006CH" in the memory dedicated to saving the count value. Every time the CPU executes an 08H interrupt, the four-byte count value is increased by 1. It is not difficult. It is calculated that every time the count value increases by 1091, exactly 1 minute has passed, and every time it has increased by 65454, exactly 1 hour has passed. The reason why the system's internal clock can keep accurate time depends on the 08H interrupt and the four-byte count value. Therefore, if we want accurate timing, we must rely on the clock count value

;---A program that can accurately emit a 1000Hz sound with a sound duration of 5 seconds-------- -------

PORTB equ 61H

code segment

assume cs:code, ds:code

org 100h

main proc near

mov al, 10110110b; initialize timer

out 43h, al

mov ax, 4a9h; set N The value is 04A9H

out 42h, al

mov al, ah

out 42h, al

in al, PORT_B; turn on timing Device and AND gate

or al, 3

out PORT_B, al

;---------------- --The following is the timing part---------------

mov ah, 0; select function 0 of the 1AH interrupt

int 1ah; Call the 1AH interrupt to obtain the current clock count

add dx, 91; add 91---5 seconds to the current clock count

mov bx, dx; save the count value when the timer expires

delay: int 1ah; call the 1AH interrupt twice to obtain the clock count value

cmp dx, bx; has the count value been reached at the end of the timer?

jne delay; If not reached, return to DELAY to continue

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

in al, PORT_B; Timing termination, close timer and AND gate

and al, 0fch; 1111 1100

out PORT_B, al

int 20h; end program

main endp

code ends

Reference material: Practical explanation of PC assembly language/edited by Li Chunsheng.

data segment

freq dw 196, 220

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

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

dw 294, 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 440, 440, 440, 440, 524, 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

dw 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

time dw 400, 400

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

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

dw 400 , 200, 400, 400, 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 1600, 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, 400

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

dw 800 , 400, 800, 400, 200

dw 2400, 400, 400

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

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

dw 400, 800, 400, 800, 800

dw 2400, 400, 400

dw 400 ,8

00, 400, 800, 400, 400

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

dw 3200

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

dw 4000

data ends

code segment

assume cs: code, ds: data

main proc far

start: mov ax, data

mov ds, ax

mov si, offset freq

mov di, offset time

l1: mov cx, [si]

cmp cx, -1

je exit

mov bx, [di]

call gensound

add si, 2

add di, 2

jmp l1

exit: mov ax, 4c00h

int 21h

main endp

gensound proc near

push dx

mov al, 0b6h

out 43h, al

mov dx, 08h

mov ax, 3208h

div cx

out 42h, al

mov al, ah

out 42h, al

in al, 61h

mov ah, al

or al, 3

out 61h, al

l2: push dx

push ax

mov dx, 8h

mov ax, 0f05h

s1: sub ax, 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

code ends

end start