PC系列机的发音方法
可编程的计时器芯片是标准PC机发声功能的核心。计时器芯片的通道2是专用于声音产生的。要产生声音,必须对通道2适当编程,并使用通道2发出的脉冲来驱动扬声器。
通过编程,计时器可以以需要的任何频率发出脉冲,但由于它并不记录声音持续了多长时间,除非把它关上,否则声音便会永远持续下去;所以,程序必须通过一些定时指令来终止发声。
1、对计时器芯片进行编程
对计时器的通道2进行编程,给通道2的计数器一个合适的倒计数值(计时器芯片用一个内部寄存器来保存这个值,以便每当计数器倒计数至0时重新设置该计数值)。把倒计数值载入计时器芯片中就立即起作用。在每个1.19318MHz的时钟周期,计时器使此计数器递减,直到递减至0,然后在通道2上输出脉冲到声音产生电路中,并重新开始倒计数。
事实上,时钟频率被计数值(即:倒计数的初值)除得到输出频率。结果是,如打开扬声器,计时器送出一系列脉冲,产生一定频率的声音。
控制计数和最终频率有如下公式的相互关系:
计数值=1193180÷频率
频率=1193180÷计数值
可以看出,高计数值可产生低频率的声音,而低计数值可产生高频率的声音。计数值为100,会产生频率大约每秒11931周期的高音,而计数值为10000,则会产生频率大约每秒119周期的低音。
在16位算术的范围内,几乎可以产生任何频率。在除数(即:分频数)为65535(FFFFH)时产生最低的频率18.2Hz,在除数为1时产生最高的频率1.193MHz。BASIC把实际频率范围控制在37到3276Hz。以下程序表明内部扬声器的实际频率范围甚至比BASIC所提供的还要小。
一旦你根据所需频率计算出计数值,就可以将它送至计时器通道2的寄存器中。这需做三次向端口的输出。第一次端口输出是向端口43H(67)送值B6H(182),通知计时器即将送来的是计数值。以后的两次输出则向端口42H(66)送一个16位无符号的字的计数值。
保? COUNT=1193180/3000 '3000是所需的频率
20 LO.COUNT=COUNT MOD 256 '计算出低字节值
30 HL.COUNT=COUNT/256 '计算出高字节值
40 OUT &H43,&HB6 '通知计时器准备好
50 OUT &H42,&LO.COUNT '送低位字节
60 OUT &HI.COUNT '送高位字节
2.激发扬声器
在对计时器编程后,为使用计时器产生的信号,还需要激发扬声器电路。正象PC和PS/2的许多部分,PC和PS/2通过向某特定的端口送某一值来控制扬声器,这一过程如图1所示。扬声器的启动是由改变61H(97)I/O端口的0位和1位的值来控制的。在该端口的8位中只有两位由扬声器使用:0位和1位。其它6位用于其它方面,所以在使用扬声器时,一定不要去改变他们。CPU
定时器准备 端口43H 向扬声器发送脉冲
置频率计数器 端口42H 8253_可编程序定时器 放大器
打开扬声器 端口61H
扬声器
图1 声音频率怎样通过系统计时器和扬声器产生的
0位,控制计时器芯片的输出信号向扬声器的传送。1位,控制扬声器的脉冲。两位须都置1,扬声器才能对计时器芯片的信号做出反应。可以通过如下操作把这两位置1,而不影响其它位:
70 OLD.PORT=INP(&H61)? '读端口61H的值
80 NEW.PORT=(OLD.PORT OR &H03) '置0位和1位
90 OUT &H61,NEW.PORT '打开扬声器
二、扬声器的直接控制
计时器通过发送周期性信号来激发扬声器的振动。也可以通过程序直接向扬声器发送信号来实现同样过程,此时要把端口61H(97)的0位置0,将扬声器关上,然后将1位轮流置1和置0以向扬声器发送脉冲。使用这种方法,程序执行得越快,声音频率越高。如下BA_SIC程序给出了这种方法的一个例子:
10 X=INP(&61)AND &HFC '读端口的值,将0位和1位置0
20 OUT &H61,X '压缩扬声器
30 OUT &H61,X OR 2 '扩张扬声器
40 GOTO 20
第20行和30行向扬声器发送脉冲,每一步占用半个周期,两步合成一个完整的声音周期。
这个例子中BASIC以其最快的速度处理程序能发出的最高音调。如晨在应用程序中需要更大的频率范围,可以使用速度更快的语言,并在每个完整的周期(周期时间减半,因为每个开或关操作都仅是半个周期)之间插入一个节拍减半频率周期的延迟时间。无论使用何种语言,都必须有一个持续计数来结束发声。为了以特定的频率发出不同的声音,如“咔嗒”或“蜂鸣”声,只需改变脉冲间的延迟时间。
尽管有这些美好的可能性,通过直接编程控制扬声器发声并不是产生声音的好办法。与使用计时器相比较,它有三大缺陷:
·程序要求不断占用CPU,所以计算机几乎没有时间去做其它工作。
·声音频率由计算机的速度决定,亦即同一程序在快慢不同的型号的机器上会发出高低不同的声音。
·时钟节拍信号引起的中断会干扰声音的光滑性,产生颤音。解决它的唯一办法是用禁止中断来挂起时钟节拍中断,但这破坏了计算机的时感。
就我们所知,直接控制产生声音的唯一优点是:使用程序延时的适当控制,控制方法就可产生丰富的复调声音。但须预先提请注意,这种作法要求十分巧妙而烦琐的编程,因而很可能麻烦,不值得这样做。
三、扬声器的音量和音质
计算机的内部扬声器无任何音量控制。而且和其它扬声器一样,其音量随频率响应的好坏而变化;有些频率听起来比其它频率声音大。在大多数的PC和PS/2机中,由于扬声器很粗糙,随着频率不同音量差别很大。可用如下程序验证这一点__它可能有助于选择你所要求的最佳音调的频率。
10 PLAY〃MF〃 '分别发声
20 FREQUENCY=37
30 WHILE FREQUENCY<32000 '使用到32000Hz的所有频率
40 PRINT USING〃.〃;FREQUENCY'e显示频率
50 SOUND FREQUENCY,5 '以5个单位持续时间发声
60 FREQUENCY=FREQUENCY1.1 '增加1/10的频率
70 WEND
须知在不同的PC和PS/2的机器中,扬声器发出的声音可能不一样。部分原因是作为扬声器附件的共振腔的材料不同。在两种不同型号的机器上,试运行如下例子,并准备听到声音的变化。
100 '声音例子
110 '
120 '颤音(两种声音快速交替)
130 FOR N%=0 TO 5
140 SOUND 440,.7
150 SOUND 466.16,.5
160 NEXT
170 WHILE(INKEY$=〃〃):WEND'等待敲键
180 '
190 '快速发出两种音调
200 SOUND 900,.1
210 SOUND 760,1
220 WHILE(INKEY$=〃〃):WEND230 '
240 '随机噪音
250 X=INP(&H61)AND &HFC
260 I=20
270 FOR N%=0 TO 500
280 IF(RND100<I)THEN OUT&H61,X OR2:OUT &H61,X
290 NEXT
附:音乐的八度音程音调的频率
音调 频 率 音 调 频 率 音 调 频 率 音调 频 率
C0 16.35 C2 65.41 C4 261.63 C6 1046.50
C#0 17.32 C#2 69.30 C#4 277.18 C#6 1108.73
D0 18.35 D2 73.42 D4 293.66 D6 1174.66
D#0 19.45 D#2 77.78 D#4 311.13 D#6 1244.51
E0 20.60 E2 82.41 E4 329.63 E6 1328.51
F0 21.83 F2 87.31 F4 349.23 F6 1396.91
F#0 23.12 F#2 92.50 F#4 369.99 F#6 1479.98
G0 24.50 G2 98.00 G4 392.00 G6 1567.98
G#0 25.96 G#2 103.83 G#4 415.30 G#6 1661.22
A0 27.50 A2 110.00 A4 440.00 A6 1760.00
A#0 29.14 A#2 116.54 A#4 466.16 A#6 1864.66
B0 30.87 B2 123.47 B4 493.88 B6 1975.53
C1 32.70 C3 130.81 C5 523.25 C7 2093.00
C#1 34.65 C#3 138.59 C#5 554.37 C#7 2217.46
D1 36.71 D3 146.83 D5 587.33 D7 2349.32
D#1 38.89 D#3 155.56 D#5 622.25 D#7 2489.02
E1 41.20 E3 164.81 E5 659.26 E7 2637.02
F1 43.65 F3 174.61 F5 659.26 F7 2637.83
F#1 46.25 F#3 185.00 F#5 739.99 F#7 2959.96
G1 49.00 G3 196.00 G5 783.99 G7 3135.96
G#1 51.91 G#3 207.65 G#5 830.61 G#7 3322.44
A1 55.00 A3 220.00 A5 880.00 A7 3520.00
A#1 58.27 A#3 233.08 A#5 932.33 A#7 3729.31
B1 61.74 B3 246.94 B5 987.77 B7 3951.07
C8 4186.01