#include #include #include #include #include #include "freertos/FreeRTOS.h" #include "freertos/task.h" #include "esp_http_client.h" #include "esp_camera.h" #define ESP32_S3_KORVO 1 // ESP32-S3-KORVO-2_V3.0配套的自定义引脚 // ESP32-S3-KORVO-2_V3.0 音频开发版 #ifdef ESP32_S3_KORVO #define CAM_PIN_PWDN -1 //没用直接接高 #define CAM_PIN_RESET -1 //software reset will be performed #define CAM_PIN_VSYNC 21 #define CAM_PIN_HREF 38 #define CAM_PIN_PCLK 42 #define CAM_PIN_XCLK 40 #define CAM_PIN_SIOD 17 #define CAM_PIN_SIOC 18 #define CAM_PIN_D0 13 #define CAM_PIN_D1 47 #define CAM_PIN_D2 14 #define CAM_PIN_D3 3 #define CAM_PIN_D4 12 #define CAM_PIN_D5 11 #define CAM_PIN_D6 41 #define CAM_PIN_D7 39 #endif // ESP32-S3-合宙的开发板 #ifdef ESP32_S3_HEZHOU #define CAM_PIN_PWDN -1 // 没用直接接高 #define CAM_PIN_RESET -1 // software reset will be performed #define CAM_PIN_VSYNC 42 #define CAM_PIN_HREF 41 #define CAM_PIN_PCLK 36 #define CAM_PIN_XCLK 39 #define CAM_PIN_SIOD 21 #define CAM_PIN_SIOC 46 #define CAM_PIN_D0 34 #define CAM_PIN_D1 47 #define CAM_PIN_D2 48 #define CAM_PIN_D3 33 #define CAM_PIN_D4 35 #define CAM_PIN_D5 37 #define CAM_PIN_D6 38 #define CAM_PIN_D7 40 #endif static const char *TAG = "example:take_picture"; #define BOUNDARY "----ESP32Boundary" 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 = 20000000, // XCLK 设置为 20MHz .ledc_timer = LEDC_TIMER_0, .ledc_channel = LEDC_CHANNEL_0, .pixel_format = PIXFORMAT_JPEG, // 使用 JPEG 格式 .frame_size = FRAMESIZE_SVGA, // 使用 QVGA (320x240) .jpeg_quality = 60, // JPEG 质量 (0-63, 低值=高质量) .fb_count = 1, // 帧缓存数量 .fb_location = CAMERA_FB_IN_DRAM, // 使用 DRAM .grab_mode = CAMERA_GRAB_WHEN_EMPTY, }; static esp_err_t init_camera(void) { esp_err_t err = esp_camera_init(&camera_config); if (err != ESP_OK) { ESP_LOGE(TAG, "Camera Init Failed"); return err; } return ESP_OK; } // 上传图片到服务器 #define MULTIPART_BOUNDARY "----WebKitFormBoundary7MA4YWxkTrZu0gW" // 多部分表单的边界 esp_err_t upload_picture(camera_fb_t *pic, long image_size) { esp_http_client_config_t config = { .url = "http://60.204.139.57:7002/upload", // 服务器地址 .timeout_ms = 20000, .buffer_size = 1024 * 20, }; // 初始化 HTTP 客户端 esp_http_client_handle_t client = esp_http_client_init(&config); if (client == NULL) { ESP_LOGE(TAG, "Failed to initialize HTTP client"); return ESP_FAIL; } esp_http_client_set_method(client, HTTP_METHOD_POST); // 设置请求头(multipart/form-data) esp_http_client_set_header(client, "Content-Type", "multipart/form-data; boundary=" MULTIPART_BOUNDARY); // 请求头开始部分 char part1[256]; int part1_len = snprintf(part1, sizeof(part1), "--" MULTIPART_BOUNDARY "\r\n" "Content-Disposition: form-data; name=\"file\"; filename=\"image.jpg\"\r\n" "Content-Type: image/jpeg\r\n\r\n"); // 构建多部分表单数据的结束部分 char part2[64]; int part2_len = snprintf(part2, sizeof(part2), "\r\n--" MULTIPART_BOUNDARY "--\r\n"); // 设置总的Content-Length long content_length = part1_len + image_size + part2_len; char content_length_str[32]; snprintf(content_length_str, sizeof(content_length_str), "%ld", content_length); esp_http_client_set_header(client, "Content-Length", content_length_str); // 开始发送请求 int err = esp_http_client_open(client, content_length); if (err != ESP_OK) { ESP_LOGE(TAG, "Failed to open HTTP connection: %s", esp_err_to_name(err)); esp_http_client_cleanup(client); // 清理 HTTP 客户端 return ESP_FAIL; } // 发送多部分表单数据的开始部分 esp_http_client_write(client, part1, part1_len); // 发送文件数据 char buffer[1024]; size_t bytes_sent = 0; while (bytes_sent < pic->len) { size_t to_send = (pic->len - bytes_sent < sizeof(buffer)) ? (pic->len - bytes_sent) : sizeof(buffer); esp_http_client_write(client, (const char *)(pic->buf + bytes_sent), to_send); bytes_sent += to_send; } // 发送多部分表单数据的结束部分 esp_http_client_write(client, part2, part2_len); int response_length = esp_http_client_fetch_headers(client); if (response_length < 0) { ESP_LOGE(TAG, "HTTP client fetch headers failed"); } else { ESP_LOGI(TAG, "HTTP client fetch headers succeeded, length=%d", response_length); } // 动态分配初始缓冲区 char *response_buffer = (char *)malloc(1024); if (response_buffer == NULL) { ESP_LOGE(TAG, "Failed to allocate memory for response buffer"); esp_http_client_cleanup(client); return ESP_FAIL; } // 读取响应内容 int read_len = esp_http_client_read(client, response_buffer, 1024 - 1); if (read_len >= 0) { response_buffer[read_len] = '\0'; // 确保字符串以null字符结尾 ESP_LOGI(TAG, "HTTP Response: %s", response_buffer); } else { ESP_LOGE(TAG, "Failed to read response"); } // 释放分配的内存 free(response_buffer); // 清理 esp_http_client_close(client); esp_http_client_cleanup(client); return err; } // 拍照并上传 void take_photo(void *param) { if (ESP_OK != init_camera()) { return; } while (true) { /* code */ ESP_LOGI(TAG, "Taking picture..."); camera_fb_t *pic = esp_camera_fb_get(); if (pic == NULL) { ESP_LOGE(TAG, "Camera capture failed"); return; } ESP_LOGI(TAG, "Picture taken! Its size was: %zu bytes", pic->len); // 上传图片 esp_err_t err = upload_picture(pic,pic->len); if (err != ESP_OK) { ESP_LOGE(TAG, "Failed to upload picture"); } esp_camera_fb_return(pic); vTaskDelay(10*60*1000 / portTICK_PERIOD_MS); } vTaskDelete(NULL); }