Skip to content

About

Raspberry Pi GPIO18 蜂鸣器播放 API(FastAPI + 硬件 PWM)

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Latest commit

 

History

28 Commits

Folders and files

Repository files navigation

Raspberry Pi Buzzer API

树莓派 GPIO18(硬件 PWM)驱动的蜂鸣器/喇叭播放 API。其他服务(飞书 bot、Web 前端、自动化脚本)通过 HTTP 即可触发播放旋律、提示音或自定义音符序列。

Pi Buzzer Console 控制台预览


目录


Web 控制台 (Web Console)

本项目内置了精致的毛玻璃极简现代 Web 控制台,部署后直接在局域网浏览器打开即可使用:

Pi Buzzer Console 控制台界面

  • 访问地址:http://<树莓派IP>:8001/ 或 http://127.0.0.1:8001/
  • 核心功能模块:
    1. 实时音频示波器与状态监控:实时捕捉发声状态,动态绘制音频方波/正弦示波动画,呈现树莓派 CPU 温度、负载与系统运行指标;
    2. 预设旋律一键点播:包含单哔、双哔、系统通知、成功、失败、紧急告警、超级马里奥、星球大战、俄罗斯方块、欢乐颂、小星星等丰富预设,支持全局音量无级滑动调节;
    3. 双八度交互式钢琴键盘 (C4 ~ B5):支持触控与电脑物理键盘快捷键(A~K 键白键,W/E/T/Y/U 黑键)实时弹奏硬件发声;
    4. 单音频信号发生器:20Hz ~ 5000Hz 连续频点无级调节,支持 440Hz、1000Hz 等快捷预设芯片;
    5. 自定义旋律编曲器:支持在线可视化编曲及 JSON 序列实时试听;
    6. API 调试与 Token 密钥管理:内置一键复制 cURL / Python 代码,支持保存 X-API-Token 到本地浏览器;
    7. 审计日志追踪:实时滚动记录最近 50 条音频播放与操作来源记录。

硬件接线与原理图

支持常见的 HS-F02P 无源蜂鸣器模块(PH2.0 3P 接口,工作电压 3.3V ~ 5.5V)。

实物接线与简易原理图

HS-F02P 无源蜂鸣器实物接线图 & 简易原理图

树莓派 40-Pin 引脚对插定义

模块正面丝印线序为从左到右:G | V | S,使用随附的 PH2.0 转杜邦线直插树莓派物理引脚即可:

导线颜色 模块端子丝印 树莓派物理引脚 说明
🟢 绿线 G Pin 6 (GND) 信号与电源公共地线(亦可接 Pin 14)
🔴 红线 V Pin 2 (5V) 推荐接 5V 核心供电,音量饱满充沛(接 Pin 1 3.3V 为弱音)
🔵 蓝线 S Pin 12 (GPIO18) 硬件 PWM0 脉冲信号线

提示:模块自带板载 Power 红色电源指示灯,正确接好 VCC 与 GND 后即会常亮,方便确认通电状态。

🔍 点击展开:完整驱动电路与保护机制原理图(含官方原厂原理图)

HS-F02P 模块驱动与保护电路原理图

官方原厂原理图 (Hello STEM HS-F02P REV 1.0)

HS-F02P 官方原厂原理图

  • 驱动核心 (Q1):SS8050 NPN 开关三极管,瞬态电流 500mA,保护树莓派 GPIO 免受线圈大电流冲击。
  • 反峰吸收 (D1):BAT60B 超高速低压降肖特基二极管,并在蜂鸣器线圈两端吸收关断反电动势尖峰。
  • 基极限流 (R2):47Ω 贴片限流电阻,降低驱动内阻,提升高频响应。
  • 电源指示 (LED1):0603 红色高亮 LED + 1kΩ 限流电阻,直观显示 VCC 供电状态。

本服务将 GPIO18 设为 ALT5(PWM0),信号由树莓派底层硬件时钟发生器驱动,CPU 占用为 0,音调纯净无抖动。

