ESP32CAM延时相机

相机

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
/*********
Rui Santos
Complete project details at https://RandomNerdTutorials.com/esp32-cam-take-photo-save-microsd-card

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 "Arduino.h"
#include "FS.h" // SD Card ESP32
#include "SD_MMC.h" // SD Card ESP32
#include "soc/soc.h" // Disable brownour problems
#include "soc/rtc_cntl_reg.h" // Disable brownour problems
#include "driver/rtc_io.h"
#include <EEPROM.h> // read and write from flash memory

// define the number of bytes you want to access
#define EEPROM_SIZE 1

// Pin definition for 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

int pictureNumber = 0;

void setup() {
WRITE_PERI_REG(RTC_CNTL_BROWN_OUT_REG, 0); //disable brownout detector
pinMode(33, OUTPUT);
Serial.begin(115200);
//Serial.setDebugOutput(true);
//Serial.println();
}

void take_pictures(){
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;

if(psramFound()){
config.frame_size = FRAMESIZE_UXGA; // FRAMESIZE_ + QVGA|CIF|VGA|SVGA|XGA|SXGA|UXGA
config.jpeg_quality = 1;
config.fb_count = 2;
} else {
config.frame_size = FRAMESIZE_SVGA;
config.jpeg_quality = 12;
config.fb_count = 1;
}

// Init Camera
esp_err_t err = esp_camera_init(&config);
if (err != ESP_OK) {
Serial.printf("Camera init failed with error 0x%x", err);
return;
}

//Serial.println("Starting SD Card");
//if(!SD_MMC.begin()){ //保持FLASH常量
if(!SD_MMC.begin("/sdcard", true)){ //保持FLASH不亮
Serial.println("SD Card Mount Failed");
return;
}

uint8_t cardType = SD_MMC.cardType();
if(cardType == CARD_NONE){
Serial.println("No SD Card attached");
return;
}

camera_fb_t * fb = NULL;
// Take Picture with Camera
fb = esp_camera_fb_get();
if(!fb) {
Serial.println("Camera capture failed");
return;
}
// initialize EEPROM with predefined size
EEPROM.begin(EEPROM_SIZE);
pictureNumber = EEPROM.read(0) + 1;

// Path where new picture will be saved in SD Card
String path = "/picture" + String(pictureNumber) +".jpg";

fs::FS &fs = SD_MMC;
Serial.printf("Picture file name: %s\n", path.c_str());

File file = fs.open(path.c_str(), FILE_WRITE);
if(!file){
Serial.println("Failed to open file in writing mode");
}
else {
file.write(fb->buf, fb->len); // payload (image), payload length
Serial.printf("Saved file to path: %s\n", path.c_str());
EEPROM.write(0, pictureNumber);
EEPROM.commit();
}
file.close();
esp_camera_fb_return(fb);

// Turns off the ESP32-CAM white on-board LED (flash) connected to GPIO 4
//pinMode(4, OUTPUT);
//digitalWrite(4, LOW);
//rtc_gpio_hold_en(GPIO_NUM_4); // 低功耗保持状态

delay(2000);
Serial.println("Going to sleep now");
//delay(2000);
//esp_deep_sleep_start();
//Serial.println("This will never be printed");
Serial.println("finished!");

}

void loop() {
take_pictures();
digitalWrite(33, LOW);// 亮
delay(100);
digitalWrite(33, HIGH);// 灭
delay(100);

delay(5000);
}


延时相机

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
// https://www.cnblogs.com/codeit/p/15580267.html

#include "esp_camera.h"
#include "FS.h"
#include <SPI.h>
#include <SD.h>
#include "SD_MMC.h"
#include <time.h>
#include <WiFi.h>
#include "string.h"

#include <WebServer.h>
// Set web server port number to 80
WebServer server(80);


const char* ntpServer = "cn.pool.ntp.org"; //pool.ntp.org为获取时间得接口,可以尝试更多得接口。比如微软的time.windows.com,美国国家标准与技术研究院的time.nist.gov
const long gmtOffset_sec = 8*60*60;//这里采用UTC计时,中国为东八区,就是 8*60*60
const int daylightOffset_sec = 0*60*60;

struct tm timeinfo; //创建一个结构体用于存储时间
char * path = "/2020_6_18_TIME_19_0_47.jpg";
char timr_str[40] = "test.jpg";

/*
*******************
***** 网络部分 *****
*******************
*/

