ESP32CAM实现

实验室留的,淘宝差不多反正

使用https://components.espressif.com/components/espressif/esp32-camera/versions/2.0.15

然后新建一个工程,依赖于hello_world。

idf.py add-dependency "espressif/esp32-camera^2.0.15"

需要启动psram

并且这个板子flash只有2MB

把SPI 改为80MHz,psram和Serial flasher config 都改。

然后add dependency后选则下,基本不变

修改下代码

/*
 * SPDX-FileCopyrightText: 2010-2022 Espressif Systems (Shanghai) CO LTD
 *
 * SPDX-License-Identifier: CC0-1.0
 */

#include <stdio.h>
#include <inttypes.h>
#include "sdkconfig.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_chip_info.h"
#include "esp_flash.h"
#include "esp_system.h"
//----------------------------------------------------------------------
#include "esp_log.h"
#include "esp_camera.h"
#define CAM_PIN_PWDN 32
#define CAM_PIN_RESET -1
#define CAM_PIN_XCLK 0
#define CAM_PIN_SIOD 26
#define CAM_PIN_SIOC 27
#define CAM_PIN_D7 35
#define CAM_PIN_D6 34
#define CAM_PIN_D5 39
#define CAM_PIN_D4 36
#define CAM_PIN_D3 21
#define CAM_PIN_D2 19
#define CAM_PIN_D1 18
#define CAM_PIN_D0 5
#define CAM_PIN_VSYNC 25
#define CAM_PIN_HREF 23
#define CAM_PIN_PCLK 22

static camera_config_t camera_config = {
    .pin_pwdn = CAM_PIN_PWDN,
    .pin_reset = CAM_PIN_RESET,
    .pin_xclk = CAM_PIN_XCLK,
    .pin_sccb_sda = CAM_PIN_SIOD,
    .pin_sccb_scl = CAM_PIN_SIOC,
    .pin_d7 = CAM_PIN_D7,
    .pin_d6 = CAM_PIN_D6,
    .pin_d5 = CAM_PIN_D5,
    .pin_d4 = CAM_PIN_D4,
    .pin_d3 = CAM_PIN_D3,
    .pin_d2 = CAM_PIN_D2,
    .pin_d1 = CAM_PIN_D1,
    .pin_d0 = CAM_PIN_D0,
    .pin_vsync = CAM_PIN_VSYNC,
    .pin_href = CAM_PIN_HREF,
    .pin_pclk = CAM_PIN_PCLK,
    .xclk_freq_hz = 8000000, // 8MHz 低时钟频率
    .ledc_timer = LEDC_TIMER_0,
    .ledc_channel = LEDC_CHANNEL_0,
    .pixel_format = PIXFORMAT_JPEG,
    .frame_size = FRAMESIZE_SVGA,   // 800x600 中等分辨率
    .jpeg_quality = 12,             // 较高质量(1-63)
    .fb_count = 2,                  // 双缓冲
    .fb_location = CAMERA_FB_IN_PSRAM,
    .grab_mode = CAMERA_GRAB_LATEST
};


static const char *TAG = "camera_example";