前置系统配置(必须,否则无声)

  1. 禁用板载音频(3.5mm 口占用 GPIO18/19):
    sudo sed -i 's/^dtparam=audio=on$/#dtparam=audio=on/' /boot/firmware/config.txt
  2. 启用硬件 PWM 并把 PWM0 指定到 GPIO18:
    echo "dtoverlay=pwm-2chan,pins_0=18,pins_1=19" | sudo tee -a /boot/firmware/config.txt
  3. 重启:sudo reboot
  4. 重启后确认:
    ls /sys/class/pwm/                 # 应出现 pwmchip0
    sudo raspi-gpio set 18 a5          # 运行时把 GPIO18 设为 PWM0(服务每次播放也会自动执行)

⚠️ 如果树莓派上有其他 GPIO 服务(如 CyberPi-GPIO-Commander,用 LGPIO 声明全部引脚),会占用 GPIO18 导致 PWM 不可用,需先停止(pm2 stop cyberpi-gpio)。


音量与音质

蜂鸣器音量由 占空比(duty) 控制:值越小,声音越小、越干净;值越大越响,但容易破音。

常用 duty 对照

duty 音量 音质
0.01(1%) 很小 干净
0.03(3%) 小 干净(推荐默认)
0.05(5%) 较小 干净
0.1(10%) 中等 良好(当前服务默认)
0.2(20%) 较大 开始有谐波/破音
0.3(30%)+ 大 破音明显

如何调音量

推荐:用 volume(0–100 百分比)——服务自动换算为占空比(100 对应占空比 0.3,避免破音):

# 20% 音量播放提示音
curl -X POST http://127.0.0.1:8001/api/play/tone \
  -H "Content-Type: application/json" \
  -d '{"frequency":1000,"duration":0.3,"volume":20}'

# 60% 音量播放旋律
curl -X POST http://127.0.0.1:8001/api/play/melody \
  -H "Content-Type: application/json" \
  -d '{"name":"ode_to_joy","volume":60}'

或直接指定占空比 "duty"(更精细,duty 优先于 volume):

# 小音量播放提示音
curl -X POST http://127.0.0.1:8001/api/play/tone \
  -H "Content-Type: application/json" \
  -d '{"frequency":1000,"duration":0.3,"duty":0.03}'

永久(改服务默认值):编辑 buzzer.py 里的 Buzzer(duty_default=0.1) 为想要的默认值(如 0.03),然后重启:

sudo systemctl restart buzzer-api

关于"破音"

  • 破音主要来自软件 PWM 频率抖动和音符切换瞬态;本服务已改用硬件 PWM(GPIO18 = PWM0),大幅改善;
  • 若仍感觉不干净,把 duty 降到 0.03–0.05 即可;
  • 蜂鸣器本身是"单音+谐波"设备,适合提示音/简单旋律;要高质量音频需外接 DAC/功放。

部署

cd ~/buzzer-api
python3 -m venv venv
./venv/bin/pip install -i https://pypi.tuna.tsinghua.edu.cn/simple fastapi uvicorn

sudo cp buzzer-api.service /etc/systemd/system/
sudo systemctl daemon-reload
sudo systemctl enable --now buzzer-api
  • 服务监听 127.0.0.1:8001(仅本机);
  • 以 root 运行(需要写 /sys/class/pwm 和执行 raspi-gpio);
  • 开机自启(systemctl enable)。

常用管理命令:

sudo systemctl status buzzer-api   # 状态
sudo systemctl restart buzzer-api  # 重启
sudo systemctl stop buzzer-api     # 停止
journalctl -u buzzer-api -n 50     # 日志

API 文档

端点总览

方法 路径 说明
GET /health 健康检查
GET /api/melodies 预置旋律列表
GET /api/status 服务状态
POST /api/play/melody 播放旋律(预置或自定义)
POST /api/play/tone 播放单音(提示音)
POST /api/stop 立即停止播放

POST /api/play/tone

播放单个频率的音。

请求体:

{
  "frequency": 1000,
  "duration": 0.3,
  "duty": 0.1
}

字段:

字段 类型 必填 说明
frequency number 是 频率(Hz),范围 20–5000
duration number 否 时长(秒),默认 0.5
volume int 否 音量百分比 0–100(推荐,自动换算占空比)
duty number 否 占空比 0–1,默认 0.1(见音量与音质)

响应:

{"ok": true, "frequency": 1000.0, "duration": 0.3}

POST /api/play/melody

播放旋律。两种模式:预置旋律(name)或自定义音符序列(notes)。

播放预置旋律:

{"name": "ode_to_joy", "duty": 0.1}

