概述
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嵌入式服务器点灯是什么?二、软件设计三、硬件设计四、运行与调试总结所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复