基于RP2350B制作的电子琴
该项目使用了RP2350B单片机,实现了PWM+LPF驱动的电子琴的设计,它的主要功能为:弹奏按键触发对应钢琴音,具有谐波与和弦功能,可存储和播放指弹旋律。
标签
嵌入式系统
开发板
PWM
扬声器
RP2350B
小小洋洋
更新2025-07-11
同济大学
19

一、项目简介

本项目基于RP2350B核心板与配套电子琴扩展板,设计并实现了一款功能完善的电子琴系统。该系统支持按键实时弹奏、和弦播放、谐波增强音色、旋律录制与回放,并可通过切换开关选择蜂鸣器或扬声器作为音频输出设备,具备良好的交互体验和音质表现。

image.png


二、硬件组成

  1. 核心控制器:RP2350B开发板,其主要特点包括:两个核心,最高运行频率均为150MHz;灵活的时钟系统;丰富的GPIO 引脚和多种接口,如SPI、I2C、UART 和PWM。RP2350B 还支持USB 1.1 主机和设备模式,并可作为大容量存储器进行程序拖放式下载。
  2. 电子琴扩展板 :包含13个钢琴键+2个上下键,1个拨码开关,1个音量调节滚轮,LPF电路,蜂鸣器和扬声器。
    • 音频输出:扬声器可通过PWM+低通滤波实现音频输出,蜂鸣器则通过PWM+三极管输出。
    • 按键模块:13个音符按键 + “上”/“下”两个音程扩展键 + 模式切换开关


三、电路介绍

核心板和电子琴扩展板均有主办方提供,这里介绍使用到的部分电路。

1. 扬声器输出:PWM + 低通滤波实现DAC功能

image.png

由于RP2350B芯片不具备原生DAC模块,本项目采用PWM结合低通滤波器(LPF)来模拟模拟音频输出。具体设计如下:

  • 设定PWM频率为250kHz,以满足音频信号中的高频部分,确保波形不失真。
  • 采样点数量为600个,可精细还原20kHz以内的音频信号。
  • PWM的占空比根据目标音频波形进行实时调整,经过LPF平滑后生成对应的模拟电压,驱动扬声器发声。

2. 核心板R-2R按键:ADC检测

image.png

R-2R电路是基于电阻串并特性构建的很有趣的层级衰减电路,即2R和2R电阻并联得到1R电阻,基于与1R电阻串联得到2R电阻,又重复并连与串联,使得电压输出呈现1/2的衰减。此电路不仅可以用在按键检测上,也可以用于模拟电压输出上(DAC)。

对于该电路,通过核心板的ADC功能读取模拟电压值,可通过二分法判断各个按键状态。

3. 核心板LED驱动:引脚的三态控制

image.png

单片机开关具备多种输入输出模式,在输出高电平、输出低电平、高阻态三种状态之间进行切换,可完成对更多的LED控制。


四、软件流程和关键代码

image.png

1. PWM配置:pwm.c

    // 设置 AUDIO_PIN 为输出模式
    gpio_set_function(pwm_pin, GPIO_FUNC_PWM);
    // 获取与 AUDIO_PIN 关联的 PWM 通道
    uint slice_num = pwm_gpio_to_slice_num(pwm_pin);

    // 设置 PWM 回调函数
    pwm_clear_irq(slice_num);
    pwm_set_irq_enabled(slice_num, true);
    irq_set_exclusive_handler(PWM_IRQ_WRAP, on_pwm_wrap);   // 全局时钟更新
    irq_set_enabled(PWM_IRQ_WRAP, true);

    // 配置 PWM 设置
    pwm_config config = pwm_get_default_config();
    // 设置 PWM 分频和占空比,其中频率计算为f=sys_clk/div/(wrap+1)。目前计算结果为 150 000 000/1/250 000=600 Hz
    pwm_config_set_clkdiv(&config, 1.0f);  // 时钟分频,调整 PWM 输出频率
    pwm_config_set_wrap(&config, AUDIO_MAX_LEVEL);     // 设置计数器最大值(PWM周期)
    pwm_init(slice_num, &config, true);  // 初始化 PWM 并启动

    // 设置 PWM 占空比(0 到 wrap 的范围内)
    pwm_set_gpio_level(pwm_pin, 0);