自定义旋律:

{
  "notes": [["C4", 0.4], ["E4", 0.4], ["G4", 0.4], ["C5", 0.8]],
  "duty": 0.1
}

字段:

字段 类型 必填 说明
name string 二选一 预置旋律名,见 /api/melodies
notes array 二选一 音符序列 [[音符或频率, 时长秒], ...]
volume int 否 音量百分比 0–100(推荐)
duty number 否 占空比,默认 0.1

支持的音符名:

C4=262  D4=294  E4=330  F4=349  G4=392  A4=440  B4=494  C5=523  D5=587

也可以直接用频率数字:[[440, 0.5], [523, 0.5]]。

POST /api/stop

立即停止当前播放(无请求体)。

错误响应

状态码 场景
400 频率越界 / 未提供 name 或 notes
404 预置旋律不存在
401 未提供正确的 X-API-Token(启用 token 后)

错误响应格式:

{"detail": "melody not found: xxx"}

调用示例

播放预置旋律《欢乐颂》:

curl -X POST http://127.0.0.1:8001/api/play/melody \
  -H "Content-Type: application/json" \
  -d '{"name":"ode_to_joy","duty":0.03}'

播放《小星星》:

curl -X POST http://127.0.0.1:8001/api/play/melody \
  -H "Content-Type: application/json" \
  -d '{"name":"twinkle","duty":0.03}'

提示音(如告警):

curl -X POST http://127.0.0.1:8001/api/play/tone \
  -H "Content-Type: application/json" \
  -d '{"frequency":1000,"duration":0.3,"duty":0.03}'

自定义旋律:

curl -X POST http://127.0.0.1:8001/api/play/melody \
  -H "Content-Type: application/json" \
  -d '{"notes":[["C4",0.4],["E4",0.4],["G4",0.4],["C5",0.8]],"duty":0.03}'

Python(requests):

import requests

requests.post(
    "http://127.0.0.1:8001/api/play/melody",
    json={"name": "ode_to_joy", "duty": 0.03},
)

飞书 bot / 自动化: 直接在同机调用上述接口即可(同机免认证)。


故障排查

完全没有声音

  1. 检查 GPIO18 是否为 PWM 功能:
    raspi-gpio get 18
    # 期望输出:18: a5 ... (PWM0_0)
    # 如果是 "op"(普通输出),执行:sudo raspi-gpio set 18 a5
  2. 检查 PWM 通道:
    ls /sys/class/pwm/   # 应有 pwmchip0
  3. 检查板载音频是否禁用(dtparam=audio=on 已注释);
  4. 检查是否有其他服务占用 GPIO18(如 CyberPi-GPIO-Commander):
    pm2 list | grep -i cyber
    # 若有:pm2 stop cyberpi-gpio
  5. 检查接线:G→GND、V→3.3V/5V、S→GPIO18;
  6. 有源蜂鸣器只响/不响(不受频率控制);确认是无源蜂鸣器/喇叭。

声音小

调大 duty(0.1–0.2);或确认 V 接的是 5V(而非 3.3V)。

破音 / 杂音

调低 duty(0.03–0.05);确认使用硬件 PWM(GPIO18 为 a5)。


扩展

启用 token(外部访问)

编辑 /etc/systemd/system/buzzer-api.service,在 [Service] 加环境变量,并把绑定改为 0.0.0.0:

Environment=BUZZER_API_TOKEN=你的token
ExecStart=/home/user/buzzer-api/venv/bin/uvicorn main:app --host 0.0.0.0 --port 8001

重启后请求需带请求头:

curl -X POST http://<树莓派IP>:8001/api/play/tone \
  -H "Content-Type: application/json" \
  -H "X-API-Token: 你的token" \
  -d '{"frequency":1000,"duration":0.3}'

开放外部访问前请务必设置 token,并确认树莓派防火墙/安全组。

目录结构

buzzer-api/
├── main.py            # FastAPI 应用与路由
├── buzzer.py          # 硬件 PWM 播放核心(sysfs + raspi-gpio)
├── melodies.py        # 音符表与预置旋律
├── requirements.txt
├── buzzer-api.service # systemd 单元
└── README.md

About

Raspberry Pi GPIO18 蜂鸣器播放 API(FastAPI + 硬件 PWM)

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages