ESP32‑CAM 应用详解

单片机/PLC wes 3 months ago (2026-07-30) 243 views
📑 本文导航

一、基础简介

ESP32‑CAM 是基于 ESP32‑S 芯片的低成本摄像头模块,集成 Wi‑Fi + Bluetooth,自带摄像头接口、MicroSD 卡卡槽;不需要外接主控,本身就可以拍照、视频流传输、图像采集。
核心芯片:ESP32‑S(双核 Tensilica‑LX6,240MHz,520KB SRAM) 工作电压:3.3V,注意!不能直接接 5V 给芯片 IO,摄像头 IO 是 3.3V 电平;模块可以 5V 供电(VIN 引脚)。 通信:Wi‑Fi 802.11 b/g/n,蓝牙 4.2 BLE。 用途:机器视觉原型、视频监控、WiFi 图传、二维码识别、颜色识别;算力远不如 OpenMV,不能本地跑复杂视觉算法。

和 OpenMV 对比

项目

 ESP32‑CAM

OpenMV4‑H7 R2

 主控

 ESP32‑S

STM32H743

 硬件

 WiFi 蓝牙,SD 卡

 无 WiFi,UART 串口输出

 本地图像处理

 只能简单像素处理;不适合复杂算法

 内置优化视觉库 blobs、apriltag

AI

TinyML,模型很小,帧率低

 FOMO,硬件无 NPU

 输出方式

 WiFi 网页流,MQTT;可串口输出

 UART 串口输出坐标给单片机

 供电

 5V VIN 供电

 3.3‑5V

ESP32‑CAM 短板:
  1. 内存很小,图像占用内存大,不能做高分辨率实时图像处理;
  2. 没有板载下载电路!烧录代码必须外接 USB 转 TTL;
  3. 没有板载按键,没有板载 LED(除摄像头闪光灯);
  4. 散热差,长时间高负载容易过热降速。

二、常用型号、摄像头传感器

1、模块主板型号

最常见两种:
  1. ESP32‑CAM‑MB(最经典,AI‑Thinker 原厂) 市面上 95% 买到的就是这一款,板载 SD 卡槽;排针没有焊接,到手自己焊排针。
⚠️没有 CH340 下载芯片,不能直接 USB 下载!
  1. ESP32‑CAM‑CH340(带底板) 底板集成 CH340 USB 转串口,直接插 USB 烧录程序,新手优先选。底板引出所有 IO。

2、摄像头传感器(OV 系列为主)

OV2640【最常用,标配】

  • 像素:200W 像素
  • 最大分辨率:UXGA (1600×1200);常用 QVGA (320×240)、VGA (640×480)
  • 接口:DVP 并行接口
  • 优势:成熟、资料最多;ESP32‑CAM 标配;适合视频流、拍照。
  • 劣势:暗光效果一般,噪点多。

OV7670

30 万像素,画质差,现在很少用。

OV3660

300 万像素,画质更好,价格贵;ESP32 内存有限,高分辨率很容易内存溢出死机,一般选 VGA/QVGA。
✅实战建议:直接买 OV2640,绝大多数项目够用,不要盲目追求高像素。分辨率越高内存占用越大,越容易死机。

板载硬件

  1. 8 个 LED 补光灯(白色闪光灯引脚 GPIO4,可以软件开关)
  2. MicroSD 卡槽:最大支持 32GB FAT32,保存照片视频
  3. DVP 摄像头接口(不是 MIPI)
  4. IO 口:GPIO0、GPIO2、GPIO12‑GPIO17;GPIO0 是下载模式引脚。

三、引脚定义(AI‑Thinker ESP32‑CAM‑MB)

表格
引脚 功能 备注
VIN 5V 电源输入 模块供电 5V
GND 地 必须共地
3.3V 模块输出 3.3V,最大几百 mA 不要用来外接大设备
GPIO0 DOWNLOAD 引脚 拉低进入烧录模式
GPIO2 LED 闪光灯 高电平点亮补光灯
GPIO12‑GPIO17 DVP 摄像头数据引脚,不要用作普通 IO
GPIO14‑GPIO15 SD 卡 SPI 接 SD 卡槽
⚠️大坑:GPIO12~GPIO17 已经硬件连接摄像头,不要当做普通 IO 外接外设,会导致摄像头无法工作。 可用自由 IO 只有:GPIO0、GPIO2。GPIO2 接闪光灯。

烧录接线(ESP32‑CAM‑MB 裸模块,没有底板)

USB‑TTL(CH340) ↔ ESP32‑CAM
  1. TXD(USB‑TTL) → GPIO3(U0R)
  2. RXD(USB‑TTL) → GPIO1(U0T)
  3. GND ↔ GND(必须共地)
  4. VIN → 5V(不要接 3.3V 供电,供电不足会重启)
  5. GPIO0 ↔ GND,上电,进入烧录模式;烧录完成断开 GPIO0‑GND 复位运行。
烧录完成后,GPIO0 不要再一直接地,否则永远进入下载模式。

四、开发环境

1.Arduino‑ESP32(最常用,新手首选)

大量现成示例代码:WebServer 视频流、拍照 SD 卡、MQTT、人脸识别、颜色采集。

2.ESP‑IDF(乐鑫官方 SDK)

适合做产品,性能更高,上手难度高;电赛、比赛一般 Arduino 足够。
❗注意内存:ESP32 的 PSRAM(外部伪静态内存)必须打开,否则高分辨率直接内存崩溃。 Arduino 工具选项中:PSRAM → Enabled。

五、典型应用详解

应用 1:WiFi 网页视频流(电赛高频)

