☰
ESP32-CAM图像传输完整教程:从硬件接线到MJPEG视频流
2026/11/6 1:08:25 网站建设 项目流程

玩嵌入式这些年,被问得最多的不是各种传感器,也不是电机驱动,而是这块几十块钱的ESP32-CAM。它带摄像头、带Wi-Fi、带蓝牙,官方库一路按到底就能出图,听起来确实很美好。但真拿到手,很多人第一步就卡在硬件接线上下载不了程序,第二步又卡在图像传输的帧率、花屏和重启问题上。这篇文章把我实测跑通的完整方案整理出来:硬件怎么接、源码怎么写、参数怎么调、坑怎么避,一次性说清楚。适合刚入门的玩家,也适合想把它用在智能家居、小型监控、视觉识别项目里的朋友。

1. 项目背景与整体设计思路

1.1 为什么大家都在用ESP32-CAM做图像传输

先说结论:ESP32-CAM几乎是目前在“低成本嵌入式视觉”这条赛道上最省事的方案。它本质上是一块ESP32-S芯片加上一个OV2640摄像头模组,板子已经帮你把数据线和电源线都排好了,你只需要通过串口烧录代码,然后模块自己就会通过Wi-Fi把摄像头采集到的JPEG图像传到局域网任意设备上。

很多朋友会问,为什么不直接用树莓派加USB摄像头?树莓派的算力当然强得多,可以跑完整的目标检测,但价格差了十倍以上,而且对于“传输一张画面到手机或电脑上看”这种需求,树莓派是杀鸡用牛刀。ESP32-CAM的方案,整个物料成本压到五六十元以内,功耗也低,一个5V/1A的充电头就能带起来。做一个鱼缸监控、宠物观察器、3D打印机的延时摄影,或者做一个简单的物联网相机,绰绰有余。

另外ESP32-CAM的生态也成熟。乐鑫官方的esp32-camera库把OV2640的寄存器配置全部封装好了,你不需要理解I2C如何配置摄像头寄存器,也不需要手动处理DMA和帧缓冲,直接调用esp_camera_fb_get()就能拿到一帧图像数据。这种“低门槛+高完成度”的组合,是它能在嵌入式社区里普及开来的根本原因。

1.2 先定方案:本机预览加局域网HTTP流

在写代码之前,我建议大家先想清楚两件事:图像要传给谁看,传给多远。如果只是手机、电脑在同一个Wi-Fi下看,最简单的方案是ESP32自建一个Web服务器,浏览器访问它时逐帧推送JPEG图片,形成MJPEG视频流。这样做的好处是完全不需要第三方平台,不依赖外部服务器,手机浏览器直接输入IP就能看。如果要做广域网远程看,那就得考虑路由器端口映射或者把图像推到云平台,复杂度会高很多,我建议新手先把局域网方案跑通。

我这次采用的是“本地Web Server + MJPEG流”的整体架构:ESP32-CAM初始化摄像头后,内部通过DMA把图像数据存入PSRAM帧缓冲;Wi-Fi连接上路由器后启动HTTP服务;浏览器请求/stream路径时,服务端以multipart/x-mixed-replace格式不断刷新JPEG帧。说人话就是,摄像头每拍一张照片就立刻发给浏览器,浏览器自动用新的图片覆盖旧的,人眼看起来就是连续视频。这个方案延迟大约在200到500毫秒,对大多数监控、预览场景足够用。

下面是整体数据流向,大家先在脑子里留下这个链路,后面所有问题排查都围绕它展开:

摄像头传感器 → 图像数据进入帧缓冲(PSRAM) → JPEG压缩 → Wi-Fi发送 → 浏览器HTTP接收并渲染

选这个方案我考虑过两点:第一是实时性。ESP32-CAM内置的OV2640最大能输出1600x1200分辨率的图像,但直接用原始YUV或RGB数据走Wi-Fi会非常慢,所以必须在摄像头端就压缩成JPEG,一张VGA分辨率压缩后大约50到100KB,在局域网里传输流畅度能接受。第二是兼容性。MJPEG流不需要安装任何App,手机、电脑、平板打开浏览器就能看,做产品原型或者临时调试都极其方便。

2. 硬件接线与前期准备

2.1 硬件清单与必备外围

玩ESP32-CAM,光靠板子本身没法烧录,因为这块板默认没有USB转串口芯片,你需要一块USB转TTL下载器。我这里列一个我实测过比较稳的硬件清单。

