ESP32-CAM拍照並且在web服務器上顯示

ESP32-CAM拍照並且在web服務器上顯示

在這篇文章中,我們將學習如何在ESP32-CAM開發板上搭建web服務器,並且將學習到如何通過發送一個命令去拍照。並且將拍照的圖片保存到SPIFFS中,然後通過瀏覽器的方式來顯示圖片,當然,我們也將添加一個旋轉圖片的選項。


ESP32-CAM拍照並且在web服務器上顯示


需要的硬件

下面我們羅列出本篇教程需要用到的硬件:

帶OV2640攝像頭的ESP32-CAM開發板

母對母杜邦線

FTDI編碼器

5V的電源支持

項目概況

下圖展示我們最後要實現的效果。


ESP32-CAM拍照並且在web服務器上顯示


當你用瀏覽器打開網站,你會看到三個按鈕:

旋轉 - 根據您的ESP32-CAM方向,您可能需要旋轉照片;

拍攝照片 - 當你點擊這個按鈕,ESP32-CAM將拍攝一張新的照片並且保存到ESP32的SPIFFS中。請在刷新網頁前至少等待5秒鐘,以確保ESP32-CAM拍攝並存儲照片;

刷新頁面 - 當你點擊這個按鈕,整個web頁面將刷新並且將顯示最新的照片。

注意:如前所述,最新捕獲的照片存儲在ESP32 SPIFF中,因此即使重新啟動主板,也可以始終訪問上次保存的照片。

安裝ESP32附加組件

我們使用Arduino IDE在ESP32開發板上編寫程序。因此,你需要首先在Arduino IDE上安裝ESP32的附加組件。(關於ESP32的附加組件的安裝,我們在前面的文章中介紹過,請查看以前的文章)

安裝開發包

要建立web服務器,我們需要用到ESPAsyncWebServer庫,而這個庫要能正常工作,又必須依賴AsyncTCP庫。

下面我們將講解如何安裝這些庫。

安裝ESPAsyncWebServer庫

1.點擊這裡下載ESPAsyncWebServer庫的zip文件

https://github.com/me-no-dev/ESPAsyncWebServer/archive/master.zip

2.解壓這個文件

3.將文件夾名改成ESPAsyncWebServer

4.移動ESPAsyncWebServer目錄到Arduino IDE的安裝庫目錄下

或者,下載庫後,可以轉到Sketch>Include library>Add.ZIP library…並選擇剛剛下載的庫。

安裝AsyncTcp庫

ESPAsyncWebServer庫需要AsyncTCP庫才能工作。下面是安裝步驟:

1.首先下載AsyncTcp庫的zip文件。

https://github.com/me-no-dev/AsyncTCP/archive/master.zip

2.解壓這個文件

3.將文件夾名改成AsyncTCP

4.移動AsyncTCP目錄到Arduino IDE的安裝庫目錄下

或者,下載庫後,可以轉到Sketch>Include library>Add.ZIP library…並選擇剛剛下載的庫。

ESP32-CAM拍照並且在web瀏覽器中顯示照片

將以下代碼複製到Arduino IDE。此代碼構建了一個web服務器,允許您使用ESP32-CAM拍攝照片並顯示最後拍攝的照片。根據ESP32-CAM的方向,您可能需要旋轉圖片,因此我們還包括了該功能。

<code>/*********/<code>
<code>  Rui Santos/<code>
<code>  Complete project details at https://RandomNerdTutorials.com/esp32-cam-take-photo-display-web-server//<code>
<code>  /<code>
<code>  IMPORTANT!!! /<code>
<code>   - Select Board "AI Thinker ESP32-CAM"/<code>
<code>   - GPIO 0 must be connected to GND to upload a sketch/<code>
<code>   - After connecting GPIO 0 to GND, press the ESP32-CAM on-board RESET button to put your board in flashing mode/<code>
<code>  /<code>
<code>  The above copyright notice and this permission notice shall be included in all/<code>
<code>  copies or substantial portions of the Software./<code>
<code>*********//<code>
<code>#include "WiFi.h"/<code>
<code>#include "esp_camera.h"/<code>
<code>#include "esp_timer.h"/<code>
<code>#include "img_converters.h"/<code>
<code>#include "Arduino.h"/<code>
<code>#include "soc/soc.h"           // Disable brownour problems/<code> 
<code>#include "soc/rtc_cntl_reg.h"  // Disable brownour problems/<code>
<code>#include "driver/rtc_io.h"/<code>
<code>#include <espasyncwebserver.h>/<code>
<code>#include <stringarray.h>/<code>
<code>#include <spiffs.h>/<code>
<code>#include <fs.h>/<code>
<code>// Replace with your network credentials/<code>
<code>const char* ssid = "REPLACE_WITH_YOUR_SSID";/<code>
<code>const char* password = "REPLACE_WITH_YOUR_PASSWORD";/<code>
<code>// Create AsyncWebServer object on port 80/<code>
<code>AsyncWebServer server(80);/<code>
<code>boolean takeNewPhoto = false;/<code>
<code>// Photo File Name to save in SPIFFS/<code>
<code>#define FILE_PHOTO "/photo.jpg"/<code>
<code>// OV2640 camera module pins (CAMERA_MODEL_AI_THINKER)/<code>
<code>#define PWDN_GPIO_NUM     32/<code>
<code>#define RESET_GPIO_NUM    -1/<code>
<code>#define XCLK_GPIO_NUM      0/<code>
<code>#define SIOD_GPIO_NUM     26/<code>
<code>#define SIOC_GPIO_NUM     27/<code>
<code>#define Y9_GPIO_NUM       35/<code>
<code>#define Y8_GPIO_NUM       34/<code>
<code>#define Y7_GPIO_NUM       39/<code>
<code>#define Y6_GPIO_NUM       36/<code>
<code>#define Y5_GPIO_NUM       21/<code> 
<code>#define Y4_GPIO_NUM       19/<code>
<code>#define Y3_GPIO_NUM       18/<code>
<code>#define Y2_GPIO_NUM        5/<code>
<code>#define VSYNC_GPIO_NUM    25/<code>
<code>#define HREF_GPIO_NUM     23/<code>
<code>#define PCLK_GPIO_NUM     22/<code>
<code>const char index_html[] PROGMEM = R"rawliteral(/<code>
<code>
<code>
<code>  /<code>
<code>  <style>/<code>
<code>    body { text-align:center; }/<code>
<code>    .vert { margin-bottom: 10%; }/<code>
<code>    .hori{ margin-bottom: 0%; }/<code>
<code>  /<code>
<code>
<code>
<code>  
<code>    

ESP32-CAM Last Photo

/<code>
<code>    

It might take more than 5 seconds to capture a photo.

/<code>
<code>    

/<code>