static esp_err_t init_camera(void)
{
    // 打印当前内存状态
    ESP_LOGI(TAG, "初始化前空闲内存: DRAM:%u, PSRAM:%u",
             heap_caps_get_free_size(MALLOC_CAP_INTERNAL),
             heap_caps_get_free_size(MALLOC_CAP_SPIRAM));

    esp_err_t err = esp_camera_init(&camera_config);

    if (err != ESP_OK)
    {
        ESP_LOGE(TAG, "摄像头初始化失败: 0x%x", err);

        // 详细错误诊断
        if (err == ESP_ERR_NO_MEM)
        {
            ESP_LOGE(TAG, "内存不足! 空闲PSRAM: %u字节",
                     heap_caps_get_free_size(MALLOC_CAP_SPIRAM));
        }
    }

    // 打印初始化后内存状态
    ESP_LOGI(TAG, "初始化后空闲内存: DRAM:%u, PSRAM:%u",
             heap_caps_get_free_size(MALLOC_CAP_INTERNAL),
             heap_caps_get_free_size(MALLOC_CAP_SPIRAM));

    return err;
}
static void take_and_process_picture(void)
{
    camera_fb_t *pic = esp_camera_fb_get();

    if (pic)
    {
        ESP_LOGI(TAG, "拍摄成功! 照片大小:%u字节", pic->len);
        ESP_LOGI(TAG, "拍照后空闲内存: DRAM:%u, PSRAM:%u",
                 heap_caps_get_free_size(MALLOC_CAP_INTERNAL),
                 heap_caps_get_free_size(MALLOC_CAP_SPIRAM));
        esp_camera_fb_return(pic);
    }
    else
    {
        ESP_LOGE(TAG, "拍照失败");
    }
}

//-------------------------------------------------------------------------------
void app_main(void)
{
    printf("Hello world!\n");

    /* Print chip information */
    esp_chip_info_t chip_info;
    uint32_t flash_size;
    esp_chip_info(&chip_info);
    printf("This is %s chip with %d CPU core(s), %s%s%s%s, ",
           CONFIG_IDF_TARGET,
           chip_info.cores,
           (chip_info.features & CHIP_FEATURE_WIFI_BGN) ? "WiFi/" : "",
           (chip_info.features & CHIP_FEATURE_BT) ? "BT" : "",
           (chip_info.features & CHIP_FEATURE_BLE) ? "BLE" : "",
           (chip_info.features & CHIP_FEATURE_IEEE802154) ? ", 802.15.4 (Zigbee/Thread)" : "");

    unsigned major_rev = chip_info.revision / 100;
    unsigned minor_rev = chip_info.revision % 100;
    printf("silicon revision v%d.%d, ", major_rev, minor_rev);
    if(esp_flash_get_size(NULL, &flash_size) != ESP_OK) {
        printf("Get flash size failed");
        return;
    }

    printf("%" PRIu32 "MB %s flash\n", flash_size / (uint32_t)(1024 * 1024),
           (chip_info.features & CHIP_FEATURE_EMB_FLASH) ? "embedded" : "external");

    printf("Minimum free heap size: %" PRIu32 " bytes\n", esp_get_minimum_free_heap_size());

    // for (int i = 10; i >= 0; i--) {
    //     printf("Restarting in %d seconds...\n", i);
    //     vTaskDelay(1000 / portTICK_PERIOD_MS);
    // }
   // printf("Restarting now.\n");
    //fflush(stdout);
    //esp_restart();
   //---------------------------------------------------
   init_camera();
   while (1)
   {
     take_and_process_picture();
     vTaskDelay(1000 / portTICK_PERIOD_MS);
   }
   //-------------------------------------------------------
}

下载需要Io0接地,下载完Io0不接重启。

现在是http网络查看

1,连wifi,同一个局域网

http_camera.c

#include "esp_camera.h"
#include "esp_http_server.h"
#include "esp_timer.h"
#include "http_camera.h"
#include "esp_log.h"
static const char *TAG = "example:httpd_camera";
typedef struct
{
    httpd_req_t *req;
    size_t len;
} jpg_chunking_t;

static size_t jpg_encode_stream(void *arg, size_t index, const void *data, size_t len)
{
    jpg_chunking_t *j = (jpg_chunking_t *)arg;
    if (!index)
    {
        j->len = 0;
    }
    if (httpd_resp_send_chunk(j->req, (const char *)data, len) != ESP_OK)
    {
        return 0;
    }
    j->len += len;
    return len;
}

