940 字
5 分钟
ESP32-CAM 实战:构建低成本定时延时摄影系统

一、 项目概述#

ESP32-CAM 是一款基于 ESP32-S 芯片的紧凑型摄像头模块,集成 OV2640 摄像头与 MicroSD 卡槽。凭借其不到 50 元的成本,它成为了 DIY 监控、延时摄影(Time-lapse)及视觉追踪项目的首选方案。

本实验目标: 利用 ESP32-CAM 硬件定时器触发快门,将拍摄的图像以自动递增的编号命名,并存储至本地 SD 卡。


二、 硬件准备与接线说明#

1. 核心清单#

  • 开发板:AI-Thinker ESP32-CAM
  • 存储:MicroSD 卡(建议容量 16GB 及以下,必须格式化为 FAT32
  • 下载器:USB 转 TTL 模块(ESP32-CAM 通常不自带 USB 接口)

2. 烧录模式接线#

由于 ESP32-CAM 没有集成的 USB 转串口芯片,烧录时需要按下表接线:

ESP32-CAMUSB 转 TTL备注
5V / 3V35V / 3.3V建议使用 5V 以保证摄像头瞬时电流
GNDGND必须共地
U0RTXD串口接收
U0TRXD串口发送
GPIO 0GND进入烧录模式的关键:必须短接

三、 软件架构设计#

本方案采用 esp_camera 驱动库。为了防止设备重启后文件名覆盖,我们利用 ESP32 的 RTC 慢速存储器(RTC_DATA_ATTR)EEPROM 来保存图片序号。

核心代码实现#

#include "esp_camera.h"
#include "Arduino.h"
#include "FS.h"
#include "SD_MMC.h"
#include "soc/soc.h" // 解决掉电检测问题
#include "soc/rtc_cntl_reg.h" // 解决掉电检测问题
#include <EEPROM.h> // 用于持久化照片编号
#define EEPROM_SIZE 1
// 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
int pictureNumber = 0;
void setup() {
WRITE_PERI_REG(RTC_CNTL_BROWN_OUT_REG, 0); // 关闭掉电检测,防止电压瞬降导致重启
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;
// 根据内存情况调整图片质量
if(psramFound()){
config.frame_size = FRAMESIZE_UXGA; // 1600x1200
config.jpeg_quality = 10;
config.fb_count = 2;
} else {
config.frame_size = FRAMESIZE_SVGA;
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, 0x%x", err);
return;
}
// 初始化 SD 卡 (使用 1-线模式以节省功耗/引脚)
if(!SD_MMC.begin("/sdcard", true)){
Serial.println("SD Card Mount Failed");
return;
}
}
void take_picture() {
camera_fb_t * fb = esp_camera_fb_get();
if(!fb) {
Serial.println("Capture failed");
return;
}
// 读取并更新编号
EEPROM.begin(EEPROM_SIZE);
pictureNumber = EEPROM.read(0) + 1;
String path = "/pic_" + String(pictureNumber) + ".jpg";
fs::FS &fs = SD_MMC;
File file = fs.open(path.c_str(), FILE_WRITE);
if(!file){
Serial.println("Failed to open file in writing mode");
} else {
file.write(fb->buf, fb->len);
Serial.printf("Saved: %s\n", path.c_str());
EEPROM.write(0, pictureNumber);
EEPROM.commit();
}
file.close();
esp_camera_fb_return(fb);
}
void loop() {
take_picture();
delay(10000); // 每 10 秒拍摄一次
}

四、 常见问题与工程优化 (FAQ)#

1. 为什么 SD 卡挂载失败?#

  • 格式问题:ESP32-CAM 对分区表很敏感,必须是 MBR 分区格式 的 FAT32。建议使用 SD Formatter 工具。
  • 引脚冲突:SD 卡使用的是 HS2 信号线,烧录完成后请拔掉引脚 0 上的跳线,否则可能干扰数据传输。

2. Brownout detector 错误#

  • 现象:摄像头工作瞬间功耗很大(峰值达 300mA+),导致电压波动重启。
  • 对策:在 5VGND 之间并联一个 100uF - 470uF 的电容,或在代码开头加入 WRITE_PERI_REG(RTC_CNTL_BROWN_OUT_REG, 0);

五、 后续进阶建议#

  1. Deep Sleep(深度睡眠): 对于野外拍摄,不建议在 loop() 中使用 delay()。应调用 esp_deep_sleep_start(),让 ESP32 在拍照间隔进入睡眠状态(功耗降至 10mA 以下)。
  2. Web Server 预览: 利用集成的 Wi-Fi,可以开启一个异步 Web 服务器,实时流式传输摄像头画面。
  3. PIR 触发: 将 GPIO 13 连接到人体红外传感器,实现“有人经过才拍摄”,大幅节省存储空间。
ESP32-CAM 实战:构建低成本定时延时摄影系统
https://hw.rscclub.website/posts/esp32cam1sdtime/
作者
杨月昌
发布于
2017-05-18
许可协议
CC BY-NC-SA 4.0