在 AT 兼容机中,蜂鸣器的默认端口号是 61H ,末尾的 H 表示的是十六进制数的意思。用 IN 指令通过该端口号输入数据,并将数据的低2位设定为 ON,然后再通过该端口号用 OUT 指令输出数据,这时蜂鸣器就会发出声音。同样的方法,将数据的低2位设定为 OFF 并输出后,蜂鸣器就停止工作。
位设定为 ON 指的是将该位设定为1,位设定为 OFF 指的是将该位设定为0 。把位设定为 ON,只需要把想要设定为 ON 的位设定为1,其他位设定为0后进行 OR 运算即可。由于这里需要把低2位置为1,因此就是和 03H 进行 OR 运算。03H 用8为二进制来表示的话是 00000011。由于即便高6位存在着具体意义。和0进行OR运算后也不会发生变化,因而就和 03H 进行 OR 运算。把位设定为 OFF,只需要把想要置 OFF 的位设定为0,其他位设定为1后进行 AND 运算即可。由于这里需要把低2位设定为0,因此就要和 FCH 进行 AND 运算。在源代码中,FCH 是用 0FCH 来记述的。在前面加 0 是汇编语言的规定,表示的是以 A - F 这些字符开头的十六进制数是数值的意思。0FCH 用8位二进制数来表示的话是 11111100。由于即便高6位存在着具体意义,和1进行 AND 运算后也不会产生变化,因而就是同 0FCH 进行 OR 运算。
void main(){ // 计数器 int i; // 蜂鸣器发声 _asm{ IN EAX, 61H OR EAX, 03H OUT 61H, EAX } // 等待一段时间 for(i = 0;i < 1000000;i++); // 蜂鸣器停止发生 _asm{ IN EAX, 61H AND EAX, 0FCH OUT 61H, EAX } }我们对上面的代码进行说明,main 是 C 语言程序起始位置的函数。在该函数中,有两个用 _asm{} 围起来的部分,它们中间有一个使用 for 循环的空循环
首先是蜂鸣器发声的部分,通过 IN EAX,61H(助记符不区分大小写)指令,把端口 61H 的数据存储到 CPU 的 EAX 寄存器中。接下来,通过 OR EAX,03H 指令,把 EAX 寄存器的低2位设定成 ON。最后,通过 OUT 61H,EAX 指令,把 EAX 寄存器的内容输出到61端口。使蜂鸣器开始发音。虽然 EAX 寄存器的长度是 32 位,不过由于蜂鸣器端口是8位,所以只需对下8位进行OR运算和AND运算就可以正常工作了。
其次是一个重复100次的空循环,主要是为了在蜂鸣器开始发音和停止发音之间稍微加上一些时间间隔。因为现在计算机器的运行速度非常快,哪怕是 100 万次循环,也几乎是瞬时间完成的。
然后是用来控制器蜂鸣器停止发声的部分。首先,通过 IN EAX,61H 指令,把端口 61H 的数据存储到 CPU 的 EAX 寄存器中。接下来,通过 AND EAX,0FCH 指令,把 EAX 寄存器的低2位设定为 OFF。最后,通过 OUT 61H,EAX 指令,把寄存器的 EAX 内容输出到61号端口,使蜂鸣器停止发音。
外围设备的中断请求IRQ(Interrupt Request) 代表的就是中断请求。IRQ 用来暂停当前正在运行的程序,并跳转到其他程序运行的必要机制。该机制被称为 处理中断。中断处理在硬件控制中担当着重要的角色。因为如果没有中断处理,就有可能无法顺畅进行处理的情况。
从中断处理开始到请求中断的程序(中断处理程序)运行结束之前,被中断的程序(主程序)的处理是停止的。这种情况就类似于在处理文档的过程中有电话打进来,电话就相当于是中断处理。假如没有中断处理的发生,就必须等到文档处理完成后才能够接听电话。由此可见,中断处理有着巨大的价值,就像是接听完电话后会返回原来的文档作业一样,中断程序处理完成后,也会返回到主程序中继续。
实施中断请求的是连接外围设备的 I/O 控制器,负责实施中断处理的是 CPU,外围设备的中断请求会使用不同于 I/O 端口的其他编号,该编号称为中断编号。在控制面板中查看软盘驱动器的属性时,IRQ处现实的数值是 06,表示的就是用06号来识别软盘驱动器发出的请求。还有就是操作系统以及 BIOS 则会提供响应中断编号的中断处理程序。
BIOS(Basic Input Output System): 位于计算机主板或者扩张卡上内置的 ROM 中,里面记录了用来控制外围设备的程序和数据。
假如有多个外围设备进行中断请求的话, CPU 需要做出选择进行处理,为此,我们可以在 I/O 控制器和 CPU 中间加入名为中断控制器的 IC 来进行缓冲。中断控制器会把从多个外围设备发出的中断请求有序的传递给 CPU。中断控制器的功能相当于就是缓冲。下面是中断控制器功能的示意图