硬件型号/规格数量说明
主控板ESP32-CAM (AI-Thinker版本)1市面主流版本,引脚定义统一
摄像头OV26401板载自带,无需额外购买
下载器FTDI FT232RL或CP21021用于串口下载和日志输出
电源5V/1A充电头或5V电源模块1摄像头工作电流大,建议独立供电
连接线杜邦线(母对母)若干接线尽量短,减少干扰
面包板无特殊要求可选转接方便,但不是必需

这里有个很容易踩的坑:很多人买的ESP32-CAM模块,摄像头排线是出厂插好的,但运输过程中可能松动。拿到手第一件事,打开包装后先检查摄像头排线是否完全插入,并且金属触点方向是否正确。我见过很多“白屏”“花屏”问题,最后发现就是排线没插到位。

2.2 三步完成硬件接线

先把下载模式接好。ESP32-CAM支持通过UART下载程序,但你需要在下载时把GPIO0拉低。AI-Thinker版本的ESP32-CAM板载了一个按键,但这个按键不是复位键,而是专门用来控制GPIO0的。下载程序时按住这个IO0按键,再给板上电,模块就会进入下载模式。

下载接线按下面这张表来,顺序不要错:

FTDI下载器引脚ESP32-CAM引脚说明
5V5V给ESP32-CAM供电,注意下载器和板子必须共地
GNDGND共地,否则串口通信不稳定
TXDU0RXD (GPIO3)FTDI发送接ESP32接收,交叉连接
RXDU0TXD (GPIO1)FTDI接收接ESP32发送,交叉连接
3.3V不接不推荐用下载器3.3V给整板供电,电流不够

接线完成后,把USB转TTL插到电脑,先按住IO0按键不松,再插上USB线,看到ESP32-CAM板载红色LED亮起,此时松开按键,设备就处于下载模式了。用Arduino IDE或esptool都可以检测到串口,串口波特率通常选115200。

运行模式就比较简单了:把IO0和GND之间的连接断开,串口线可以拔掉,只保留5V和GND给ESP32-CAM供电。如果你希望同时看串口日志,可以继续接着TX/RX线,但注意下载时连接线和运行时连接线不能反,很多朋友在运行时把TXD/RXD接反了,导致日志输出乱码。

2.3 供电问题:是重启和花屏的第一元凶

我在这个项目上踩得最深的一个坑就是供电。ESP32-CAM启动瞬间电流非常大,特别是摄像头初始化、Wi-Fi发射功率拉满的时候,瞬时电流能达到500mA到800mA,峰值甚至超过1A。用USB转TTL下载器的3.3V引脚供电,基本稳死,出现的情况就是:串口能识别,但是下载到一半就“Connecting...___”卡死,或者程序运行时频繁重启。

正确做法是:下载阶段可以用下载器的5V供电,但最好还是用独立电源;运行阶段直接把ESP32-CAM的5V接到充电头或者5V/2A电源模块的正极,GND接到负极。关键是电源地和下载器地必须连在一起,不然串口电平参考点不一致,日志会乱码,下载也会时好时坏。

我还建议给摄像头芯片加一个散热片。OV2640长时间运行还好,但ESP32主芯片在高分辨率、高帧率模式下温度不低,尤其是夏天密闭空间,摸上去烫手是正常的,但过高的温度会影响Wi-Fi稳定性。A2以后我都在芯片上贴了一个小铝散热片,几十克重,不存在散热焦虑。

3. 环境搭建与源码解析

3.1 搭建Arduino IDE环境

ESP32-CAM的开发环境我推荐用Arduino IDE,不是因为它比ESP-IDF能力强,而是因为社区生态和示例代码最丰富,对新手最友好。打开Arduino IDE后,在“文件→首选项→附加开发板管理器网址”里填入乐鑫官方的ESP32开发板索引地址:

https://raw.githubusercontent.com/espressif/arduino-esp32/gh-pages/package_esp32_index.json

然后在“工具→开发板→开发板管理器”里搜索esp32,安装Espressif ESP32开发包。这里提醒一句,新版Arduino ESP32核心从2.x到了3.x,API有些变动。我用的是2.0.17版本,稳定性和示例代码兼容性最好,如果你只想快速跑通,不建议一上来就用最新版3.x,因为部分老的摄像头驱动调用方式会有变化。