<code>      <button>ROTATE/<button>/<code>
<code>      <button>CAPTURE PHOTO/<button>/<code>
<code>      <button>REFRESH PAGE/<button>/<code>
<code>    /<code>
<code>  /<code>
/<code>
<code>  
/<code>
<code>
<code><script>/<code>
<code>  var deg = 0;/<code>
<code>  function capturePhoto() {/<code>
<code>    var xhr = new XMLHttpRequest();/<code>
<code>    xhr.open('GET', "/capture", true);/<code>
<code>    xhr.send();/<code>
<code>  }/<code>
<code>  function rotatePhoto() {/<code>
<code>    var img = document.getElementById("photo");/<code>
<code>    deg += 90;/<code>
<code>    if(isOdd(deg/90)){ document.getElementById("container").className = "vert"; }/<code>
<code>    else{ document.getElementById("container").className = "hori"; }/<code>
<code>    img.style.transform = "rotate(" + deg + "deg)";/<code>
<code>  }/<code>
<code>  function isOdd(n) { return Math.abs(n % 2) == 1; }/<code>
<code>
<code>)rawliteral";/<code>
<code>void setup() {/<code>
<code>  // Serial port for debugging purposes/<code>
<code>  Serial.begin(115200);/<code>
<code>  // Connect to Wi-Fi/<code>
<code>  WiFi.begin(ssid, password);/<code>
<code>  while (WiFi.status() != WL_CONNECTED) {/<code>
<code>    delay(1000);/<code>
<code>    Serial.println("Connecting to WiFi...");/<code>
<code>  }/<code>
<code>  if (!SPIFFS.begin(true)) {/<code>
<code>    Serial.println("An Error has occurred while mounting SPIFFS");/<code>
<code>    ESP.restart();/<code>
<code>  }/<code>
<code>  else {/<code>
<code>    delay(500);/<code>
<code>    Serial.println("SPIFFS mounted successfully");/<code>
<code>  }/<code>
<code>  // Print ESP32 Local IP Address/<code>
<code>  Serial.print("IP Address: http://");/<code>
<code>  Serial.println(WiFi.localIP());/<code>
<code>  // Turn-off the 'brownout detector'/<code>
<code>  WRITE_PERI_REG(RTC_CNTL_BROWN_OUT_REG, 0);/<code>
<code>  // OV2640 camera module/<code>
<code>  camera_config_t config;/<code>
<code>  config.ledc_channel = LEDC_CHANNEL_0;/<code>
<code>  config.ledc_timer = LEDC_TIMER_0;/<code>
<code>  config.pin_d0 = Y2_GPIO_NUM;/<code>
<code>  config.pin_d1 = Y3_GPIO_NUM;/<code>
<code>  config.pin_d2 = Y4_GPIO_NUM;/<code>
<code>  config.pin_d3 = Y5_GPIO_NUM;/<code>
<code>  config.pin_d4 = Y6_GPIO_NUM;/<code>
<code>  config.pin_d5 = Y7_GPIO_NUM;/<code>
<code>  config.pin_d6 = Y8_GPIO_NUM;/<code>
<code>  config.pin_d7 = Y9_GPIO_NUM;/<code>
<code>  config.pin_xclk = XCLK_GPIO_NUM;/<code>
<code>  config.pin_pclk = PCLK_GPIO_NUM;/<code>
<code>  config.pin_vsync = VSYNC_GPIO_NUM;/<code>
<code>  config.pin_href = HREF_GPIO_NUM;/<code>
<code>  config.pin_sscb_sda = SIOD_GPIO_NUM;/<code>
<code>  config.pin_sscb_scl = SIOC_GPIO_NUM;/<code>
<code>  config.pin_pwdn = PWDN_GPIO_NUM;/<code>
<code>  config.pin_reset = RESET_GPIO_NUM;/<code>
<code>  config.xclk_freq_hz = 20000000;/<code>
<code>  config.pixel_format = PIXFORMAT_JPEG;/<code>
<code>  if (psramFound()) {/<code>
<code>    config.frame_size = FRAMESIZE_UXGA;/<code>
<code>    config.jpeg_quality = 10;/<code>
<code>    config.fb_count = 2;/<code>
<code>  } else {/<code>
<code>    config.frame_size = FRAMESIZE_SVGA;/<code>
<code>    config.jpeg_quality = 12;/<code>
<code>    config.fb_count = 1;/<code>
<code>  }/<code>
<code>  // Camera init/<code>
<code>  esp_err_t err = esp_camera_init(&config);/<code>
<code>  if (err != ESP_OK) {/<code>
<code>    Serial.printf("Camera init failed with error 0x%x", err);/<code>
<code>    ESP.restart();/<code>
<code>  }/<code>
<code>  // Route for root / web page/<code>
<code>  server.on("/", HTTP_GET, [](AsyncWebServerRequest * request) {/<code>
<code>    request->send_P(200, "text/html", index_html);/<code>
<code>  });/<code>
<code>  server.on("/capture", HTTP_GET, [](AsyncWebServerRequest * request) {/<code>
<code>    takeNewPhoto = true;/<code>
<code>    request->send_P(200, "text/plain", "Taking Photo");/<code>
<code>  });/<code>
<code>  server.on("/saved-photo", HTTP_GET, [](AsyncWebServerRequest * request) {/<code>
<code>    request->send(SPIFFS, FILE_PHOTO, "image/jpg", false);/<code>
<code>  });/<code>
<code>  // Start server/<code>
<code>  server.begin();/<code>
<code>}/<code>
<code>void loop() {/<code>
<code>  if (takeNewPhoto) {/<code>
<code>    capturePhotoSaveSpiffs();/<code>
<code>    takeNewPhoto = false;/<code>
<code>  }/<code>
<code>  delay(1);/<code>
<code>}/<code>
<code>// Check if photo capture was successful/<code>
<code>bool checkPhoto( fs::FS &fs ) {/<code>
<code>  File f_pic = fs.open( FILE_PHOTO );/<code>
<code>  unsigned int pic_sz = f_pic.size();/<code>
<code>  return ( pic_sz > 100 );/<code>
<code>}/<code>
<code>// Capture Photo and Save it to SPIFFS/<code>
<code>void capturePhotoSaveSpiffs( void ) {/<code>
<code>  camera_fb_t * fb = NULL; // pointer/<code>
<code>  bool ok = 0; // Boolean indicating if the picture has been taken correctly/<code>
<code>  do {/<code>
<code>    // Take a photo with the camera/<code>
<code>    Serial.println("Taking a photo...");/<code>
<code>    fb = esp_camera_fb_get();/<code>
<code>    if (!fb) {/<code>
<code>      Serial.println("Camera capture failed");/<code>
<code>      return;/<code>
<code>    }/<code>
<code>    // Photo file name/<code>
<code>    Serial.printf("Picture file name: %s\\n", FILE_PHOTO);/<code>
<code>    File file = SPIFFS.open(FILE_PHOTO, FILE_WRITE);/<code>
<code>    // Insert the data in the photo file/<code>
<code>    if (!file) {/<code>
<code>      Serial.println("Failed to open file in writing mode");/<code>
<code>    }/<code>
<code>    else {/<code>
<code>      file.write(fb->buf, fb->len); // payload (image), payload length/<code>
<code>      Serial.print("The picture has been saved in ");/<code>
<code>      Serial.print(FILE_PHOTO);/<code>
<code>      Serial.print(" - Size: ");/<code>
<code>      Serial.print(file.size());/<code>
<code>      Serial.println(" bytes");/<code>
<code>    }/<code>
<code>    // Close the file/<code>
<code>    file.close();/<code>
<code>    esp_camera_fb_return(fb);/<code>
<code>    // check if file has been correctly saved in SPIFFS/<code>
<code>    ok = checkPhoto(SPIFFS);/<code>
<code>  } while ( !ok );/<code>
<code>}/<code>

