You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

树莓派GPIO控制:按键按下/释放播放不同MP3的问题求助

树莓派按键切换MP3播放问题解决

需求

无焊面包板按键未按下时播放一段MP3,按住时播放另一段(类似《Deal or No Deal》电话预录音效),使用Raspberry Pi 3B通过GPIO引脚连接按键。

原代码

主脚本

from gpiozero import Button
from signal import pause

button = Button(2)

while True:
    if button.is_pressed == True:
        import playLeft       #run the playLeft script when button is pressed
    else:
        import playRight   #run the playRight script when not pressed

playLeft脚本

#import the Pygame sound module
import pygame

#designate where the files are located declared in variables
path = "/home/pi/"
sound_files = "phoneLEFT.mp3"

#initialise Pygame
pygame.mixer.init()
speaker_volume = 1.0  #100% speaker volume
pygame.mixer.music.set_volume(speaker_volume) #sets the mixer volume to the speaker_volume variable

for sound_file in sound_files: #iterating loop playing the files in the sound_files variable 
    pygame.mixer.music.load("/home/john/phoneLEFT.mp3") #using the pygame module loads the sound file...
    pygame.mixer.music.play() #plays the sound file

playRight脚本

#import the Pygame sound module
import pygame

#designate where the files are located declared in variables
path = "/home/pi/"
sound_files = "handsetright.mp3"

#initialise Pygame
pygame.mixer.init()
speaker_volume = 1.0  #100% speaker volume
pygame.mixer.music.set_volume(speaker_volume) #sets the mixer volume to the speaker_volume variable

for sound_file in sound_files: #iterating loop playing the files in the sound_files variable 
    pygame.mixer.music.load("/home/john/handsetright.mp3") #using the pygame module loads the sound file...
    pygame.mixer.music.play() #plays the sound file

当前问题

启动后播放playRight音频,按住按键可切换到playLeft,但释放按键无法切回playRight。

问题根源

  1. import机制限制:Python里模块一旦被导入,后续再import不会重新执行代码,只会引用已加载的模块。第一次按按键导入playLeft后,释放时再import playRight根本不会触发播放逻辑。
  2. 播放逻辑错误:playLeft/playRight里的for sound_file in sound_files是错误的——sound_files是字符串,循环会逐个字符遍历,导致重复加载播放;而且每次导入都初始化pygame.mixer,既冗余又可能引发冲突。
  3. 轮询效率低:while True循环持续占用CPU,不如用gpiozero的事件回调更合理。

优化后的完整代码

from gpiozero import Button
import pygame
import time

# 初始化pygame mixer,只做一次
pygame.mixer.init()
pygame.mixer.music.set_volume(1.0)

# 替换成你实际的音频文件路径
RIGHT_SOUND = "/home/john/handsetright.mp3"
LEFT_SOUND = "/home/john/phoneLEFT.mp3"

# 记录当前播放的音频类型
current_playing = "right"

button = Button(2)

def play_sound(sound_path, sound_type):
    global current_playing
    # 已经在播放目标音频,直接返回
    if current_playing == sound_type:
        return
    # 停止当前播放的音频
    pygame.mixer.music.stop()
    # 加载新音频并设置无限循环播放
    pygame.mixer.music.load(sound_path)
    pygame.mixer.music.play(-1)  # -1表示无限循环
    current_playing = sound_type

# 按键按下时触发
def on_button_press():
    play_sound(LEFT_SOUND, "left")

# 按键释放时触发
def on_button_release():
    play_sound(RIGHT_SOUND, "right")

# 绑定按键事件
button.when_pressed = on_button_press
button.when_released = on_button_release

# 程序启动时默认播放right音频
play_sound(RIGHT_SOUND, "right")

# 保持程序运行
while True:
    time.sleep(0.1)

优化说明

  • 复用初始化:只在主脚本初始化一次pygame.mixer,避免重复初始化的资源冲突。
  • 事件回调替代轮询:用gpiozero的when_pressed/when_released事件,CPU占用更低,逻辑更清晰。
  • 避免重复播放:通过current_playing变量跟踪状态,只有状态变化时才切换音频,减少无效操作。
  • 循环播放设置:play(-1)让音频无限循环,符合“未按下/按住时持续播放”的需求。
  • 整合逻辑:把原来拆分的两个脚本合并到主脚本,更简洁易维护。
  • 修复路径问题:原代码里path变量和实际加载路径不一致,现在统一成正确路径(记得根据你的实际情况调整)。

内容的提问来源于stack exchange,提问作者jHouse82

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.14 20:15:42