选择开发板时要指定为“AI Thinker ESP32-CAM”或“ESP32 CAM”,在“工具”菜单里还需要设置:

配置项推荐值
Flash Size4MB(2MB APP/2MB SPIFFS)
Partition SchemeHuge APP (3MB No OTA/1MB SPIFFS)
Upload Speed921600或115200
Core Debug LevelInfo

分区方案必须选“Huge APP”,不然编译出来的固件可能超出默认分区大小,烧录会失败。这是新手高频报错点之一,后面我发现九成是这里没设置。

3.2 可运行源码逐行拆解

下面这套源码是我整理过的极简版,保留了图像传输的核心逻辑,去掉了官方CameraWebServer里面的评判附属功能。你把它完整复制到Arduino IDE里,改掉Wi-Fi名称和密码就能跑。完整工程我放在下面这段代码里,针对AI-Thinker ESP32-CAM引脚定义已经预设好。

#include "esp_camera.h" #include <WiFi.h> #include <WebServer.h> // 修改成你家的Wi-Fi信息 const char* ssid = "你的WiFi名称"; const char* password = "你的WiFi密码"; WebServer server(80); // AI-Thinker ESP32-CAM 引脚定义,其他板子请对照修改 #define PWDN_GPIO_NUM 32 #define RESET_GPIO_NUM -1 #define XCLK_GPIO_NUM 0 #define SIOD_GPIO_NUM 26 #define SIOC_GPIO_NUM 27 #define Y9_GPIO_NUM 35 #define Y8_GPIO_NUM 34 #define Y7_GPIO_NUM 39 #define Y6_GPIO_NUM 36 #define Y5_GPIO_NUM 21 #define Y4_GPIO_NUM 19 #define Y3_GPIO_NUM 18 #define Y2_GPIO_NUM 5 #define VSYNC_GPIO_NUM 25 #define HREF_GPIO_NUM 23 #define PCLK_GPIO_NUM 22 void startCamera() { camera_config_t config; config.ledc_channel = LEDC_CHANNEL_0; config.ledc_timer = LEDC_TIMER_0; config.pin_d0 = Y2_GPIO_NUM; config.pin_d1 = Y3_GPIO_NUM; config.pin_d2 = Y4_GPIO_NUM; config.pin_d3 = Y5_GPIO_NUM; config.pin_d4 = Y6_GPIO_NUM; config.pin_d5 = Y7_GPIO_NUM; config.pin_d6 = Y8_GPIO_NUM; config.pin_d7 = Y9_GPIO_NUM; config.pin_xclk = XCLK_GPIO_NUM; config.pin_pclk = PCLK_GPIO_NUM; config.pin_vsync = VSYNC_GPIO_NUM; config.pin_href = HREF_GPIO_NUM; config.pin_sccb_sda = SIOD_GPIO_NUM; config.pin_sccb_scl = SIOC_GPIO_NUM; config.pin_pwdn = PWDN_GPIO_NUM; config.pin_reset = RESET_GPIO_NUM; config.xclk_freq_hz = 20000000; config.pixel_format = PIXFORMAT_JPEG; config.frame_size = FRAMESIZE_VGA; config.jpeg_quality = 12; config.fb_count = 2; esp_err_t err = esp_camera_init(&config); if (err != ESP_OK) { Serial.printf("摄像头初始化失败: 0x%x\n", err); return; } } void handleFrame() { camera_fb_t* fb = esp_camera_fb_get(); if (!fb) { server.send(500, "text/plain", "Camera capture failed"); return; } server.send(200, "image/jpeg", (const char*)fb->buf, fb->len); esp_camera_fb_return(fb); } void handleStream() { WiFiClient client = server.client(); String response = "HTTP/1.1 200 OK\r\n"; response += "Content-Type: multipart/x-mixed-replace; boundary=frame\r\n"; response += "Cache-Control: no-cache\r\n"; response += "Connection: keep-alive\r\n\r\n"; client.print(response); while (client.connected()) { camera_fb_t* fb = esp_camera_fb_get(); if (!fb) { Serial.println("获取图像帧失败"); break; } client.print("--frame\r\n"); client.print("Content-Type: image/jpeg\r\n\r\n"); client.write(fb->buf, fb->len); client.print("\r\n"); esp_camera_fb_return(fb); } } void setup() { Serial.begin(115200); delay(1000); Serial.println("ESP32-CAM启动"); startCamera(); WiFi.begin(ssid, password); while (WiFi.status() != WL_CONNECTED) { delay(500); Serial.print("."); } Serial.println(""); Serial.println("Wi-Fi连接成功"); Serial.println(WiFi.localIP()); server.on("/frame", HTTP_GET, handleFrame); server.on("/stream", HTTP_GET, handleStream); server.on("/", HTTP_GET, []() { server.send(200, "text/html", "<html><body><h2>ESP32-CAM图像传输</h2>" "<img src='/stream' style='width:100%; max-width:640px;'/></body></html>"); }); server.begin(); Serial.println("HTTP服务已启动"); } void loop() { server.handleClient(); }

这段代码有几个关键点一定要理解。

startCamera()函数里,config.pixel_format = PIXFORMAT_JPEG表示让摄像头直接输出JPEG格式,这样帧缓冲里存的就是压缩好的图片,省去软件压缩的CPU开销。config.frame_size = FRAMESIZE_VGA把分辨率设置为640x480,这是实时性和清晰度比较平衡的点。config.jpeg_quality = 12控制JPEG压缩质量,数值范围一般是0到63,数值越小画质越好但帧体积越大,我实测12是比较稳的VGA档位。config.fb_count = 2是双帧缓冲,摄像头在写入下一帧时,网络传输可以同时读取上一帧,能明显提高帧率。

handleFrame()负责返回单张JPEG图片,适合用来做拍照功能。handleStream()则是MJPEG流的核心,它先向浏览器声明multipart/x-mixed-replace类型,这不是普通的HTTP响应,而是一种连续推流格式,浏览器会一直等待并刷新下面的图片帧。client.connected()判断摄像机客户端是否还连着,如果浏览器关闭页面就及时退出循环,避免ESP32一直在无意义地传图。

我特别提醒一点:官方示例里通常把HTML页面直接内嵌在代码中,并把所有浏览器刷新、预览功能都写在里面,初学看起来很炫,但对ESP32来说,动辄几KB的HTML和JS字符串会占掉不少内存。上面这个极简版只保留了一个图片标签,<img src='/stream'>,浏览器请求首页时自动加载视频流,逻辑最干净,出错点也最少。

3.3 下载与烧录实操

烧录之前,先确认下载器被系统识别为COM口,Windows设备管理器里能看到“USB Serial Port”。如果看不到,大概率是驱动问题,FT232RL需要装驱动,CP2102也需要装对应的VCP驱动。

然后按我之前说的:按住IO0按键,插上USB线,让ESP32-CAM进入下载模式。在Arduino IDE里点“上传”按钮,波特率如果选921600失败,改成115200再试,慢一些但稳定。上传过程中串口监视器会打印:

Connecting...___.....

如果卡在这一步不动,基本就是GPIO0没有成功拉低,或者电源不稳,检查一下IO0到GND的接线。上传成功后,IO0恢复高电平,按一下板上的RST复位键或者重新上电,程序就开始跑。这时候打开串口监视器(波特率115200),应该能看到Wi-Fi连接的IP地址,浏览器输入这个IP就能看到实时画面。

烧录成功后如果你发现代码反复重启,优先怀疑电源。把ESP32-CAM从下载器上摘下来,用独立5V电源供电,大部分重启问题能直接解决。如果还是重启,再考虑是不是代码中Wi-Fi连接超时后进入异常状态,可以在while(WiFi.status()!=WL_CONNECTED)里加一个超时计数,超过20秒后重启模块,做一次软复位。

4. 图像传输实现与优化

4.1 MJPEG流是怎么工作的

很多人看到multipart/x-mixed-replace这个头就懵,其实它不难理解。普通HTTP请求是一次性返回一个完整文件,而MJPEG流返回的是一串“以固定分隔符隔开的图片集合”。浏览器知道这个响应不会马上结束,它会一直保持连接,每次收到一个--frame分隔符和一张image/jpeg图片就刷新一次页面里的img标签。

这样做的好处是整个视频流只用了一个TCP连接,不需要每个图片都建立一次握手。延迟可控,实现也简单,只要ESP32不断拍到照片、不断写进这个HTTP响应里就行。缺点是每一帧都是完整的JPEG图片,数据量比H.264视频编码大不少,对带宽要求稍高。但ESP32-CAM性能有限,硬件H.264编码能力也弱,所以MJPEG是最务实的方案。

