<aside> <img src="/icons/battery-charging_blue.svg" alt="/icons/battery-charging_blue.svg" width="40px" />

ESP32 스타터 키트


C++ 언어로 학습하기

Python 언어로 학습하기

<aside> ⚙


예제 코드 다운 받기

제품 구매 링크

아이씨뱅큐 유튜브

아이씨뱅큐 네이버 블로그

아이씨뱅큐 네이버 카페

</aside>



<aside>

</aside>

1. 서론

이번 프로젝트는 ESP32-CAM을 사용하여 사진을 찍고 SD 카드에 저장해보겠습니다.

2. 준비물

ESP32, 확장 보드가 필요해요.

3. 준비하기

  1. 카드 리더기를 사용하여 SD 카드를 컴퓨터에 꽂아 포맷을 해주세요.
  2. 포맷 후 SD 카드를 확장 보드에 꽂아주세요.

image.png

  1. 확장 보드에 카메라를 연결해주세요.

https://docs.sunfounder.com/projects/esp32-starter-kit/en/latest/_static/video/plugin_camera.mp4

  1. USB 케이블을 연결하여 ESP32를 컴퓨터에 연결해주세요.

image.png

  1. PSRAM을 활성화 해주세요.

image.png

  1. Partition Scheme을 **Huge APP (3MB No OTA/1MB SPIFFS)**로 설정해주세요.

image.png

  1. reset 버튼을 눌러 사진을 찍어주세요. 시리얼 모니터를 확인해서 잘 캡쳐가 된다면, 아래 문구를 확인할 수 있습니다.
Picture file name: /picture9.jpg
Saved file to path: /picture9.jpg
Going to sleep now

image.png

  1. 이제 확장 보드에서 SD 카드를 제거하고 컴퓨터에 꽂아보면 방금 찍은 사진들을 확인할 수 있습니다.

image.png

4. 코드 알아보기

/*********
  Rui Santos
  Complete project details at <https://RandomNerdTutorials.com/esp32-cam-take-photo-save-microsd-card>
  
  IMPORTANT!!! 
   - Select Board "AI Thinker ESP32-CAM"
   - GPIO 0 must be connected to GND to upload a sketch
   - After connecting GPIO 0 to GND, press the ESP32-CAM on-board RESET button to put your board in flashing mode
  
  Permission is hereby granted, free of charge, to any person obtaining a copy
  of this software and associated documentation files.
  The above copyright notice and this permission notice shall be included in all
  copies or substantial portions of the Software.
*********/

#include "esp_camera.h"
#include "Arduino.h"
#include "FS.h"                // SD Card ESP32
#include "SD_MMC.h"            // SD Card ESP32
#include "soc/soc.h"           // Disable brownour problems
#include "soc/rtc_cntl_reg.h"  // Disable brownour problems
#include "driver/rtc_io.h"
#include <EEPROM.h>  // read and write from flash memory

// define the number of bytes you want to access
#define EEPROM_SIZE 1

// Pin definition for CAMERA_MODEL_AI_THINKER
#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);  //disable brownout detector

  Serial.begin(115200);
  //Serial.setDebugOutput(true);
  //Serial.println();

  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;  // FRAMESIZE_ + QVGA|CIF|VGA|SVGA|XGA|SXGA|UXGA
    config.jpeg_quality = 10;
    config.fb_count = 2;
  } else {
    config.frame_size = FRAMESIZE_SVGA;
    config.jpeg_quality = 12;
    config.fb_count = 1;
  }

  // Init Camera
  esp_err_t err = esp_camera_init(&config);
  if (err != ESP_OK) {
    Serial.printf("Camera init failed with error 0x%x", err);
    return;
  }

  //Serial.println("Starting SD Card");
  if (!SD_MMC.begin()) {
    Serial.println("SD Card Mount Failed");
    return;
  }

  uint8_t cardType = SD_MMC.cardType();
  if (cardType == CARD_NONE) {
    Serial.println("No SD Card attached");
    return;
  }

  // initialize EEPROM with predefined size
  EEPROM.begin(EEPROM_SIZE);
  pictureNumber = EEPROM.read(0) + 1;

  for (int shoot = 0; shoot < 5; shoot++) {
    camera_fb_t *fb = NULL;

    // Take Picture with Camera
    fb = esp_camera_fb_get();
    if (!fb) {
      Serial.println("Camera capture failed");
      return;
    }

    // Path where new picture will be saved in SD Card
    String path = "/picture" + String(pictureNumber) + ".jpg";

    fs::FS &fs = SD_MMC;
    // Serial.printf("Picture file name: %s\\n", path.c_str());

    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);  // Write image data to file
      if (shoot == 4) {
        Serial.printf("Saved file to path: %s\\n", path.c_str());
      }else{
        Serial.printf("Shooting... \\n");
      }
      EEPROM.write(0, pictureNumber);  // Update the picture number in EEPROM
      EEPROM.commit();
    }
    file.close();                      // Close the file
    esp_camera_fb_return(fb);          // Return the frame buffer back to the camera driver
    delay(200);                        // Short delay between shots
  }
  // Turns off the ESP32-CAM white on-board LED (flash) connected to GPIO 4
  pinMode(4, OUTPUT);
  digitalWrite(4, LOW);
  rtc_gpio_hold_en(GPIO_NUM_4);

  // Put the ESP32-CAM to deep sleep
  delay(2000);
  Serial.println("Going to sleep now");
  delay(2000);
  esp_deep_sleep_start();
  Serial.println("This will never be printed");
}

