基于RP2350B实现蜂鸣器音乐播放器
该项目使用了RP2350B,实现了PWM音乐播放器的设计,它的主要功能为:使用PWM驱动蜂鸣器,支持播放三个音乐。
标签
嵌入式系统
枫雪天
更新2025-07-08
13

任务介绍

    本项目实现了硬禾RP2350B核心板评测活动的任务四——基于RP2350B开发板的PWM蜂鸣器音乐播放器。系统支持通过模拟按键选择歌曲,并控制蜂鸣器播放对应旋律,同时联动数码管和OLED显示屏,实时显示当前歌曲序号与名称。

硬件平台

    本次评测使用的主控设备为 RP2350B 核心板,搭载 RP2350B 微控制器,它有独特的双核、双架构,搭载了双核 ARM Cortex-M33 处理器和双核 Hazard3 RISC-V 处理器,运行频率均高达 150MHz 灵活时钟。这种双核异构处理能力,使得它很适合高精度音频播放与多任务调度

本次使用的外设模块包括:

  • 模拟电压按键输入(通过 ADC 检测按键状态)
  • 数码管显示模块(ShiftDisplay 驱动,共阴极)
  • OLED 屏幕(SSD1306 显示驱动,U8g2 中文字体支持)
  • 蜂鸣器输出(使用 Arduino tone API 实现 PWM 音频输出)

主控设备:RP2350B核心板

  • 控制芯片:RP2350B
  • 外设引脚资源丰富,支持多线程任务调度(Core 0/1)
  • 使用 PIO 状态机实现精确音频波形输出

传感执行器扩展板

  • 无源蜂鸣器 + GPIO 驱动电路
  • 共阴极两位数码管(ShiftDisplay 库驱动)
  • 128x32 SSD1306 OLED 屏幕(Adafruit_SSD1306 + U8g2 GFX 支持中文显示)

任务分析与实现

本系统实现了基于 RP2350B 的蜂鸣器音乐播放器,主要功能包括:

  • 三首可选曲目(以及默认静音模式)
  • 按键切换歌曲并即时播放
  • OLED 显示当前歌曲中文名
  • 数码管同步显示歌曲编号(00~03)
  • Core 0 负责按键检测、显示刷新
  • Core 1 独立运行音乐播放逻辑,避免阻塞主线程


方案框图:

代码详解

一、硬件初始化与传感器配置

系统上电后完成以下初始化操作:

  • 初始化 OLED 显示屏,加载中文字体
  • 设置数码管引脚与模式
  • 启动 Core 1 音乐播放任务
  • 初始化 MillisTaskManager 定时任务调度器
void setup() {
  Serial.begin(115200);
  analogReadResolution(ADC_BITS);

  if (!displayOLED.begin(SSD1306_SWITCHCAPVCC)) {
    for (;;); // 停止程序
  }
  u8g2.begin(displayOLED);

  multicore_launch_core1(core1_playback_task);

  taskManager.TaskRegister(0, keyDetectionTask, 400);
  taskManager.TaskRegister(1, displayTask, 200);
  taskManager.TaskRegister(2, displayTask2, 10);
}

二、双核任务调度机制

Core 0:负责按键扫描、OLED 刷新、数码管高频刷新

Core 1:独立运行 player.play() 函数,防止阻塞 UI 更新

void core1_playback_task() {
  while (true) {
    if (startPlayback) {
      switch (songIndex) {
        case 0: noTone(BUZZER_PIN); break;
        case 1: player.play(melody_mario, notes_mario, tempo_mario); break;
        case 2: player.play(melody_nokia, notes_nokia, tempo_nokia); break;
        case 3: player.play(melody_birthday, notes_birthday, tempo_birthday); break;
      }
    }
    delayMicroseconds(100);
  }
}

三、按键扫描任务设计

采用模拟电压检测方式读取按键状态,结合防抖机制,实现稳定切换歌曲。

void keyDetectionTask() {
  int raw = analogRead(ANALOG_PIN);
  float voltage = raw * (VREF / ADC_MAX);

  currentKeyState = (voltage > KEY_THRESHOLD) ? HIGH : LOW;

  if ((millis() - lastDebounceTime) > DEBOUNCE_DELAY && currentKeyState == LOW) {
    shouldStop = true;
    songIndex = (songIndex + 1) % 4;
    startPlayback = true;
    shouldUpdateDisplay = true;
  }
}

四、显示更新任务设计

将 OLED 与数码管显示分离,仅在内容变化时刷新 OLED,数码管每 10ms 高频刷新保持亮度。

void update7SegDisplay() {
if (songIndex != lastSongIndex) {
strcpy(segBuf, songs[songIndex].display);
display7seg.set(segBuf, ALIGN_RIGHT);
lastSongIndex = songIndex;
shouldUpdateDisplay = true;
}
display7seg.show();
}

void updateOLED() {
if (shouldUpdateDisplay) {
u8g2.print(songs[songIndex].name);
displayOLED.display();
shouldUpdateDisplay = false;
}
}

使用结构体统一管理歌曲名称与数码管显示值,提高可维护性。

struct SongInfo {
  const char* name;       // OLED 显示的中文名称
  const char display[3];  // 数码管显示的两位字符串
};

const SongInfo songs[] = {
  {"静音模式", "00"},
  {"超级马里奥", "01"},
  {"诺基亚铃声", "02"},
  {"生日快乐歌", "03"}
};

效果展示

遇到的难题与解决办法

问题

tone() 阻塞播放导致按键扫描等其他任务无法执行。

解法

将 player.play() 移至 Core 1 执行,Core 0 继续运行按键和显示任务,实现非阻塞播放。

活动感想

通过本项目的实践,深入掌握了 RP2350 的双核编程技巧、PIO 波形生成原理以及多任务调度策略。OLED + 数码管双显联动提升了交互体验,也为后续多功能嵌入式项目打下基础。

特别感谢硬禾学堂组织本次活动,提供 RP2350 开发平台,让我得以全面锻炼嵌入式系统开发能力,祝硬禾的活动越办越好!

附件下载
ToneBox_RP2350多核阻塞完成带数码管.rar
团队介绍
个人
团队成员
枫雪天
评论
0 / 100
查看更多
硬禾服务号
关注最新动态
0512-67862536
info@eetree.cn
江苏省苏州市苏州工业园区新平街388号腾飞创新园A2幢815室
苏州硬禾信息科技有限公司
Copyright © 2024 苏州硬禾信息科技有限公司 All Rights Reserved 苏ICP备19040198号