ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

VS1053硬件解码芯片与Arduino打造MP3播放器实战指南

VS1053硬件解码芯片与Arduino打造MP3播放器实战指南 MP3播放器这东西说起来简单做起来坑不少。我前前后后折腾过好几版方案从最开始的软件解码到后来的专用解码芯片最后稳定下来的组合就是VS1053模块加Arduino。为什么选这个组合因为VS1053是一颗硬件解码芯片支持MP3、WAV、MIDI、OGG等多种格式解码这件事完全交给它Arduino只负责通过SPI总线喂数据、读状态、控制播放主控几乎不占什么资源。你甚至可以用一块最普通的Arduino Uno跑起来音质还相当能打。这篇文章面向的是想自己动手做一台独立音乐播放器的朋友不管你是刚接触Arduino的新手还是已经玩过不少模块的老手都能从里面找到有用的东西。我会从硬件选型、接线方案、SPI通信原理、代码实现、OLED显示配合一直讲到实际调试中遇到的各种坑和解决思路。代码部分会给完整的可运行版本拿到就能烧录测试。1. 为什么偏偏选了VS1053这颗解码芯片1.1 软件解码和硬件解码的本质区别很多人第一反应是用Arduino直接软件解码MP3。我一开始也是这么想的结果发现根本跑不动。Arduino Uno用的是ATmega328P16MHz主频2KB SRAM你要它实时解码128kbps的MP3数据流光是解码算法本身的计算量就远超它的处理能力。就算勉强用一些轻量级解码库出来的声音也是断断续续像卡带一样。VS1053的思路完全不同。它内部有一颗专门的DSP数字信号处理核心硬件电路直接完成MP3解码你只需要把压缩的音频数据通过SPI接口送进去它自己解码完通过内部DAC输出模拟音频信号。整个过程主控的负担极小基本上就是个数据搬运工的角色。这就好比你自己在家做饭和叫外卖的区别——软件解码是你从买菜到洗碗全包硬件解码是你只管把外卖拿进来摆桌上。VS1053支持的解码格式包括MP3、WAV(PCM/IMA ADPCM)、MIDI、OGG Vorbis、WMA、FLAC等基本上常见的音频格式都覆盖了。它还内置了耳机驱动放大器可以直接推32欧姆的耳机输出功率大概30mW左右日常听歌够用了。如果嫌声音小后面加个PAM8403功放板推小喇叭也没问题。1.2 VS1053模块的引脚分布和功能划分市面上常见的VS1053模块一般引出以下关键引脚引脚名称功能说明连接对象VCC电源正极3.3VArduino 3.3V输出GND电源地Arduino GNDMISOSPI主入从出Arduino D12MOSISPI主出从入Arduino D11SCKSPI时钟Arduino D13XCS命令片选低有效Arduino D7XDCS数据片选低有效Arduino D6DREQ数据请求信号Arduino D2XRST复位低有效Arduino D8XDREQ中断/数据请求同DREQ这里要特别注意几个点。XCS和XDCS是两个独立的片选信号XCS管命令通道写寄存器、读状态XDCS管数据通道写音频数据。这种设计的好处是命令和数据可以分开操作不会互相干扰。DREQ是VS1053给主控的反馈信号高电平表示芯片内部缓冲区还有空间可以继续喂数据低电平表示缓冲区满了你得等着。这个信号是整条数据链路的节拍器必须接好。XRST是复位引脚低电平复位。模块上一般已经有上拉电阻但为了可靠起见建议接到Arduino的一个IO口上上电时主动拉低再拉高确保芯片进入确定状态。1.3 供电这件事比你想的要讲究VS1053模块标称工作电压3.3V但它的电流消耗不小播放时峰值能到50mA以上。Arduino Uno板载的3.3V输出是从USB的5V经过线性稳压芯片得来的电流能力有限大概只有50mA左右。如果你直接用Uno的3.3V给VS1053供电再加上OLED屏幕的消耗很可能会出现电压跌落导致VS1053工作不稳定表现为播放卡顿、无声或者直接死机。我的建议是单独给VS1053供3.3V。有两种方案一是用一块独立的3.3V稳压模块比如AMS1117-3.3从5V降压到3.3V能提供800mA电流绰绰有余二是如果你的Arduino板子是3.3V版本比如Arduino Due或者某些ESP32开发板那就直接用它自己的3.3V输出但也要确认电流余量。注意VS1053的IO引脚耐压也是3.3V虽然实际测试中5V逻辑电平短时间接入不会立刻烧毁但长期使用会缩短芯片寿命。如果你的主控是5V逻辑比如Arduino Uno建议在SPI信号线上加电平转换或者至少串联100欧姆电阻做限流。2. SPI通信协议在VS1053上的具体落地2.1 SPI的四种模式和VS1053的匹配SPI通信有四种模式由时钟极性CPOL和时钟相位CPHA组合决定。VS1053使用的是SPI模式0也就是CPOL0、CPHA0。具体来说时钟空闲时为低电平数据在时钟上升沿采样。这个细节很关键如果你用其他模式数据读写会完全错乱。Arduino的SPI库默认就是模式0所以直接用SPI.begin()初始化就行不需要额外设置。但如果你用的是ESP32或者其他平台要确认SPI模式配置正确。我在ESP32上试过默认配置也是模式0直接能用。SPI的时钟频率方面VS1053支持最高大概12MHz左右。Arduino Uno的SPI时钟是主频的二分频也就是8MHz完全在范围内。实际使用中不需要降速8MHz跑起来很稳。但如果你接线比较长超过10厘米建议降到4MHz试试避免信号完整性问题。2.2 命令通道和数据通道的切换逻辑VS1053的SPI通信分两个通道操作方式不同写命令寄存器时拉低XCS选中命令通道通过SPI发送寄存器地址一个字节通过SPI发送数据高字节通过SPI发送数据低字节拉高XCS释放命令通道写数据音频流时等待DREQ变高拉低XDCS选中数据通道通过SPI连续发送音频数据字节拉高XDCS释放数据通道读寄存器时拉低XCS发送寄存器地址通过SPI读取两个字节高字节在前拉高XCS这里有个容易踩的坑读寄存器的时候发送地址后需要先读一个空字节再读有效数据。因为SPI是全双工发送地址的同时MISO上会有一个无效字节必须丢弃。很多初学者在这里卡住读出来的值永远是0或者乱码。2.3 DREQ信号的处理策略DREQ是VS1053数据流控制的核心。当DREQ为高时表示芯片内部至少还有32字节的缓冲区空间可以继续写入数据当DREQ为低时表示缓冲区快满了必须停止写入否则数据会丢失。在实际代码中有两种处理方式阻塞等待法每次写数据前用while(!digitalRead(DREQ_PIN))死等直到DREQ变高再写。这种方法简单但在等待期间主控什么都做不了如果还要刷新OLED显示或者处理按键就会卡顿。状态机轮询法在主循环中检查DREQ状态高就写一批数据低就去做其他事情刷新显示、读按键下次循环再检查。这种方法更高效适合需要同时处理多个任务的场景。我推荐用第二种方式。具体做法是每次DREQ为高时写入32字节的数据块然后立即返回主循环这样既保证了数据吞吐量又不会阻塞其他任务。实测下来128kbps的MP3数据流Arduino Uno在8MHz SPI下完全跟得上不会出现断音。3. 从零搭建硬件系统的完整过程3.1 元器件清单和选型建议先列一下我最终定下来的物料清单Arduino Uno R3 一块或者其他5V逻辑的Arduino兼容板VS1053 MP3解码模块 一块注意买带3.3V稳压和电平转换的版本省事很多0.96寸OLED显示屏 一块SSD1306驱动IIC接口128x64分辨率MicroSD卡模块 一块SPI接口用于读取MP3文件MicroSD卡 一张建议8GB以下格式化为FAT323.3V稳压模块 一块如果VS1053模块自带稳压就不需要耳机或小喇叭 一个面包板 一块杜邦线 若干关于VS1053模块的选购市面上有两种一种是裸芯片加必要外围电路的简版另一种是带3.3V稳压、电平转换、SD卡槽的完整版。强烈建议买完整版虽然贵几块钱但省去了电平转换和稳压的麻烦接线也简单很多。完整版模块通常自带SD卡槽连SD卡模块都省了。OLED屏幕选IIC接口的只需要两根信号线SDA、SCL比SPI接口的省引脚。0.96寸128x64的分辨率显示歌曲名、播放时间、音量这些信息足够了。3.2 接线方案和引脚分配完整的接线方案如下Arduino引脚连接目标说明D2VS1053 DREQ数据请求信号D6VS1053 XDCS数据片选D7VS1053 XCS命令片选D8VS1053 XRST复位信号D11VS1053 MOSISPI数据输出D12VS1053 MISOSPI数据输入D13VS1053 SCKSPI时钟A4OLED SDAIIC数据线A5OLED SCLIIC时钟线3.3VVS1053 VCC电源正极5VOLED VCCOLED供电GND所有模块GND共地如果VS1053模块自带SD卡槽SD卡的SPI信号和VS1053共用MOSI、MISO、SCK但需要独立的片选引脚。通常模块上会引出SD_CS接到Arduino的D4或者D10都行。提示所有模块必须共地这是最基本的但新手经常忘。GND没接好会出现各种莫名其妙的问题比如OLED亮但不出字、VS1053没声音等。3.3 焊接和组装中容易忽略的细节如果你买的是需要自己焊接的模块有几个地方要特别注意。VS1053芯片是LQFP封装引脚间距0.5mm手工焊接难度不小。建议用热风枪配合焊膏或者找已经焊好的成品模块。如果非要自己焊先用放大镜检查有没有连锡特别是相邻引脚之间。SD卡槽的焊接也要注意卡槽的固定脚要焊牢不然插拔几次就松了。信号脚焊完后用万用表测一下有没有虚焊。OLED屏幕一般是插针式的直接插在面包板上就行。但要注意OLED的VCC是3.3V还是5V兼容的大部分0.96寸OLED是3.3V供电但IIC信号线可以耐受5V。如果不确定查一下模块的规格书。4. 代码实现从寄存器操作到完整播放逻辑4.1 VS1053的初始化序列VS1053上电后需要一系列初始化操作才能正常工作。完整的初始化流程如下#include SPI.h #include Wire.h #include Adafruit_GFX.h #include Adafruit_SSD1306.h #include SD.h #define VS1053_XCS 7 #define VS1053_XDCS 6 #define VS1053_DREQ 2 #define VS1053_XRST 8 #define SD_CS 4 // VS1053寄存器地址 #define SCI_MODE 0x00 #define SCI_STATUS 0x01 #define SCI_BASS 0x02 #define SCI_CLOCKF 0x03 #define SCI_DECODE_TIME 0x04 #define SCI_AUDATA 0x05 #define SCI_WRAM 0x06 #define SCI_WRAMADDR 0x07 #define SCI_HDAT0 0x08 #define SCI_HDAT1 0x09 #define SCI_AIADDR 0x0A #define SCI_VOL 0x0B void vs1053_write_reg(uint8_t addr, uint16_t data) { while (!digitalRead(VS1053_DREQ)); digitalWrite(VS1053_XCS, LOW); SPI.transfer(0x02); SPI.transfer(addr); SPI.transfer(data 8); SPI.transfer(data 0xFF); digitalWrite(VS1053_XCS, HIGH); } uint16_t vs1053_read_reg(uint8_t addr) { while (!digitalRead(VS1053_DREQ)); digitalWrite(VS1053_XCS, LOW); SPI.transfer(0x03); SPI.transfer(addr); uint16_t result SPI.transfer(0x00) 8; result | SPI.transfer(0x00); digitalWrite(VS1053_XCS, HIGH); return result; } void vs1053_init() { pinMode(VS1053_XCS, OUTPUT); pinMode(VS1053_XDCS, OUTPUT); pinMode(VS1053_XRST, OUTPUT); pinMode(VS1053_DREQ, INPUT); digitalWrite(VS1053_XCS, HIGH); digitalWrite(VS1053_XDCS, HIGH); // 硬件复位 digitalWrite(VS1053_XRST, LOW); delay(10); digitalWrite(VS1053_XRST, HIGH); delay(100); // 软件复位 vs1053_write_reg(SCI_MODE, 0x0804); delay(100); // 设置时钟倍频 vs1053_write_reg(SCI_CLOCKF, 0x8800); delay(100); // 设置音量0x0000最大0xFEFE最小 vs1053_write_reg(SCI_VOL, 0x2020); // 设置低音增强 vs1053_write_reg(SCI_BASS, 0x00FF); }这段代码里有几个关键点。软件复位时写入SCI_MODE的值是0x0804bit 2是软件复位位bit 11是SDI新模式位。复位后需要等待一段时间让芯片稳定。SCI_CLOCKF设置为0x8800表示时钟倍频为3.5倍这是VS1053在12.288MHz晶振下的推荐值能提供更好的解码性能。4.2 音频数据的读取和写入播放MP3文件的核心逻辑就是从SD卡读数据通过SPI写入VS1053。但这里有个关键问题——SD卡和VS1053共用SPI总线必须分时复用。也就是说读SD卡的时候要拉高VS1053的片选写VS1053的时候要拉高SD卡的片选。uint8_t mp3_buffer[32]; void play_mp3_file(const char *filename) { File mp3_file SD.open(filename); if (!mp3_file) { Serial.println(文件打开失败); return; } while (mp3_file.available()) { // 等待VS1053准备好接收数据 if (digitalRead(VS1053_DREQ)) { // 从SD卡读取32字节 int bytes_read mp3_file.read(mp3_buffer, 32); if (bytes_read 0) { // 写入VS1053数据通道 digitalWrite(VS1053_XDCS, LOW); for (int i 0; i bytes_read; i) { SPI.transfer(mp3_buffer[i]); } digitalWrite(VS1053_XDCS, HIGH); } } // 这里可以插入按键检测、OLED刷新等任务 } mp3_file.close(); }这段代码看起来简单但实际运行时会发现一个问题SD卡的读取速度可能跟不上VS1053的消耗速度。特别是用一些低速SD卡的时候读一个扇区要好几毫秒VS1053的缓冲区很快就空了导致断音。解决办法是增大缓冲区。不要一次只读32字节而是一次读512字节一个扇区存到内存缓冲区里然后分批次写入VS1053。Arduino Uno有2KB SRAM开一个512字节的缓冲区完全没问题。uint8_t mp3_buffer[512]; int buffer_index 0; int buffer_length 0; void fill_buffer(File file) { buffer_length file.read(mp3_buffer, 512); buffer_index 0; } void feed_vs1053() { if (buffer_index buffer_length) { return; // 缓冲区空了需要重新填充 } if (digitalRead(VS1053_DREQ)) { digitalWrite(VS1053_XDCS, LOW); int bytes_to_write min(32, buffer_length - buffer_index); for (int i 0; i bytes_to_write; i) { SPI.transfer(mp3_buffer[buffer_index]); } digitalWrite(VS1053_XDCS, HIGH); } }这种双缓冲的思路在实际项目中非常实用。主循环里先检查缓冲区是否需要填充然后调用feed_vs1053()喂数据剩下的时间用来处理按键和刷新显示。4.3 音量控制和音效调节VS1053的音量控制通过SCI_VOL寄存器实现高字节是左声道音量低字节是右声道音量。值越小音量越大0x0000是最大音量0xFEFE是最小几乎静音。实际使用中我一般把初始值设在0x2020左右相当于中等音量。void set_volume(uint8_t left, uint8_t right) { uint16_t vol (left 8) | right; vs1053_write_reg(SCI_VOL, vol); } // 音量增大 void volume_up() { if (current_vol 0x10) { current_vol - 0x10; set_volume(current_vol, current_vol); } } // 音量减小 void volume_down() { if (current_vol 0xFE) { current_vol 0x10; set_volume(current_vol, current_vol); } }SCI_BASS寄存器可以调节低音和高音增强。高字节的低4位是低音增强幅度高4位是低音频率低字节的低4位是高音增强幅度高4位是高音频率。我一般设置成0x00FF也就是低音增强关闭高音增强最大这样人声更清晰。5. OLED显示配合与交互设计5.1 SSD1306的IIC驱动要点0.96寸OLED用的是SSD1306驱动芯片IIC接口。Arduino上直接用Adafruit_SSD1306库就行但要注意IIC地址。大部分模块的地址是0x3C少数是0x3D。如果不确定可以用IIC扫描程序查一下。#include Adafruit_SSD1306.h #define SCREEN_WIDTH 128 #define SCREEN_HEIGHT 64 Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, Wire, -1); void oled_init() { if (!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) { Serial.println(OLED初始化失败); return; } display.clearDisplay(); display.setTextSize(1); display.setTextColor(SSD1306_WHITE); display.display(); }IIC的时钟频率默认是100kHz对于128x64的OLED来说刷新一屏大概需要20-30ms。如果你在主循环里频繁刷新会明显拖慢MP3数据的喂给速度。解决办法是降低刷新频率比如每500ms刷新一次或者只在播放状态变化时才刷新。5.2 播放界面的布局设计OLED屏幕只有128x64像素能显示的信息有限。我的布局是这样的第一行播放状态图标播放/暂停/停止第二行歌曲文件名滚动显示因为文件名可能很长第三行播放时间分:秒格式第四行音量条用矩形块表示void update_display() { display.clearDisplay(); // 播放状态 display.setCursor(0, 0); if (is_playing) { display.print( ); } else { display.print(|| ); } // 文件名滚动 display.setCursor(16, 0); display.print(scroll_text); // 播放时间 display.setCursor(0, 24); display.print(format_time(elapsed_seconds)); // 音量条 display.setCursor(0, 48); display.print(VOL:); int bar_width map(current_vol, 0xFE, 0x00, 0, 80); display.fillRect(32, 48, bar_width, 8, SSD1306_WHITE); display.display(); }文件名滚动显示是个实用技巧。因为OLED一行只能显示16个字符6x8字体大部分MP3文件名都超过这个长度。实现方法是维护一个字符串偏移量每次刷新时递增超过长度就归零。5.3 按键交互和状态机设计一个完整的播放器至少需要三个按键播放/暂停、上一曲、下一曲。如果还要调音量再加两个。Arduino Uno的IO口有限可以用模拟引脚做ADC按键一个引脚识别多个按键。#define BTN_PLAY 9 #define BTN_NEXT 10 #define BTN_PREV 3 int last_btn_state HIGH; void check_buttons() { int play_state digitalRead(BTN_PLAY); if (play_state LOW last_btn_state HIGH) { delay(20); // 消抖 if (digitalRead(BTN_PLAY) LOW) { toggle_play_pause(); } } last_btn_state play_state; }按键消抖是必须的机械按键按下时会有10-20ms的抖动不处理的话一次按下会触发多次。简单的做法是检测到低电平后延时20ms再确认一次。播放器的状态机可以设计成几个状态停止、播放、暂停。状态之间的转换由按键触发同时更新OLED显示和VS1053的寄存器。6. 实际调试中踩过的坑和解决思路6.1 播放时断断续续甚至完全没声音这是最常见的问题原因可能有以下几种供电不足。前面说过VS1053峰值电流能到50mA以上如果和OLED、SD卡共用Arduino的3.3V输出电压会被拉低。用万用表测一下VS1053的VCC引脚播放时如果低于3.0V基本就是供电问题。解决办法是单独供3.3V。SPI时钟太快。虽然VS1053标称支持12MHz但实际模块的PCB走线质量参差不齐。如果杜邦线比较长8MHz可能会出错。把SPI时钟降到4MHz试试在SPI.beginTransaction()里设置SPISettings(4000000, MSBFIRST, SPI_MODE0)。DREQ信号没接好。DREQ是数据流的节拍器如果接触不良或者接错引脚VS1053的缓冲区会溢出或者饿死。用示波器看一下DREQ波形正常播放时应该是高低交替的脉冲。SD卡读取速度不够。有些低速SD卡或者山寨卡读取速度只有几百KB/s跟不上MP3的数据率。换一张Class 10以上的卡试试。6.2 OLED屏幕不亮或者显示乱码OLED不亮的原因通常有三个IIC地址不对、供电电压不对、初始化时序问题。先用IIC扫描程序确认地址。如果扫描不到任何设备检查SDA和SCL有没有接反VCC有没有供电。如果扫描到了但显示乱码可能是初始化参数不对试试在display.begin()之前加一个delay(100)。还有一种情况是OLED模块的IIC上拉电阻没有焊接。有些廉价模块为了省成本省掉了4.7k的上拉电阻导致IIC通信失败。解决办法是在SDA和SCL上各接一个4.7k电阻到3.3V。6.3 SD卡初始化失败SD卡初始化失败最常见的原因是格式不对。Arduino的SD库只支持FAT16和FAT32格式不支持exFAT和NTFS。如果你的卡是64GB以上的默认可能是exFAT需要用工具格式化成FAT32。另外SD卡的片选引脚要接对。如果和VS1053共用SPI总线SD卡的片选必须独立不能和VS1053的XCS或XDCS共用。初始化的时候要先初始化SD卡再初始化VS1053否则SPI总线状态可能冲突。6.4 播放速度不对或者音调异常如果播放出来的声音速度明显偏快或偏慢音调也跟着变那多半是时钟配置问题。VS1053的SCI_CLOCKF寄存器决定了内部时钟倍频如果设置不对解码器的采样率就会偏移。检查一下你的VS1053模块用的是多少MHz的晶振。常见的有12.288MHz和12.0MHz两种。12.288MHz的晶振配0x8800的CLOCKF值是正确的如果是12.0MHz的晶振需要调整成0x8000或者其他值。具体可以参考VS1053的数据手册。7. 功能扩展的一些思路7.1 加入红外遥控用VS1838B红外接收头加一个红外遥控器可以实现远程控制。红外接收头输出的是38kHz载波的解调信号Arduino用外部中断或者定时器捕获解码。IRremote库可以直接用支持大部分常见遥控器协议。接线上VS1838B的输出脚接到Arduino的D3支持外部中断VCC接5VGND接地。代码里用IRrecv对象接收decode()解析根据键值映射到播放、暂停、音量加减等操作。7.2 用ESP32替换Arduino UnoESP32的SPI速度更快最高80MHzRAM更大520KB还自带蓝牙和WiFi。用ESP32做播放器可以实现蓝牙音频接收、网络电台播放等高级功能。不过ESP32是3.3V逻辑和VS1053的电平完全匹配不需要电平转换接线更简单。在ESP32上使用VS1053SPI引脚可以自定义不限于默认的VSPI引脚。用SPIClass对象可以灵活配置。DREQ引脚用中断方式处理响应更快。7.3 添加频谱显示VS1053有一个很酷的功能它可以输出当前解码音频的频谱数据。通过读取SCI_HDAT0和SCI_HDAT1寄存器可以获取32个频段的能量值。把这些值用OLED的柱状图显示出来就是一个简单的频谱分析仪。不过这个功能需要VS1053运行在特定的模式下而且读取频谱数据会占用SPI带宽可能影响音频播放的流畅度。建议在播放低比特率MP3时使用或者降低频谱刷新频率。7.4 支持更多音频格式VS1053原生支持MP3、WAV、MIDI、OGG、WMA、FLAC等格式。如果你有一些特殊格式的音频文件比如AAC或者M4AVS1053是不支持的。这时候有两个选择一是用软件转换工具提前转成MP3二是换用支持更多格式的解码芯片比如VS1063支持AAC和MP3编码。FLAC是无损格式VS1053可以解码但数据率比MP3高很多通常800kbps以上对SD卡读取速度和SPI带宽要求更高。用Arduino Uno播放FLAC可能会卡顿建议用ESP32或者STM32。8. 关于代码优化和资源管理的一些经验Arduino Uno的资源非常有限2KB SRAM、32KB Flash写代码的时候要精打细算。全局变量尽量少用能用const的放Flash里用PROGMEM关键字字符串常量不要重复定义。SPI通信是整个系统的瓶颈。SD卡读取和VS1053写入共用一条SPI总线必须分时操作。我的做法是在主循环里设置一个优先级DREQ为高时优先喂VS1053数据DREQ为低时才去读SD卡。这样能最大程度保证音频流的连续性。中断的使用要谨慎。Arduino Uno只有两个外部中断D2和D3DREQ信号变化频繁如果用中断处理会消耗大量CPU时间。我建议DREQ用轮询方式按键用中断方式这样分工比较合理。最后说一下电源管理。如果你打算用电池供电VS1053和Arduino的功耗加起来大概100mA左右用一块2000mAh的锂电池能撑20小时左右。但要注意锂电池的电压范围是3.7V-4.2V不能直接接VS1053的3.3V输入需要加一个降压模块。TP4056充电模块加AMS1117-3.3的组合就很合适充电和稳压一体。我在实际使用中发现VS1053模块对电源纹波比较敏感如果降压模块的质量不好播放时会有底噪。解决办法是在VS1053的VCC和GND之间并一个100uF的电解电容和一个0.1uF的陶瓷电容能明显改善音质。这个技巧在官方文档里不会写但实测非常有效。
返回列表