//以下是WIFI的链接用户名和密码
#define ssid "MERCURY"
#define password "11235813"
// 网络链接
void connectToNetwork(){
WiFi.begin(ssid,password);
WiFi.setAutoReconnect(true);
while (WiFi.status()!= WL_CONNECTED) {
delay(1000);
Serial.println("try to connecting ...");
}
Serial.println("Connectedto network");
}

void wifi_connect(){
connectToNetwork();//链接到wifi
Serial.println(WiFi.macAddress()); //打印出mac地址
Serial.println(WiFi.localIP()); //打印出本地ip地址
Serial.println("wifi连接成功"); //打印出本地ip地址
}

/*
***************************
***** 摄像头初始化参数 *****
***************************
*/

static camera_config_t camera_config = {
.pin_pwdn = 32,
.pin_reset = -1,
.pin_xclk = 0,
.pin_sscb_sda = 26,
.pin_sscb_scl = 27,

.pin_d7 = 35,
.pin_d6 = 34,
.pin_d5 = 39,
.pin_d4 = 36,
.pin_d3 = 21,
.pin_d2 = 19,
.pin_d1 = 18,
.pin_d0 = 5,
.pin_vsync = 25,
.pin_href = 23,
.pin_pclk = 22,

.xclk_freq_hz = 20000000,
.ledc_timer = LEDC_TIMER_0,
.ledc_channel = LEDC_CHANNEL_0,

.pixel_format = PIXFORMAT_JPEG, //YUV422,GRAYSCALE,RGB565,JPEG
.frame_size = FRAMESIZE_UXGA, // FRAMESIZE_ + QVGA|CIF|VGA|SVGA|XGA|SXGA|UXGA

.jpeg_quality = 10, //0-63 lower number means higher quality
.fb_count = 1 //if more than one, i2s runs in continuous mode. Use only with JPEG

};

esp_err_t camera_init() {
//initialize the camera
esp_err_t err = esp_camera_init(&camera_config);
if (err != ESP_OK) {
Serial.print("Camera Init Failed");
return err;
}
sensor_t * s = esp_camera_sensor_get();
//initial sensors are flipped vertically and colors are a bit saturated
if (s->id.PID == OV2640_PID) {
// s->set_vflip(s, 1);//flip it back
// s->set_brightness(s, 1);//up the blightness just a bit
// s->set_contrast(s, 1);
}
Serial.print("Camera Init OK");
return ESP_OK;
}

/*
***************************
***** SD卡路径操作函数 *****
**** 列出路径,创建路径,删除路径******
***************************
*/

// 列出路径
void listDir(fs::FS &fs, const char * dirname, uint8_t levels){
Serial.printf("Listing directory: %s\n", dirname);

File root = fs.open(dirname);
if(!root){
Serial.println("Failed to open directory");
return;
}
if(!root.isDirectory()){
Serial.println("Not a directory");
return;
}

File file = root.openNextFile();
while(file){
if(file.isDirectory()){
Serial.print(" DIR : ");
Serial.print (file.name());
time_t t= file.getLastWrite();
struct tm * tmstruct = localtime(&t);
Serial.printf(" LAST WRITE: %d-%02d-%02d %02d:%02d:%02d\n",(tmstruct->tm_year)+1900,( tmstruct->tm_mon)+1, tmstruct->tm_mday,tmstruct->tm_hour , tmstruct->tm_min, tmstruct->tm_sec);
if(levels){
listDir(fs, file.name(), levels -1);
}
} else {
Serial.print(" FILE: ");
Serial.print(file.name());
Serial.print(" SIZE: ");
Serial.print(file.size());
time_t t= file.getLastWrite();
struct tm * tmstruct = localtime(&t);
Serial.printf(" LAST WRITE: %d-%02d-%02d %02d:%02d:%02d\n",(tmstruct->tm_year)+1900,( tmstruct->tm_mon)+1, tmstruct->tm_mday,tmstruct->tm_hour , tmstruct->tm_min, tmstruct->tm_sec);
}
file = root.openNextFile();
}
}

/*
***************************
***** SD卡初始化参数 *****
***************************
*/

