拓冰建站拓冰建站
首页 / 资讯中心 / 正文

ESP32音频播放实战:从本地MP3到网络电台的完整方案

开头说个真实的体验我当初第一次让ESP32出声的时候那种“芯片居然在唱歌”的兴奋感确实比点了块LED灯来得强烈得多。玩ESP32的人大多数都经历过三个阶段点灯、连WiFi、然后就开始琢磨能不能做点“有声音”的东西。如果你正好卡在第三阶段想给ESP32加上播放音乐的功能从本地读MP3再到联网播网络电台这篇内容可以让你少走不少弯路。这篇文章的内容会覆盖一条比较完整的路径硬件上怎么选解码方案、I2S是什么、本地播放SPIFFS/SD卡怎么写、网络播放HTTP流/网络电台怎么接再加上我实际调试中遇到的各种坑。适合零基础但已经会Arduino基本操作、想认真做个能出声项目的朋友也适合那些已经在ESP32上点过灯、但对音频模块完全没概念的人。1. 先从选型说起为什么拿ESP32做音乐播放器很多人的第一反应是播放音乐不是随便一个带音频输出的单片机都能干吗其实不一样。ESP32在音频这件事上有它很特殊的位置。1.1 内置DAC和I2S的关系ESP32芯片内部其实有一个数模转换器DAC两个通道可以直接输出模拟音频信号。听起来很省事对吧但实际用起来有个明显的限制内置DAC精度是8位信噪比一般推耳机还行稍微讲究一点音质的人就受不了。更麻烦的是如果你同时要用WiFi和蓝牙某些封装下内置DAC的引脚和射频部分会产生干扰。所以真正靠谱的做法是使用芯片上的I2S外设。I2S是一种专门用来传输数字音频的总线协议和I2C、SPI并列但干的活完全不同。它至少有三根线位时钟BCLK、帧时钟/左右声道时钟LRCLK也叫WS、串行数据DIN/DOUT。ESP32的I2S外设负责把MP3解码出来的数字音频数据按照固定的位宽和采样率送到外部DAC芯片或者数字功放芯片由外部芯片完成数模转换和功率放大。换句话说ESP32负责“读文件、解码、吐数字流”I2S负责“把数字流送出去”外部DAC/功放负责“让喇叭响起来”。三层各干各的这样架构清晰音质天花板也更高。1.2 对比其他方案的取舍我把几种常见做法放在一起比较一下你就知道为什么最终选了ESP32。方案优点缺点适用场景Arduino Uno MP3模块如DFPlayer简单、代码量极少只能播放模块内SD卡的文件不能联网流式播放玩具级项目树莓派 MPD/Moode音质上限高、系统生态丰富成本高、体积大、启动慢、功耗高桌面音响、HiFi系统ESP32 I2S DAC/功放成本低、体积小、WiFi蓝牙都有、实时性强需要自己写代码、内存有限DIY播放器、智能音箱、小作品ESP32 内置DAC硬件最少音质差、引脚受限只是“能响”的Demo我的建议是别用内置DAC起步直接用I2S外接解码模块。原因后面会说调试难度其实不相上下但音质和后续扩展空间完全是两个量级。2. 硬件准备与接线我把踩过的坑写在这里播放音乐这事硬件接线的坑比代码多。我踩过的几个硬件坑后面会详细说先把最稳妥的方案给你。2.1 核心元件清单ESP32开发板我用的是经典的DevKit V1ESP32-WROOM-32不带额外扩展板纯粹用杜邦线。I2S解码/功放模块推荐MAX98357A模块一个小板子集成了I2S接收、DAC数模转换和D类功放直接接喇叭就能响不需要额外耳机放大电路。你也可以用PCM5102纯DAC需要再接功放或者AC101音频编解码芯片但MAX98357A对新手最友好接线最少。喇叭4Ω或8Ω、3W左右的普通小喇叭就行不需要买太贵的。SD卡模块本地播放用常见的SPI接口SD卡读卡器模块配一张FAT32格式的MicroSD卡。若干杜邦线、面包板非必需接线麻烦但好在出问题好改。MAX98357A模块有几个关键引脚VIN电源、GND、BCLK、LRCLRCLK、DIN。注意它的供电范围是2.7V到5.5V可以直接用ESP32的3.3V或者5V引脚供电但如果你用的是5V逻辑电平还是3.3V的I2S信号MAX98357A的I2S输入逻辑电平兼容3.3V没问题。2.2 接线表以下是我实测稳定的一组引脚分配你可以直接照着接MAX98357AESP32 DevKit V1说明VIN3V3 或 5V模块供电GNDGND共地BCLKGPIO26位时钟LRCGPIO25帧时钟DINGPIO22串行数据这里有个细节ESP32的I2S引脚在很多例程里用的是GPIO26/25/22或者GPIO27/26/25其实I2S外设在ESP32上是支持GPIO矩阵映射的也就是说很多引脚都可以复用成I2S信号但为了保险建议你用我上面这组。GPIO22在ESP32-AudioI2S库里默认是I2S_DOUTGPIO26默认是BCLKGPIO25默认是LRC这样就不需要额外配置引脚映射少踩一个坑。2.3 关于供电的提醒一个特别容易犯的错误**喇叭和ESP32共用一个USB供电结果放歌放到音量大的时候板子直接重启。**原因很简单——D类功放瞬间电流需求很大USB口供电能力又有限电压跌落ESP32就复位了。我的建议是调试阶段用USB供电还行但一旦接喇叭长时间跑最好用5V/2A以上的外部电源或者用18650电池供电。MAX98357A模块上的D类功放瞬态电流可以到1A以上3.3V的LDO稳压器根本扛不住这种脉冲负载。如果你非要用USB供电把喇叭音量限制在中等以下至少能稳一点。3. 本地播放从SPIFFS到SD卡先把声音弄响说到IO口折腾得差不多了接下来就是让代码跑起来。我个人习惯是“先本地后网络”先把本地文件播放搞定再碰网络流这样定位问题会清晰很多。3.1 开发环境配置播放音频在Arduino环境下有现成的库我强烈推荐ESP32-AudioI2S作者pschatzmann。这个库封装了MP3、AAC、FLAC、WAV等常见格式的解码流程也支持网络流播放一个库全搞定。安装方式Arduino IDE的库管理器搜索“ESP32-AudioI2S”直接安装。如果你还在用老掉牙的ESP32 Arduino Core 1.x建议先升级到2.x版本否则编译容易报各种莫名奇妙的错。打开Arduino IDE还要确认开发板类型工具 - 开发板 - 开发板管理器里搜索esp32安装Espressif官方包。这一步如果你是从零开始的搜“ESP32”会有很多第三方包认准“Espressif Systems”这个作者。3.2 播放Flash里的MP3先来个最小的能响的代码把一首MP3文件上传到ESP32的SPIFFS文件系统里然后播放。#include Arduino.h #include WiFi.h #include Audio.h // 定义I2S引脚 #define I2S_DOUT 22 #define I2S_BCLK 26 #define I2S_LRC 25 Audio audio; void setup() { Serial.begin(115200); // 挂载SPIFFS文件系统 if(!SPIFFS.begin(true)) { Serial.println(SPIFFS mount failed); return; } // 配置音频输出 audio.setPinout(I2S_BCLK, I2S_LRC, I2S_DOUT); audio.setVolume(65); // 音量0-100 // 播放SPIFFS里的文件 audio.connecttoFS(SPIFFS, /test.mp3); } void loop() { audio.loop(); }这段代码很简洁但背后有几个点值得说audio.setPinout的参数顺序是BCLK、LRC、DOUT。网上很多例程顺序不一样有的写成setPinout(I2S_BCLK, I2S_LRC, I2S_DOUT)有的写成setPinout(BCLK, LRC, DOUT)注意这个库的接口是“先时钟、后帧、再数据”别搞反了。audio.connecttoFS的第一个参数是文件系统对象指针第二个是文件路径。这个函数会从文件头解析音频格式所以文件后缀不重要但编码格式一定要是库支持的常见MP3、WAV、FLAC都能放。audio.loop()必须在主循环里反复调用所有音频数据的解码、发送、状态回调都是在这个函数内部处理的。如果你在主循环里放一个delay(1000)声音会变成卡顿的“机器人声”因为音频数据流中断了。把MP3上传到SPIFFS的方式工具 - ESP32 Sketch Data Upload。第一次用会提示安装“ESP32FS”插件现在Arduino IDE 2.x版本内置了上传工具直接选就行。注意SPIFFS分区大小默认是1.9MB一首3分钟的MP3完全能装下但如果是高品质320kbps的歌曲文件可能逼近8-10MB就放不下了。3.3 升级到SD卡播放SPIFFS容量有限想本地放更多歌就走SD卡。接线还是那些只是多了SD卡模块的SPI接口。SD卡模块接线使用VSPISD卡模块ESP32 DevKit V1CSGPIO5MOSIGPIO23SCKGPIO18MISOGPIO19VCC5VGNDGND对应的代码改动很小#include FS.h #include SD.h #include SPI.h #include Audio.h #define I2S_DOUT 22 #define I2S_BCLK 26 #define I2S_LRC 25 #define SD_CS 5 Audio audio; void setup() { Serial.begin(115200); // 初始化SD卡 if(!SD.begin(SD_CS)) { Serial.println(SD Card Mount Failed); return; } // 读取完整路径 audio.setPinout(I2S_BCLK, I2S_LRC, I2S_DOUT); audio.setVolume(65); audio.connecttoFS(SD, /music/test.mp3); } void loop() { audio.loop(); }SD.begin的参数是CS引脚这个很容易漏。很多人的SD卡模块没有板载CS控制必须给一个GPIO作为片选。如果你用默认的SPI引脚ESP32上VSPI默认是GPIO5/18/19/23CS接GPIO5刚好。这里有个经验SD卡格式必须FAT32exFAT的卡在大多数ESP32例程里读不了因为ESP32的SD库是基于FatFs的FAT32兼容性最好。还有SD卡供电最好用5V因为部分SD卡对3.3V供电比较挑剔常出现初始化失败的现象。3.4 为什么用ESP32-AudioI2S库而不是自己写解码器写代码之前我想先说清楚这个库的价值否则你会觉得“不过是调了个库”而已。ESP32要播放MP3核心工作有两块一是解码MP3数据二是通过I2S外设输出PCM数据。这两块如果用官方底层API写代码量至少在几百行以上还要处理缓冲区管理、采样率转换、解码器初始化等一大堆细节。ESP32-AudioI2S库把大部分解码器MP3/AAC/FLAC/WAV都包了一层把你需要关心的接口简化成几个函数。但这也带来一个代价库作者更新频繁接口偶尔会有小变化。特别是版本更新后某些API的参数类型、回调函数名可能变了导致老代码编译不过。我的建议是装好库之后先跑一下库自带的示例File-Examples-ESP32-AudioI2S确认能响再改自己的代码。别直接拿网上的老代码粘贴否则光是对API版本就够折腾的。4. 网络播放接上WiFi让ESP32自己联网放歌本地播放跑通之后你会发现这还不够爽——总得手动往SD卡里拷歌。网络播放就是解决这个痛点的ESP32自己连WiFi从网络电台拉流或者从HTTP服务器点播歌曲。4.1 网络电台/HTTP流音频的原理很多人第一次接触“网络电台”这个概念会以为和普通HTTP下载文件差不多。其实有区别普通HTTP下载文件服务器把完整文件传给你传完就结束。ESP32要等全部下载完成才能开始播放。HTTP流媒体Streaming服务器持续不断地发送音频数据ESP32边接收边解码边播放像一个无限长的水管。网络电台的Shoutcast/ICEcast协议就是用这种方式另外还有HLS、RTSP等不同的流媒体协议。ESP32-AudioI2S库支持最常见的HTTP流和网络电台ICY协议通过connecttohost或者connecttoURL即可。比如// 播放网络电台使用ICY协议 audio.connecttohost(stream.example.com:8000); // 或者播放HTTP服务器上的MP3文件 audio.connecttoURL(http://example.com/song.mp3);注意connecttohost只接受主机名和端口connecttoURL接受完整的URL路径。如果你直接传http://开头的字符串给connecttohost会解析失败。很多人的代码出错就出在这个细节上。4.2 connecttohost 播放网络电台完整代码和本地播放差不了太多只是初始化时要连WiFi#include Arduino.h #include WiFi.h #include Audio.h #define I2S_DOUT 22 #define I2S_BCLK 26 #define I2S_LRC 25 const char* ssid YOUR_WIFI_SSID; const char* password YOUR_WIFI_PASSWORD; // 一个稳定的网络电台地址 const char* streamURL stream.zeno.fm:80/radio; Audio audio; void setup() { Serial.begin(115200); WiFi.mode(WIFI_STA); WiFi.begin(ssid, password); while (WiFi.status() ! WL_CONNECTED) { delay(500); Serial.print(.); } Serial.println(WiFi connected); Serial.print(IP: ); Serial.println(WiFi.localIP()); audio.setPinout(I2S_BCLK, I2S_LRC, I2S_DOUT); audio.setVolume(60); audio.connecttohost(streamURL); } void loop() { audio.loop(); }编译烧录后串口监视器会打出一堆日志正在连接服务器、解析流信息、获取音频元数据当前播放的歌名、码率等……看到“Audio Info: SampleRate44100, BitsPerSample16, Channels2”这类信息就说明已经连上了。这个库默认是通过回调函数把元数据输出到串口的你可以重写audio_info这个回调函数来提取当前播放的歌名void audio_info(const char *info) { Serial.print(audio_info: ); Serial.println(info); }在setup里不需要额外注册库会隐式调用。如果你想把这些信息显示在OLED上就可以在这个回调里做处理。4.3 做一个简单的HTTP点播网络电台适合播放实时流但如果想点按一下播指定歌曲可以自己搭一个最简单的HTTP文件服务器比如用Python的http.server模块起一个静态文件服务然后ESP32通过connecttoURL播放。Python侧# 在歌曲目录下运行 python3 -m http.server 8080ESP32侧audio.connecttoURL(http://192.168.1.100:8080/test.mp3);这种方式其实本质上还是“先下载一部分、边下边播”的渐进式播放。ESP32-AudioI2S库内部有缓冲机制会先填充一定的数据量再开始播放避免网络抖动导致的抽卡。默认缓冲大小在库的头文件里可以调如果你发现播放卡顿可以尝试调大缓冲区。4.4 缓冲与断流处理网络播放最容易出的问题就是卡顿和断流。说实话这是个不可避免的问题因为ESP32的内存就那么几百KBWiFi信号在2.4GHz频段上各种干扰也多。几个实测有效的应对方法缓冲区调大在Audio.h库文件里找到CONFIG_AUDIO_BUFFER_SIZE之类的宏从默认值往上调。但ESP32的堆内存有限调太大反而会因为申请内存失败而崩溃。我的经验是调到8KB到16KB之间相对稳。选择低码率的网络电台128kbps的MP3流比320kbps的流稳定得多尤其当你的路由器信号一般的时候。用5GHz WiFi如果用的是ESP32-S3等支持2.4GHz/5GHz双频的型号连5GHz频段干扰更少。但老款ESP32只支持2.4GHz所以没有这个选择。加一个超时重连机制断流后自动重连。库提供了audio.stopSong()和audio.connecttohost()你可以在audio_showstation或者audio_id3data回调里检测状态但最简单的还是在主循环里周期性检测音频状态unsigned long lastCheck 0; void loop() { audio.loop(); if (millis() - lastCheck 5000) { lastCheck millis(); if (!audio.isRunning()) { Serial.println(Stream lost, reconnecting...); audio.connecttohost(streamURL); } } }audio.isRunning()返回当前是否在播放状态。如果网络断了这个函数大概率会返回false你就可以抓住时机重连。不过要注意如果是因为服务器端拒绝连接导致的重连过快的重连会把自己IP封了建议加个5到10秒的间隔。5. 音质与功耗从能响到好听的几个细节能出声音只是第一步声音好不好听、系统稳不稳定又是另一层功夫。这一节说几个直接影响体验的细节。5.1 采样率与位深数字音频的核心参数是采样率Sample Rate和位深Bit Depth。CD音质是44.1kHz/16bit即每秒采样44100次每次采样用16位二进制表示振幅。采样率决定频率上限位深决定动态范围。ESP32的I2S外设支持常见的采样率从8kHz到96kHz和位深16bit、24bit、32bit解码器会自动识别源文件格式并把数据交给I2S外设。你不需要在代码里手动设置采样率ESP32-AudioI2S库在播放MP3时会从文件头解析这些信息。但如果你用外部DAC要确保DAC芯片支持该采样率。MAX98357A最高支持到96kHz完全没问题。有个小坑某些格式比如某些FLAC文件采样率是48kHz或96kHz当你拿一个不支持该采样率的解码器解码时声音变调或者速度不对。这时候需要重采样ESP32-AudioI2S内部自带重采样功能但会占用大量CPU时间可能导致其他任务卡顿。我的建议是尽量用44.1kHz的音频源兼容性最好。5.2 MAX98357A上的音量设置MAX98357A除了I2S数据还有一个GAIN引脚通过不同接法可以设置最大模拟增益GAIN引脚接法增益悬空9dB接VIN12dB接GND15dB通过电阻到VIN可调 3~12dB我用的时候直接悬空9dB默认就好。如果喇叭声音太小可以在代码里调大audio.setVolume()的值这个值对应的是数字音量——其实是在I2S数据层面做衰减不会增加模拟噪声。如果数字音量已经调到最大还觉得声音小再把GAIN引脚接到VIN提高到12dB。但有个反直觉的现象数字音量调得过高反而容易破音。因为MAX98357A的D类功放输出功率有限当输出接近削波时喇叭会发出明显的“滋滋”声。所以调整音量的正确顺序应该是先把数字音量调到70%左右听一听是否有破音如果破音就降低数字音量同时提高GAIN引脚增益来保持整体响度。5.3 电源滤波与噪声我用杜邦线连接MAX98357A和ESP32时喇叭里总有一种持续的背景“嘶嘶”声尤其是在待机不播放的时候。排查下来发现主要原因有三个共地不良ESP32和功放模块虽然都连到GND但杜邦线接触不良会导致接地阻抗偏高数字地噪声串入模拟地。开关电源纹波大USB供电的纹波会直接进入功放电源引脚被放大后出现在喇叭上。I2S信号线的串扰BCLK上升沿很陡如果DIN线和BCLK线靠得太近数据会互相干扰导致音质劣化。实际解决办法用尽量短的杜邦线或者干脆把功放模块焊到洞洞板上减小杂散电感和电容。在MAX98357A的VIN和GND之间加一个10uF钽电容和0.1uF陶瓷电容并联给瞬态电流提供就近的储能。让I2S的BCLK、LRC、DIN三根线尽量短、尽量远离电源线。我现在做项目基本都遵循一个习惯数字地和模拟地单点接地在电源入口处用一个小磁珠隔离数字地与模拟地效果立竿见影。不过如果你是面包板快速验证先把线缩短、电容补上嘶嘶声一般能压下去不少。6. 实战排查无声、爆音、卡顿怎么定位代码写完、硬件接完到了上电的时候总会有各种意外。我把最常见的问题和定位思路整理成一套排查链路你照着顺序查基本能解决90%的问题。6.1 第一类问题喇叭完全无声遇到无声不要急着怀疑代码。按这个顺序查查供电用万用表测MAX98357A的VIN和GND之间电压正常应该在3.3V到5V之间。如果是0V查电源线接反或者杜邦线接触不良。查I2S引脚映射你的代码里audio.setPinout(BCLK, LRC, DOUT)的参数顺序和接线是否一致。很多人栽在这里代码里写的是setPinout(26, 25, 22)实际接的是26、22、25就差一根线声音完全出不来。查串口日志打开串口监视器看有没有类似“Connect to ... failed”的错误。如果有说明网络连接或文件系统挂载失败了不是音频链路的问题。查解码器状态如果日志显示“Couldnt open file”或者“Format not supported”说明文件本身有问题或者库不支持该编码格式。换一个网上下载的标准MP3文件再试。最后才查喇叭把喇叭拔下来用万用表的通断档测一下喇叭阻抗正常应该有个几欧姆。如果开路那就是喇叭坏了。有一次我排查了半小时无声问题最后发现是喇叭的鳄鱼夹线接反了接虚了。真的先查物理连接再查代码。6.2 第二类问题有声音但爆音/杂音爆音分为两种一种是持续的背景噪声嘶嘶声、沙沙声另一种是每过一段时间突然“噗”一声。持续的背景噪声大概率是电源纹波或地线干扰。先看5.3节的解决办法加电容、缩短线、分离电源线。突发的“噗”声则是数据流中断的表现。可以用Arduino IDE的串口绘图仪看看3.3V电源轨上是否有瞬间跌落或者直接在代码里加一个状态打印看是不是audio.loop()执行的间隔偶尔超过了几百毫秒导致音频缓冲区欠载。还有一个很容易被忽略的点播放过程中如果WiFi在同时做TCP重传CPU占用率会突然升高I2S数据来不及填充就会出现“噗”声。我在项目里一般是把WiFi功率降低一点WiFi.setTxPower(WIFI_POWER_8_5dBm)保证通信但不抢CPU这样爆音概率低很多。6.3 第三类问题网络播放卡顿卡顿的本质是音频消费速率大于网络传输速率。要么是网络太慢要么是缓冲区太小。你可以先在电脑上用VLC等软件测同一个网络电台地址看电脑上卡不卡。如果电脑也卡说明是电台服务器或者网络本身的问题换一个电台地址即可。如果电脑不卡、ESP32卡那大概率是ESP32的WiFi连接质量问题可以放在离路由器近一点的位置测一下。另外说一个容易忽略的事某些公共网络电台会做地区限制或并发连接数限制你在家里能访问不代表ESP32在另一个网络环境能稳定连接。所以如果真的卡成狗先把电台换成几个大平台的公开流地址试试比如SomaFM、BBC Radio稳定不过你可能需要根据所在网络调整。6.4 用日志和状态输出加快排障ESP32-AudioI2S库的日志输出其实能帮上大忙。在setup阶段可以打开详细的日志audio.setTone(1, 1, 1);这个函数比较冷门其实可以设置左右声道音调。我一般更常用的是audio.setBalance(0)这种基础设置日志输出级别可以用esp_log_level_set(*, ESP_LOG_INFO);来控制但如果你不清楚具体用法直接在串口监视器看日志就够了。常见日志含义对照日志内容含义对策Audio Info: SampleRate44100, BitsPerSample16, Channels2正常解析到音频参数无需处理Connect to host xxx failed无法连接流服务器检查WiFi、确认服务器地址正确Cant open file文件打开失败检查文件路径、文件系统挂载Format not supported编码格式不支持换MP3或WAV再试Underrun或Buffer underrun音频缓冲区欠载调大缓冲区或改善网络出现“Buffer underrun”时先不要动代码检查一下WiFi信号强度。如果信号质量在-70dBm以下优先改善信号比调缓冲区有效得多。7. 从播放器到完整作品还能扩展什么到这里本地播放和网络播放的核心逻辑都通了。但如果只是让开发板放出声音说实话离“作品”还差一点。最后聊聊几个我尝试过、反馈很好的扩展方向给想继续折腾的人一个参考。用手机或按键控制选曲。你可以在ESP32上开一个简单的Web服务器手机浏览器访问IP直接点播歌曲或者用几个物理按键切换上一曲/下一曲。我在项目里用过一个非常轻量的方案ESP32开HTTP Server提供一个下拉列表所有SD卡里的MP3文件名列出来点击后调用audio.connecttoFS播放。这个方案的代码量不大但体验感直接拉满。增加OLED显示屏显示歌名。用的SSD1306显示屏I2C接口和MAX98357A完全独立。每次audio_info回调里拿到“STATIONNAME”或者“StreamTitle”信息截取后显示在屏幕上。这是让一个DIY作品有“产品感”最快的办法。用定时器实现音乐闹钟。结合NTP对时设定闹钟时间到点播放网络电台或本地音乐比普通闹钟好玩多了也是智能音箱最常见的基础功能。支持语音指令。ESP32可以用离线唤醒词库但比较占资源也可以接讯飞等云语音平台但联网识别延迟是个问题。如果做本地语音指令用ESP32-S3会从容一些。利用MicroROS把播放器状态上报到机器人系统。如果你在玩ROS 2可以在ESP32上跑micro-ROS节点把当前播放状态、音量等信息发布到ROS话题里或者用ROS话题来控制播放。这个方向偏进阶但把音频外设和ROS生态打通后可以做很多有意思的机器人交互场景。我只能说一条“播放音乐”的线拉出来可以延伸到UI交互、网络协议、文件系统、功率管理、语音识别、嵌入式通信等一大堆知识点。对一个零基础开始玩的人来说这个项目给的锻炼比“点灯”大得多。我做这个项目的个人体会是音频这件事比GPIO和传感器更贴近人的感知出问题时反馈也更强听得出卡顿、爆音、底噪所以调试起来虽然烦但一旦调通成就感也非常直接。如果你在做这个项目的过程中遇到具体问题建议先看串口日志再量电压然后带着具体现象去查报错——报错信息远比“猜测引脚”靠谱。如果只是卡在某一步不妨按我在第6节写的排查顺序走一遍大概率能解决。
分享:

看完干货,该让你的企业上线了

免费需求沟通 · 48 小时内出具建站方案 · 河南本地可上门