void loop() {
  // Empty loop as we are putting the ESP32-CAM to deep sleep
}
#include "esp_camera.h"
#include "Arduino.h"
#include "FS.h"                // SD Card ESP32
#include "SD_MMC.h"            // SD Card ESP32
#include "soc/soc.h"           // Disable brownour problems
#include "soc/rtc_cntl_reg.h"  // Disable brownour problems
#include "driver/rtc_io.h"
#include <EEPROM.h>  // read and write from flash memory

ESP32, 파일 시스템(FS), SD 카드 및 EEPROM에 필요한 라이브러리를 포함합니다.

#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

카메라 모듈에 대한 ESP32-CAM의 핀 연결을 나타내는 상수를 설정합니다.

int pictureNumber = 0;

촬영된 사진의 수를 저장합니다.

  1. BROWN OUT 감지기는 고전류 소모(예: 카메라 작동 시) 동안 ESP32-CAM이 재설정되는 것을 방지하기 위해 비활성화합니다.
WRITE_PERI_REG(RTC_CNTL_BROWN_OUT_REG, 0);  //disable brownout detector
  1. 시리얼 통신은 디버깅을 위해 초기화합니다.
Serial.begin(115200);
  1. 카메라 구성은 GPIO 핀, XCLK 주파수, 픽셀 형식, 프레임 크기, JPEG 품질 및 프레임 버퍼 수를 포함하여 camra_config_t 로 설정됩니다.
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;
  1. 그런 다음 구성에 따라 카메라가 초기화되고 실패하면 오류 메시지가 출력됩니다.
esp_err_t err = esp_camera_init(&config);
if (err != ESP_OK) {
    Serial.printf("Camera init failed with error 0x%x", err);
    return;
}
  1. SD 카드가 초기화되는데에 실패하면 오류 메시지가 출력됩니다.
if (!SD_MMC.begin()) {
    Serial.println("SD Card Mount Failed");
    return;
}

uint8_t cardType = SD_MMC.cardType();
if (cardType == CARD_NONE) {
    Serial.println("No SD Card attached");
    return;
}
  1. 카메라로 사진을 캡쳐하여 프레임 버퍼에 저장합니다.
fb = esp_camera_fb_get();
if (!fb) {
    Serial.println("Camera capture failed");
    return;
}
  1. EEPROM을 읽어 마지막 사진의 번호를 검색한 다음 새 사진의 사진 번호를 증가시킵니다.
EEPROM.begin(EEPROM_SIZE);
pictureNumber = EEPROM.read(0) + 1;
  1. 새 사진의 경로는 사진 번호에 해당하는 파일 이름과 함께 SD 카드에 생성됩니다.
String path = "/picture" + String(pictureNumber) + ".jpg";

fs::FS &fs = SD_MMC;
Serial.printf("Picture file name: %s\\n", path.c_str());
  1. 사진을 저장한 후 사진 번호는 전원을 꼈다 켜도 검색할 수 있도록 EEPROM에 다시 저장됩니다.
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);  // payload (image), payload length
    Serial.printf("Saved file to path: %s\\n", path.c_str());
    EEPROM.write(0, pictureNumber);
    EEPROM.commit();
}
file.close();
esp_camera_fb_return(fb);
  1. 마지막으로 온보드 LED(플래시)가 꺼지고 ESP32-CAM이 절전모드에 들어갑니다.
pinMode(4, OUTPUT);
digitalWrite(4, LOW);
rtc_gpio_hold_en(GPIO_NUM_4);