void sd_init()
{
if(!SD_MMC.begin()){
Serial.println("Card Mount Failed");
return;
}
uint8_t cardType = SD_MMC.cardType();
if(cardType == CARD_NONE){
Serial.println("No SD card attached");
return;
}
Serial.print("SD Card Type: ");
if(cardType == CARD_MMC){
Serial.println("MMC");
}
else if(cardType == CARD_SD){ Serial.println("SDSC"); }
else if(cardType == CARD_SDHC){ Serial.println("SDHC"); }
else { Serial.println("UNKNOWN"); }

uint64_t cardSize = SD_MMC.cardSize() / (1024 * 1024); //获取SD卡大小,大小单位是MB
Serial.printf("SD 卡容量大小: %lluMB\n", cardSize);

//*************** 调用SD卡的 路径操作函数 **********************************************************************
Serial.println("现在列出目前SD卡内部根目录下所有的路径:");
listDir(SD_MMC, "/", 0);
}

/*
***************************
***** 获取当前时间作为返回的函数部分 *****
***************************
*/

void get_time_path() //获取目前时间返回字符串
{
memset(timr_str, 0, sizeof(timr_str));
configTime(gmtOffset_sec, daylightOffset_sec, ntpServer);
if(!getLocalTime(&timeinfo))
{
Serial.println("Failed to obtain time");
sprintf(timr_str, "/TIME_get_failed.jpg");
}
else
{
//Serial.println(&timeinfo, "%A, %B %d %Y %H:%M:%S");
Serial.print("现在时间是:");
// Serial.print("年份是:");Serial.println(timeinfo.tm_year + 1900);
// Serial.print("月份是:");Serial.println(timeinfo.tm_mon + 1);
// Serial.print("号数是:");Serial.println(timeinfo.tm_mday);
// Serial.print("小时数是:");Serial.println(timeinfo.tm_hour ); //中国区
// Serial.print("分钟数是:");Serial.println(timeinfo.tm_min);
// Serial.print("秒数是:");Serial.println(timeinfo.tm_sec);

sprintf(timr_str, "/%d_%d_%d_TIME_%d_%d_%d.jpg",timeinfo.tm_year+1900,timeinfo.tm_mon + 1,timeinfo.tm_mday,timeinfo.tm_hour,timeinfo.tm_min,timeinfo.tm_sec);
Serial.println(timr_str);
}
}

/*
***************************
***** webserver *****
***************************
*/

void handle_OnConnect() {

server.send(200, "text/html", SendHTML(timr_str));
}

void handle_NotFound(){
server.send(404, "text/plain", "Not found");
}


void webserver_init(){
server.on("/", handle_OnConnect);
server.onNotFound(handle_NotFound);

server.begin();
Serial.println("HTTP server started");
}


/*
***************************
***** 主函数部分 *****
***************************
*/
void setup() {
Serial.begin(115200);
wifi_connect();
camera_init(); //摄像头初始化
sd_init(); //SD卡初始化
webserver_init();
}


void loop()
{
delay(1000); // 1 000 ms
get_time_path();

server.handleClient();

//拍照并且把图片保存到SD卡当中,而照片名字就保存为目前的时间
// delay(60000); // 延时摄影,时间间隔:60 000 ms
while (timeinfo.tm_sec == 0)
{
delay(1000); // 1 000 ms
get_time_path();

if (timeinfo.tm_min == 30) // 整点重启
{

Serial.println("Resetting ESP");
ESP.restart(); //ESP.reset();
}
else // 非整点拍照
{
Serial.println("即将进行拍照!!!");
camera_fb_t * fb = esp_camera_fb_get();
// get_time_path();
Serial.print("存入的图片名称为:");Serial.println(timr_str);
path = timr_str;
if(fb == NULL)
{
Serial.println( "get picture failed"); //代表获取图片失败
}
else
{
//char * path = time_str;
fs::FS &fs = SD_MMC;
Serial.printf("Writing file: %s\n", path);
File file = fs.open(path, FILE_WRITE);
if (!file)
{
Serial.println("文件创建失败");
}
else
{
file.write(fb->buf , fb->len); //payload , lengte vd payload
Serial.println("成功写入照片");
}
//return the frame buffer back to the driver for reuse
esp_camera_fb_return(fb);
}
}
}// while 结束
}