代碼是怎樣工作的

首先,包括使用相機、構建web服務器和使用SPIFFS所需的庫。

<code>#include "WiFi.h"/<code>
<code>#include "esp_camera.h"/<code>
<code>#include "esp_timer.h"/<code>
<code>#include "img_converters.h"/<code>
<code>#include "Arduino.h"/<code>
<code>#include "soc/soc.h"           // Disable brownout problems/<code>
<code>#include "soc/rtc_cntl_reg.h"  // Disable brownout problems/<code>
<code>#include "driver/rtc_io.h"/<code>
<code>#include <espasyncwebserver.h>/<code>
<code>#include <stringarray.h>/<code>
<code>#include <spiffs.h>/<code>
<code>#include <fs.h>/<code>

接下來,在以下變量中寫入您的網絡憑據,以便ESP32-CAM可以連接到您的本地網絡。

<code>const char* ssid = "REPLACE_WITH_YOUR_SSID";/<code>
<code>const char* password = "REPLACE_WITH_YOUR_PASSWORD";/<code>

在80端口建立一個AsyncWebServer

<code>AsyncWebServer server(80);/<code>

take new photo布爾變量指示何時拍攝新照片。

boolean takeNewPhoto = false;

然後定時我們保存在SPIFFS中的照片的路徑和名稱。

