經典 Linux 控制台蜂鳴器(PC Speaker)直接編程範例,透過 I/O 端口操作 8254 可程式化間隔定時器 產生方波聲音,無需音效卡驅動支援。
#include <sys/io.h>
#include <unistd.h>
void play(unsigned int* freq, unsigned int* delay);
int main() {
// 樂譜資料:頻率(Hz) 與 持續時間(單位)
unsigned int freq[] = { 330, 392, 330, 294, 330, 392,
330, 394, 330, 330, 392, 330,
294, 262, 294, 330, 392, 294,
262, 262, 220, 196, 196, 220,
262, 294, 330, 262, 0 };
unsigned int time[] = { 50, 50, 50, 25, 25, 50,
25, 25, 100, 50, 50, 25,
25, 50, 50, 25, 25, 100,
50, 25, 25, 50, 25, 25,
50, 25, 25, 100 };
// 更多樂曲資料...
unsigned int freq_alert[] = { 2000, 2400, 0 };
unsigned int time_alert[] = { 50, 60 };
// 播放提示音 5 次
for (int i = 0; i < 5; i++) play(freq_alert, time_alert);
// 播放主樂曲
play(freq2, time2);
return 0;
}
void play(unsigned int* freq, unsigned int* time) {
for (int i = 0; freq[i] != 0; i++) {
speaker(freq[i], time[i]);
}
}
int speaker(unsigned int freq, unsigned int delay) {
static int flag = 0, bit;
if (flag == 0) {
flag = 1;
iopl(3); // 獲取 I/O 特權 (需 root)
}
outb(0xB6, 0x43); // 設定計數器 2 模式
outb(freq & 0xFF, 0x42); // 寫入低位元組
outb((freq >> 8) & 0xFF, 0x42); // 寫入高位元組
bit = inb(0x61); // 讀取喇叭控制狀態
outb(bit | 3, 0x61); // 開啟喇叭 (bit 0,1 = 1)
usleep(10000 * delay); // 延遲 (delay * 10ms)
outb(bit & 0xFC, 0x61); // 關閉喇叭 (bit 0,1 = 0)
return 0;
}
gcc -o beep beep.c
sudo ./beep # 必須 root 權限執行 iopl(3)
10110110,選擇計數器 2、低高位元組寫入、模式 3 (方波產生器)、二進制計數。pcspkr 核心模組:modprobe pcspkr。警告: 直接硬體端口操作需 root 權限,屬低層級編程,現代系統建議使用 ALSA/PulseAudio 等標準音訊 API。本範例僅供教學與嵌入式環境參考。