测试这个方法最直接的工具是浏览器。连上同Wi-Fi后,手机扫码或手动打开http://ESP32的IP/,页面出现实时画面。电脑上可以用浏览器直接打开http://ESP32的IP/stream,看到的就是视频流。如果浏览器显示白屏,检查端口是否被占用、Wi-Fi是否真的搜到信号,以及页面里的img执行跨域访问正常。

4.2 画质与帧率调优

帧率和画质永远是一对矛盾,ESP32-CAM的处理能力有限,你必须找到自己的平衡点。我实测过几组参数,给大家一个参考。

分辨率帧尺寸枚举值JPEG质量实测帧率适用场景
1600x1200FRAMESIZE_UXGA101-3 FPS清晰度优先,适合拍照
1280x720FRAMESIZE_HD123-5 FPS高清预览
640x480FRAMESIZE_VGA128-12 FPS实时监控兼顾清晰度
320x240FRAMESIZE_QVGA1015-20 FPS帧率优先,适合识别

这个表是我在ESP32-CAM主频240MHz、Wi-Fi信号良好的条件下测出来的。实际体验是,VGA分辨率加质量12档是目前综合最好的组合,画面能看清人脸和车牌,流畅度也不至于让人难受。

如果你想改动分辨率,不需要重新配置整个摄像头,在初始化之后调用:

sensor_t* s = esp_camera_sensor_get(); s->set_framesize(s, FRAMESIZE_QVGA); s->set_quality(s, 10); s->set_vflip(s, 1); // 画面反向矫正,根据安装角度调整 s->set_hmirror(s, 0);

这几个set函数可以直接在代码运行中调整,我把它们放在串口命令里做成一个小菜单,调试时输入“vga”或“qvga”就能快速切换,不用反复编译烧录。具体做法是解析Serial.readStringUntil('\n'),然后调用上面的函数,串口监视器直接输入指令即可。

4.3 优化传输稳定性的几个细节

图像传输最怕的不是慢,而是断。我处理稳定性的经验可以总结为三条:控制帧率、控制缓冲区、控制失败重传。

第一,不要把loop()里的逻辑写得太多,server.handleClient()必须高频调用,否则浏览器收到的帧之间间隔过长,看起来就像卡死。第二,图像传输过程中任何耗时操作都不要在推流循环里做,比如把图片写入SD卡、发送到云端,这些都放在帧获取的间隙之外,最好的做法是单独用一个任务去跑。第三,esp_camera_fb_get()如果返回空指针,说明摄像头或内存出问题了,别硬等,直接continue或return重来。

另外,Wi-Fi信号是另一个大坑。ESP32-CAM的天线是板载PCB天线,方向性比较强,金属外壳、路由器隔着几堵墙都会极大影响稳定性。实测中,把板载天线方向对准路由器,帧率能提升接近一倍。如果项目要放在固定位置,可以考虑外接IPEX天线版本。

5. 踩坑记录与排查经验

5.1 高频问题速查表

我把实际调试中遇到的高频问题整理成一张速查表,你就按表排查,基本能解决九成问题。

现象可能原因解决办法
编译失败,报错说固件过大分区方案不正确选Huge APP (3MB No OTA)
上传卡在“Connecting…”GPIΟ0没拉低或电源不足按住IO0键再上电,换独立5V电源
上电后反复重启循环供电电流不足用5V/1A以上电源,检查电源线质量
串口日志全乱码TX/RX接反或波特率不对交叉重接TX/RX,确认115200
浏览器打开画面为白屏摄像头初始化失败看串口日志报错码,检查排线
画面花屏/颜色错乱排线松动或传感器配置错误重插排线,调整vflip/hmirror
推流卡顿严重Wi-Fi信号弱或分辨率过高对准天线,降低分辨率到VGA
/stream能打开但无画面fb_get失败或PSRAM不足启用PSRAM,降低fb_count重试

这里面最隐蔽的是“PSRAM不足”问题。ESP32-CAM内置的PSRAM(外部pseudo-SRAM)是摄像头帧缓冲的关键,代码初始化时会自动尝试使用PSRAM,如果禁用或老化,帧缓冲分配会失败。如果你在串口日志看到fb_alloc failed之类的报错,或者初始化代码返回ESP_ERR_NO_MEM,多半就是PSRAM相关的内存分配问题。

5.2 我自己实操踩过的三个坑