String SendHTML(char* timr_str){
String ptr = "<!DOCTYPE html> <html>\n";
ptr +="<head><meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0, user-scalable=no\">\n";
ptr +="<title>ESP32CAM STATUS</title>\n";
ptr +="<style>html { font-family: Helvetica; display: inline-block; margin: 0px auto; text-align: center;}\n";
ptr +="body{margin-top: 50px;} h1 {color: #444444;margin: 50px auto 30px;}\n";
ptr +="p {font-size: 24px;color: #444444;margin-bottom: 10px;}\n";
ptr +="</style>\n";
ptr +="</head>\n";
ptr +="<body>\n";
ptr +="<div id=\"webpage\">\n";
ptr +="<h1>ESP32CAM PIC INFOMATION</h1>\n";

ptr +="<p>TIME: ";
ptr +=timr_str;


// ptr +="<p>Pressure: ";
// ptr +=pressure;
//
// ptr +="<p>Altitude: ";
// ptr +=altitude;

ptr +="</div>\n";
ptr +="</body>\n";
ptr +="</html>\n";
return ptr;
}

公网映射监控

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
#include "esp_camera.h"
#include <WiFi.h>

const char* ssid = "xxxxxxxx";
const char* password = "xxxxxxxxx";

#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

WiFiServer server(80);
bool connected = false;
WiFiClient live_client;


String index_html = "<meta charset=\"utf-8\"/>\n" \
"<style>\n" \
"#content {\n" \
"display: flex;\n" \
"flex-direction: column;\n" \
"justify-content: center;\n" \
"align-items: center;\n" \
"text-align: center;\n" \
"min-height: 100vh;}\n" \
"</style>\n" \
"<body bgcolor=\"#000000\"><div id=\"content\"><h2 style=\"color:#ffffff\">Murphy LIVE</h2><img src=\"video\"></div></body>";

void configCamera(){
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_QVGA;
config.jpeg_quality = 9;
config.fb_count = 1;

esp_err_t err = esp_camera_init(&config);
if (err != ESP_OK) {
Serial.printf("Camera init failed with error 0x%x", err);
return;
}
}

//continue sending camera frame
void liveCam(WiFiClient &client){
camera_fb_t * fb = esp_camera_fb_get();
if (!fb) {
Serial.println("Frame buffer could not be acquired");
return;
}
client.print("--frame\n");
client.print("Content-Type: image/jpeg\n\n");
client.flush();
client.write(fb->buf, fb->len);
client.flush();
client.print("\n");
esp_camera_fb_return(fb);
}

void setup() {
Serial.begin(115200);
WiFi.begin(ssid, password);
Serial.println("");
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println("");
String IP = WiFi.localIP().toString();
Serial.println("IP address: " + IP);
index_html.replace("server_ip", IP);
server.begin();
configCamera();
}

void http_resp(){
WiFiClient client = server.available();
if (client.connected()) {
String req = "";
while(client.available()){
req += (char)client.read();
}
Serial.println("request " + req);
int addr_start = req.indexOf("GET") + strlen("GET");
int addr_end = req.indexOf("HTTP", addr_start);
if (addr_start == -1 || addr_end == -1) {
Serial.println("Invalid request " + req);
return;
}
req = req.substring(addr_start, addr_end);
req.trim();
Serial.println("Request: " + req);
client.flush();

String s;
if (req == "/")
{
s = "HTTP/1.1 200 OK\n";
s += "Content-Type: text/html\n\n";
s += index_html;
s += "\n";
client.print(s);
client.stop();
}
else if (req == "/video")
{
live_client = client;
live_client.print("HTTP/1.1 200 OK\n");
live_client.print("Content-Type: multipart/x-mixed-replace; boundary=frame\n\n");
live_client.flush();
connected = true;
}
else
{
s = "HTTP/1.1 404 Not Found\n\n";
client.print(s);
client.stop();
}
}
}

void loop() {
http_resp();
if(connected == true){
liveCam(live_client);
}
}


ESP32CAM延时相机
https://cosmicdusty.cc/post/Ideas/ESP32CAMTimeLapseCamera/
作者
Murphy
发布于
2022年10月2日
许可协议