#define FILE_PHOTO "/photo.jpg"

下面,定義ESP32-CAM AI THINKER開發板照相用的引腳

<code>#define PWDN_GPIO_NUM     32/<code>
<code>#define RESET_GPIO_NUM    -1/<code>
<code>#define XCLK_GPIO_NUM      0/<code>
<code>#define SIOD_GPIO_NUM     26/<code>
<code>#define SIOC_GPIO_NUM     27/<code>
<code>#define Y9_GPIO_NUM       35/<code>
<code>#define Y8_GPIO_NUM       34/<code>
<code>#define Y7_GPIO_NUM       39/<code>
<code>#define Y6_GPIO_NUM       36/<code>
<code>#define Y5_GPIO_NUM       21/<code>
<code>#define Y4_GPIO_NUM       19/<code>
<code>#define Y3_GPIO_NUM       18/<code>
<code>#define Y2_GPIO_NUM        5/<code>
<code>#define VSYNC_GPIO_NUM    25/<code>
<code>#define HREF_GPIO_NUM     23/<code>
<code>#define PCLK_GPIO_NUM     22/<code>

建立一個web頁面

首先構建一個html頁面:

<code>const char index_html[] PROGMEM = R"rawliteral(/<code>
<code>
<code>
<code>  /<code>
<code>  <style>/<code>
<code>    body { text-align:center; }/<code>
<code>    .vert { margin-bottom: 10%; }/<code>
<code>    .hori{ margin-bottom: 0%; }/<code>
<code>  /<code>
<code>
<code>
<code>  
<code>    

ESP32-CAM Last Photo

/<code>
<code>    

It might take more than 5 seconds to capture a photo.

/<code>
<code>    

/<code>

<code>      <button>ROTATE/<button>/<code>
<code>      <button>CAPTURE PHOTO/<button>/<code>
<code>      <button>REFRESH PAGE/<button>/<code>
<code>    /<code>
<code>  /<code>
/<code>
<code>  
/<code>
<code>
<code><script>/<code>
<code>  var deg = 0;/<code>
<code>  function capturePhoto() {/<code>
<code>    var xhr = new XMLHttpRequest();/<code>
<code>    xhr.open('GET', "/capture", true);/<code>
<code>    xhr.send();/<code>
<code>  }/<code>
<code>  function rotatePhoto() {/<code>
<code>    var img = document.getElementById("photo");/<code>
<code>    deg += 90;/<code>
<code>    if(isOdd(deg/90)){ document.getElementById("container").className = "vert"; }/<code>
<code>    else{ document.getElementById("container").className = "hori"; }/<code>
<code>    img.style.transform = "rotate(" + deg + "deg)";/<code>
<code>  }/<code>
<code>  function isOdd(n) { return Math.abs(n % 2) == 1; }/<code>
<code>
<code>)rawliteral";/<code>

我們不會詳細討論這個HTML是如何工作的。我們只是簡單地概述一下。

基本上,創建三個按鈕:旋轉;捕獲照片和刷新頁面。每個照片都調用不同的JavaScript函數:rotatePhoto()、capturePhoto()和reload()。

<code><button>ROTATE/<button>/<code>
<code><button>CAPTURE PHOTO/<button>/<code>
<code><button>REFRESH PAGE/<button>/<code>

capturePhoto()函數的作用是:在/capture URL上向ESP32發送一個請求,以便它拍攝一張新照片。

