在很早的电脑里,就带有一个小喇叭,可以发出不同频率的声音。主要用来判断系统是否有问题使用,比如BIOS检查硬有问题时,就会发出不同的声音,提醒用户是那里出问题了。在操作系统里,也经常使用这个小喇叭来提醒用户是什么问题,比如输入非法的按键时,就响一声。在早期的五笔输入法时,输入的字不对,就会用这个小喇叭提醒,让忘打的操作人员回到屏幕上选择所需要的字。那么这个小喇叭的驱动是怎么样进行的呢?这里就来研究这个问题,在ReactOS的HAL层代码如下:
#001 /*
#002 * @implemented
#003 */
#004 BOOLEAN
#005 NTAPI
#006 HalMakeBeep(IN ULONG Frequency)
#007 {
#008 UCHAR Data;
#009 ULONG Divider;
#010 BOOLEAN Result = TRUE;
#011
#012 /* FIXME: Acquire CMOS Lock */
#013
关闭寄存器。
#014 /* Turn the register off */
#015 Data = READ_PORT_UCHAR(PORT_B);
#016 WRITE_PORT_UCHAR(PORT_B, Data & 0xFC);
#017
检查是否有输出的频率。
#018 /* Check if we have a frequency */
#019 if (Frequency)
#020 {
根据时钟和频率来计算产生波形的定时器值。
#021 /* Set the divider */
#022 Divider = CLOCKFREQ / Frequency;
#023
溢出判断。
#024 /* Check if it's too large */
#025 if (Divider > 0x10000)
#026 {
#027 /* Fail */
#028 Result = FALSE;
#029 goto Cleanup;
#030 }
#031
设置定时器的值,就可以产生相应的波形来发出声音。
#032 /* Set timer divider */
#033 WRITE_PORT_UCHAR(TIMER3, 0xB6);
#034 WRITE_PORT_UCHAR(TIMER2, (UCHAR)(Divider & 0xFF));
#035 WRITE_PORT_UCHAR(TIMER2, (UCHAR)((Divider>>8) & 0xFF));
#036
#037 /* Turn speaker on */
#038 WRITE_PORT_UCHAR(PORT_B, READ_PORT_UCHAR(PORT_B) | 0x03);
#039 }
#040
#041 Cleanup:
#042 /* FIXME: Release hardware lock */
#043
#044 /* Return result */
#045 return Result;
#046 }
发声原理:
扬声器接受两个发声信号:一个来自定时器芯片(8253)的通道2的输出
信号OUT2;另一个来自外围设备接口芯片(8255)端口B的第一位发出的信号(注:在386微机中
采用与8255和8253芯片功能兼容的类8255和类8253芯片)。
8255芯片通过I/O端口61H的PB1和PBO两位来选择扬声器的驱动。当PBO为1时,控制825
33定时器发出脉冲;当PB1为1时,扬声器的与门电路接通并一直保持到PB1变到)时关闭;在此
期间,由8253芯片通道2以及选通扬声器的作用。
8253芯片有三个相同且各自独立的通道,其通道2的输出OUT2在初始化后发出一定频率
的脉冲信号。此脉冲信号可以通过对通道的编程而进行改变,这样,就使得扬声器能发出各
种频率的声音。我们用程序设定通道2输出波形的频率和延续时间,就能控制扬声器的单调
和发声的长短。
2.发声软件设计及实例
根据发声电路,我们知道要使扬声器发出一定频率的声音,需要完成以下几项工作:
①根据已知的声音频率,求送8253芯片通道2的计数时间常数TIME;
②往8253指令寄存器(43H)送指令码oB6H,使通道2输出脉冲信号;
③把时间常数TIME送入8253的通道2;
④把8255芯片的PB1、PBO置为1,开启扬声器;
⑤持续若干时间。