void start_picture_server()
{
    httpd_config_t config = HTTPD_DEFAULT_CONFIG();
    config.server_port = 80; // 使用不同的端口80
    config.ctrl_port = 32768; // 控制端口

    httpd_handle_t server = NULL;

    // 启动HTTP服务器
    if (httpd_start(&server, &config) == ESP_OK)
    {
        // 注册JPEG图像路由
        httpd_uri_t jpg_uri = {
            .uri = "/jpg", // 访问路径
            .method = HTTP_GET,
            .handler = jpg_picture_httpd_handler,
            .user_ctx = NULL};
        httpd_register_uri_handler(server, &jpg_uri);

        ESP_LOGI(TAG, "HTTP服务器启动成功,访问 /jpg 获取图像");
    }
}

esp_err_t jpg_picture_httpd_handler(httpd_req_t *req)
{
    camera_fb_t *fb = NULL;
    esp_err_t res = ESP_OK;
    size_t fb_len = 0;
    int64_t fr_start = esp_timer_get_time();

    fb = esp_camera_fb_get();
    if (!fb)
    {
        ESP_LOGE(TAG, "Camera capture failed");
        httpd_resp_send_500(req);
        return ESP_FAIL;
    }
    res = httpd_resp_set_type(req, "image/jpeg");
    if (res == ESP_OK)
    {
        res = httpd_resp_set_hdr(req, "Content-Disposition", "inline; filename=capture.jpg");
    }

    if (res == ESP_OK)
    {
        if (fb->format == PIXFORMAT_JPEG)
        {
            fb_len = fb->len;
            res = httpd_resp_send(req, (const char *)fb->buf, fb->len);
        }
        else
        {
            jpg_chunking_t jchunk = {req, 0};
            res = frame2jpg_cb(fb, 80, jpg_encode_stream, &jchunk) ? ESP_OK : ESP_FAIL;
            httpd_resp_send_chunk(req, NULL, 0);
            fb_len = jchunk.len;
        }
    }
    esp_camera_fb_return(fb);
    int64_t fr_end = esp_timer_get_time();

    ESP_LOGI(TAG, "JPG: %" PRIu32 "KB %" PRIu32 "ms", (uint32_t)(fb_len / 1024), (uint32_t)((fr_end - fr_start) / 1000));
    return res;
}

#include "esp_camera.h"
#include "esp_http_server.h"
#include "esp_timer.h"

#define PART_BOUNDARY "123456789000000000000987654321"
static const char *_STREAM_CONTENT_TYPE = "multipart/x-mixed-replace;boundary=" PART_BOUNDARY;
static const char *_STREAM_BOUNDARY = "\r\n--" PART_BOUNDARY "\r\n";
static const char *_STREAM_PART = "Content-Type: image/jpeg\r\nContent-Length: %u\r\n\r\n";