2. 音调与谐波合成:audio.c

  • 基础音调由基频freq正弦波构成,不同音高对应不同频率。
  • 音色增强:为提升听感效果,在基频的基础上添加最多14阶谐波Amp[numharmonic],模拟实际乐器中丰富的频谱特性。
  • 包络控制:音调随时间进行动态调制,加入快速上升与缓慢衰减的幅度包络attenuation,模拟自然的音量变化过程。
#define numharmonic 15
float Amp[numharmonic] = {1, 0.340, 0.102, 0.085, 0.070, 0.065, 0.028, 0.085, 0.011, 0.030, 0.010, 0.014, 0.012, 0.013, 0.004};
/**
 * 具有谐波和衰减特性的正弦波叠加
 */
#define harmonic_sine_k 2 * _PI / 1000000.0f
float harmonic_sine_wave(uint64_t time_us, float freq, uint64_t time_start)
{
    // 计算频率叠加
    float res = 0;
    for (int i = 0; i < 15; i++) {
        res += _sin(harmonic_sine_k * freq * (i + 1) * (time_us % 10000000)) * Amp[i];
}
    res = res * attenuation((time_us - time_start) / 1000);
    return res;
}

3. 和弦功能:audio.c

支持多个按键同时按下,系统可将不同频率的音符及其对应谐波信号进行叠加,实现和弦演奏效果。

/**
 * 继进行叠加多个按键
 */
float merged_harmonic_sine_wave(uint64_t time_us, float *freqs, uint64_t *times, uint8_t* states)
{
    float res = 0;
    for (uint8_t i = 0; i < 13; i++) {
        if (states[i]) {
            res += harmonic_sine_wave(time_us, freqs[i], times[i])*0.9; // 叠加多个频率,增加一个衰减防止失真
        }
    }
    return res;
}

4. 2-2R按键控制:adckey.c

这里使用12位ADC读取引脚电压,判断前三个按键的状态:

#define KEYPAD_PIN 47
#define KEY_THRESHOLD_HIGH 4095
// 读取按键的状态
uint8_t read_keypad() {
    // 读取 ADC 值(范围 0 到 4095)
    uint16_t adc_value = adc_read();  // 12 位 ADC 读取值
   
    if(adc_value<(KEY_THRESHOLD_HIGH/2-10)) {
        return 1;
    }else if((adc_value%2048)<(KEY_THRESHOLD_HIGH/4-10)) {
        return 2;
    }else if((adc_value%1024)<(KEY_THRESHOLD_HIGH/8-10)) {
        return 3;
    }
    return 0;  // 没有按键被按下
}

5. 音乐录制与回放:recorder.c

  • 系统利用RP2350B内置Flash,分配4KB空间用于旋律数据的存储。
  • 记录内容包括:按键音高、按压时间、按下/释放状态等。
  • Flash写入前需执行擦除操作,符合Flash存储特性。
  • 回放时系统按顺序解析数据并通过PWM输出音频信号,自动重现用户演奏的旋律。
// 1. 一个音符存储使用7字节    
recorder_data[recorder_index] = mode;
recorder_data[recorder_index + 1] = (uint8_t)(tone >> 8);     // 高字节
recorder_data[recorder_index + 2] = (uint8_t)(tone & 0xFF);   // 低字节
recorder_data[recorder_index + 3] = (uint8_t)(time_us >> 24); // 时间高字节
recorder_data[recorder_index + 4] = (uint8_t)(time_us >> 16);
recorder_data[recorder_index + 5] = (uint8_t)(time_us >> 8);
recorder_data[recorder_index + 6] = (uint8_t)(time_us); // 时间低字节