功能:ESP32‑CAM 启动 WiFi,开启网页服务器;电脑 / 手机浏览器访问 IP,实时查看摄像头画面。
  • 常用分辨率 QVGA 320×240,帧率 10‑18fps;VGA (640×480) 帧率 5‑10fps。
  • 局限:ESP32 本身算力弱,只负责采集图像,图像识别不能在 ESP32 本地做。
使用方案 A:电脑 OpenCV 读取网页 MJPG 流,电脑做图像处理,结果通过网络下发给小车主控。 使用方案 B:ESP32 截图,通过 WiFi 发送图片给 STM32;不推荐,延迟极高。
对比 OpenMV:OpenMV 直接 UART 输出坐标;ESP32‑CAM 本身不做识别,识别交给电脑。

应用 2:拍照 + SD 卡存储

触发条件可以是按键、定时器、网页请求;照片保存到 SD 卡。适合巡检抓拍。

应用 3:二维码 / 条形码识别

ESP32‑CAM + Arduino 库 ESP32QRCodeReader。
限制:帧率低;镜头距离二维码需要合适,暗光识别很差。适合静态识别,高速运动识别几乎不可用。

应用 4:简单颜色识别(本地)

ESP32 可以读取图像像素 RGB 值,遍历像素统计色块;不支持 HSV Blobs 算法,没有 OpenMV 的优化库,速度很慢。QVGA 分辨率一帧遍历耗时几十‑上百 ms。
电赛不推荐 ESP32‑CAM 本地做颜色循迹,实时性差,容易死机;优先 OpenMV。

应用 5:TinyML 本地 AI 推理

支持训练好的模型(比如人脸检测、物体识别),模型必须很小。
  • 速度很慢,QVGA 下 1‑3FPS;只能识别简单目标。
  • 适合演示,比赛实时闭环项目慎用。

应用 6:远程监控,MQTT 上传图片

连接路由器,抓拍图片上传 MQTT 服务器,物联网项目。

应用 7:作为图像采集单元配合 STM32 小车(两种方案)

  1. 方案 1(推荐)ESP32‑CAM 输出 MJPG 视频流,电脑 OpenCV 处理图像,串口 / WiFi 下发坐标给 STM32。
优点:电脑算力强,可以跑完整 OpenCV 算法;缺点:必须要有电脑。
  1. 方案 2 ESP32 本地简单图像处理,串口发送坐标给 STM32;不推荐,延迟高、不稳定,容易死机。
✔️比赛选型建议
  • 需要小车板载视觉,无电脑,直接选 OpenMV4‑H7;
  • 可以带电脑,电脑做图像处理,选 ESP32‑CAM。

六、常见问题总结(高频问题)

  1. 供电不足:ESP32‑CAM 瞬时电流峰值 400mA,USB‑TTL 很多板子供电能力弱,表现反复重启。优先外部 5V 电源供电。
  2. GPIO12‑17 已经接摄像头,不能做普通 IO;自由 IO 极少。
  3. 烧录模式:GPIO0 上电拉低;运行时 GPIO0 必须断开。
  4. PSRAM 没有开启,高分辨率直接死机,Arduino 工具选项打开 PSRAM。
  5. 电平 3.3V,不要把 5V 信号接到 IO 口,直接烧毁模块。
  6. OV2640 镜头焦距出厂没有调好!到手旋转镜头调节清晰度,旋转镜头调好之后胶水固定。镜头模糊一切算法都白搭。
  7. SD 卡必须格式化为 FAT32,簇大小 4096 字节,大于 32GB 不支持。
  8. 内存有限,不要使用太高分辨率,优先 QVGA (320×240) 做开发。
  9. ESP32‑CAM 不适合高速闭环控制,图像采集 + 处理延迟很大。

七、Arduino 最小示例代码:WiFi 视频流(ESP32‑CAM‑MB + OV2640)

注意修改 wifi 账号密码
cpp

#include "esp_camera.h"
#include 

//摄像头引脚定义 AI‑Thinker ESP32‑CAM‑MB
#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

const char* ssid     = "你的WiFi名称";
const char* password = "WiFi密码";

WiFiServer server(80);

void setup() {
  Serial.begin(115200);
  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_sscb_sda = SIOD_GPIO_NUM;
  config.pin_sscb_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;

  //PSRAM开启用QVGA
  if(psramFound()){
    config.frame_size = FRAMESIZE_QVGA; //320*240
    config.jpeg_quality = 12;
    config.fb_count = 2;
  } else {
    config.frame_size = FRAMESIZE_QQVGA;
    config.jpeg_quality = 12;
    config.fb_count = 1;
  }

  esp_err_t err = esp_camera_init(&config);
  if (err != ESP_OK) {
    Serial.printf("Camera init failed %d",err);
    return;
  }

  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
  }
  server.begin();
}

void loop() {
  WiFiClient client = server.accept();
  if (client) {
    String response = "HTTP/1.1 200 OK\r\nContent-Type: multipart/x-mixed-replace; boundary=frame\r\n\r\n";
    client.print(response);
    while(client.connected()){
      camera_fb_t *fb = esp_camera_fb_get();
      if (!fb) break;
      client.print(String("--frame\r\nContent‑Type:image/jpeg\r\nContent‑Length:")+fb->len+"\r\n\r\n");
      client.write(fb->buf, fb->len);
      client.print("\r\n");
      esp_camera_fb_return(fb);
    }
    client.stop();
  }
}
下载运行,串口打印 IP 地址;浏览器打开 http://IP 即可查看实时视频流。

 


↑