// 启动视频流服务器
void start_stream_server()
{
    httpd_config_t config = HTTPD_DEFAULT_CONFIG();
    config.server_port = 81; // 使用不同的端口81
    config.ctrl_port = 32769; // 控制端口`
    httpd_handle_t server = NULL;
    if (httpd_start(&server, &config) == ESP_OK)
    {
        // 注册视频流路由
        httpd_uri_t stream_uri = {
            .uri = "/stream",
            .method = HTTP_GET,
            .handler = jpg_stream_httpd_handler,
            .user_ctx = NULL};
        httpd_register_uri_handler(server, &stream_uri);

        ESP_LOGI(TAG, "Stream server started at http://<IP>:81/stream");
    }
    else
    {
        ESP_LOGE(TAG, "Failed to start stream server");
    }
}
esp_err_t jpg_stream_httpd_handler(httpd_req_t *req)
{
    camera_fb_t *fb = NULL;
    esp_err_t res = ESP_OK;
    size_t _jpg_buf_len;
    uint8_t *_jpg_buf;
    char *part_buf[64];
    static int64_t last_frame = 0;
    if (!last_frame)
    {
        last_frame = esp_timer_get_time();
    }

    res = httpd_resp_set_type(req, _STREAM_CONTENT_TYPE);
    if (res != ESP_OK)
    {
        return res;
    }

    while (true)
    {
        fb = esp_camera_fb_get();
        if (!fb)
        {
            ESP_LOGE(TAG, "Camera capture failed");
            res = ESP_FAIL;
            break;
        }
        if (fb->format != PIXFORMAT_JPEG)
        {
            bool jpeg_converted = frame2jpg(fb, 80, &_jpg_buf, &_jpg_buf_len);
            if (!jpeg_converted)
            {
                ESP_LOGE(TAG, "JPEG compression failed");
                esp_camera_fb_return(fb);
                res = ESP_FAIL;
            }
        }
        else
        {
            _jpg_buf_len = fb->len;
            _jpg_buf = fb->buf;
        }

        if (res == ESP_OK)
        {
            res = httpd_resp_send_chunk(req, _STREAM_BOUNDARY, strlen(_STREAM_BOUNDARY));
        }
        if (res == ESP_OK)
        {
            size_t hlen = snprintf((char *)part_buf, 64, _STREAM_PART, _jpg_buf_len);

            res = httpd_resp_send_chunk(req, (const char *)part_buf, hlen);
        }
        if (res == ESP_OK)
        {
            res = httpd_resp_send_chunk(req, (const char *)_jpg_buf, _jpg_buf_len);
        }
        if (fb->format != PIXFORMAT_JPEG)
        {
            free(_jpg_buf);
        }
        esp_camera_fb_return(fb);
        if (res != ESP_OK)
        {
            break;
        }
        int64_t fr_end = esp_timer_get_time();
        int64_t frame_time = fr_end - last_frame;
        last_frame = fr_end;
        frame_time /= 1000;
        ESP_LOGI(TAG, "MJPG: %" PRIu32 "KB %" PRIu32 "ms (%.1ffps)",
                 (uint32_t)(_jpg_buf_len / 1024),
                 (uint32_t)frame_time, 1000.0 / (uint32_t)frame_time);
    }

    last_frame = 0;
    return res;
}

http_camera.h

#ifndef HTTP_CAMERA_H
#define HTTP_CAMERA_H

#include "esp_err.h"
#include "esp_http_server.h"

#ifdef __cplusplus
extern "C" {
#endif


void start_picture_server(void);
void start_stream_server(void);

esp_err_t jpg_stream_httpd_handler(httpd_req_t *req);
esp_err_t jpg_picture_httpd_handler(httpd_req_t *req);

#ifdef __cplusplus
}
#endif

#endif // JPEG_HTTP_CAPTURE_H

main

/*
 * SPDX-FileCopyrightText: 2010-2022 Espressif Systems (Shanghai) CO LTD
 *
 * SPDX-License-Identifier: CC0-1.0
 */

#include <stdio.h>
#include <inttypes.h>
#include "sdkconfig.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_chip_info.h"
#include "esp_flash.h"
#include "esp_system.h"

#include "wifi_manager.h"
#include "http_camera.h"
//----------------------------------------------------------------------
#include "esp_log.h"
#include "esp_camera.h"
#define CAM_PIN_PWDN 32
#define CAM_PIN_RESET -1
#define CAM_PIN_XCLK 0
#define CAM_PIN_SIOD 26
#define CAM_PIN_SIOC 27
#define CAM_PIN_D7 35
#define CAM_PIN_D6 34
#define CAM_PIN_D5 39
#define CAM_PIN_D4 36
#define CAM_PIN_D3 21
#define CAM_PIN_D2 19
#define CAM_PIN_D1 18
#define CAM_PIN_D0 5
#define CAM_PIN_VSYNC 25
#define CAM_PIN_HREF 23
#define CAM_PIN_PCLK 22

static camera_config_t camera_config = {
    .pin_pwdn = CAM_PIN_PWDN,
    .pin_reset = CAM_PIN_RESET,
    .pin_xclk = CAM_PIN_XCLK,
    .pin_sccb_sda = CAM_PIN_SIOD,
    .pin_sccb_scl = CAM_PIN_SIOC,
    .pin_d7 = CAM_PIN_D7,
    .pin_d6 = CAM_PIN_D6,
    .pin_d5 = CAM_PIN_D5,
    .pin_d4 = CAM_PIN_D4,
    .pin_d3 = CAM_PIN_D3,
    .pin_d2 = CAM_PIN_D2,
    .pin_d1 = CAM_PIN_D1,
    .pin_d0 = CAM_PIN_D0,
    .pin_vsync = CAM_PIN_VSYNC,
    .pin_href = CAM_PIN_HREF,
    .pin_pclk = CAM_PIN_PCLK,
    .xclk_freq_hz = 8000000, // 8MHz 低时钟频率
    .ledc_timer = LEDC_TIMER_0,
    .ledc_channel = LEDC_CHANNEL_0,
    .pixel_format = PIXFORMAT_JPEG,
    .frame_size = FRAMESIZE_SVGA,   // 800x600 中等分辨率
    .jpeg_quality = 10,             // 较高质量(1-63)
    .fb_count = 3,                  // 缓冲
    .fb_location = CAMERA_FB_IN_PSRAM,
    .grab_mode = CAMERA_GRAB_LATEST
};


static const char *TAG = "camera_example";


static esp_err_t init_camera(void)
{
    // 打印当前内存状态
    ESP_LOGI(TAG, "初始化前空闲内存: DRAM:%u, PSRAM:%u",
             heap_caps_get_free_size(MALLOC_CAP_INTERNAL),
             heap_caps_get_free_size(MALLOC_CAP_SPIRAM));

    esp_err_t err = esp_camera_init(&camera_config);

    if (err != ESP_OK)
    {
        ESP_LOGE(TAG, "摄像头初始化失败: 0x%x", err);

        // 详细错误诊断
        if (err == ESP_ERR_NO_MEM)
        {
            ESP_LOGE(TAG, "内存不足! 空闲PSRAM: %u字节",
                     heap_caps_get_free_size(MALLOC_CAP_SPIRAM));
        }
    }

    // 打印初始化后内存状态
    ESP_LOGI(TAG, "初始化后空闲内存: DRAM:%u, PSRAM:%u",
             heap_caps_get_free_size(MALLOC_CAP_INTERNAL),
             heap_caps_get_free_size(MALLOC_CAP_SPIRAM));

    return err;
}
static void take_and_process_picture(void)
{
    camera_fb_t *pic = esp_camera_fb_get();

    if (pic)
    {
        ESP_LOGI(TAG, "拍摄成功! 照片大小:%u字节", pic->len);
        ESP_LOGI(TAG, "拍照后空闲内存: DRAM:%u, PSRAM:%u",
                 heap_caps_get_free_size(MALLOC_CAP_INTERNAL),
                 heap_caps_get_free_size(MALLOC_CAP_SPIRAM));
        esp_camera_fb_return(pic);
    }
    else
    {
        ESP_LOGE(TAG, "拍照失败");
    }
}

//-------------------------------------------------------------------------------

void app_main(void)
{
    printf("Hello world!\n");

    /* Print chip information */
    esp_chip_info_t chip_info;
    uint32_t flash_size;
    esp_chip_info(&chip_info);
    printf("This is %s chip with %d CPU core(s), %s%s%s%s, ",
           CONFIG_IDF_TARGET,
           chip_info.cores,
           (chip_info.features & CHIP_FEATURE_WIFI_BGN) ? "WiFi/" : "",
           (chip_info.features & CHIP_FEATURE_BT) ? "BT" : "",
           (chip_info.features & CHIP_FEATURE_BLE) ? "BLE" : "",
           (chip_info.features & CHIP_FEATURE_IEEE802154) ? ", 802.15.4 (Zigbee/Thread)" : "");

    unsigned major_rev = chip_info.revision / 100;
    unsigned minor_rev = chip_info.revision % 100;
    printf("silicon revision v%d.%d, ", major_rev, minor_rev);
    if(esp_flash_get_size(NULL, &flash_size) != ESP_OK) {
        printf("Get flash size failed");
        return;
    }

    printf("%" PRIu32 "MB %s flash\n", flash_size / (uint32_t)(1024 * 1024),
           (chip_info.features & CHIP_FEATURE_EMB_FLASH) ? "embedded" : "external");

    printf("Minimum free heap size: %" PRIu32 " bytes\n", esp_get_minimum_free_heap_size());

    // for (int i = 10; i >= 0; i--) {
    //     printf("Restarting in %d seconds...\n", i);
    //     vTaskDelay(1000 / portTICK_PERIOD_MS);
    // }
   // printf("Restarting now.\n");
    //fflush(stdout);
    //esp_restart();
   //---------------------------------------------------
     esp_err_t ret = nvs_flash_init();
    if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND)
    {
        ESP_ERROR_CHECK(nvs_flash_erase());
        ret = nvs_flash_init();
    }
    ESP_ERROR_CHECK(ret);
    ESP_LOGI(TAG, "NVS初始化完成");
    
   initialise_wifi();
    // 优化WiFi性能
    esp_wifi_set_ps(WIFI_PS_NONE);
    esp_wifi_set_bandwidth(ESP_IF_WIFI_STA, WIFI_BW_HT20);

   init_camera();
   vTaskDelay(500 / portTICK_PERIOD_MS);
    ESP_LOGI(TAG, "picture前查看空闲内存: DRAM:%u, PSRAM:%u",
             heap_caps_get_free_size(MALLOC_CAP_INTERNAL),
             heap_caps_get_free_size(MALLOC_CAP_SPIRAM));
   //start_picture_server();
    vTaskDelay(2000 / portTICK_PERIOD_MS);
    ESP_LOGI(TAG, "stream前查看空闲内存: DRAM:%u, PSRAM:%u",
             heap_caps_get_free_size(MALLOC_CAP_INTERNAL),
             heap_caps_get_free_size(MALLOC_CAP_SPIRAM));
   start_stream_server();
   while (1)
   {
     //take_and_process_picture();
      ESP_LOGI(TAG, "while(1)循环查看空闲内存: DRAM:%u, PSRAM:%u",
              heap_caps_get_free_size(MALLOC_CAP_INTERNAL),
              heap_caps_get_free_size(MALLOC_CAP_SPIRAM));
     vTaskDelay(5000 / portTICK_PERIOD_MS);
   }
   //-------------------------------------------------------
}

两个均可以同时运行,http://192.168.137.181:81/stream http://192.168.137.181/jpg

一个http配一个端口和控制口。

具体图像质量,帧数,跟缓冲区,等关系挺大,再看怎么改吧