<code>function capturePhoto() {/<code>
<code>  var xhr = new XMLHttpRequest();/<code>
<code>  xhr.open('GET', "/capture", true);/<code>
<code>  xhr.send();/<code>
<code>}/<code>
<code>rotatePhoto()函數用於旋轉照片。/<code>
<code>function rotatePhoto() {/<code>
<code>  var img = document.getElementById("photo");/<code>
<code>  deg += 90;/<code>
<code>  if(isOdd(deg/90)){ document.getElementById("container").className = "vert"; }/<code>
<code>  else{ document.getElementById("container").className = "hori"; }/<code>
<code>  img.style.transform = "rotate(" + deg + "deg)";/<code>
<code>}/<code>
<code>function isOdd(n) { return Math.abs(n % 2) == 1; }/<code>

我們不確定用JavaScript旋轉照片的“最佳”方法是什麼。這種方法工作得很好,但可能有更好的方法來做到這一點。如果您有任何建議,請與我們分享。

最後,以下部分顯示照片。

當你點擊刷新按鈕的時候,它將顯示最新的照片。

<code>setup()/<code>
<code>setup()用於初始化串行通信:/<code>
<code>Serial.begin(115200);/<code>
<code>然後本地連接你的wifi/<code>
<code>WiFi.begin(ssid, password);/<code>
<code>while (WiFi.status() != WL_CONNECTED) {/<code>
<code>  delay(1000);/<code>
<code>  Serial.println("Connecting to WiFi...");/<code>
<code>}/<code>

初始化SPIFFS

<code>if (!SPIFFS.begin(true)) {/<code>
<code>  Serial.println("An Error has occurred while mounting SPIFFS");/<code>
<code>  ESP.restart();/<code>
<code>}/<code>
<code>else {/<code>
<code>  delay(500);/<code>
<code>  Serial.println("SPIFFS mounted successfully");/<code>
<code>}/<code>
<code>打印ESP32-CAM本地的IP地址:/<code>
<code>Serial.print("IP Address: http://");/<code>
<code>Serial.println(WiFi.localIP());/<code>

接下來的幾行,用正確的設置配置和初始化相機。

處理Web服務器

接下來,我們需要處理當ESP32-CAM接收到URL上的請求時發生的情況。

當ESP32-CAM接收到根/URL上的請求時,我們發送HTML文本來構建web頁面。

server.on("/", HTTP_GET, [](AsyncWebServerRequest * request) {

request->send_P(200, "text/html", index_html);

});

當我們按下web服務器上的“拍照”按鈕時,我們會向ESP32/CAPTURE URL發送一個請求。當發生這種情況時,我們將takeNewPhoto變量設置為true,這樣我們就知道是時候拍攝新照片了。

server.on("/capture", HTTP_GET, [](AsyncWebServerRequest * request) {

takeNewPhoto = true;

request->send_P(200, "text/plain", "Taking Photo");

});

如果對/saved photo URL有請求,請將以SPIFFS格式保存的照片發送到連接的客戶端:

server.on("/saved-photo", HTTP_GET, [](AsyncWebServerRequest * request) {

request->send(SPIFFS, FILE_PHOTO, "image/jpg", false);

});

最後啟動web服務器。

server.begin();

loop()

在loop()中,如果takeNewPhoto變量為True,則調用capturePhotoSaveSpiffs()來拍攝新照片並將其保存到SPIFFS。然後,將takeNewPhoto變量設置為false。

void loop() {

if (takeNewPhoto) {

capturePhotoSaveSpiffs();

takeNewPhoto = false;

}

delay(1);

}

拍照

草圖中還有另外兩個函數:checkPhoto()和capturePhotoSaveSpiffs()。

函數的作用是:檢查照片是否成功保存到SPIFFS。

