Ubuntu Linux下用GNU Assembly实现扬声器指定频率振动(求示例)
GNU汇编实现PC扬声器可控蜂鸣(x86-64 Ubuntu)
下面是适配你硬件和系统的GNU汇编代码,直接通过硬件端口控制PC扬声器,支持指定频率(赫兹)和发声时长(毫秒),功能等价于C语言的Beep()函数:
.global _start # 硬件端口与常量定义 .equ PIT_CTRL, 0x43 # PIT(可编程间隔定时器)控制端口 .equ PIT_COUNTER0,0x40 # PIT计数器0端口(用于驱动扬声器) .equ SPEAKER_PORT,0x61 # PC扬声器控制端口 .equ PIT_BASE_FREQ,1193180 # PIT基准时钟频率(固定值) _start: # 示例:调用beep函数,播放440Hz(标准A调),时长1000毫秒 mov $440, %rdi # 第一个参数:发声频率(Hz) mov $1000, %rsi # 第二个参数:发声时长(ms) call beep # 退出程序 mov $60, %rax # syscall编号:exit xor %rdi, %rdi # 退出码0 syscall # beep函数:rdi=频率(Hz), rsi=时长(ms) beep: # 保存调用者寄存器(GNU汇编调用约定:rax/rbx/rcx/rdx需手动保存) push %rax push %rbx push %rcx push %rdx # 1. 计算PIT分频值:分频 = 基准频率 / 目标频率 mov $PIT_BASE_FREQ, %rax div %rdi # rax = 基准频率 / 频率,余数存入rdx(忽略) mov %rax, %cx # 分频值存入16位寄存器cx # 2. 配置PIT为模式3(方波发生器),使用计数器0 mov $0b10110110, %al # 控制字:计数器0、低字节先写、模式3、二进制计数 out %al, $PIT_CTRL # 3. 向计数器0写入分频值(低字节优先) mov %cl, %al out %al, $PIT_COUNTER0 mov %ch, %al out %al, $PIT_COUNTER0 # 4. 打开扬声器:置位0x61端口的第0、1位(允许数据+扬声器使能) in $SPEAKER_PORT, %al or $0b11, %al out %al, $SPEAKER_PORT # 5. 延时指定毫秒 mov %rsi, %rdi # 将时长参数传入msleep函数 call msleep # 6. 关闭扬声器:清除0x61端口的第0、1位 in $SPEAKER_PORT, %al and $0b11111100, %al out %al, $SPEAKER_PORT # 恢复寄存器并返回 pop %rdx pop %rcx pop %rbx pop %rax ret # msleep函数:rdi=时长(ms) msleep: # 使用nanosleep系统调用实现高精度延时 push %rax push %rdi push %rsi # 构造timespec结构体:tv_sec = 毫秒数/1000,tv_nsec = (毫秒数%1000)*1000000 xor %rdx, %rdx mov $1000, %rbx div %rbx # rax=秒数,rdx=剩余毫秒数 mov %rax, (%rsp) # 写入tv_sec字段 mov %rdx, %rax mov $1000000, %rbx mul %rbx # rax=纳秒数 mov %rax, 8(%rsp) # 写入tv_nsec字段 mov $35, %rax # syscall编号:nanosleep mov %rsp, %rdi # 指向timespec结构体的指针 xor %rsi, %rsi # 忽略剩余未休眠时间 syscall pop %rsi pop %rdi pop %rax ret
编译与运行步骤
- 将代码保存为
beep.s - 编译汇编文件:
as -o beep.o beep.s - 链接生成可执行文件:
ld -o beep beep.o - 必须以root权限运行(硬件端口访问需要权限):
sudo ./beep
关键说明
- 代码直接操作硬件端口,而非调用系统默认提示音,完全可控频率和时长
- 支持20Hz~20000Hz的人耳可听频率范围
- 延时依赖Linux原生
nanosleep系统调用,精度可靠 - Dell Optiplex 960的PC扬声器完全兼容该硬件控制逻辑
内容的提问来源于stack exchange,提问作者Colton Paul Badock
相关产品推荐
相关产品推荐

