Windows API 里面有一个 Beep 函数,作用是发出蜂鸣声。这个蜂鸣功能历史悠久,BIOS 的报警声就是从主板蜂鸣器里出来的,其原理是调用几乎每台机器都有的 Programmable Interval Timer (PIT)。可惜从 Windows Vista 开始,这个函数的行为变成了调用扬声器发声,而不再是使用主板蜂鸣器发声了。

如何在 Windows Vista 以上的系统里使用主板蜂鸣器发声呢?是不是必须写个 Windows 驱动呢?其实利用 WinDbg 内核调试器的功能,只需要一行代码就能搞定。下面一行代码以 800 Hz 的频率让主板蜂鸣器发声 1000 毫秒。

1
n 10; r $t0=800; r $t1=1000; ob 0x43 0xb6; ob 0x42 (1193180/$t0)&0xff; ob 0x42 (1193180/$t0)>>8; ob 0x61 3; .sleep $t1; ob 0x61 0

使用方法:

  1. 下载安装 WinDbg
  2. 打开内核调试。管理员权限运行
    1
    bcdedit /debug on
    ,重启。
  3. 管理员权限打开 WinDbg,File->Kernel Debug,选择 “Local” 选项卡,确定。不出意外的话,就会进入 kernel debug session。
  4. 输入这段代码,如果你的主板蜂鸣器正常的话,应该就能听到蜂鸣声了。(可惜,截图里不带声音)

原理:

1
2
3
4
5
6
7
8
9
n 10;          设置十进制,默认 WinDbg 是 16 进制
r $t0=800; 设置 WinDbg 内部寄存器 t0 为 800,表示发声频率
r $t1=1000; 设置 WinDbg 内部寄存器 t1 为 1000,表示发声时长(毫秒)
ob 0x43 0xb6; 设置 PIT 输出到主板蜂鸣器的 PWM 波周期(这里的 ob 和 Linux 的 outb 相同)
ob 0x42 (1193180/$t0)&0xff; PWM 波周期的低字节
ob 0x42 (1193180/$t0)>>8; PWM 波周期的高字节
ob 0x61 3; 开始发声
.sleep $t1; 持续发声 $t1 这么长时间(毫秒)
ob 0x61 0; 发声结束

感谢 负一的平方根 (zzh1996) 出的题。

参考:http://wiki.osdev.org/PC_Speaker

Comments

2016-12-24