// 2. 存储数据到flash
irq_set_enabled(PWM_IRQ_WRAP, false); // 停止PWM中断,防止写入错误
{
    flash_erase(FLASH_TARGET_OFFSET, MAX_DATA_SIZE);
    sleep_ms(5); // 添加延时,否则会死机
    flash_write(FLASH_TARGET_OFFSET, recorder_data, MAX_DATA_SIZE);
    sleep_ms(5);
}
irq_set_enabled(PWM_IRQ_WRAP, true);

// 3. 播放旋律按照时间顺序播放
stored_tone = (recorder_data[recorder_index + 1] << 8) | recorder_data[recorder_index + 2];
stored_time_us = ((uint64_t)recorder_data[recorder_index + 3] << 24) |
                    ((uint64_t)recorder_data[recorder_index + 4] << 16) |
                    ((uint64_t)recorder_data[recorder_index + 5] << 8) |
                    (recorder_data[recorder_index + 6]);
// 比较时间,检查是否达到了播放的时间点
if (stored_time_us <= elapsed_time)
{
    // 如果当前时间 >= 存储的时间,播放数据
    *mode = stored_mode;
    *tone = stored_tone;


    // 移动到下一条记录
    recorder_index += 7;
    return 2; // 返回播放数据
}

6. 音频设备切换功能:piano.c

支持两种播放方式,可通过物理拨码开关在蜂鸣器与扬声器间切换。系统根据拨码状态初始化对应的输出引脚并重启音频模块。

// 1. 读取mode引脚状态
mode_now = mode_state;
if (mode_state == 0) // 喇叭
    audio_init(BEEP_PIN);
else // 蜂鸣器
    audio_init(SPEAKER_PIN);

// 2. 读取到拨码开关后进行重启
void software_reset_simple()
{
    watchdog_reboot(0, 0, 0); // 立即触发看门狗复位
}


五、功能展示

由于钢琴弹奏主要通过声音展示,请查看上方的视频。主要展示内容包括:

  1. 单个按键弹奏播放钢琴音色,上下按键切换频率范围。
  2. 单个按键长按播放随时间变化的强度。
  3. 多个按键弹奏和弦。
  4. 存储旋律与回放旋律。
  5. 切换蜂鸣器弹奏。


六、关键问题与解决方案

问题

解决策略

PWM输出不够平滑,音色失真

PWM频率至250kHz,占空比可设置0-599,使用阶梯值平滑控制

Flash存储无法重复写入

在每次写入前进行擦除操作

多音符叠加导致失真

控制最大谐波阶数并加入限幅机制

音色不佳

通过基频+谐波共15个频率按不同幅度叠加,并模拟钢琴按下时音量先增加后减少特性控制幅度

七、复刻教程

1. 工程创建

  • 推荐在良好网络环境下使用VSCode+Raspberry PI Pico插件创建工程。
  • CMakeLists.txt需提前声明所需模块(如pwmflashadc等)。

2. 烧录流程

  • 默认支持一键烧录。
  • 若遇到单片机死机导致烧录失败,可:
    1. 断电
    2. 短接Boot引脚
    3. 上电进入Bootloader模式
    4. 再次烧录恢复


八、项目总结与心得体会

通过本项目,我们深入理解了数字音频合成、PWM模拟DAC、谐波叠加、Flash存储机制、嵌入式系统设计等关键技术。项目不仅提升了我们对嵌入式软硬件协同设计的能力,也激发了我们对音频数字处理、乐器仿真等方向的进一步探索兴趣。


附件下载
piano.uf2
可直接烧录的固件
Piano_Pad_RP2350B.zip
完整工程(VS Code打开)
团队介绍
评论
0 / 100
查看更多
硬禾服务号
关注最新动态
0512-67862536
info@eetree.cn
江苏省苏州市苏州工业园区新平街388号腾飞创新园A2幢815室
苏州硬禾信息科技有限公司
Copyright © 2024 苏州硬禾信息科技有限公司 All Rights Reserved 苏ICP备19040198号