<code>bool checkPhoto( fs::FS &fs ) {/<code>
<code>  File f_pic = fs.open( FILE_PHOTO );/<code>
<code>  unsigned int pic_sz = f_pic.size();/<code>
<code>  return ( pic_sz > 100 );/<code>
<code>}/<code>
<code>capturePhotoSaveSpiffs()函數的作用是:拍攝照片並保存到SPIFFS。/<code>
<code>void capturePhotoSaveSpiffs( void ) {/<code>
<code>  camera_fb_t * fb = NULL; // pointer/<code>
<code>  bool ok = 0; // Boolean indicating if the picture has been taken correctly/<code>
<code>  do {/<code>
<code>    // Take a photo with the camera/<code>
<code>    Serial.println("Taking a photo...");/<code>
<code>    fb = esp_camera_fb_get();/<code>
<code>    if (!fb) {/<code>
<code>      Serial.println("Camera capture failed");/<code>
<code>      return;/<code>
<code>    }/<code>
<code>    // Photo file name/<code>
<code>    Serial.printf("Picture file name: %s\\n", FILE_PHOTO);/<code>
<code>    File file = SPIFFS.open(FILE_PHOTO, FILE_WRITE);/<code>
<code>    // Insert the data in the photo file/<code>
<code>    if (!file) {/<code>
<code>      Serial.println("Failed to open file in writing mode");/<code>
<code>    }/<code>
<code>    else {/<code>
<code>      file.write(fb->buf, fb->len); // payload (image), payload length/<code>
<code>      Serial.print("The picture has been saved in ");/<code>
<code>      Serial.print(FILE_PHOTO);/<code>
<code>      Serial.print(" - Size: ");/<code> 
<code>      Serial.print(file.size());/<code>
<code>      Serial.println(" bytes");/<code>
<code>    }/<code>
<code>    // Close the file/<code>
<code>    file.close();/<code>
<code>    esp_camera_fb_return(fb);/<code>
<code>    // check if file has been correctly saved in SPIFFS/<code>
<code>    ok = checkPhoto(SPIFFS);/<code>
<code>  } while ( !ok );/<code>
<code>}/<code>

ESP32-CAM上傳代碼

要上傳代碼到ESP32-CAM開發板上,你需要連接FTDI編碼器。

下圖是它們之間的連接圖:


ESP32-CAM拍照並且在web服務器上顯示


(注意點:GPIO 0 需要連接到GND才能上傳代碼額)

大多數FTDI編碼器允許你接3.3v和5v的電源,所以請確認你的跳線要在正確的位置接上5v的電源。

ESP32-CAMFTDI Programmer

GNDGND

5VVCC (5V)

U0RTX

U0TRX

GPIO 0GND

燒錄代碼需要下面幾步:

1)點擊Tools->Board,並選擇AI-Thinker ESP32-CAM

2)點擊Tools->Port,並選擇與ESP32連接的COM端口

3)然後點擊上傳按鈕上傳代碼


ESP32-CAM拍照並且在web服務器上顯示


4)如下圖所示,當您開始在調試窗口上看到這些提示時,請按ESP32-CAM開發板上的RST按鈕。


ESP32-CAM拍照並且在web服務器上顯示


然後等幾秒鐘,代碼將成功上傳到你的開發板上。

示例

打開瀏覽器並鍵入ESP32-CAM IP地址。然後,單擊“捕獲照片”以拍攝新照片,並等待幾秒鐘以將照片保存為SPIFFS格式。

然後,如果按“刷新頁面”按鈕,頁面將更新為最新保存的照片。如果需要調整圖像方向,可以始終使用“旋轉”按鈕進行調整。


ESP32-CAM拍照並且在web服務器上顯示


在你的串口監視器中,你將看到下面的輸出:


ESP32-CAM拍照並且在web服務器上顯示


收尾

我們希望你發現這個例子有用。我們已經盡力使它儘可能簡單,這樣您就可以輕鬆地修改它並將其包含在您自己的項目中。您可以將此示例與帶有照片捕獲的ESP32-CAM PIR運動檢測器相結合,以便在檢測到運動時捕獲並顯示新照片。

原文地址:

https://randomnerdtutorials.com/esp32-cam-take-photo-display-web-server/


分享到:


相關文章: