我是靠谱客的博主 无私毛豆,最近开发中收集的这篇文章主要介绍ESP32-CAM、ESP8266、WIFI、蓝牙、摄像头设备实现嵌入式服务器点灯ESP32-CAM ArduinoIDE开发系列文章目录前言一、ESP32-CAM嵌入式服务器点灯是什么?二、软件设计三、硬件设计四、运行与调试总结,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

ESP32-CAM ArduinoIDE开发系列文章目录


第一篇:ESP32-CAM高性价比WIFI图传方案快速入门教程
第二篇:ESP32-CAM第一个无线点灯程序


文章目录

  • ESP32-CAM ArduinoIDE开发系列文章目录
  • 前言
  • 一、ESP32-CAM嵌入式服务器点灯是什么?
  • 二、软件设计
    • 1.构建webserver嵌入式服务器
    • 2.接收数据
  • 三、硬件设计
    • 1.说明
  • 四、运行与调试
    • 1.下载程序
    • 2.打开串口监视器获取IP地址
    • 3.打开浏览器输入IP地址,在网页控制点灯
  • 总结


前言

    daodanjishui物联网核心原创技术之ESP32 Arduino IDE开发之嵌入式网页服务器架设、http请求收发与解析、单片机IO口操作和串口打印技术组成:ESP32-CAM实现嵌入式服务器点灯。


一、ESP32-CAM嵌入式服务器点灯是什么?

    在上一篇的免费项目中:高性价比WIFI图传方案快速入门教程 的介绍中,详细地介绍了ESP32-CAM模块的简单使用 ,其裁剪了官方图传和人脸识别的代码改造成简单的图传代码,由官方四个文件的代码缩减成一个文件的代码。目的就是让读者能快速上手这个源码。让这个源码复杂度降低很多,利于阅读和学习。
    在这一篇的免费项目中,真真真真正正动手写代码了:daodanjishui修改了上一篇的项目的源码,实现嵌入式web server功能实现远程浏览器WIFI点灯的操作(PIN4的IO口集成了闪光灯LED,所以不用外接灯了,亮瞎眼的亮度),实现了将服务器嵌入到单片机,单片机wifi联网之后,局域网访问单片机主页(通过串口打印的网址)就可以在网页里面控制开发板的灯,该设计是ESP32-CAM物联网应用的一个巨大的尝试,daodanjishui用生命谱写了两天代码,踩了很多坑,也学到很多,写了一共三个版本的代码,此版本的代码是最便宜的一个版本,也是性价比最高的版本,不会接线和操作的看第一篇的项目即可,这里不再重复说明了,重要的事情说一遍:我有收费版的代码,服务更周到。
下面是优酷视频演示效果地址:https://v.youku.com/v_show/id_XNTE3ODU5MTY2NA==.html

直接看下面视频

ESP32

二、软件设计

1.构建webserver嵌入式服务器

    要用网页点灯,那么必须要有一个服务器存放一个网页,浏览器客户端登录服务器,服务器给客户端推送一个点灯网页,客户端在网页上操作发送get请求提交on字符串,服务器接收到on字符串,就操作单片机的IO口点亮ESP32-CAM自带的闪光灯,并且返回一个字符串“on ok”给客户端浏览器。

网页设计代码如下,存入单片机(示例):

String  index_html=String("")+"<html> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /"+
"  <head>   "+
"  </head>"+
"  <body>   "+
"    <h1>daodanjishui ESP32-cam免费开源点灯程序</h1><p>                        "+
"     <form action="control" method="get">"+
"   <table align="center" width="450">"+
"     <tr>"+
"       <td align="center" colspan="2">"+
"         <h2>说明:指令是on点击发送则开灯,反之off则关灯</h2>"+
"         <hr>"+
"       </td>"+
"     </tr>"+
"     <tr>"+
"       <td align="right">指令:</td>"+
"       <td><input type="text" name="var" value="on" /></td>"+
"     </tr>"+
"     <tr>"+
"       <td align="right">数值:</td>"+
"       <td><input type="text" name="val" value="168"/></td>"+
"     </tr>"+
"     <tr>"+
"       <td align="center" colspan="2">"+
"         <input type="submit" value="发送">    "+
"       </td>"+
"     </tr>"+
"   </table>"+
" </form>     "+
"  </body>"+
"</html>";

2.接收数据

接收数据通过的方式是网页的get请求传递的,读者看到网页里面有提交表单的动作吧?
代码如下(示例):

 if(!strcmp(variable, "on")){     
    controlLamp(true);
    httpd_resp_set_type(req, "text/html");
    httpd_resp_set_hdr(req, "Access-Control-Allow-Origin", "*");
    return httpd_resp_send(req, "on ok", 5);  
    }else if(!strcmp(variable, "off")){    
    controlLamp(false);
    httpd_resp_set_type(req, "text/html");
    httpd_resp_set_hdr(req, "Access-Control-Allow-Origin", "*");
    return httpd_resp_send(req, "off ok", 6);   
    }else {
        res = -1;
    }

点灯和关灯操作在于一个驱动函数 controlLamp();这是我写的

void controlLamp(bool lampVal) {
  pinMode(LAMP_PIN, OUTPUT);
  digitalWrite(LAMP_PIN, lampVal);
  Serial.printf("Turn lamp %sn", lampVal ? "On" : "Off");
}

三、硬件设计

1.说明

使用ESP32-CAM开发板基本不用设计硬件,因为板载一个LED闪光灯,连接线都不需要,注意的是要根据第一篇的原理图看出那个LED是GPIO4,所以代码有了下面的宏定义。

#define LAMP_PIN 4

四、运行与调试

1.下载程序

程序下载地址
或者直接复制下面代码和新建一个工程:

/*********
  author:daodanjishui
  Complete project details at https://RandomNerdTutorials.com/esp32-cam-video-streaming-web-server-camera-home-assistant/
  
  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 <WiFi.h>
#include "esp_timer.h"
#include "img_converters.h"
#include "Arduino.h"
#include "fb_gfx.h"
#include "soc/soc.h" //disable brownout problems
#include "soc/rtc_cntl_reg.h"  //disable brownout problems
#include "esp_http_server.h"
String  index_html=String("")+"<html> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /"+
"  <head>   "+
"  </head>"+
"  <body>   "+
"    <h1>daodanjishui ESP32-cam免费开源点灯程序</h1><p>                        "+
"     <form action="control" method="get">"+
"   <table align="center" width="450">"+
"     <tr>"+
"       <td align="center" colspan="2">"+
"         <h2>说明:指令是on点击发送则开灯,反之off则关灯</h2>"+
"         <hr>"+
"       </td>"+
"     </tr>"+
"     <tr>"+
"       <td align="right">指令:</td>"+
"       <td><input type="text" name="var" value="on" /></td>"+
"     </tr>"+
"     <tr>"+
"       <td align="right">数值:</td>"+
"       <td><input type="text" name="val" value="168"/></td>"+
"     </tr>"+
"     <tr>"+
"       <td align="center" colspan="2">"+
"         <input type="submit" value="发送">    "+
"       </td>"+
"     </tr>"+
"   </table>"+
" </form>     "+
"  </body>"+
"</html>";

//Replace with your network credentials
const char* ssid = "你路由器的账号";
const char* password = "你路由器的密码";
#define PART_BOUNDARY "123456789000000000000987654321"
#define LAMP_PIN 4
// This project was tested with the AI Thinker Model, M5STACK PSRAM Model and M5STACK WITHOUT PSRAM
#define CAMERA_MODEL_AI_THINKER
//#define CAMERA_MODEL_M5STACK_PSRAM
//#define CAMERA_MODEL_M5STACK_WITHOUT_PSRAM
// Not tested with this model
//#define CAMERA_MODEL_WROVER_KIT
#if defined(CAMERA_MODEL_WROVER_KIT)
  #define PWDN_GPIO_NUM    -1
  #define RESET_GPIO_NUM   -1
  #define XCLK_GPIO_NUM    21
  #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      19
  #define Y4_GPIO_NUM      18
  #define Y3_GPIO_NUM       5
  #define Y2_GPIO_NUM       4
  #define VSYNC_GPIO_NUM   25
  #define HREF_GPIO_NUM    23
  #define PCLK_GPIO_NUM    22

#elif defined(CAMERA_MODEL_M5STACK_PSRAM)
  #define PWDN_GPIO_NUM     -1
  #define RESET_GPIO_NUM    15
  #define XCLK_GPIO_NUM     27
  #define SIOD_GPIO_NUM     25
  #define SIOC_GPIO_NUM     23
  
  #define Y9_GPIO_NUM       19
  #define Y8_GPIO_NUM       36
  #define Y7_GPIO_NUM       18
  #define Y6_GPIO_NUM       39
  #define Y5_GPIO_NUM        5
  #define Y4_GPIO_NUM       34
  #define Y3_GPIO_NUM       35
  #define Y2_GPIO_NUM       32
  #define VSYNC_GPIO_NUM    22
  #define HREF_GPIO_NUM     26
  #define PCLK_GPIO_NUM     21

#elif defined(CAMERA_MODEL_M5STACK_WITHOUT_PSRAM)
  #define PWDN_GPIO_NUM     -1
  #define RESET_GPIO_NUM    15
  #define XCLK_GPIO_NUM     27
  #define SIOD_GPIO_NUM     25
  #define SIOC_GPIO_NUM     23
  
  #define Y9_GPIO_NUM       19
  #define Y8_GPIO_NUM       36
  #define Y7_GPIO_NUM       18
  #define Y6_GPIO_NUM       39
  #define Y5_GPIO_NUM        5
  #define Y4_GPIO_NUM       34
  #define Y3_GPIO_NUM       35
  #define Y2_GPIO_NUM       17
  #define VSYNC_GPIO_NUM    22
  #define HREF_GPIO_NUM     26
  #define PCLK_GPIO_NUM     21

#elif defined(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
#else
  #error "Camera model not selected"
#endif
static const char* _STREAM_CONTENT_TYPE = "multipart/x-mixed-replace;boundary=" PART_BOUNDARY;
static const char* _STREAM_BOUNDARY = "rn--" PART_BOUNDARY "rn";
static const char* _STREAM_PART = "Content-Type: image/jpegrnContent-Length: %urnrn";
httpd_handle_t stream_httpd = NULL;
httpd_handle_t camera_httpd = NULL;
void controlLamp(bool lampVal) {
  pinMode(LAMP_PIN, OUTPUT);
  digitalWrite(LAMP_PIN, lampVal);
  Serial.printf("Turn lamp %sn", lampVal ? "On" : "Off");
}

static esp_err_t index_handler(httpd_req_t *req){
    httpd_resp_set_type(req, "text/html");
    sensor_t * s = esp_camera_sensor_get();
    if (s->id.PID == OV3660_PID) {
   }
    int length=index_html.length();
    char buf[length];
    strcpy(buf, index_html.c_str());
    return httpd_resp_send(req, buf,sizeof(buf)/sizeof(buf[0]));
}

static esp_err_t cmd_handler(httpd_req_t *req){
    char*  buf;
    size_t buf_len;
    char variable[32] = {0,};
    char value[32] = {0,};

    buf_len = httpd_req_get_url_query_len(req) + 1;
    if (buf_len > 1) {
        buf = (char*)malloc(buf_len);
        if(!buf){
            httpd_resp_send_500(req);
            return ESP_FAIL;
        }
        if (httpd_req_get_url_query_str(req, buf, buf_len) == ESP_OK) {
            if (httpd_query_key_value(buf, "var", variable, sizeof(variable)) == ESP_OK &&
                httpd_query_key_value(buf, "val", value, sizeof(value)) == ESP_OK) {
            } else {
                free(buf);
                httpd_resp_send_404(req);
                return ESP_FAIL;
            }
        } else {
            free(buf);
            httpd_resp_send_404(req);
            return ESP_FAIL;
        }
        free(buf);
    } else {
        httpd_resp_send_404(req);
        return ESP_FAIL;
    }
    int val = atoi(value);
    sensor_t * s = esp_camera_sensor_get();
    int res = 0;
    if(!strcmp(variable, "framesize")) {
        if(s->pixformat == PIXFORMAT_JPEG) res = s->set_framesize(s, (framesize_t)val);
    }
    else if(!strcmp(variable, "quality")){
    res = s->set_quality(s, val);
    }else if(!strcmp(variable, "on")){     
    controlLamp(true);
    httpd_resp_set_type(req, "text/html");
    httpd_resp_set_hdr(req, "Access-Control-Allow-Origin", "*");
    return httpd_resp_send(req, "on ok", 5);  
    }else if(!strcmp(variable, "off")){    
    controlLamp(false);
    httpd_resp_set_type(req, "text/html");
    httpd_resp_set_hdr(req, "Access-Control-Allow-Origin", "*");
    return httpd_resp_send(req, "off ok", 6);   
    }else {
        res = -1;
    }
    if(res){
        return httpd_resp_send_500(req);
    }
    httpd_resp_set_hdr(req, "Access-Control-Allow-Origin", "*");
    return httpd_resp_send(req, NULL, 0);  
}
static esp_err_t stream_handler(httpd_req_t *req){
  camera_fb_t * fb = NULL;
  esp_err_t res = ESP_OK;
  size_t _jpg_buf_len = 0;
  uint8_t * _jpg_buf = NULL;
  char * part_buf[64];
  res = httpd_resp_set_type(req, _STREAM_CONTENT_TYPE);
  if(res != ESP_OK){
    return res;
  }
  while(true){
    fb = esp_camera_fb_get();
    if (!fb) {
      Serial.println("Camera capture failed");
      res = ESP_FAIL;
    } else {     
        if(fb->format != PIXFORMAT_JPEG){
           Serial.println("fb->format != PIXFORMAT_JPEG");
          bool jpeg_converted = frame2jpg(fb, 80, &_jpg_buf, &_jpg_buf_len);
          esp_camera_fb_return(fb);
          fb = NULL;
          if(!jpeg_converted){
            Serial.println("JPEG compression failed");
            res = ESP_FAIL;
          }
        } else {
           Serial.println("fb->format == PIXFORMAT_JPEG");
            //Serial.println((char*)fb->buf);
          _jpg_buf_len = fb->len;
          _jpg_buf = fb->buf;
        }
      }
    
    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(res == ESP_OK){
      res = httpd_resp_send_chunk(req, _STREAM_BOUNDARY, strlen(_STREAM_BOUNDARY));
    }
    if(fb){
      esp_camera_fb_return(fb);
      fb = NULL;
      _jpg_buf = NULL;
    } else if(_jpg_buf){
      free(_jpg_buf);
      _jpg_buf = NULL;
    }
    if(res != ESP_OK){
      break;
    }
    Serial.printf("MJPG: %uBn",(uint32_t)(_jpg_buf_len));
  }
  return res;
}

void startCameraServer(){
  httpd_config_t config = HTTPD_DEFAULT_CONFIG();
  config.server_port = 80;

  httpd_uri_t index_uri = {
    .uri       = "/",
    .method    = HTTP_GET,
    .handler   = index_handler,
    .user_ctx  = NULL
  };

  httpd_uri_t cmd_uri = {
        .uri       = "/control",
        .method    = HTTP_GET,
        .handler   = cmd_handler,
        .user_ctx  = NULL
    };
 Serial.printf("Starting web server on port: '%d'n", config.server_port);
    if (httpd_start(&camera_httpd, &config) == ESP_OK) {
        httpd_register_uri_handler(camera_httpd, &index_uri);
        httpd_register_uri_handler(camera_httpd, &cmd_uri);
    }
}

void setup() {
  //WRITE_PERI_REG(RTC_CNTL_BROWN_OUT_REG, 0); //disable brownout detector 
  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; 
 // config.frame_size = FRAMESIZE_QQVGA;
 config.frame_size = FRAMESIZE_QVGA;
  config.jpeg_quality = 10;
  config.fb_count = 2;
  esp_err_t err = esp_camera_init(&config);
  if (err != ESP_OK) {
    Serial.printf("Camera init failed with error 0x%x", err);
    return;
  }
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  Serial.println("");
  Serial.println("WiFi connected"); 
  Serial.print("Web server Ready! Go to: http://");
  Serial.println(WiFi.localIP());
  startCameraServer();
}
void loop() {
  delay(1);
}

在这里插入图片描述

2.打开串口监视器获取IP地址

在这里插入图片描述

3.打开浏览器输入IP地址,在网页控制点灯

在这里插入图片描述


## 4.享受点灯的快乐 ![在这里插入图片描述](https://img-blog.csdnimg.cn/20210706182246172.jpg?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L25pcnV4aTA0MDE=,size_16,color_FFFFFF,t_70#pic_center)

总结

    项目总结:这次是利用ESP32-CAM模块对物联网应用的一次巨大的尝试,在电路城目前好像还没有相关的教程,在B站虽然有类似的项目,但是根本没有源码,也没有教程,而且功能没有我这个那么强大,因为我这个嵌入式服务器是有反馈的,而且支持网页手动输入指令,开灯或者关灯指令发送之后服务器会给客户端一个响应的,代码都是自己手工完成的,也借鉴过很多相关的项目。只要掌握这个嵌入式服务器远程点灯的项目,那么其他类似的设计就可以举一反三了。需要注意的是这个版本的代码是没有任何注释的,代码冗余度也很大,收费版的代码更加精简和加入详细注释(最关键)和调试代码。如下所示:
在这里插入图片描述
所以收费版代码传送地址:https://www.cirmall.com/circuit/19262/
点我直接跳转

    后期的的项目会涉及到图像处理(颜色识别,人脸检测,人脸识别,颜色跟踪,智能小车,手机app客户端控制,云平台语音识别,云平台图像识别等等,私有云图像处理,私有云监控搭建)全部原创开源,敬请期待。

最后

以上就是无私毛豆为你收集整理的ESP32-CAM、ESP8266、WIFI、蓝牙、摄像头设备实现嵌入式服务器点灯ESP32-CAM ArduinoIDE开发系列文章目录前言一、ESP32-CAM嵌入式服务器点灯是什么?二、软件设计三、硬件设计四、运行与调试总结的全部内容,希望文章能够帮你解决ESP32-CAM、ESP8266、WIFI、蓝牙、摄像头设备实现嵌入式服务器点灯ESP32-CAM ArduinoIDE开发系列文章目录前言一、ESP32-CAM嵌入式服务器点灯是什么?二、软件设计三、硬件设计四、运行与调试总结所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(67)

评论列表共有 0 条评论

立即
投稿
返回
顶部