<think>好的,我现在需要帮助用户了解如何使用ESP32-CAM实现远程监控功能。首先,我得回忆一下ESP32-CAM的基本信息。ESP32-CAM是一个集成了摄像头和Wi-Fi功能的开发板,适合图像采集和无线传输。用户的需求是远程监控,所以需要涉及Wi-Fi连接、视频流传输以及可能的远程访问方法。 首先,用户可能需要硬件连接方面的指导。ESP32-CAM需要正确连接电源和摄像头模块。不过,用户可能已经熟悉硬件部分,所以重点可能在软件配置和代码示例上。接下来是设置Wi-Fi连接,这是实现远程监控的基础。需要确保ESP32-CAM能够连接到本地网络,这样才能进行数据传输。 然后是视频流的传输。通常,使用HTTP服务器来传输视频流是一个常见的方法。ESP32-CAM可以通过创建HTTP服务器,将摄像头捕获的图像以JPEG格式发送到客户端。用户可能需要示例代码来演示如何初始化摄像头和启动服务器。 另外,远程访问需要考虑网络环境。如果是在本地网络,直接通过IP地址访问即可。但如果需要从外部网络访问,可能需要端口转发或者使用内网穿透工具,比如Ngrok。这部分可能需要简要说明,但用户的具体网络环境不同,可能需要他们自行配置路由器。 安全性也是一个考虑因素,但用户的问题中没有提到,可能在后续问题中提及。示例代码需要包括必要的库引用、WiFi连接、摄像头初始化和服务器处理函数。代码注释要清晰,方便用户理解每一步的作用。 用户可能需要知道如何测试代码,比如使用浏览器访问IP地址查看视频流。此外,常见问题如无法连接Wi-Fi或视频卡顿,可能需要给出解决建议,比如检查电源是否稳定,降低分辨率等。 最后,按照用户的要求,生成相关问题,比如优化视频流、添加SD卡存储、远程控制摄像头等,这些扩展功能可能对用户后续有帮助。 现在需要确保代码符合ESP32-CAM的库要求,比如使用Arduino的WiFi库和ESP32摄像头驱动库。同时,代码中的WiFi SSID和密码需要用户自行修改,这点要提醒用户。另外,服务器处理部分需要正确捕获图像并发送HTTP响应,可能需要注意内存管理,及时释放图像缓冲区。 可能还需要提到OTA更新,方便用户后续升级固件而不必重新接线。不过这可能属于进阶内容,用户当前问题可能不需要,但可以作为相关问题提出。 总结步骤:硬件连接、Wi-Fi配置、视频流服务器、远程访问设置、示例代码和测试。确保各部分解释清晰,代码正确,并覆盖常见问题。</think>以下是使用ESP32-CAM实现远程监控的分步解决方案: ### 一、硬件准备 1. ESP32-CAM开发板(含OV2640摄像头) 2. Micro USB转TTL模块(用于程序烧录) 3. 5V/2A电源适配器 4. 连接线路:建议使用独立电源供电避免电压不稳 ### 二、软件配置 1. 安装Arduino IDE 2. 添加ESP32开发板支持 - 附加开发板管理器地址:`https://espressif.github.io/arduino-esp32/package_esp32_index.json` 3. 安装必要库: ```arduino WiFi.h ESPmDNS.h ESP32Camera.h ``` ### 三、核心代码实现 ```arduino #include <WiFi.h> #include <ESPmDNS.h> #include <ESP32Camera.h> // WiFi配置 const char* ssid = "your_SSID"; const char* password = "your_PASSWORD"; // 摄像头配置 #define CAMERA_MODEL_AI_THINKER CameraClass camera; void setup() { Serial.begin(115200); // 初始化摄像头 camera.config.frame_size = FRAMESIZE_SVGA; camera.config.jpeg_quality = 12; camera.init(); // 连接WiFi WiFi.begin(ssid, password); while (WiFi.status() != WL_CONNECTED) { delay(500); Serial.print("."); } Serial.println("\nWiFi connected"); // 启动HTTP视频流服务器 startCameraServer(); Serial.print("Camera Ready! Use 'http://"); Serial.print(WiFi.localIP()); Serial.println("' to connect"); } void loop() { delay(10000); } ``` ### 四、远程访问设置 1. **局域网访问**: - 上传代码后通过串口监视器查看设备IP - 浏览器访问`http://[ESP32-IP]/stream` 2. **公网访问**(需路由器支持): ```bash # 使用ngrok实现内网穿透(示例) ngrok http [ESP32-IP]:80 ``` - 获取ngrok生成的公网地址即可远程访问 ### 五、关键参数优化 $$ Q = \frac{FPS \times R}{B} $$ 其中: - $FPS$:帧率(建议8-15) - $R$:分辨率(SVGA=800×600) - $B$:带宽(需根据网络状况调整) ### 六、常见问题处理 1. **图像卡顿**: - 降低分辨率至`FRAMESIZE_VGA` - 调整`jpeg_quality`(12-20) 2. **无法连接WiFi**: - 检查电源稳定性(峰值电流需1A以上) - 确认路由器开启2.4GHz频段
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值