第一个坑是劣质USB线导致的反复重启。当时我为了图方便,拿了一根之前充手机用的Micro USB线,线又细又长。结果摄像头一初始化就重启,串口日志刚打出“Camera Init”就断电。后来换了根粗短线,问题彻底消失。这里告诉大家一个判断方法:如果ESP32-CAM启动瞬间,红光LED明显闪一下又灭了,优先换电源线,别急着怀疑代码。

第二个坑是下载模式时IO0按键操作顺序反了。正确顺序是先按住IO0,再上电或插USB线。我一开始是插好线再按IO0,结果怎么都进不了下载模式,串口一直在重试连接。后来养成了习惯:先断开电源,按住按键,通电,两秒后松开,百发百中。

第三个坑更隐蔽,是软件层面。官方CameraWebServer在浏览器打开首页时会加载一个比较复杂的HTML页面,包括分辨率选择、质量滑块、人脸检测开关,这些功能全部由ESP32的WebServer库动态响应。问题是当图像流和前端控件交互同时发生时,ESP32主线程忙不过来,经常出现一调整参数就断流。我后来把前端精简成上面那个极简版,只保留img标签,所有参数用串口改,项目稳定性大幅提高。这个思路也供你参考:嵌入式Web服务里,前端越精简越好,能省则省。

6. 后续扩展与实用建议

6.1 定时拍照上传到服务器

跑通了实时图像传输,后续最常加的功能就是定时拍照并上传。这个功能逻辑很简单:在loop()里做一个毫秒计时,每5分钟调用一次esp_camera_fb_get()拿一帧JPEG,然后通过HTTP POST multipart的方式提交到你自己服务器上,服务器端用一行Python或Node脚本接收图片并保存。

我给出的建议是,先别急着把拍照上传写在推流循环里。因为推流已经占用了大量网络带宽,再加一个上传请求,帧率会掉得很厉害。正确做法是在推流停止时(比如你关闭浏览器页面)触发上传,或者用独立的定时器任务,延迟高一点没关系。实际上我做过一个阳台植物监测项目,就是每隔1小时拍一张,然后上传到局域网NAS,功耗和稳定性都很理想。

6.2 加低功耗自动唤醒

如果项目要长期运行,功耗是绕不开的问题。ESP32-CAM在正常工作模式下,Wi-Fi传输时功耗大约200mA到300mA,做电池应用要控制好。简单方案是启用深度睡眠,每隔一段时间醒来拍一张照片,然后继续睡。调用方式非常直接:

esp_sleep_enable_timer_wakeup(600 * 1000000ULL); // 600秒 esp_deep_sleep_start();

这样模块会在拍完照、传完图之后进入深睡,整机功耗降到几十微安级别。需要注意的是,深睡后RAM内容会丢失,所有全局变量都要重新初始化,所以每次唤醒后Wi-Fi要重新连接。另外,ESP32-CAM的板载稳压电路待机功耗并不算理想,追求极致功耗的话需要重新设计供电电路,但作为一个低成本的定时监控方案,这套逻辑够用。

6.3 在智能家居里能玩出什么

图像传输只是基础能力,往上叠加才是ESP32-CAM真正发光的地方。最简单的是把它做成一个“有人移动就拍照并推送通知”的看家助手,使用摄像头的帧间差分或运动检测区域设置,检测到画面变化就截帧保存。进阶一点可以用ESP32自带的Faces Detection功能,虽然识别率不如手机端,但已经可以过滤掉大量白天光影变化的假警报。

放到智能家居里,它还能做人脸识别开门:训练好目标人脸后,摄像头捕捉到人脸就通过HTTP协议调用你家里的智能门锁API,自动开门。这个玩法需要一点OpenCV或者TensorFlow Lite的前置知识,但不影响先迈出图像传输这一步。我自己个人的体会是,一块几十元的板子带给你的扩展空间远比想象中大,很多复杂项目都是从这一条稳定的图像传输链路开始的。

最后再分享一个我反复强调的小技巧:在你开发阶段,给ESP32-CAM加一个可拔插供电开关,不要直接用USB热插拔供电,这样能减少因为瞬间电压跌落导致的分区表损坏和Wi-Fi连接异常。等整套方案稳定跑通一周以上,再去考虑怎么优化功耗、美化外壳。先把图像传输这条主链路做扎实,后面所有功能都建立在这个地基上。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询