comment |
This program uses the 8253 Timer Chip to generate a square wave at a
given frequency and the 8255 Programmable Peripheral Interface to
control passage of this square wave to the speaker. The low-order 2
bits of the 8255 output register (port 61h) are used to control the
timer chip and speaker. If bit 0 is a 1, then the output of channel 2
of the 8253 timer will be anabled; otherwise, it is disabled. Bit 1 of
the 8255 output register effectively goes to an AND gate which also has
timer channel 2 as an input. The approach this program takes to
generating sounds is to set both bits 0 and 1 to 1, thus enabling timer
channel 2 and also gating its output to the speaker.
The 8253 timer contains three "channels", each of which can operate in
six modes. Mode 3, the one of concern here, generates a square wave on
the channel's output based on the input clock signal and the setting on
a 2-byte internal counter register. The channel 2 output is connected
to the speaker through the AND gate shown, and is enabled by bit 0 of
the 8255. A timer command register (port 43h) must be loaded with the
proper value to place each channel into the desired mode and to specify
how transfers are to be made into the channel's counter register.
Loading the command register with b6h places timer channel 2 in mode 3
while at the same time permitting the counter register (port 42h) to be
loaded in two successive byte transfers using a standard OUT
instruction.
When in mode 3, a given timer operation begins with the contents of the
counter register being saved in another internal 8253 register. The
counter is then decremented at the input clock frequency until zero is
reached. The counter is now reloaded with its saved value, and the
decrementing process is started. In mode 3, the output of the channel
is held high until the counter has decremented to half its initial
value, and then it is held low until it has decremented to zero. As
this process is repeated, a square wave is generated at the channel
output, and in the case of channel 2 this output is fed (with the proper
setting of the 8255) into the speaker, thus generating a tone. This
cycle continues and the tone remains until a change of mode or a change
in the 8255 control bits. Once this is started, no further program
interaction is necessary. |
DSEG SEGMENT ;Notes of the scale starting with middle C
notes dw 262,277,294,311,330,349,370,392,415,440,466,494
DSEG ENDS
CSEG SEGMENT
sound proc far
assume CS:CSEG,DS:DSEG
start:
push ds ;Stack gets the return segment address
xor ax,ax
push ax ;Stack gets a zero return address
mov ax,DSEG ;set up DataSegment register
mov ds,ax
xor si,si ;SI is used as a note pointer.
mov bx,12 ;BX holds the note count.
;Set up timer command register and counter register.
mov al,0b6h ;Set 8253 command register
out 43h,al ; for channel 2, mode 3, etc.
NLoop:
mov ax,34dch ;AX gets the low part of the clock freq.
mov dx,12h ;DX gets high part of clock frequency
div [notes + SI] ;AX gets most significant byte.
out 42h,al ;8253 chip gets most significant byte.
mov al,ah ;Al gets the most significant byte.
out 42h,al ;8253 gets the most sig. byte.
;Turn on low bits in 8255 output port
in al,61h ;Read in current value of 8255 port
or al,3 ;Set low bits.
out 61h,al ;Send out new port value.
;Loop while note is sounding
mov cx,28000
RPTA: loop RPTA ;change the delay to whatever is cool!
;Turn off speaker, check note count, set up next note
xor al,3 ;Turn off speaker bit and timer gate.
out 61h,al ;Send out new 8255 port value.
mov cx,2800
RPTB: loop RPTB ;Shorter delay...
inc si ;Increment note pointer.
inc si ; do it twice cause Notes are words!
dec bx ;Decrement note counter.
jnz NLoop ;loop until BX == 0.
ret
SOUND ENDP
CSEG ENDS
END START